<commit_before>//===- Hello.cpp - Example code from "Writing an LLVM Pass" ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements two versions of the LLVM "Hello World" pass described
// in docs/WritingAnLLVMPass.html
//
//===----------------------------------------------------------------------===//

#include <map>
#include <utility>
#include <set>
#include <vector>
#include <memory>
#include <fstream>

#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/CallSite.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;
using namespace std;

#define DEBUG_TYPE "CGRAPH"
#define ENTRY_FUNC "main"

namespace {

  struct cgraph : public ModulePass {
    static char ID; // Pass identification, replacement for typeid
    cgraph() : ModulePass(ID) {}

    typedef map<Value *, Value *> VariableStore;
    typedef shared_ptr<VariableStore> VariableStore_Ptr;
    typedef pair<BasicBlock *, VariableStore_Ptr> WorkListItem;
    typedef shared_ptr<WorkListItem> WorkListItem_Ptr;
    typedef map<Function *, set<Value*> > CallGraphResult;

  private:
    vector<Function *> functions;
    Function *mainFn = NULL;
    StringRef module_name;

    bool runOnModule(Module &M) override {
      for (Function &Func: M) {
        functions.push_back(&Func);
      }

      // TODO: collect the call graph
      Function *mainFn = M.getFunction(ENTRY_FUNC);
      if (!mainFn) {
        errs() << "No main function defined\n";
        return false;
      }

      CallGraphResult resultMap;
      VariableStore gmap;
      VariableStore lmap;
      map<Function *, int> status;

      collectCallGraph(*mainFn, resultMap, gmap, lmap, status);

      // for (Function* f : functions) {
      //   lmap.clear();
      //   status.clear();
      //   collectCallGraph(*f, resultMap, gmap, lmap, status);
      // }

      // dump the call graph
      dumpCallGraph(resultMap);

      return false;
    }

    bool doInitialization(Module &M) {
      // errs() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
      // errs() << "Call Graph pass to initialization\n";
      // errs() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
      module_name = M.getName();
      return false;
    }

    bool isGlobal(Value *v) {
      if (isa<GlobalVariable>(v))
        return true;

      if (GEPOperator *gepOp = dyn_cast<GEPOperator>(v)) {
        if (isa<GlobalVariable>(gepOp->getPointerOperand())){
          return true;
        }
      }

      return false;
    }

    /***
     * how to get elements of a struct initializer
     *  - GlobalVariable::hasInitilizer()
     *  - GlobalVariable::getInitilizer() returns a Constant pointer
     *    How can we get individual parts of the initializer?
     */
    void collectCallGraph(Function &func, CallGraphResult &result,
                          VariableStore &globalMap, VariableStore &localMap,
                          map<Function *, int> &status) {

      // errs() << "~~~ Start handling " << func.getName() << " ~~~\n";
      if (func.isDeclaration()) {
        errs() << func.getName() << " is just a declaration, skipping\n";
        return;
      }

      if (status.find(&func) != status.end() && status[&func] == 1) {
        errs() << "recursion detected\n";
        return;
      }

      status[&func] = 1;
      vector<WorkListItem_Ptr> worklist;
      set<BasicBlock *> visited;

      if (result.find(&func) == result.end()) {
        result[&func] = set<Value *>();
      }
      // worklist algorithm
      BasicBlock *entryBlock = &func.getEntryBlock();
      VariableStore_Ptr initStore = VariableStore_Ptr(new VariableStore(localMap));
      WorkListItem_Ptr initItem = WorkListItem_Ptr(new WorkListItem(entryBlock, initStore));
      worklist.push_back(initItem);

      while (!worklist.empty()) {
        // extract an unexplored path
        WorkListItem_Ptr item = worklist.back();
        worklist.pop_back();
        BasicBlock *bb1 = item->first;
        VariableStore_Ptr p_VariableStore = item->second;
        BasicBlock *nextBlk = NULL;

        while (true) {

          nextBlk = NULL;

          for (Instruction &inst: *bb1) {

            switch (inst.getOpcode()) {
            case Instruction::Call: {
              // errs() << "Handling call instruction\n";
              CallSite cs(&inst);

              Value* called = cs.getCalledValue()->stripPointerCasts();
              // errs() << "called:" << *called << "\n";
              Function *f = dyn_cast<Function>(called);
              if (!f){
                // indirect call
                Value *lv = NULL;
                if (isGlobal(called)) {
                  // errs() << "called is global\n";
                  if (globalMap.find(called) == globalMap.end()) {
                    errs() << "Could not find the calle function\n";
                  } else {
                    lv = globalMap[called];
                  }
                } else {
                  // errs() << "called is local\n";
                  if (p_VariableStore->find(called) == p_VariableStore->end()) {
                    errs() << "Could not find the calle function\n";
                  } else {
                    lv = (*p_VariableStore)[called];
                  }
                }

                if (lv == NULL) {
                  errs() << "lv: is NULL\n";
                } else {
                  f = dyn_cast<Function>(lv);
                  if (!f) {
                    errs() << "called destination is not a function " <<  *lv <<  "\n";
                    // exit here
                  }
                }
              }

              if (f != NULL) {
                // add it to the called functions
                result[&func].insert(f);

                VariableStore lm;
                int i = 0;
                // construct the arg map;
                for (Function::arg_iterator it = f->arg_begin(); it != f->arg_end(); it++) {
                  // lm[&(*it)] = cs.getArgOperand(i++);
                  // bind args
                  // TODO: var arg support

                  // errs() << "it:" << *it << "\n";
                  Value *v = cs.getArgOperand(i++);

                  if (ConstantExpr *ce = dyn_cast<ConstantExpr>(v)) {
                    if (ce->getOpcode() == Instruction::BitCast)
                      v = ce->getOperand(0);
                  }
                  // errs() << "v:" << *v << "\n";

                  if (isa<Function>(v)) {
                    // errs() << "==== Function\n";
                    lm[&(*it)] = v;
                  } else if (isGlobal(v)) {
                    // errs() << "==== from global store\n";
                    lm[&(*it)] = globalMap[v];
                  } else {
                    // errs() << "==== Not from global store\n";
                    lm[&(*it)] = (*p_VariableStore)[v];
                  }
                }
                // FIXME: recursive functions
                collectCallGraph(*f, result, globalMap, lm, status);
              }

              break;
            }

            case Instruction::Br: {
              // the end of a basic block
              // i.e. there should be no Instruction after this
              BranchInst *branchInst = dyn_cast<BranchInst>(&inst);
              if (branchInst->isUnconditional()) {
                nextBlk = branchInst->getSuccessor(0);
              } else {
                // very important part
                BasicBlock *b0 = branchInst->getSuccessor(0);
                BasicBlock *b1 = branchInst->getSuccessor(1);

                // handle branch instruction only if its successors
                // are not visited
                if (visited.find(b0) == visited.end() &&
                    visited.find(b1) == visited.end()) {
                  nextBlk = b0;

                  VariableStore_Ptr tmp_vs_p = VariableStore_Ptr(new VariableStore(*p_VariableStore));
                  worklist.push_back(WorkListItem_Ptr(new WorkListItem(b1, tmp_vs_p)));

                  // mark them as visited
                  visited.insert(b0);
                  visited.insert(b1);
                }
              }
              break;
            }

            case Instruction::Switch: {

              break;
            }

            case Instruction::Load: {
              LoadInst *loadInst = dyn_cast<LoadInst>(&inst);
              Value *src = loadInst->getOperand(0);

              if (isGlobal(src)) {
                (*p_VariableStore)[loadInst] = globalMap[src];
              } else {
                (*p_VariableStore)[loadInst] = (*p_VariableStore)[src];
              }

              // errs() << "load src:"<< *src << "==> " << *(*p_VariableStore)[loadInst] << "\n";

              break;
            }

            case Instruction::Store: {

              StoreInst *storeInst = dyn_cast<StoreInst>(&inst);
              Value *from = storeInst->getOperand(0);
              Value *to = storeInst->getOperand(1);

              // errs() << "from:" << *from << "\n";
              // errs() << "to:" << *to << "\n";
              if (isa<Constant>(from)) {
                // errs() << "from is constant\n";
                if (ConstantExpr *ce = dyn_cast<ConstantExpr>(from)) {
                  // we are only interested in function pointers
                  if (ce->getOpcode() == Instruction::BitCast) {
                    // ugly code
                    if (isGlobal(to)) {
                      // errs() << "to is global\n";
                      globalMap[to] =  ce->getOperand(0);
                    } else {
                      // errs() << "to is local, " << *to <<" -> " <<  *(ce->getOperand(0)) <<"\n";
                      (*p_VariableStore)[to] = ce->getOperand(0);
                    }
                  }
                }
              } else {
                // errs() << "from is not constant\n";
                // it is an indirect store
                if (isGlobal(to)) {
                  // errs() << "to is global\n";
                  if (isGlobal(from)) {

                    // errs() << "from is global\n";
                    // TODO: refractor this part
                    if (globalMap.find(from) != globalMap.end()) {
                      globalMap[to] = globalMap[from];
                    } else {
                      errs() << "No corresponding mapping for:" << *from << "\n";
                    }
                  } else {
                    // errs() << "from is local\n";
                    globalMap[to] = (*p_VariableStore)[from];
                  }

                } else {
                  // errs() << "to is local\n";
                  if (isGlobal(from)) {
                    // errs() << "from is global\n";
                    (*p_VariableStore)[to] = globalMap[from];
                  } else {
                    // errs() << "from is local\n";
                    (*p_VariableStore)[to] = (*p_VariableStore)[from];
                  }
                }
              }

              break;
            }
            default:

              break;
            }
          }

          if (nextBlk == NULL) {
            break;
          }

          bb1 = nextBlk;
        }
      }

      status[&func] = 2;
      // errs() << "=== End handling " << func.getName() << " ===\n";
    }

    void dumpCallGraph(CallGraphResult &result) {
      ofstream dotfile;
      dotfile.open(module_name.str() +  "_callgraph.dot", ios::out | ios::trunc);

      dotfile << "digraph callgraph {" << endl;
      for (CallGraphResult::iterator it = result.begin(); it != result.end(); it ++) {
        errs() << it->first->getName() << ":";

        for (set<Value *>::iterator its = it->second.begin(); its != it->second.end(); its ++) {
          if (Function *f = dyn_cast<Function>(*its)) {
             errs() << f->getName() << ",";
             dotfile << "\t" << it->first->getName().str() << " -> " << f->getName().str() << ";" << endl;
             continue;
          }

          if (ConstantExpr *ce = dyn_cast<ConstantExpr>(*its)) {
            errs() << *ce << ",";
          } else {
            errs() << "N/A,";
          }
        }

        errs() << "\n";
      }

      dotfile << "}" << endl;
      errs() << "Call graph dot file was written to " << module_name << "_callgraph.dot\n";

      dotfile.close();
    }

    bool doFinalization(Module & M) {
      return false;
    }

    // We don't modify the program, so we preserve all analyses.
    void getAnalysisUsage(AnalysisUsage &AU) const override {
      AU.setPreservesAll();
    }
  };
}

char cgraph::ID = 0;
static RegisterPass<cgraph> CGRAPH("cgraph", "Call Graph Pass");
<commit_msg>Fix the possible . in the nodes of the graph<commit_after>//===- Hello.cpp - Example code from "Writing an LLVM Pass" ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements two versions of the LLVM "Hello World" pass described
// in docs/WritingAnLLVMPass.html
//
//===----------------------------------------------------------------------===//

#include <map>
#include <utility>
#include <set>
#include <vector>
#include <memory>
#include <fstream>
#include <string>
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/CallSite.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;
using namespace std;

#define DEBUG_TYPE "CGRAPH"
#define ENTRY_FUNC "main"

namespace {

  struct cgraph : public ModulePass {
    static char ID; // Pass identification, replacement for typeid
    cgraph() : ModulePass(ID) {}

    typedef map<Value *, Value *> VariableStore;
    typedef shared_ptr<VariableStore> VariableStore_Ptr;
    typedef pair<BasicBlock *, VariableStore_Ptr> WorkListItem;
    typedef shared_ptr<WorkListItem> WorkListItem_Ptr;
    typedef map<Function *, set<Value*> > CallGraphResult;

  private:
    vector<Function *> functions;
    Function *mainFn = NULL;
    StringRef module_name;

    bool runOnModule(Module &M) override {
      for (Function &Func: M) {
        functions.push_back(&Func);
      }

      // TODO: collect the call graph
      Function *mainFn = M.getFunction(ENTRY_FUNC);
      if (!mainFn) {
        errs() << "No main function defined\n";
        return false;
      }

      CallGraphResult resultMap;
      VariableStore gmap;
      VariableStore lmap;
      map<Function *, int> status;

      collectCallGraph(*mainFn, resultMap, gmap, lmap, status);

      // for (Function* f : functions) {
      //   lmap.clear();
      //   status.clear();
      //   collectCallGraph(*f, resultMap, gmap, lmap, status);
      // }

      // dump the call graph
      dumpCallGraph(resultMap);

      return false;
    }

    bool doInitialization(Module &M) {
      // errs() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
      // errs() << "Call Graph pass to initialization\n";
      // errs() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
      module_name = M.getName();
      return false;
    }

    bool isGlobal(Value *v) {
      if (isa<GlobalVariable>(v))
        return true;

      if (GEPOperator *gepOp = dyn_cast<GEPOperator>(v)) {
        if (isa<GlobalVariable>(gepOp->getPointerOperand())){
          return true;
        }
      }

      return false;
    }

    /***
     * how to get elements of a struct initializer
     *  - GlobalVariable::hasInitilizer()
     *  - GlobalVariable::getInitilizer() returns a Constant pointer
     *    How can we get individual parts of the initializer?
     */
    void collectCallGraph(Function &func, CallGraphResult &result,
                          VariableStore &globalMap, VariableStore &localMap,
                          map<Function *, int> &status) {

      // errs() << "~~~ Start handling " << func.getName() << " ~~~\n";
      if (func.isDeclaration()) {
        errs() << func.getName() << " is just a declaration, skipping\n";
        return;
      }

      if (status.find(&func) != status.end() && status[&func] == 1) {
        errs() << "recursion detected\n";
        return;
      }

      status[&func] = 1;
      vector<WorkListItem_Ptr> worklist;
      set<BasicBlock *> visited;

      if (result.find(&func) == result.end()) {
        result[&func] = set<Value *>();
      }
      // worklist algorithm
      BasicBlock *entryBlock = &func.getEntryBlock();
      VariableStore_Ptr initStore = VariableStore_Ptr(new VariableStore(localMap));
      WorkListItem_Ptr initItem = WorkListItem_Ptr(new WorkListItem(entryBlock, initStore));
      worklist.push_back(initItem);

      while (!worklist.empty()) {
        // extract an unexplored path
        WorkListItem_Ptr item = worklist.back();
        worklist.pop_back();
        BasicBlock *bb1 = item->first;
        VariableStore_Ptr p_VariableStore = item->second;
        BasicBlock *nextBlk = NULL;

        while (true) {

          nextBlk = NULL;

          for (Instruction &inst: *bb1) {

            switch (inst.getOpcode()) {
            case Instruction::Call: {
              // errs() << "Handling call instruction\n";
              CallSite cs(&inst);

              Value* called = cs.getCalledValue()->stripPointerCasts();
              // errs() << "called:" << *called << "\n";
              Function *f = dyn_cast<Function>(called);
              if (!f){
                // indirect call
                Value *lv = NULL;
                if (isGlobal(called)) {
                  // errs() << "called is global\n";
                  if (globalMap.find(called) == globalMap.end()) {
                    errs() << "Could not find the calle function\n";
                  } else {
                    lv = globalMap[called];
                  }
                } else {
                  // errs() << "called is local\n";
                  if (p_VariableStore->find(called) == p_VariableStore->end()) {
                    errs() << "Could not find the calle function\n";
                  } else {
                    lv = (*p_VariableStore)[called];
                  }
                }

                if (lv == NULL) {
                  errs() << "lv: is NULL\n";
                } else {
                  f = dyn_cast<Function>(lv);
                  if (!f) {
                    errs() << "called destination is not a function " <<  *lv <<  "\n";
                    // exit here
                  }
                }
              }

              if (f != NULL) {
                // add it to the called functions
                result[&func].insert(f);

                VariableStore lm;
                int i = 0;
                // construct the arg map;
                for (Function::arg_iterator it = f->arg_begin(); it != f->arg_end(); it++) {
                  // lm[&(*it)] = cs.getArgOperand(i++);
                  // bind args
                  // TODO: var arg support

                  // errs() << "it:" << *it << "\n";
                  Value *v = cs.getArgOperand(i++);

                  if (ConstantExpr *ce = dyn_cast<ConstantExpr>(v)) {
                    if (ce->getOpcode() == Instruction::BitCast)
                      v = ce->getOperand(0);
                  }
                  // errs() << "v:" << *v << "\n";

                  if (isa<Function>(v)) {
                    // errs() << "==== Function\n";
                    lm[&(*it)] = v;
                  } else if (isGlobal(v)) {
                    // errs() << "==== from global store\n";
                    lm[&(*it)] = globalMap[v];
                  } else {
                    // errs() << "==== Not from global store\n";
                    lm[&(*it)] = (*p_VariableStore)[v];
                  }
                }
                // FIXME: recursive functions
                collectCallGraph(*f, result, globalMap, lm, status);
              }

              break;
            }

            case Instruction::Br: {
              // the end of a basic block
              // i.e. there should be no Instruction after this
              BranchInst *branchInst = dyn_cast<BranchInst>(&inst);
              if (branchInst->isUnconditional()) {
                nextBlk = branchInst->getSuccessor(0);
              } else {
                // very important part
                BasicBlock *b0 = branchInst->getSuccessor(0);
                BasicBlock *b1 = branchInst->getSuccessor(1);

                // handle branch instruction only if its successors
                // are not visited
                if (visited.find(b0) == visited.end() &&
                    visited.find(b1) == visited.end()) {
                  nextBlk = b0;

                  VariableStore_Ptr tmp_vs_p = VariableStore_Ptr(new VariableStore(*p_VariableStore));
                  worklist.push_back(WorkListItem_Ptr(new WorkListItem(b1, tmp_vs_p)));

                  // mark them as visited
                  visited.insert(b0);
                  visited.insert(b1);
                }
              }
              break;
            }

            case Instruction::Switch: {

              break;
            }

            case Instruction::Load: {
              LoadInst *loadInst = dyn_cast<LoadInst>(&inst);
              Value *src = loadInst->getOperand(0);

              if (isGlobal(src)) {
                (*p_VariableStore)[loadInst] = globalMap[src];
              } else {
                (*p_VariableStore)[loadInst] = (*p_VariableStore)[src];
              }

              // errs() << "load src:"<< *src << "==> " << *(*p_VariableStore)[loadInst] << "\n";

              break;
            }

            case Instruction::Store: {

              StoreInst *storeInst = dyn_cast<StoreInst>(&inst);
              Value *from = storeInst->getOperand(0);
              Value *to = storeInst->getOperand(1);

              // errs() << "from:" << *from << "\n";
              // errs() << "to:" << *to << "\n";
              if (isa<Constant>(from)) {
                // errs() << "from is constant\n";
                if (ConstantExpr *ce = dyn_cast<ConstantExpr>(from)) {
                  // we are only interested in function pointers
                  if (ce->getOpcode() == Instruction::BitCast) {
                    // ugly code
                    if (isGlobal(to)) {
                      // errs() << "to is global\n";
                      globalMap[to] =  ce->getOperand(0);
                    } else {
                      // errs() << "to is local, " << *to <<" -> " <<  *(ce->getOperand(0)) <<"\n";
                      (*p_VariableStore)[to] = ce->getOperand(0);
                    }
                  }
                }
              } else {
                // errs() << "from is not constant\n";
                // it is an indirect store
                if (isGlobal(to)) {
                  // errs() << "to is global\n";
                  if (isGlobal(from)) {

                    // errs() << "from is global\n";
                    // TODO: refractor this part
                    if (globalMap.find(from) != globalMap.end()) {
                      globalMap[to] = globalMap[from];
                    } else {
                      errs() << "No corresponding mapping for:" << *from << "\n";
                    }
                  } else {
                    // errs() << "from is local\n";
                    globalMap[to] = (*p_VariableStore)[from];
                  }

                } else {
                  // errs() << "to is local\n";
                  if (isGlobal(from)) {
                    // errs() << "from is global\n";
                    (*p_VariableStore)[to] = globalMap[from];
                  } else {
                    // errs() << "from is local\n";
                    (*p_VariableStore)[to] = (*p_VariableStore)[from];
                  }
                }
              }

              break;
            }
            default:

              break;
            }
          }

          if (nextBlk == NULL) {
            break;
          }

          bb1 = nextBlk;
        }
      }

      status[&func] = 2;
      // errs() << "=== End handling " << func.getName() << " ===\n";
    }

    void dumpCallGraph(CallGraphResult &result) {
      ofstream dotfile;
      dotfile.open(module_name.str() +  "_callgraph.dot", ios::out | ios::trunc);

      dotfile << "digraph callgraph {" << endl;
      for (CallGraphResult::iterator it = result.begin(); it != result.end(); it ++) {
        errs() << it->first->getName() << ":";

        for (set<Value *>::iterator its = it->second.begin(); its != it->second.end(); its ++) {
          if (Function *f = dyn_cast<Function>(*its)) {
	    string fname = it->first->getName().str();
	    string sname = it->first->getName().str();

	    if (fname.find(".") == fname::npos) {
	      fname = "\"" + fname + "\"";
	    }
	    if (sname.find(".") == sname::npos) {
	      sname = "\"" + sname + "\"";
	    }

             errs() << f->getName() << ",";
             dotfile << "\t" << fname << " -> " << sname << ";" << endl;
             continue;
          }

          if (ConstantExpr *ce = dyn_cast<ConstantExpr>(*its)) {
            errs() << *ce << ",";
          } else {
            errs() << "N/A,";
          }
        }

        errs() << "\n";
      }

      dotfile << "}" << endl;
      errs() << "Call graph dot file was written to " << module_name << "_callgraph.dot\n";

      dotfile.close();
    }

    bool doFinalization(Module & M) {
      return false;
    }

    // We don't modify the program, so we preserve all analyses.
    void getAnalysisUsage(AnalysisUsage &AU) const override {
      AU.setPreservesAll();
    }
  };
}

char cgraph::ID = 0;
static RegisterPass<cgraph> CGRAPH("cgraph", "Call Graph Pass");
<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "stdafx.h"

#include "diagnostics/assert.h"
#include "system/globalenv.h"

#include "store/naive/string_pool.h"
#include "store/naive/qname_pool.h"
#include "store/naive/atomic_items.h"
#include "store/naive/simple_store.h"
#include "store/naive/store_defs.h"
#include "store/naive/node_items.h"
#include "store/api/collection.h"
#include "zorbatypes/datetime.h"
#include "util/string_util.h"

namespace zorba { namespace simplestore {

/*******************************************************************************

********************************************************************************/
QNamePool::QNamePool(ulong size, StringPool* nspool)
  :
  theCache(new QNameItem[size]),
  theCacheSize(size),
  theFirstFree(1),
  theNumFree(size - 1),
  theHashSet(2 * size),
  theNamespacePool(nspool)
{
  // Put all the preallocated slots in the free list of the cahce.
  QNameItem* qn = &theCache[1];
  QNameItem* last = qn + size - 1;

  for (uint16_t i = 1; qn < last; qn++, i++)
  {
    qn->theNextFree = i + 1;
    qn->thePrevFree = i - 1;
    qn->thePosition = i;
  }
  (--qn)->theNextFree = 0;
}

/*******************************************************************************

********************************************************************************/
QNamePool::~QNamePool()
{
  csize n = theHashSet.theHashTab.size();
  for (csize i = 0; i < n; ++i)
  {
    if (!theHashSet.theHashTab[i].isFree() &&
        theHashSet.theHashTab[i].theItem->isOverflow())
      delete theHashSet.theHashTab[i].theItem;
  }

  if (theCache != NULL)
  {
    delete [] theCache;
    theCache = NULL;
  }
}

/*******************************************************************************

********************************************************************************/
void QNamePool::remove(QNameItem* qn)
{
  SYNC_CODE(AutoMutex lock(&theHashSet.theMutex);)

  if (qn->getRefCount() > 0 || hasNormalizingBackPointers(qn))
    return;

  if (qn->isInCache())
  {
    qn->theNextFree = (uint16_t)theFirstFree;
    theCache[theFirstFree].thePrevFree = qn->thePosition;
    theFirstFree = qn->thePosition;
    theNumFree++;
  }
  else
  {
    // If all the pointers to QNameItems were smart pointers, we could leave
    // qn in the pool, and let the pool garbage-collect it later (if it still
    // unused). If however QNameItems may be referenced by regular pointers as
    // well, then qn must be removed from the pool and really deleted
    QNameItem* normVictim = NULL;
    unregisterNormalizingBackPointer(qn, normVictim);
    theHashSet.eraseNoSync(qn);
    qn->invalidate();
    delete qn;

    if (normVictim)
    {
      // Tail call. Should avoid deadlock because no new stack frame.
      remove(normVictim);
    }
  }
}

store::Item_t QNamePool::insert(const char* ns,
                                const char* pre,
                                const char* ln,
                                bool        sync)
{
  return insert_internal(ns, pre, ln, sync);
}

store::Item_t QNamePool::insert(const zstring& ns,
                                const zstring& pre,
                                const zstring& ln,
                                bool        sync)
{
  return insert_internal(ns, pre, ln, sync);
}

/*******************************************************************************
  If the pool does not already contain a qname with the given namespace, prefix,
  and local name, then create such a qname, insert it in the pool and return an
  rchandle to it. Otherwise, return an rchandle to the existing qname.

  Note: The given namespace, prefix, and local name pointers may point to heap
  or stack allocated strings. If a qname is inserted, then the strings are
  copied internally into zstring objects. So, it's always the caller who is
  resposnible for freeing the given strings.
********************************************************************************/
QNameItem* QNamePool::insert_internal(
    const char* ns,
    const char* pre,
    const char* ln,
    bool        sync)
{
  QNameItem* qn;
  QNameItem* normVictim = NULL;
  SYNC_CODE(bool haveLock = false;)
  QNameItem* normQName = NULL;

  bool normalized = (pre == NULL || *pre == '\0');

  if (ns == NULL) ns = "";
  if (pre == NULL) pre = "";
  ZORBA_FATAL(ln != NULL && *ln != '\0', "");

  zstring pooledNs;
  theNamespacePool->insertc(ns, pooledNs);

  ulong hval = hashfun::h32(pre, hashfun::h32(ln, hashfun::h32(ns)));

  try
  {
retry:
    SYNC_CODE(theHashSet.theMutex.lock();\
    haveLock = true;)

    QNHashEntry* entry = hashFind(ns, pre, ln,
                                  (ulong)pooledNs.size(), (ulong)strlen(pre), (ulong)strlen(ln),
                                  hval);
    if (entry == 0)
    {
      if (normalized)
      {
        // Build a new QName (either new object or in cache).
        qn = cacheInsert(normVictim);
        qn->initializeAsNormalizedQName(pooledNs, zstring(ln));
      }
      else
      {
        if (normQName == NULL)
        {
          SYNC_CODE(theHashSet.theMutex.unlock();\
          haveLock = false;)

          normQName = insert_internal(ns, NULL, ln, false);

          goto retry;
        }
        // Build a new QName (either new object or in cache).
        qn = cacheInsert(normVictim);
        qn->initializeAsUnnormalizedQName(normQName, pre);
        registerNormalizingBackPointer(qn);
      }

      bool found;
      entry = theHashSet.hashInsert(qn, hval, found);
      entry->theItem = qn;
      ZORBA_FATAL(!found, "");
    }
    else
    {
      qn = entry->theItem;
      cachePin(qn);
    }

    SYNC_CODE(theHashSet.theMutex.unlock();\
    haveLock = false;)
  }
  catch (...)
  {
    SYNC_CODE(if (haveLock) \
      theHashSet.theMutex.unlock();)

    ZORBA_FATAL(0, "Unexpected exception");
  }

  if (normVictim)
  {
    remove(normVictim);
  }
  return qn;
}

/*******************************************************************************
  If the pool does not already contain a qname with the given namespace, prefix,
  and local name, then create such a qname, insert it in the pool and return an
  rchandle to it. Otherwise, return an rchandle to the existing qname.
********************************************************************************/
QNameItem* QNamePool::insert_internal(
    const zstring& ns,
    const zstring& pre,
    const zstring& ln,
    bool sync)
{
  QNameItem* qn = NULL;
  QNameItem* normVictim = NULL;
  SYNC_CODE(bool haveLock = false;)
  QNameItem* normQName = NULL;

  bool normalized = pre.empty();

  zstring pooledNs;
  theNamespacePool->insert(ns, pooledNs);

  ulong hval = hashfun::h32(pre.c_str(),
                            hashfun::h32(ln.c_str(),
                                         hashfun::h32(ns.c_str())));
  try
  {
retry:
    SYNC_CODE(theHashSet.theMutex.lock();\
    haveLock = true;)

    QNHashEntry* entry = hashFind(ns.c_str(), pre.c_str(), ln.c_str(),
                                  (ulong)ns.size(), (ulong)pre.size(), (ulong)ln.size(),
                                  hval);
    if (entry == 0)
    {
      if (normalized)
      {
        // Build a new QName (either new object or in cache).
        qn = cacheInsert(normVictim);
        qn->initializeAsNormalizedQName(pooledNs, ln);
      }
      else
      {
        if (normQName == NULL)
        {
          SYNC_CODE(theHashSet.theMutex.unlock();\
          haveLock = false;)

          // This call will need the lock.
          normQName = insert_internal(pooledNs, zstring(), ln, false);

          goto retry;
        }
        // Build a new QName (either new object or in cache).
        qn = cacheInsert(normVictim);
        qn->initializeAsUnnormalizedQName(normQName, pre);
        registerNormalizingBackPointer(qn);
      }

      bool found;
      entry = theHashSet.hashInsert(qn, hval, found);
      entry->theItem = qn;
      ZORBA_FATAL(!found, "");
    }
    else
    {
      qn = entry->theItem;
      cachePin(qn);
    }

    SYNC_CODE(theHashSet.theMutex.unlock();\
    haveLock = false;)
  }
  catch (...)
  {
  SYNC_CODE(  if (haveLock) \
      theHashSet.theMutex.unlock();)

    ZORBA_FATAL(0, "Unexpected exception");
  }

  if (normVictim)
  {
    remove(normVictim);
  }
  return qn;
}

/*******************************************************************************
  Return a qname slot for a new qname to be stored in. If the cache free list
  is not empty, we use the 1st slot from tha list; the qname currently in that
  slot (if any) is removed from the pool. If the cache free list is empty a new
  QNameItem is allocated from the heap.
********************************************************************************/
QNameItem* QNamePool::cacheInsert(QNameItem*& normVictim)
{
  assert (normVictim == NULL);
  if (theFirstFree != 0)
  {
    QNameItem* qn = &theCache[theFirstFree];

    theFirstFree = qn->theNextFree;
    theCache[theFirstFree].thePrevFree = 0;

    if (qn->isValid())
    {
      unregisterNormalizingBackPointer(qn, normVictim);
      ulong hval = CompareFunction::hash(qn);
      theHashSet.eraseNoSync(qn, hval);
      qn->invalidate();
    }

    qn->theNextFree = qn->thePrevFree = 0;

    theNumFree--;
    return qn;
  }
  else
  {
    return new QNameItem();
  }
}

/*******************************************************************************
  If the given qname slot is in the free list of the cache, remove it from that
  list.
********************************************************************************/
void QNamePool::cachePin(QNameItem* qn)
{
  if (qn->isInCache() && (qn->theNextFree != 0 || qn->thePrevFree != 0))
  {
    if (qn->theNextFree != 0)
      theCache[qn->theNextFree].thePrevFree = qn->thePrevFree;

    if (qn->thePrevFree != 0)
    {
      theCache[qn->thePrevFree].theNextFree = qn->theNextFree;
    }
    else if (theFirstFree == qn->thePosition)
    {
      theFirstFree = qn->theNextFree;
    }

    qn->theNextFree = qn->thePrevFree = 0;
    theNumFree--;
  }
}

/*******************************************************************************

********************************************************************************/
QNamePool::QNHashEntry* QNamePool::hashFind(
    const char* ns,
    const char* pre,
    const char* ln,
    ulong       nslen,
    ulong       prelen,
    ulong       lnlen,
    ulong       hval)
{
  QNHashEntry* entry = theHashSet.bucket(hval);

  if (entry->isFree())
    return NULL;

  while (entry != NULL)
  {
    QNameItem* qn = entry->theItem;

    if (ztd::equals(qn->getLocalName(), ln, lnlen) &&
        ztd::equals(qn->getNamespace(), ns, nslen) &&
        ztd::equals(qn->getPrefix(), pre, prelen))
      return entry;

    entry = entry->getNext();
  }

  return NULL;
}

bool QNamePool::hasNormalizingBackPointers(const QNameItem* aNormalizedQName) const
{
  std::map<const QNameItem*, std::set<const QNameItem*> >::const_iterator lIterator =
  theWhoNormalizesToMe.find(aNormalizedQName);
  return !lIterator->second.empty();
}

void QNamePool::registerNormalizingBackPointer(const QNameItem* aQName)
{
  if (!aQName->isNormalized())
  {
    theWhoNormalizesToMe[aQName->getNormalized()].insert(aQName);
  }
}

void QNamePool::unregisterNormalizingBackPointer(const QNameItem* aQName,
                                                 QNameItem*& normVictim)
{
  if (aQName->isNormalized())
  {
    return;
  }
  // Entry exists for this normalized QName.
  assert(theWhoNormalizesToMe.find(aQName->getNormalized())
         != theWhoNormalizesToMe.end());
  // Backpointer exists.
  assert(theWhoNormalizesToMe[aQName->getNormalized()].find(aQName)
         != theWhoNormalizesToMe[aQName->getNormalized()].end());

  std::set<const QNameItem*>& lSet =
      theWhoNormalizesToMe[aQName->getNormalized()];

  // Remove backpointer.
  lSet.erase(aQName);

  // Set normalization victim if the set is now empty.
  if (lSet.empty())
    normVictim = const_cast<QNameItem*>(aQName->getNormalized());
}

} // namespace store
} // namespace zorba

/* vim:set et sw=2 ts=2: */
<commit_msg>Added an assert.<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "stdafx.h"

#include "diagnostics/assert.h"
#include "system/globalenv.h"

#include "store/naive/string_pool.h"
#include "store/naive/qname_pool.h"
#include "store/naive/atomic_items.h"
#include "store/naive/simple_store.h"
#include "store/naive/store_defs.h"
#include "store/naive/node_items.h"
#include "store/api/collection.h"
#include "zorbatypes/datetime.h"
#include "util/string_util.h"

namespace zorba { namespace simplestore {

/*******************************************************************************

********************************************************************************/
QNamePool::QNamePool(ulong size, StringPool* nspool)
  :
  theCache(new QNameItem[size]),
  theCacheSize(size),
  theFirstFree(1),
  theNumFree(size - 1),
  theHashSet(2 * size),
  theNamespacePool(nspool)
{
  // Put all the preallocated slots in the free list of the cahce.
  QNameItem* qn = &theCache[1];
  QNameItem* last = qn + size - 1;

  for (uint16_t i = 1; qn < last; qn++, i++)
  {
    qn->theNextFree = i + 1;
    qn->thePrevFree = i - 1;
    qn->thePosition = i;
  }
  (--qn)->theNextFree = 0;
}

/*******************************************************************************

********************************************************************************/
QNamePool::~QNamePool()
{
  csize n = theHashSet.theHashTab.size();
  for (csize i = 0; i < n; ++i)
  {
    if (!theHashSet.theHashTab[i].isFree() &&
        theHashSet.theHashTab[i].theItem->isOverflow())
      delete theHashSet.theHashTab[i].theItem;
  }

  if (theCache != NULL)
  {
    delete [] theCache;
    theCache = NULL;
  }
}

/*******************************************************************************

********************************************************************************/
void QNamePool::remove(QNameItem* qn)
{
  SYNC_CODE(AutoMutex lock(&theHashSet.theMutex);)

  if (qn->getRefCount() > 0 || hasNormalizingBackPointers(qn))
    return;

  if (qn->isInCache())
  {
    qn->theNextFree = (uint16_t)theFirstFree;
    theCache[theFirstFree].thePrevFree = qn->thePosition;
    theFirstFree = qn->thePosition;
    theNumFree++;
  }
  else
  {
    // If all the pointers to QNameItems were smart pointers, we could leave
    // qn in the pool, and let the pool garbage-collect it later (if it still
    // unused). If however QNameItems may be referenced by regular pointers as
    // well, then qn must be removed from the pool and really deleted
    QNameItem* normVictim = NULL;
    unregisterNormalizingBackPointer(qn, normVictim);
    theHashSet.eraseNoSync(qn);
    qn->invalidate();
    delete qn;

    if (normVictim)
    {
      // Tail call. Should avoid deadlock because no new stack frame.
      remove(normVictim);
    }
  }
}

store::Item_t QNamePool::insert(const char* ns,
                                const char* pre,
                                const char* ln,
                                bool        sync)
{
  return insert_internal(ns, pre, ln, sync);
}

store::Item_t QNamePool::insert(const zstring& ns,
                                const zstring& pre,
                                const zstring& ln,
                                bool        sync)
{
  return insert_internal(ns, pre, ln, sync);
}

/*******************************************************************************
  If the pool does not already contain a qname with the given namespace, prefix,
  and local name, then create such a qname, insert it in the pool and return an
  rchandle to it. Otherwise, return an rchandle to the existing qname.

  Note: The given namespace, prefix, and local name pointers may point to heap
  or stack allocated strings. If a qname is inserted, then the strings are
  copied internally into zstring objects. So, it's always the caller who is
  resposnible for freeing the given strings.
********************************************************************************/
QNameItem* QNamePool::insert_internal(
    const char* ns,
    const char* pre,
    const char* ln,
    bool        sync)
{
  QNameItem* qn;
  QNameItem* normVictim = NULL;
  SYNC_CODE(bool haveLock = false;)
  QNameItem* normQName = NULL;

  bool normalized = (pre == NULL || *pre == '\0');

  if (ns == NULL) ns = "";
  if (pre == NULL) pre = "";
  ZORBA_FATAL(ln != NULL && *ln != '\0', "");

  zstring pooledNs;
  theNamespacePool->insertc(ns, pooledNs);

  ulong hval = hashfun::h32(pre, hashfun::h32(ln, hashfun::h32(ns)));

  try
  {
retry:
    SYNC_CODE(theHashSet.theMutex.lock();\
    haveLock = true;)

    QNHashEntry* entry = hashFind(ns, pre, ln,
                                  (ulong)pooledNs.size(), (ulong)strlen(pre), (ulong)strlen(ln),
                                  hval);
    if (entry == 0)
    {
      if (normalized)
      {
        // Build a new QName (either new object or in cache).
        qn = cacheInsert(normVictim);
        qn->initializeAsNormalizedQName(pooledNs, zstring(ln));
      }
      else
      {
        if (normQName == NULL)
        {
          SYNC_CODE(theHashSet.theMutex.unlock();\
          haveLock = false;)

          normQName = insert_internal(ns, NULL, ln, false);

          goto retry;
        }
        // Build a new QName (either new object or in cache).
        qn = cacheInsert(normVictim);
        qn->initializeAsUnnormalizedQName(normQName, pre);
        registerNormalizingBackPointer(qn);
      }

      bool found;
      entry = theHashSet.hashInsert(qn, hval, found);
      entry->theItem = qn;
      ZORBA_FATAL(!found, "");
    }
    else
    {
      qn = entry->theItem;
      cachePin(qn);
    }

    SYNC_CODE(theHashSet.theMutex.unlock();\
    haveLock = false;)
  }
  catch (...)
  {
    SYNC_CODE(if (haveLock) \
      theHashSet.theMutex.unlock();)

    ZORBA_FATAL(0, "Unexpected exception");
  }

  if (normVictim)
  {
    remove(normVictim);
  }
  return qn;
}

/*******************************************************************************
  If the pool does not already contain a qname with the given namespace, prefix,
  and local name, then create such a qname, insert it in the pool and return an
  rchandle to it. Otherwise, return an rchandle to the existing qname.
********************************************************************************/
QNameItem* QNamePool::insert_internal(
    const zstring& ns,
    const zstring& pre,
    const zstring& ln,
    bool sync)
{
  QNameItem* qn = NULL;
  QNameItem* normVictim = NULL;
  SYNC_CODE(bool haveLock = false;)
  QNameItem* normQName = NULL;

  bool normalized = pre.empty();

  zstring pooledNs;
  theNamespacePool->insert(ns, pooledNs);

  ulong hval = hashfun::h32(pre.c_str(),
                            hashfun::h32(ln.c_str(),
                                         hashfun::h32(ns.c_str())));
  try
  {
retry:
    SYNC_CODE(theHashSet.theMutex.lock();\
    haveLock = true;)

    QNHashEntry* entry = hashFind(ns.c_str(), pre.c_str(), ln.c_str(),
                                  (ulong)ns.size(), (ulong)pre.size(), (ulong)ln.size(),
                                  hval);
    if (entry == 0)
    {
      if (normalized)
      {
        // Build a new QName (either new object or in cache).
        qn = cacheInsert(normVictim);
        qn->initializeAsNormalizedQName(pooledNs, ln);
      }
      else
      {
        if (normQName == NULL)
        {
          SYNC_CODE(theHashSet.theMutex.unlock();\
          haveLock = false;)

          // This call will need the lock.
          normQName = insert_internal(pooledNs, zstring(), ln, false);

          goto retry;
        }
        // Build a new QName (either new object or in cache).
        qn = cacheInsert(normVictim);
        qn->initializeAsUnnormalizedQName(normQName, pre);
        registerNormalizingBackPointer(qn);
      }

      bool found;
      entry = theHashSet.hashInsert(qn, hval, found);
      entry->theItem = qn;
      ZORBA_FATAL(!found, "");
    }
    else
    {
      qn = entry->theItem;
      cachePin(qn);
    }

    SYNC_CODE(theHashSet.theMutex.unlock();\
    haveLock = false;)
  }
  catch (...)
  {
  SYNC_CODE(  if (haveLock) \
      theHashSet.theMutex.unlock();)

    ZORBA_FATAL(0, "Unexpected exception");
  }

  if (normVictim)
  {
    remove(normVictim);
  }
  return qn;
}

/*******************************************************************************
  Return a qname slot for a new qname to be stored in. If the cache free list
  is not empty, we use the 1st slot from tha list; the qname currently in that
  slot (if any) is removed from the pool. If the cache free list is empty a new
  QNameItem is allocated from the heap.
********************************************************************************/
QNameItem* QNamePool::cacheInsert(QNameItem*& normVictim)
{
  assert (normVictim == NULL);
  if (theFirstFree != 0)
  {
    QNameItem* qn = &theCache[theFirstFree];

    theFirstFree = qn->theNextFree;
    theCache[theFirstFree].thePrevFree = 0;

    if (qn->isValid())
    {
      unregisterNormalizingBackPointer(qn, normVictim);
      ulong hval = CompareFunction::hash(qn);
      theHashSet.eraseNoSync(qn, hval);
      qn->invalidate();
    }

    qn->theNextFree = qn->thePrevFree = 0;

    theNumFree--;
    return qn;
  }
  else
  {
    return new QNameItem();
  }
}

/*******************************************************************************
  If the given qname slot is in the free list of the cache, remove it from that
  list.
********************************************************************************/
void QNamePool::cachePin(QNameItem* qn)
{
  if (qn->isInCache() && (qn->theNextFree != 0 || qn->thePrevFree != 0))
  {
    if (qn->theNextFree != 0)
      theCache[qn->theNextFree].thePrevFree = qn->thePrevFree;

    if (qn->thePrevFree != 0)
    {
      theCache[qn->thePrevFree].theNextFree = qn->theNextFree;
    }
    else if (theFirstFree == qn->thePosition)
    {
      theFirstFree = qn->theNextFree;
    }

    qn->theNextFree = qn->thePrevFree = 0;
    theNumFree--;
  }
}

/*******************************************************************************

********************************************************************************/
QNamePool::QNHashEntry* QNamePool::hashFind(
    const char* ns,
    const char* pre,
    const char* ln,
    ulong       nslen,
    ulong       prelen,
    ulong       lnlen,
    ulong       hval)
{
  QNHashEntry* entry = theHashSet.bucket(hval);

  if (entry->isFree())
    return NULL;

  while (entry != NULL)
  {
    QNameItem* qn = entry->theItem;

    if (ztd::equals(qn->getLocalName(), ln, lnlen) &&
        ztd::equals(qn->getNamespace(), ns, nslen) &&
        ztd::equals(qn->getPrefix(), pre, prelen))
      return entry;

    entry = entry->getNext();
  }

  return NULL;
}

bool QNamePool::hasNormalizingBackPointers(const QNameItem* aNormalizedQName) const
{
  std::map<const QNameItem*, std::set<const QNameItem*> >::const_iterator lIterator =
  theWhoNormalizesToMe.find(aNormalizedQName);
  return !lIterator->second.empty();
}

void QNamePool::registerNormalizingBackPointer(const QNameItem* aQName)
{
  if (!aQName->isNormalized())
  {
    theWhoNormalizesToMe[aQName->getNormalized()].insert(aQName);
  }
}

void QNamePool::unregisterNormalizingBackPointer(const QNameItem* aQName,
                                                 QNameItem*& normVictim)
{
  assert (normVictim == NULL);
  if (aQName->isNormalized())
  {
    return;
  }
  // Entry exists for this normalized QName.
  assert(theWhoNormalizesToMe.find(aQName->getNormalized())
         != theWhoNormalizesToMe.end());
  // Backpointer exists.
  assert(theWhoNormalizesToMe[aQName->getNormalized()].find(aQName)
         != theWhoNormalizesToMe[aQName->getNormalized()].end());

  std::set<const QNameItem*>& lSet =
      theWhoNormalizesToMe[aQName->getNormalized()];

  // Remove backpointer.
  lSet.erase(aQName);

  // Set normalization victim if the set is now empty.
  if (lSet.empty())
    normVictim = const_cast<QNameItem*>(aQName->getNormalized());
}

} // namespace store
} // namespace zorba

/* vim:set et sw=2 ts=2: */
<|endoftext|>


<commit_before>//---------------------------------------------------------------------------//
/*
  Copyright (c) 2012, Stuart R. Slattery
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:

  *: Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.

  *: Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.

  *: Neither the name of the University of Wisconsin - Madison nor the
  names of its contributors may be used to endorse or promote products
  derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//---------------------------------------------------------------------------//
/*!
 * \brief DTK_ConsistentInterpolationOperator_impl.hpp
 * \author Stuart R. Slattery
 * \brief Consistent interpolation oprator.
 */
//---------------------------------------------------------------------------//

#ifndef DTK_CONSISTENTINTERPOLATIONOPERATOR_IMPL_HPP
#define DTK_CONSISTENTINTERPOLATIONOPERATOR_IMPL_HPP

#include <algorithm>
#include <unordered_set>
#include <unordered_map>

#include "DTK_DBC.hpp"
#include "DTK_ParallelSearch.hpp"
#include "DTK_BasicEntityPredicates.hpp"
#include "DTK_PredicateComposition.hpp"

#include <Teuchos_OrdinalTraits.hpp>

#include <Tpetra_Map.hpp>
#include <Tpetra_Distributor.hpp>

#include <Thyra_VectorSpaceBase.hpp>

#include <Thyra_TpetraThyraWrappers.hpp>
#include <Thyra_TpetraLinearOp.hpp>

namespace DataTransferKit
{
//---------------------------------------------------------------------------//
// Constructor.
template<class Scalar>
ConsistentInterpolationOperator<Scalar>::ConsistentInterpolationOperator(
    const Teuchos::RCP<const TpetraMap>& domain_map,
    const Teuchos::RCP<const TpetraMap>& range_map,
    const Teuchos::ParameterList& parameters )
    : Base( domain_map, range_map )
    , d_missed_range_entity_ids( 0 )
{
    // Get the search list.
    d_search_list = parameters.sublist( "Search" );
}

//---------------------------------------------------------------------------//
// Setup the map operator.
template<class Scalar>
void ConsistentInterpolationOperator<Scalar>::setup(
    const Teuchos::RCP<FunctionSpace>& domain_space,
    const Teuchos::RCP<FunctionSpace>& range_space )
{
    DTK_REQUIRE( Teuchos::nonnull(domain_space) );
    DTK_REQUIRE( Teuchos::nonnull(range_space) );

    // Extract the Support maps.
    const Teuchos::RCP<const typename Base::TpetraMap> domain_map
	= this->getDomainMap();
    const Teuchos::RCP<const typename Base::TpetraMap> range_map
	= this->getRangeMap();

    // Get the parallel communicator.
    Teuchos::RCP<const Teuchos::Comm<int> > comm = domain_map->getComm();

    // Determine if we have range and domain data on this process.
    bool nonnull_domain = Teuchos::nonnull( domain_space->entitySet() );
    bool nonnull_range = Teuchos::nonnull( range_space->entitySet() );

    // Get the physical dimension.
    int physical_dimension = 0;
    if ( nonnull_domain )
    {
	physical_dimension = domain_space->entitySet()->physicalDimension();
    }
    else if ( nonnull_range )
    {
	physical_dimension = range_space->entitySet()->physicalDimension();
    }

    // We will only operate on entities that are locally-owned.
    LocalEntityPredicate local_predicate( comm->getRank() );

    // Get an iterator over the domain entities.
    EntityIterator domain_iterator;
    if ( nonnull_domain )
    {
	PredicateFunction domain_predicate =
	    PredicateComposition::And(
		domain_space->selectFunction(),	local_predicate.getFunction() );
	domain_iterator = domain_space->entitySet()->entityIterator(
	    domain_space->entitySet()->physicalDimension(),
	    domain_predicate );
    }

    // Build a parallel search over the domain.
    ParallelSearch psearch( comm,
			    physical_dimension,
			    domain_iterator,
			    domain_space->localMap(),
			    d_search_list );

    // Get an iterator over the range entities.
    EntityIterator range_iterator;
    if ( nonnull_range )
    {
	PredicateFunction range_predicate =
	    PredicateComposition::And(
		range_space->selectFunction(), local_predicate.getFunction() );
	range_iterator =
	    range_space->entitySet()->entityIterator( 0, range_predicate );
    }

    // Search the domain with the range.
    psearch.search( range_iterator, range_space->localMap(), d_search_list );

    // If we are keeping track of range entities that were not mapped, extract
    // them.
    d_missed_range_entity_ids =
	Teuchos::Array<EntityId>( psearch.getMissedRangeEntityIds() );

    // Determine the Support ids for the range entities found in the local domain
    // on this process and the number of domain entities they were found in
    // globally for averaging.
    std::unordered_map<EntityId,GO> range_support_id_map;
    std::unordered_map<EntityId,GO> range_support_count_map;
    {
	// Extract the set of local range entities that were found in domain
	// entities.
	Teuchos::Array<int> export_ranks;
	Teuchos::Array<GO> export_data;
	Teuchos::Array<EntityId> domain_ids;
	Teuchos::Array<EntityId>::const_iterator domain_id_it;
	Teuchos::Array<GO> range_support_ids;
	EntityIterator range_it;
	EntityIterator range_begin = range_iterator.begin();
	EntityIterator range_end = range_iterator.end();
	for ( range_it = range_begin;
	      range_it != range_end;
	      ++range_it )
	{
	    psearch.getDomainEntitiesFromRange( range_it->id(), domain_ids );

	    for ( domain_id_it = domain_ids.begin();
		  domain_id_it != domain_ids.end();
		  ++domain_id_it )
	    {
		range_space->shapeFunction()->entitySupportIds(
		    *range_it, range_support_ids );
		DTK_CHECK( 1 == range_support_ids.size() );

		export_ranks.push_back(
		    psearch.domainEntityOwnerRank(*domain_id_it) );

		export_data.push_back( range_support_ids[0] );
		export_data.push_back(
		    Teuchos::as<GO>(range_it->id()) );
		export_data.push_back(
		    Teuchos::as<GO>(domain_ids.size()) );
	    }
	}

	// Communicate the range entity Support data back to the domain parallel
	// decomposition.
	Tpetra::Distributor range_to_domain_dist( comm );
	int num_import = range_to_domain_dist.createFromSends( export_ranks() );
	Teuchos::Array<GO> import_data( 3*num_import );
	Teuchos::ArrayView<const GO> export_data_view =
	    export_data();
	range_to_domain_dist.doPostsAndWaits( export_data_view,
					      3,
					      import_data() );

	// Map the range entities to their support ids.
	for ( int i = 0; i < num_import; ++i )
	{
	    range_support_id_map.insert(
		std::pair<EntityId,GO>(
		    Teuchos::as<EntityId>(import_data[3*i+1]),
		    import_data[3*i]) );
	    range_support_count_map.insert(
		std::pair<EntityId,GO>(
		    Teuchos::as<EntityId>(import_data[3*i+1]),
		    import_data[3*i+2]) );
	}
    }

    // Allocate the coupling matrix.
    d_coupling_matrix =
	Tpetra::createCrsMatrix<Scalar,LO,GO>( range_map );

    // Construct the entries of the coupling matrix.
    Teuchos::Array<EntityId> range_entity_ids;
    Teuchos::Array<EntityId>::const_iterator range_entity_id_it;
    Teuchos::ArrayView<const double> range_parametric_coords;
    Teuchos::Array<double> domain_shape_values;
    Teuchos::Array<double>::iterator domain_shape_it;
    Teuchos::Array<GO> domain_support_ids;
    EntityIterator domain_it;
    EntityIterator domain_begin = domain_iterator.begin();
    EntityIterator domain_end = domain_iterator.end();
    double scale_val = 0.0;
    for ( domain_it = domain_begin; domain_it != domain_end; ++domain_it )
    {
	// Get the domain Support ids supporting the domain entity.
	domain_space->shapeFunction()->entitySupportIds(
	    *domain_it, domain_support_ids );

	// Get the range entities that mapped into this domain entity.
	psearch.getRangeEntitiesFromDomain( domain_it->id(), range_entity_ids );

	// Sum into the global coupling matrix row for each domain.
	for ( range_entity_id_it = range_entity_ids.begin();
	      range_entity_id_it != range_entity_ids.end();
	      ++range_entity_id_it )
	{
	    // Get the parametric coordinates of the range entity in the
	    // domain entity.
	    psearch.rangeParametricCoordinatesInDomain(
		domain_it->id(), *range_entity_id_it, range_parametric_coords );

	    // Evaluate the shape function at the coordinates.
	    domain_space->shapeFunction()->evaluateValue(
		*domain_it, range_parametric_coords, domain_shape_values );
	    DTK_CHECK( domain_shape_values.size() == domain_support_ids.size() );

	    // Add the entries as a row in the matrix.
	    if ( range_support_id_map.count(*range_entity_id_it) )
	    {
		// Compute an average interpolated quantity if the range
		// entity was found in multiple domain entities.
		scale_val =
		    1.0 / range_support_count_map.find(*range_entity_id_it)->second;
		for ( domain_shape_it = domain_shape_values.begin();
		      domain_shape_it != domain_shape_values.end();
		      ++domain_shape_it )
		{
		    *domain_shape_it *= scale_val;
		}

		// Consistent interpolation requires one Support per range
		// entity. Load the row for this range Support into the matrix.
		d_coupling_matrix->insertGlobalValues(
		    range_support_id_map.find(*range_entity_id_it)->second,
		    domain_support_ids(),
		    domain_shape_values() );
	    }
	}
    }

    // Finalize the coupling matrix.
    d_coupling_matrix->fillComplete( domain_map, range_map );
    DTK_ENSURE( Teuchos::nonnull(d_coupling_matrix) );
}

//---------------------------------------------------------------------------//
// Apply the operator.
template<class Scalar>
void ConsistentInterpolationOperator<Scalar>::applyImpl(
    const TpetraMultiVector& X,
    TpetraMultiVector &Y,
    Teuchos::ETransp mode,
    Scalar alpha,
    Scalar beta ) const
{
    d_coupling_matrix->apply( X, Y, mode, alpha, beta );
}

//---------------------------------------------------------------------------//
// Return the ids of the range entities that were not mapped during the last
// setup phase (i.e. those that are guaranteed to not receive data from the
// transfer).
template<class Scalar>
Teuchos::ArrayView<const EntityId>
ConsistentInterpolationOperator<Scalar>::getMissedRangeEntityIds() const
{
    return d_missed_range_entity_ids();
}

//---------------------------------------------------------------------------//

} // end namespace DataTransferKit

# endif // end DTK_CONSISTENTINTERPOLATIONOPERATOR_IMPL_HPP

//---------------------------------------------------------------------------//
// end DTK_ConsistentInterpolationOperator_impl.hpp
//---------------------------------------------------------------------------//
<commit_msg>Refactoring normalization in consistent interpolation operator.<commit_after>//---------------------------------------------------------------------------//
/*
  Copyright (c) 2012, Stuart R. Slattery
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:

  *: Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.

  *: Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.

  *: Neither the name of the University of Wisconsin - Madison nor the
  names of its contributors may be used to endorse or promote products
  derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//---------------------------------------------------------------------------//
/*!
 * \brief DTK_ConsistentInterpolationOperator_impl.hpp
 * \author Stuart R. Slattery
 * \brief Consistent interpolation oprator.
 */
//---------------------------------------------------------------------------//

#ifndef DTK_CONSISTENTINTERPOLATIONOPERATOR_IMPL_HPP
#define DTK_CONSISTENTINTERPOLATIONOPERATOR_IMPL_HPP

#include <algorithm>
#include <unordered_set>
#include <unordered_map>

#include "DTK_DBC.hpp"
#include "DTK_ParallelSearch.hpp"
#include "DTK_BasicEntityPredicates.hpp"
#include "DTK_PredicateComposition.hpp"

#include <Teuchos_OrdinalTraits.hpp>

#include <Tpetra_Map.hpp>
#include <Tpetra_Distributor.hpp>

namespace DataTransferKit
{
//---------------------------------------------------------------------------//
// Constructor.
template<class Scalar>
ConsistentInterpolationOperator<Scalar>::ConsistentInterpolationOperator(
    const Teuchos::RCP<const TpetraMap>& domain_map,
    const Teuchos::RCP<const TpetraMap>& range_map,
    const Teuchos::ParameterList& parameters )
    : Base( domain_map, range_map )
    , d_missed_range_entity_ids( 0 )
{
    // Get the search list.
    d_search_list = parameters.sublist( "Search" );
}

//---------------------------------------------------------------------------//
// Setup the map operator.
template<class Scalar>
void ConsistentInterpolationOperator<Scalar>::setup(
    const Teuchos::RCP<FunctionSpace>& domain_space,
    const Teuchos::RCP<FunctionSpace>& range_space )
{
    DTK_REQUIRE( Teuchos::nonnull(domain_space) );
    DTK_REQUIRE( Teuchos::nonnull(range_space) );

    // Extract the Support maps.
    const Teuchos::RCP<const typename Base::TpetraMap> domain_map
	= this->getDomainMap();
    const Teuchos::RCP<const typename Base::TpetraMap> range_map
	= this->getRangeMap();

    // Get the parallel communicator.
    Teuchos::RCP<const Teuchos::Comm<int> > comm = domain_map->getComm();

    // Determine if we have range and domain data on this process.
    bool nonnull_domain = Teuchos::nonnull( domain_space->entitySet() );
    bool nonnull_range = Teuchos::nonnull( range_space->entitySet() );

    // Get the physical dimension.
    int physical_dimension = 0;
    if ( nonnull_domain )
    {
	physical_dimension = domain_space->entitySet()->physicalDimension();
    }
    else if ( nonnull_range )
    {
	physical_dimension = range_space->entitySet()->physicalDimension();
    }

    // We will only operate on entities that are locally-owned.
    LocalEntityPredicate local_predicate( comm->getRank() );

    // Get an iterator over the domain entities.
    EntityIterator domain_iterator;
    if ( nonnull_domain )
    {
	PredicateFunction domain_predicate =
	    PredicateComposition::And(
		domain_space->selectFunction(),	local_predicate.getFunction() );
	domain_iterator = domain_space->entitySet()->entityIterator(
	    domain_space->entitySet()->physicalDimension(),
	    domain_predicate );
    }

    // Build a parallel search over the domain.
    ParallelSearch psearch( comm,
			    physical_dimension,
			    domain_iterator,
			    domain_space->localMap(),
			    d_search_list );

    // Get an iterator over the range entities.
    EntityIterator range_iterator;
    if ( nonnull_range )
    {
	PredicateFunction range_predicate =
	    PredicateComposition::And(
		range_space->selectFunction(), local_predicate.getFunction() );
	range_iterator =
	    range_space->entitySet()->entityIterator( 0, range_predicate );
    }

    // Search the domain with the range.
    psearch.search( range_iterator, range_space->localMap(), d_search_list );

    // If we are keeping track of range entities that were not mapped, extract
    // them.
    d_missed_range_entity_ids =
	Teuchos::Array<EntityId>( psearch.getMissedRangeEntityIds() );

    // Determine the Support ids for the range entities found in the local domain
    // on this process and the number of domain entities they were found in
    // globally for averaging.
    std::unordered_map<EntityId,GO> range_support_id_map;
    Teuchos::RCP<Tpetra::Vector<Scalar,int,SupportId> > scale_vector =
	Tpetra::createVector<Scalar,int,SupportId>( range_map );
    {
	// Extract the set of local range entities that were found in domain
	// entities.
	Teuchos::Array<int> export_ranks;
	Teuchos::Array<GO> export_data;
	Teuchos::Array<EntityId> domain_ids;
	Teuchos::Array<EntityId>::const_iterator domain_id_it;
	Teuchos::Array<GO> range_support_ids;
	EntityIterator range_it;
	EntityIterator range_begin = range_iterator.begin();
	EntityIterator range_end = range_iterator.end();
	for ( range_it = range_begin;
	      range_it != range_end;
	      ++range_it )
	{
	    // Get the support id for the range entity.
	    range_space->shapeFunction()->entitySupportIds(
		*range_it, range_support_ids );
	    DTK_CHECK( 1 == range_support_ids.size() );

	    // Get the domain entities in which the range entity was found.
	    psearch.getDomainEntitiesFromRange( range_it->id(), domain_ids );

	    // Add a scale factor for this range entity to the scaling vector.
	    DTK_CHECK( range_map->isNodeGlobalElement(range_support_ids[0]) );
	    scale_vector->replaceGlobalValue( range_support_ids[0],
					      1.0 / domain_ids.size() );

	    // For each supporting domain entity, pair the range entity id and
	    // its support id.
	    for ( domain_id_it = domain_ids.begin();
		  domain_id_it != domain_ids.end();
		  ++domain_id_it )
	    {
		export_ranks.push_back(
		    psearch.domainEntityOwnerRank(*domain_id_it) );

		export_data.push_back( range_support_ids[0] );
		export_data.push_back( Teuchos::as<GO>(range_it->id()) );
	    }
	}

	// Communicate the range entity Support data back to the domain parallel
	// decomposition.
	Tpetra::Distributor range_to_domain_dist( comm );
	int num_import = range_to_domain_dist.createFromSends( export_ranks() );
	Teuchos::Array<GO> import_data( 2*num_import );
	Teuchos::ArrayView<const GO> export_data_view =
	    export_data();
	range_to_domain_dist.doPostsAndWaits( export_data_view,
					      2,
					      import_data() );

	// Map the range entities to their support ids.
	for ( int i = 0; i < num_import; ++i )
	{
	    range_support_id_map.emplace(
		Teuchos::as<EntityId>(import_data[2*i+1]),
		import_data[2*i] );
	}
    }

    // Allocate the coupling matrix.
    d_coupling_matrix =
	Tpetra::createCrsMatrix<Scalar,LO,GO>( range_map );

    // Construct the entries of the coupling matrix.
    Teuchos::Array<EntityId> range_entity_ids;
    Teuchos::Array<EntityId>::const_iterator range_entity_id_it;
    Teuchos::ArrayView<const double> range_parametric_coords;
    Teuchos::Array<double> domain_shape_values;
    Teuchos::Array<double>::iterator domain_shape_it;
    Teuchos::Array<GO> domain_support_ids;
    EntityIterator domain_it;
    EntityIterator domain_begin = domain_iterator.begin();
    EntityIterator domain_end = domain_iterator.end();
    for ( domain_it = domain_begin; domain_it != domain_end; ++domain_it )
    {
	// Get the domain Support ids supporting the domain entity.
	domain_space->shapeFunction()->entitySupportIds(
	    *domain_it, domain_support_ids );

	// Get the range entities that mapped into this domain entity.
	psearch.getRangeEntitiesFromDomain( domain_it->id(), range_entity_ids );

	// Sum into the global coupling matrix row for each domain.
	for ( range_entity_id_it = range_entity_ids.begin();
	      range_entity_id_it != range_entity_ids.end();
	      ++range_entity_id_it )
	{
	    // Get the parametric coordinates of the range entity in the
	    // domain entity.
	    psearch.rangeParametricCoordinatesInDomain(
		domain_it->id(), *range_entity_id_it, range_parametric_coords );

	    // Evaluate the shape function at the coordinates.
	    domain_space->shapeFunction()->evaluateValue(
		*domain_it, range_parametric_coords, domain_shape_values );
	    DTK_CHECK( domain_shape_values.size() == domain_support_ids.size() );

	    // Consistent interpolation requires one support location per
	    // range entity. Load the row for this range support location into
	    // the matrix.
	    d_coupling_matrix->insertGlobalValues(
		range_support_id_map.find(*range_entity_id_it)->second,
		domain_support_ids(),
		domain_shape_values() );
	}
    }

    // Finalize the coupling matrix.
    d_coupling_matrix->fillComplete( domain_map, range_map );

    // Left-scale the matrix with the number of domain entities in which each
    // range entity was found.
    d_coupling_matrix->leftScale( *scale_vector );
}

//---------------------------------------------------------------------------//
// Apply the operator.
template<class Scalar>
void ConsistentInterpolationOperator<Scalar>::applyImpl(
    const TpetraMultiVector& X,
    TpetraMultiVector &Y,
    Teuchos::ETransp mode,
    Scalar alpha,
    Scalar beta ) const
{
    d_coupling_matrix->apply( X, Y, mode, alpha, beta );
}

//---------------------------------------------------------------------------//
// Return the ids of the range entities that were not mapped during the last
// setup phase (i.e. those that are guaranteed to not receive data from the
// transfer).
template<class Scalar>
Teuchos::ArrayView<const EntityId>
ConsistentInterpolationOperator<Scalar>::getMissedRangeEntityIds() const
{
    return d_missed_range_entity_ids();
}

//---------------------------------------------------------------------------//

} // end namespace DataTransferKit

# endif // end DTK_CONSISTENTINTERPOLATIONOPERATOR_IMPL_HPP

//---------------------------------------------------------------------------//
// end DTK_ConsistentInterpolationOperator_impl.hpp
//---------------------------------------------------------------------------//
<|endoftext|>


<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2015 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
** disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
** following disclaimer in the documentation and/or other materials provided with the distribution.
** * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "ConflictPairs.h"

namespace FilePersistence {

ConflictPairs::ConflictPairs() {}
ConflictPairs::~ConflictPairs() {}

void ConflictPairs::insert(std::shared_ptr<ChangeDescription>& changeA,
									std::shared_ptr<ChangeDescription>& changeB)
{
	pairs_.insert(changeA, changeB);
	pairs_.insert(changeB, changeA);
}

void ConflictPairs::remove(std::shared_ptr<ChangeDescription>& changeA,
									std::shared_ptr<ChangeDescription>& changeB)
{
	pairs_.remove(changeA, changeB);
	pairs_.remove(changeB, changeA);
}

} /* namespace FilePersistence */
<commit_msg>fix to avoid duplicates in conflictPairs<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2015 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
** disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
** following disclaimer in the documentation and/or other materials provided with the distribution.
** * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "ConflictPairs.h"

namespace FilePersistence {

ConflictPairs::ConflictPairs() {}
ConflictPairs::~ConflictPairs() {}

void ConflictPairs::insert(std::shared_ptr<ChangeDescription>& changeA,
									std::shared_ptr<ChangeDescription>& changeB)
{
	if (!pairs_.contains(changeA, changeB))
	{
		pairs_.insert(changeA, changeB);
		pairs_.insert(changeB, changeA);
	}
}

void ConflictPairs::remove(std::shared_ptr<ChangeDescription>& changeA,
									std::shared_ptr<ChangeDescription>& changeB)
{
	pairs_.remove(changeA, changeB);
	pairs_.remove(changeB, changeA);
}

} /* namespace FilePersistence */
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 *
 */
#ifndef PCL_REGISTRATION_IMPL_CORRESPONDENCE_REJECTION_FEATURES_HPP_
#define PCL_REGISTRATION_IMPL_CORRESPONDENCE_REJECTION_FEATURES_HPP_

//////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::registration::CorrespondenceRejectorFeatures::getRemainingCorrespondences (
    const pcl::Correspondences& original_correspondences,
    pcl::Correspondences& remaining_correspondences)
{
  unsigned int number_valid_correspondences = 0;
  remaining_correspondences.resize (original_correspondences.size ());
  // For each set of features, go over each correspondence from input_correspondences_
  for (size_t i = 0; i < input_correspondences_->size (); ++i)
  {
    // Go over the map of features
    for (FeaturesMap::const_iterator it = features_map_.begin (); it != features_map_.end (); ++it)
    {
      // Check if the score in feature space is above the given threshold
      // (assume that the number of feature correspondenecs is the same as the number of point correspondences)
      if (!it->second->isCorrespondenceValid (i))
        break;

      remaining_correspondences[number_valid_correspondences] = original_correspondences[i];
      ++number_valid_correspondences;
    }
  }
  remaining_correspondences.resize (number_valid_correspondences);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename FeatureT> inline void
pcl::registration::CorrespondenceRejectorFeatures::setSourceFeature (
    const typename pcl::PointCloud<FeatureT>::ConstPtr &source_feature, const std::string &key)
{
  if (features_map_.count (key) == 0)
    features_map_[key].reset (new FeatureContainer<FeatureT>);
  boost::static_pointer_cast<FeatureContainer<FeatureT> > (features_map_[key])->setSourceFeature (source_feature);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename FeatureT> inline typename pcl::PointCloud<FeatureT>::ConstPtr
pcl::registration::CorrespondenceRejectorFeatures::getSourceFeature (const std::string &key)
{
  if (features_map_.count (key) == 0)
    return (boost::shared_ptr<pcl::PointCloud<const FeatureT> > ());
  else
    return (boost::static_pointer_cast<FeatureContainer<FeatureT> > (features_map_[key])->getSourceFeature ());
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename FeatureT> inline void
pcl::registration::CorrespondenceRejectorFeatures::setTargetFeature (
    const typename pcl::PointCloud<FeatureT>::ConstPtr &target_feature, const std::string &key)
{
  if (features_map_.count (key) == 0)
    features_map_[key].reset (new FeatureContainer<FeatureT>);
  boost::static_pointer_cast<FeatureContainer<FeatureT> > (features_map_[key])->setTargetFeature (target_feature);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename FeatureT> inline typename pcl::PointCloud<FeatureT>::ConstPtr
pcl::registration::CorrespondenceRejectorFeatures::getTargetFeature (const std::string &key)
{
  typedef pcl::PointCloud<FeatureT> FeatureCloud;
  typedef typename FeatureCloud::ConstPtr FeatureCloudConstPtr;

  if (features_map_.count (key) == 0)
    return (boost::shared_ptr<const pcl::PointCloud<FeatureT> > ());
  else
    return (boost::static_pointer_cast<FeatureContainer<FeatureT> > (features_map_[key])->getTargetFeature ());
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename FeatureT> inline void
pcl::registration::CorrespondenceRejectorFeatures::setDistanceThreshold (
    double thresh, const std::string &key)
{
  if (features_map_.count (key) == 0)
    features_map_[key].reset (new FeatureContainer<FeatureT>);
  boost::static_pointer_cast<FeatureContainer<FeatureT> > (features_map_[key])->setDistanceThreshold (thresh);
}

//////////////////////////////////////////////////////////////////////////////////////////////
inline bool
pcl::registration::CorrespondenceRejectorFeatures::hasValidFeatures ()
{
  if (features_map_.empty ())
    return (false);
  typename FeaturesMap::const_iterator feature_itr;
  for (feature_itr = features_map_.begin (); feature_itr != features_map_.end (); ++feature_itr)
    if (!feature_itr->second->isValid ())
      return (false);
  return (true);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename FeatureT> inline void
pcl::registration::CorrespondenceRejectorFeatures::setFeatureRepresentation (
  const typename pcl::PointRepresentation<FeatureT>::ConstPtr &fr,
  const std::string &key)
{
  if (features_map_.count (key) == 0)
    features_map_[key].reset (new FeatureContainer<FeatureT>);
  boost::static_pointer_cast<FeatureContainer<FeatureT> > (features_map_[key])->setFeatureRepresentation (fr);
}

#endif /* PCL_REGISTRATION_IMPL_CORRESPONDENCE_REJECTION_FEATURES_HPP_ */
<commit_msg>fixed a visual studio compilation error<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 *
 */
#ifndef PCL_REGISTRATION_IMPL_CORRESPONDENCE_REJECTION_FEATURES_HPP_
#define PCL_REGISTRATION_IMPL_CORRESPONDENCE_REJECTION_FEATURES_HPP_

//////////////////////////////////////////////////////////////////////////////////////////////
void
pcl::registration::CorrespondenceRejectorFeatures::getRemainingCorrespondences (
    const pcl::Correspondences& original_correspondences,
    pcl::Correspondences& remaining_correspondences)
{
  unsigned int number_valid_correspondences = 0;
  remaining_correspondences.resize (original_correspondences.size ());
  // For each set of features, go over each correspondence from input_correspondences_
  for (size_t i = 0; i < input_correspondences_->size (); ++i)
  {
    // Go over the map of features
    for (FeaturesMap::const_iterator it = features_map_.begin (); it != features_map_.end (); ++it)
    {
      // Check if the score in feature space is above the given threshold
      // (assume that the number of feature correspondenecs is the same as the number of point correspondences)
      if (!it->second->isCorrespondenceValid (i))
        break;

      remaining_correspondences[number_valid_correspondences] = original_correspondences[i];
      ++number_valid_correspondences;
    }
  }
  remaining_correspondences.resize (number_valid_correspondences);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename FeatureT> inline void
pcl::registration::CorrespondenceRejectorFeatures::setSourceFeature (
    const typename pcl::PointCloud<FeatureT>::ConstPtr &source_feature, const std::string &key)
{
  if (features_map_.count (key) == 0)
    features_map_[key].reset (new FeatureContainer<FeatureT>);
  boost::static_pointer_cast<FeatureContainer<FeatureT> > (features_map_[key])->setSourceFeature (source_feature);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename FeatureT> inline typename pcl::PointCloud<FeatureT>::ConstPtr
pcl::registration::CorrespondenceRejectorFeatures::getSourceFeature (const std::string &key)
{
  if (features_map_.count (key) == 0)
    return (boost::shared_ptr<pcl::PointCloud<const FeatureT> > ());
  else
    return (boost::static_pointer_cast<FeatureContainer<FeatureT> > (features_map_[key])->getSourceFeature ());
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename FeatureT> inline void
pcl::registration::CorrespondenceRejectorFeatures::setTargetFeature (
    const typename pcl::PointCloud<FeatureT>::ConstPtr &target_feature, const std::string &key)
{
  if (features_map_.count (key) == 0)
    features_map_[key].reset (new FeatureContainer<FeatureT>);
  boost::static_pointer_cast<FeatureContainer<FeatureT> > (features_map_[key])->setTargetFeature (target_feature);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename FeatureT> inline typename pcl::PointCloud<FeatureT>::ConstPtr
pcl::registration::CorrespondenceRejectorFeatures::getTargetFeature (const std::string &key)
{
  typedef pcl::PointCloud<FeatureT> FeatureCloud;
  typedef typename FeatureCloud::ConstPtr FeatureCloudConstPtr;

  if (features_map_.count (key) == 0)
    return (boost::shared_ptr<const pcl::PointCloud<FeatureT> > ());
  else
    return (boost::static_pointer_cast<FeatureContainer<FeatureT> > (features_map_[key])->getTargetFeature ());
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename FeatureT> inline void
pcl::registration::CorrespondenceRejectorFeatures::setDistanceThreshold (
    double thresh, const std::string &key)
{
  if (features_map_.count (key) == 0)
    features_map_[key].reset (new FeatureContainer<FeatureT>);
  boost::static_pointer_cast<FeatureContainer<FeatureT> > (features_map_[key])->setDistanceThreshold (thresh);
}

//////////////////////////////////////////////////////////////////////////////////////////////
inline bool
pcl::registration::CorrespondenceRejectorFeatures::hasValidFeatures ()
{
  if (features_map_.empty ())
    return (false);
  FeaturesMap::const_iterator feature_itr;
  for (feature_itr = features_map_.begin (); feature_itr != features_map_.end (); ++feature_itr)
    if (!feature_itr->second->isValid ())
      return (false);
  return (true);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename FeatureT> inline void
pcl::registration::CorrespondenceRejectorFeatures::setFeatureRepresentation (
  const typename pcl::PointRepresentation<FeatureT>::ConstPtr &fr,
  const std::string &key)
{
  if (features_map_.count (key) == 0)
    features_map_[key].reset (new FeatureContainer<FeatureT>);
  boost::static_pointer_cast<FeatureContainer<FeatureT> > (features_map_[key])->setFeatureRepresentation (fr);
}

#endif /* PCL_REGISTRATION_IMPL_CORRESPONDENCE_REJECTION_FEATURES_HPP_ */
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 2006, ALICE Experiment at CERN, All rights reserved.      *
 *                                                                        *
 * Author: Per Thomas Hille for the ALICE HLT Project.                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

#include "AliHLTPHOSRawAnalyzerPeakFinderComponent.h"
#include "AliHLTPHOSRawAnalyzerPeakFinder.h"

//ClassImp(AliHLTPHOSRawAnalyzerPeakFinderComponent)
AliHLTPHOSRawAnalyzerPeakFinderComponent gAliHLTPHOSRawAnalyzerPeakFinderComponent;

AliHLTPHOSRawAnalyzerPeakFinderComponent::AliHLTPHOSRawAnalyzerPeakFinderComponent():AliHLTPHOSRawAnalyzerComponent()
{
  Double_t tmpAVector[70];
  Double_t tmpTVector[70];
  analyzerPtr = new AliHLTPHOSRawAnalyzerPeakFinder();
  analyzerPtr->SetStartIndex(0);
  FILE *fp;
  fp = fopen("/home/perthi/cern/aliroot/AliRoot_head/HLT/PHOS/PFVectors/start0N70tau2fs10.txt", "r");

  if(fp != 0)
    {
      for(int i=0; i < 70; i++)
	{
	  fscanf(fp, "%lf", &tmpAVector[i]);
	}

      fscanf(fp, "\n");

      for(int i=0; i < 70; i++)
	{
	  	  fscanf(fp, "%lf", &tmpTVector[i]);
	}

      analyzerPtr->SetAVector(tmpAVector, 70);
      analyzerPtr->SetTVector(tmpTVector, 70);

      fclose(fp);

    }

  else
    {
      cout <<"AliHLTPHOSRawAnalyzerPeakFinderComponent, ERROR: could not  open PF vector file" << endl;
    }

}

AliHLTPHOSRawAnalyzerPeakFinderComponent::~AliHLTPHOSRawAnalyzerPeakFinderComponent()
{

}

AliHLTPHOSRawAnalyzerPeakFinderComponent::AliHLTPHOSRawAnalyzerPeakFinderComponent(const AliHLTPHOSRawAnalyzerPeakFinderComponent & ) : AliHLTPHOSRawAnalyzerComponent()
{

}

const char*
AliHLTPHOSRawAnalyzerPeakFinderComponent::GetComponentID()
{
  //cout << "AliHLTPHOSRawAnalyzerPeakFinderComponent returning ID" << endl;
  return "PhosRawPeakFinder";
}

AliHLTComponent*
AliHLTPHOSRawAnalyzerPeakFinderComponent::Spawn()
{
  //  cout << "AliHLTPHOSRawAnalyzerPeakFinderComponent spawning new instance" << endl;
  return new AliHLTPHOSRawAnalyzerPeakFinderComponent;
}

<commit_msg>Bug fix, path to peakfinder vectors was hardcoded into the code for debugging purphoses but was not removed when the code was commited. the error message reads<commit_after>/**************************************************************************
 * Copyright(c) 2006, ALICE Experiment at CERN, All rights reserved.      *
 *                                                                        *
 * Author: Per Thomas Hille for the ALICE HLT Project.                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

#include "AliHLTPHOSRawAnalyzerPeakFinderComponent.h"
#include "AliHLTPHOSRawAnalyzerPeakFinder.h"

//ClassImp(AliHLTPHOSRawAnalyzerPeakFinderComponent)
AliHLTPHOSRawAnalyzerPeakFinderComponent gAliHLTPHOSRawAnalyzerPeakFinderComponent;

AliHLTPHOSRawAnalyzerPeakFinderComponent::AliHLTPHOSRawAnalyzerPeakFinderComponent():AliHLTPHOSRawAnalyzerComponent()
{
  Double_t tmpAVector[70];
  Double_t tmpTVector[70];
  analyzerPtr = new AliHLTPHOSRawAnalyzerPeakFinder();
  analyzerPtr->SetStartIndex(0);
  FILE *fp;
  fp = fopen("/home/perthi/cern/aliroot/AliRoot_head/HLT/PHOS/PFVectors/start0N70tau2fs10.txt", "r");

  if(fp != 0)
    {
      for(int i=0; i < 70; i++)
	{
	  fscanf(fp, "%lf", &tmpAVector[i]);
	}

      fscanf(fp, "\n");

      for(int i=0; i < 70; i++)
	{
	  	  fscanf(fp, "%lf", &tmpTVector[i]);
	}

      analyzerPtr->SetAVector(tmpAVector, 70);
      analyzerPtr->SetTVector(tmpTVector, 70);

      fclose(fp);

    }

  else
    {
      //   cout <<"AliHLTPHOSRawAnalyzerPeakFinderComponent, ERROR: could not  open PF vector file" << endl;
    }

}

AliHLTPHOSRawAnalyzerPeakFinderComponent::~AliHLTPHOSRawAnalyzerPeakFinderComponent()
{

}

AliHLTPHOSRawAnalyzerPeakFinderComponent::AliHLTPHOSRawAnalyzerPeakFinderComponent(const AliHLTPHOSRawAnalyzerPeakFinderComponent & ) : AliHLTPHOSRawAnalyzerComponent()
{

}

const char*
AliHLTPHOSRawAnalyzerPeakFinderComponent::GetComponentID()
{
  //cout << "AliHLTPHOSRawAnalyzerPeakFinderComponent returning ID" << endl;
  return "PhosRawPeakFinder";
}

AliHLTComponent*
AliHLTPHOSRawAnalyzerPeakFinderComponent::Spawn()
{
  //  cout << "AliHLTPHOSRawAnalyzerPeakFinderComponent spawning new instance" << endl;
  return new AliHLTPHOSRawAnalyzerPeakFinderComponent;
}

<|endoftext|>


<commit_before>
#include <stdio.h>

#include <mpi.h>

#include "controller.h"

int
main()
{

  return 0;
}
<commit_msg>Add printf()<commit_after>
#include <stdio.h>

#include <mpi.h>

#include "controller.h"

int
main()
{
  printf("OK\n");
  return 0;
}
<|endoftext|>