<commit_before>//===- Dominators.cpp - Dominator Calculation -----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements simple dominator construction algorithms for finding
// forward dominators.  Postdominators are available in libanalysis, but are not
// included in libvmcore, because it's not needed.  Forward dominators are
// needed to support the Verifier pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/Dominators.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/DominatorInternals.h"
#include "llvm/Instructions.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include <algorithm>
using namespace llvm;

// Always verify dominfo if expensive checking is enabled.
#ifdef XDEBUG
static bool VerifyDomInfo = true;
#else
static bool VerifyDomInfo = false;
#endif
static cl::opt<bool,true>
VerifyDomInfoX("verify-dom-info", cl::location(VerifyDomInfo),
               cl::desc("Verify dominator info (time consuming)"));

//===----------------------------------------------------------------------===//
//  DominatorTree Implementation
//===----------------------------------------------------------------------===//
//
// Provide public access to DominatorTree information.  Implementation details
// can be found in DominatorCalculation.h.
//
//===----------------------------------------------------------------------===//

TEMPLATE_INSTANTIATION(class llvm::DomTreeNodeBase<BasicBlock>);
TEMPLATE_INSTANTIATION(class llvm::DominatorTreeBase<BasicBlock>);

char DominatorTree::ID = 0;
INITIALIZE_PASS(DominatorTree, "domtree",
                "Dominator Tree Construction", true, true);

bool DominatorTree::runOnFunction(Function &F) {
  DT->recalculate(F);
  return false;
}

void DominatorTree::verifyAnalysis() const {
  if (!VerifyDomInfo) return;

  Function &F = *getRoot()->getParent();

  DominatorTree OtherDT;
  OtherDT.getBase().recalculate(F);
  assert(!compare(OtherDT) && "Invalid DominatorTree info!");
}

void DominatorTree::print(raw_ostream &OS, const Module *) const {
  DT->print(OS);
}

// dominates - Return true if A dominates a use in B. This performs the
// special checks necessary if A and B are in the same basic block.
bool DominatorTree::dominates(const Instruction *A, const Instruction *B) const{
  const BasicBlock *BBA = A->getParent(), *BBB = B->getParent();

  // If A is an invoke instruction, its value is only available in this normal
  // successor block.
  if (const InvokeInst *II = dyn_cast<InvokeInst>(A))
    BBA = II->getNormalDest();

  if (BBA != BBB) return dominates(BBA, BBB);

  // It is not possible to determine dominance between two PHI nodes
  // based on their ordering.
  if (isa<PHINode>(A) && isa<PHINode>(B))
    return false;

  // Loop through the basic block until we find A or B.
  BasicBlock::const_iterator I = BBA->begin();
  for (; &*I != A && &*I != B; ++I)
    /*empty*/;

  return &*I == A;
}

//===----------------------------------------------------------------------===//
//  DominanceFrontier Implementation
//===----------------------------------------------------------------------===//

char DominanceFrontier::ID = 0;
INITIALIZE_PASS(DominanceFrontier, "domfrontier",
                "Dominance Frontier Construction", true, true);

void DominanceFrontier::verifyAnalysis() const {
  if (!VerifyDomInfo) return;

  DominatorTree &DT = getAnalysis<DominatorTree>();

  DominanceFrontier OtherDF;
  const std::vector<BasicBlock*> &DTRoots = DT.getRoots();
  OtherDF.calculate(DT, DT.getNode(DTRoots[0]));
  assert(!compare(OtherDF) && "Invalid DominanceFrontier info!");
}

// NewBB is split and now it has one successor. Update dominance frontier to
// reflect this change.
void DominanceFrontier::splitBlock(BasicBlock *NewBB) {
  assert(NewBB->getTerminator()->getNumSuccessors() == 1
         && "NewBB should have a single successor!");
  BasicBlock *NewBBSucc = NewBB->getTerminator()->getSuccessor(0);

  SmallVector<BasicBlock*, 8> PredBlocks;
  for (pred_iterator PI = pred_begin(NewBB), PE = pred_end(NewBB);
       PI != PE; ++PI)
    PredBlocks.push_back(*PI);

  if (PredBlocks.empty())
    // If NewBB does not have any predecessors then it is a entry block.
    // In this case, NewBB and its successor NewBBSucc dominates all
    // other blocks.
    return;

  // NewBBSucc inherits original NewBB frontier.
  DominanceFrontier::iterator NewBBI = find(NewBB);
  if (NewBBI != end()) {
    DominanceFrontier::DomSetType NewBBSet = NewBBI->second;
    DominanceFrontier::DomSetType NewBBSuccSet;
    NewBBSuccSet.insert(NewBBSet.begin(), NewBBSet.end());
    addBasicBlock(NewBBSucc, NewBBSuccSet);
  }

  // If NewBB dominates NewBBSucc, then DF(NewBB) is now going to be the
  // DF(NewBBSucc) without the stuff that the new block does not dominate
  // a predecessor of.
  DominatorTree &DT = getAnalysis<DominatorTree>();
  if (DT.dominates(NewBB, NewBBSucc)) {
    DominanceFrontier::iterator DFI = find(NewBBSucc);
    if (DFI != end()) {
      DominanceFrontier::DomSetType Set = DFI->second;
      // Filter out stuff in Set that we do not dominate a predecessor of.
      for (DominanceFrontier::DomSetType::iterator SetI = Set.begin(),
             E = Set.end(); SetI != E;) {
        bool DominatesPred = false;
        for (pred_iterator PI = pred_begin(*SetI), E = pred_end(*SetI);
             PI != E; ++PI)
          if (DT.dominates(NewBB, *PI))
            DominatesPred = true;
        if (!DominatesPred)
          Set.erase(SetI++);
        else
          ++SetI;
      }

      if (NewBBI != end()) {
        for (DominanceFrontier::DomSetType::iterator SetI = Set.begin(),
               E = Set.end(); SetI != E; ++SetI) {
          BasicBlock *SB = *SetI;
          addToFrontier(NewBBI, SB);
        }
      } else
        addBasicBlock(NewBB, Set);
    }

  } else {
    // DF(NewBB) is {NewBBSucc} because NewBB does not strictly dominate
    // NewBBSucc, but it does dominate itself (and there is an edge (NewBB ->
    // NewBBSucc)).  NewBBSucc is the single successor of NewBB.
    DominanceFrontier::DomSetType NewDFSet;
    NewDFSet.insert(NewBBSucc);
    addBasicBlock(NewBB, NewDFSet);
  }

  // Now we must loop over all of the dominance frontiers in the function,
  // replacing occurrences of NewBBSucc with NewBB in some cases.  All
  // blocks that dominate a block in PredBlocks and contained NewBBSucc in
  // their dominance frontier must be updated to contain NewBB instead.
  //
  for (Function::iterator FI = NewBB->getParent()->begin(),
         FE = NewBB->getParent()->end(); FI != FE; ++FI) {
    DominanceFrontier::iterator DFI = find(FI);
    if (DFI == end()) continue;  // unreachable block.

    // Only consider nodes that have NewBBSucc in their dominator frontier.
    if (!DFI->second.count(NewBBSucc)) continue;

    // Verify whether this block dominates a block in predblocks.  If not, do
    // not update it.
    bool BlockDominatesAny = false;
    for (SmallVectorImpl<BasicBlock*>::const_iterator BI = PredBlocks.begin(),
           BE = PredBlocks.end(); BI != BE; ++BI) {
      if (DT.dominates(FI, *BI)) {
        BlockDominatesAny = true;
        break;
      }
    }

    // If NewBBSucc should not stay in our dominator frontier, remove it.
    // We remove it unless there is a predecessor of NewBBSucc that we
    // dominate, but we don't strictly dominate NewBBSucc.
    bool ShouldRemove = true;
    if ((BasicBlock*)FI == NewBBSucc || !DT.dominates(FI, NewBBSucc)) {
      // Okay, we know that PredDom does not strictly dominate NewBBSucc.
      // Check to see if it dominates any predecessors of NewBBSucc.
      for (pred_iterator PI = pred_begin(NewBBSucc),
           E = pred_end(NewBBSucc); PI != E; ++PI)
        if (DT.dominates(FI, *PI)) {
          ShouldRemove = false;
          break;
        }
    }

    if (ShouldRemove)
      removeFromFrontier(DFI, NewBBSucc);
    if (BlockDominatesAny && (&*FI == NewBB || !DT.dominates(FI, NewBB)))
      addToFrontier(DFI, NewBB);
  }
}

namespace {
  class DFCalculateWorkObject {
  public:
    DFCalculateWorkObject(BasicBlock *B, BasicBlock *P,
                          const DomTreeNode *N,
                          const DomTreeNode *PN)
    : currentBB(B), parentBB(P), Node(N), parentNode(PN) {}
    BasicBlock *currentBB;
    BasicBlock *parentBB;
    const DomTreeNode *Node;
    const DomTreeNode *parentNode;
  };
}

const DominanceFrontier::DomSetType &
DominanceFrontier::calculate(const DominatorTree &DT,
                             const DomTreeNode *Node) {
  BasicBlock *BB = Node->getBlock();
  DomSetType *Result = NULL;

  std::vector<DFCalculateWorkObject> workList;
  SmallPtrSet<BasicBlock *, 32> visited;

  workList.push_back(DFCalculateWorkObject(BB, NULL, Node, NULL));
  do {
    DFCalculateWorkObject *currentW = &workList.back();
    assert (currentW && "Missing work object.");

    BasicBlock *currentBB = currentW->currentBB;
    BasicBlock *parentBB = currentW->parentBB;
    const DomTreeNode *currentNode = currentW->Node;
    const DomTreeNode *parentNode = currentW->parentNode;
    assert (currentBB && "Invalid work object. Missing current Basic Block");
    assert (currentNode && "Invalid work object. Missing current Node");
    DomSetType &S = Frontiers[currentBB];

    // Visit each block only once.
    if (visited.count(currentBB) == 0) {
      visited.insert(currentBB);

      // Loop over CFG successors to calculate DFlocal[currentNode]
      for (succ_iterator SI = succ_begin(currentBB), SE = succ_end(currentBB);
           SI != SE; ++SI) {
        // Does Node immediately dominate this successor?
        if (DT[*SI]->getIDom() != currentNode)
          S.insert(*SI);
      }
    }

    // At this point, S is DFlocal.  Now we union in DFup's of our children...
    // Loop through and visit the nodes that Node immediately dominates (Node's
    // children in the IDomTree)
    bool visitChild = false;
    for (DomTreeNode::const_iterator NI = currentNode->begin(),
           NE = currentNode->end(); NI != NE; ++NI) {
      DomTreeNode *IDominee = *NI;
      BasicBlock *childBB = IDominee->getBlock();
      if (visited.count(childBB) == 0) {
        workList.push_back(DFCalculateWorkObject(childBB, currentBB,
                                                 IDominee, currentNode));
        visitChild = true;
      }
    }

    // If all children are visited or there is any child then pop this block
    // from the workList.
    if (!visitChild) {

      if (!parentBB) {
        Result = &S;
        break;
      }

      DomSetType::const_iterator CDFI = S.begin(), CDFE = S.end();
      DomSetType &parentSet = Frontiers[parentBB];
      for (; CDFI != CDFE; ++CDFI) {
        if (!DT.properlyDominates(parentNode, DT[*CDFI]))
          parentSet.insert(*CDFI);
      }
      workList.pop_back();
    }

  } while (!workList.empty());

  return *Result;
}

void DominanceFrontierBase::print(raw_ostream &OS, const Module* ) const {
  for (const_iterator I = begin(), E = end(); I != E; ++I) {
    OS << "  DomFrontier for BB ";
    if (I->first)
      WriteAsOperand(OS, I->first, false);
    else
      OS << " <<exit node>>";
    OS << " is:\t";

    const std::set<BasicBlock*> &BBs = I->second;

    for (std::set<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end();
         I != E; ++I) {
      OS << ' ';
      if (*I)
        WriteAsOperand(OS, *I, false);
      else
        OS << "<<exit node>>";
    }
    OS << "\n";
  }
}

void DominanceFrontierBase::dump() const {
  print(dbgs());
}

<commit_msg>Fix formatting.<commit_after>//===- Dominators.cpp - Dominator Calculation -----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements simple dominator construction algorithms for finding
// forward dominators.  Postdominators are available in libanalysis, but are not
// included in libvmcore, because it's not needed.  Forward dominators are
// needed to support the Verifier pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/Dominators.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/DominatorInternals.h"
#include "llvm/Instructions.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include <algorithm>
using namespace llvm;

// Always verify dominfo if expensive checking is enabled.
#ifdef XDEBUG
static bool VerifyDomInfo = true;
#else
static bool VerifyDomInfo = false;
#endif
static cl::opt<bool,true>
VerifyDomInfoX("verify-dom-info", cl::location(VerifyDomInfo),
               cl::desc("Verify dominator info (time consuming)"));

//===----------------------------------------------------------------------===//
//  DominatorTree Implementation
//===----------------------------------------------------------------------===//
//
// Provide public access to DominatorTree information.  Implementation details
// can be found in DominatorCalculation.h.
//
//===----------------------------------------------------------------------===//

TEMPLATE_INSTANTIATION(class llvm::DomTreeNodeBase<BasicBlock>);
TEMPLATE_INSTANTIATION(class llvm::DominatorTreeBase<BasicBlock>);

char DominatorTree::ID = 0;
INITIALIZE_PASS(DominatorTree, "domtree",
                "Dominator Tree Construction", true, true);

bool DominatorTree::runOnFunction(Function &F) {
  DT->recalculate(F);
  return false;
}

void DominatorTree::verifyAnalysis() const {
  if (!VerifyDomInfo) return;

  Function &F = *getRoot()->getParent();

  DominatorTree OtherDT;
  OtherDT.getBase().recalculate(F);
  assert(!compare(OtherDT) && "Invalid DominatorTree info!");
}

void DominatorTree::print(raw_ostream &OS, const Module *) const {
  DT->print(OS);
}

// dominates - Return true if A dominates a use in B. This performs the
// special checks necessary if A and B are in the same basic block.
bool DominatorTree::dominates(const Instruction *A, const Instruction *B) const{
  const BasicBlock *BBA = A->getParent(), *BBB = B->getParent();

  // If A is an invoke instruction, its value is only available in this normal
  // successor block.
  if (const InvokeInst *II = dyn_cast<InvokeInst>(A))
    BBA = II->getNormalDest();

  if (BBA != BBB) return dominates(BBA, BBB);

  // It is not possible to determine dominance between two PHI nodes
  // based on their ordering.
  if (isa<PHINode>(A) && isa<PHINode>(B))
    return false;

  // Loop through the basic block until we find A or B.
  BasicBlock::const_iterator I = BBA->begin();
  for (; &*I != A && &*I != B; ++I)
    /*empty*/;

  return &*I == A;
}

//===----------------------------------------------------------------------===//
//  DominanceFrontier Implementation
//===----------------------------------------------------------------------===//

char DominanceFrontier::ID = 0;
INITIALIZE_PASS(DominanceFrontier, "domfrontier",
                "Dominance Frontier Construction", true, true);

void DominanceFrontier::verifyAnalysis() const {
  if (!VerifyDomInfo) return;

  DominatorTree &DT = getAnalysis<DominatorTree>();

  DominanceFrontier OtherDF;
  const std::vector<BasicBlock*> &DTRoots = DT.getRoots();
  OtherDF.calculate(DT, DT.getNode(DTRoots[0]));
  assert(!compare(OtherDF) && "Invalid DominanceFrontier info!");
}

// NewBB is split and now it has one successor. Update dominance frontier to
// reflect this change.
void DominanceFrontier::splitBlock(BasicBlock *NewBB) {
  assert(NewBB->getTerminator()->getNumSuccessors() == 1 &&
         "NewBB should have a single successor!");
  BasicBlock *NewBBSucc = NewBB->getTerminator()->getSuccessor(0);

  SmallVector<BasicBlock*, 8> PredBlocks;
  for (pred_iterator PI = pred_begin(NewBB), PE = pred_end(NewBB);
       PI != PE; ++PI)
    PredBlocks.push_back(*PI);

  if (PredBlocks.empty())
    // If NewBB does not have any predecessors then it is a entry block.
    // In this case, NewBB and its successor NewBBSucc dominates all
    // other blocks.
    return;

  // NewBBSucc inherits original NewBB frontier.
  DominanceFrontier::iterator NewBBI = find(NewBB);
  if (NewBBI != end()) {
    DominanceFrontier::DomSetType NewBBSet = NewBBI->second;
    DominanceFrontier::DomSetType NewBBSuccSet;
    NewBBSuccSet.insert(NewBBSet.begin(), NewBBSet.end());
    addBasicBlock(NewBBSucc, NewBBSuccSet);
  }

  // If NewBB dominates NewBBSucc, then DF(NewBB) is now going to be the
  // DF(NewBBSucc) without the stuff that the new block does not dominate
  // a predecessor of.
  DominatorTree &DT = getAnalysis<DominatorTree>();
  if (DT.dominates(NewBB, NewBBSucc)) {
    DominanceFrontier::iterator DFI = find(NewBBSucc);
    if (DFI != end()) {
      DominanceFrontier::DomSetType Set = DFI->second;
      // Filter out stuff in Set that we do not dominate a predecessor of.
      for (DominanceFrontier::DomSetType::iterator SetI = Set.begin(),
             E = Set.end(); SetI != E;) {
        bool DominatesPred = false;
        for (pred_iterator PI = pred_begin(*SetI), E = pred_end(*SetI);
             PI != E; ++PI)
          if (DT.dominates(NewBB, *PI))
            DominatesPred = true;
        if (!DominatesPred)
          Set.erase(SetI++);
        else
          ++SetI;
      }

      if (NewBBI != end()) {
        for (DominanceFrontier::DomSetType::iterator SetI = Set.begin(),
               E = Set.end(); SetI != E; ++SetI) {
          BasicBlock *SB = *SetI;
          addToFrontier(NewBBI, SB);
        }
      } else
        addBasicBlock(NewBB, Set);
    }

  } else {
    // DF(NewBB) is {NewBBSucc} because NewBB does not strictly dominate
    // NewBBSucc, but it does dominate itself (and there is an edge (NewBB ->
    // NewBBSucc)).  NewBBSucc is the single successor of NewBB.
    DominanceFrontier::DomSetType NewDFSet;
    NewDFSet.insert(NewBBSucc);
    addBasicBlock(NewBB, NewDFSet);
  }

  // Now we must loop over all of the dominance frontiers in the function,
  // replacing occurrences of NewBBSucc with NewBB in some cases.  All
  // blocks that dominate a block in PredBlocks and contained NewBBSucc in
  // their dominance frontier must be updated to contain NewBB instead.
  //
  for (Function::iterator FI = NewBB->getParent()->begin(),
         FE = NewBB->getParent()->end(); FI != FE; ++FI) {
    DominanceFrontier::iterator DFI = find(FI);
    if (DFI == end()) continue;  // unreachable block.

    // Only consider nodes that have NewBBSucc in their dominator frontier.
    if (!DFI->second.count(NewBBSucc)) continue;

    // Verify whether this block dominates a block in predblocks.  If not, do
    // not update it.
    bool BlockDominatesAny = false;
    for (SmallVectorImpl<BasicBlock*>::const_iterator BI = PredBlocks.begin(),
           BE = PredBlocks.end(); BI != BE; ++BI) {
      if (DT.dominates(FI, *BI)) {
        BlockDominatesAny = true;
        break;
      }
    }

    // If NewBBSucc should not stay in our dominator frontier, remove it.
    // We remove it unless there is a predecessor of NewBBSucc that we
    // dominate, but we don't strictly dominate NewBBSucc.
    bool ShouldRemove = true;
    if ((BasicBlock*)FI == NewBBSucc || !DT.dominates(FI, NewBBSucc)) {
      // Okay, we know that PredDom does not strictly dominate NewBBSucc.
      // Check to see if it dominates any predecessors of NewBBSucc.
      for (pred_iterator PI = pred_begin(NewBBSucc),
           E = pred_end(NewBBSucc); PI != E; ++PI)
        if (DT.dominates(FI, *PI)) {
          ShouldRemove = false;
          break;
        }
    }

    if (ShouldRemove)
      removeFromFrontier(DFI, NewBBSucc);
    if (BlockDominatesAny && (&*FI == NewBB || !DT.dominates(FI, NewBB)))
      addToFrontier(DFI, NewBB);
  }
}

namespace {
  class DFCalculateWorkObject {
  public:
    DFCalculateWorkObject(BasicBlock *B, BasicBlock *P,
                          const DomTreeNode *N,
                          const DomTreeNode *PN)
    : currentBB(B), parentBB(P), Node(N), parentNode(PN) {}
    BasicBlock *currentBB;
    BasicBlock *parentBB;
    const DomTreeNode *Node;
    const DomTreeNode *parentNode;
  };
}

const DominanceFrontier::DomSetType &
DominanceFrontier::calculate(const DominatorTree &DT,
                             const DomTreeNode *Node) {
  BasicBlock *BB = Node->getBlock();
  DomSetType *Result = NULL;

  std::vector<DFCalculateWorkObject> workList;
  SmallPtrSet<BasicBlock *, 32> visited;

  workList.push_back(DFCalculateWorkObject(BB, NULL, Node, NULL));
  do {
    DFCalculateWorkObject *currentW = &workList.back();
    assert (currentW && "Missing work object.");

    BasicBlock *currentBB = currentW->currentBB;
    BasicBlock *parentBB = currentW->parentBB;
    const DomTreeNode *currentNode = currentW->Node;
    const DomTreeNode *parentNode = currentW->parentNode;
    assert (currentBB && "Invalid work object. Missing current Basic Block");
    assert (currentNode && "Invalid work object. Missing current Node");
    DomSetType &S = Frontiers[currentBB];

    // Visit each block only once.
    if (visited.count(currentBB) == 0) {
      visited.insert(currentBB);

      // Loop over CFG successors to calculate DFlocal[currentNode]
      for (succ_iterator SI = succ_begin(currentBB), SE = succ_end(currentBB);
           SI != SE; ++SI) {
        // Does Node immediately dominate this successor?
        if (DT[*SI]->getIDom() != currentNode)
          S.insert(*SI);
      }
    }

    // At this point, S is DFlocal.  Now we union in DFup's of our children...
    // Loop through and visit the nodes that Node immediately dominates (Node's
    // children in the IDomTree)
    bool visitChild = false;
    for (DomTreeNode::const_iterator NI = currentNode->begin(),
           NE = currentNode->end(); NI != NE; ++NI) {
      DomTreeNode *IDominee = *NI;
      BasicBlock *childBB = IDominee->getBlock();
      if (visited.count(childBB) == 0) {
        workList.push_back(DFCalculateWorkObject(childBB, currentBB,
                                                 IDominee, currentNode));
        visitChild = true;
      }
    }

    // If all children are visited or there is any child then pop this block
    // from the workList.
    if (!visitChild) {

      if (!parentBB) {
        Result = &S;
        break;
      }

      DomSetType::const_iterator CDFI = S.begin(), CDFE = S.end();
      DomSetType &parentSet = Frontiers[parentBB];
      for (; CDFI != CDFE; ++CDFI) {
        if (!DT.properlyDominates(parentNode, DT[*CDFI]))
          parentSet.insert(*CDFI);
      }
      workList.pop_back();
    }

  } while (!workList.empty());

  return *Result;
}

void DominanceFrontierBase::print(raw_ostream &OS, const Module* ) const {
  for (const_iterator I = begin(), E = end(); I != E; ++I) {
    OS << "  DomFrontier for BB ";
    if (I->first)
      WriteAsOperand(OS, I->first, false);
    else
      OS << " <<exit node>>";
    OS << " is:\t";

    const std::set<BasicBlock*> &BBs = I->second;

    for (std::set<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end();
         I != E; ++I) {
      OS << ' ';
      if (*I)
        WriteAsOperand(OS, *I, false);
      else
        OS << "<<exit node>>";
    }
    OS << "\n";
  }
}

void DominanceFrontierBase::dump() const {
  print(dbgs());
}

<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
*
* tile_test.cpp
* file description
*
* Copyright(c) 2015, CMU
*
* /n-store/test/tile_test.cpp
*
*-------------------------------------------------------------------------
*/

#include "gtest/gtest.h"

#include "backend/storage/tile.h"
#include "backend/storage/tile_group.h"
#include "backend/storage/tile_iterator.h"

namespace peloton {
namespace test {

//===--------------------------------------------------------------------===//
// Tile Tests
//===--------------------------------------------------------------------===//

TEST(TileTests, BasicTest) {

	std::vector<catalog::ColumnInfo> columns;

	catalog::ColumnInfo column1(VALUE_TYPE_INTEGER, GetTypeSize(VALUE_TYPE_INTEGER), "A", true);
	catalog::ColumnInfo column2(VALUE_TYPE_INTEGER, GetTypeSize(VALUE_TYPE_INTEGER), "B", true);
	catalog::ColumnInfo column3(VALUE_TYPE_TINYINT, GetTypeSize(VALUE_TYPE_TINYINT), "C", true);
	catalog::ColumnInfo column4(VALUE_TYPE_VARCHAR, 25, "D", false);
	catalog::ColumnInfo column5(VALUE_TYPE_VARCHAR, 25, "E", false);

	columns.push_back(column1);
	columns.push_back(column2);
	columns.push_back(column3);
	columns.push_back(column4);
	columns.push_back(column4);

	catalog::Schema *schema = new catalog::Schema(columns);

	std::vector<std::string> column_names;

	column_names.push_back("COL 1");
	column_names.push_back("COL 2");
	column_names.push_back("COL 3");
	column_names.push_back("COL 4");
	column_names.push_back("COL 5");

	const int tuple_count = 6;

	storage::AbstractBackend *backend = new storage::VMBackend();
	storage::TileGroupHeader *header = new storage::TileGroupHeader(backend, tuple_count);

	storage::Tile *tile = storage::TileFactory::GetTile(INVALID_OID, INVALID_OID, INVALID_OID, INVALID_OID,
													  	  header, backend, *schema, nullptr, tuple_count);

	//std::cout << "tile size: " << tile->GetInlinedSize() << std::endl;
	//std::cout << "allocated tuple count: " << tile->GetAllocatedTupleCount() << std::endl;

	storage::Tuple *tuple1 = new storage::Tuple(schema, true);
	storage::Tuple *tuple2 = new storage::Tuple(schema, true);
	storage::Tuple *tuple3 = new storage::Tuple(schema, true);

	tuple1->SetValue(0, ValueFactory::GetIntegerValue(1));
	tuple1->SetValue(1, ValueFactory::GetIntegerValue(1));
	tuple1->SetValue(2, ValueFactory::GetTinyIntValue(1));
	tuple1->SetValue(3, ValueFactory::GetStringValue("vivek sengupta", tile->GetPool()));
	tuple1->SetValue(4, ValueFactory::GetStringValue("vivek sengupta again", tile->GetPool()));

	tuple2->SetValue(0, ValueFactory::GetIntegerValue(2));
	tuple2->SetValue(1, ValueFactory::GetIntegerValue(2));
	tuple2->SetValue(2, ValueFactory::GetTinyIntValue(2));
	tuple2->SetValue(3, ValueFactory::GetStringValue("ming fang", tile->GetPool()));
	tuple2->SetValue(4, ValueFactory::GetStringValue("ming fang again", tile->GetPool()));

	tuple3->SetValue(0, ValueFactory::GetIntegerValue(3));
	tuple3->SetValue(1, ValueFactory::GetIntegerValue(3));
	tuple3->SetValue(2, ValueFactory::GetTinyIntValue(3));
	tuple3->SetValue(3, ValueFactory::GetStringValue("jinwoong kim", tile->GetPool()));
	tuple3->SetValue(4, ValueFactory::GetStringValue("jinwoong kim again", tile->GetPool()));

	tile->InsertTuple(0, tuple1);
	tile->InsertTuple(1, tuple2);
	tile->InsertTuple(2, tuple3);

	//std::cout << (*tile);

	//tile->InsertTuple(2, tuple1);

	//std::cout << (*tile);

	/*
	 * Print details of old tile
	 */

	const catalog::Schema *old_schema;
	bool old_tile_is_inlined;
	uint16_t old_tile_allocated_tuple_count, old_tile_active_tuple_count;
	uint32_t old_tile_size;
	uint32_t old_tile_tuple_size;

	std::cout << "-------------------" << std::endl;
	std::cout << "Details of old tile" << std::endl;
	std::cout << "-------------------" << std::endl;

	std::cout << "base address of old tile: " << static_cast<void *>(tile) << std::endl;

	old_tile_size = tile->GetInlinedSize();
	std::cout << "old tile size: " << old_tile_size << std:: endl;

	old_tile_allocated_tuple_count = tile->GetAllocatedTupleCount();
	std::cout << "old tile allocated tuple count: " << old_tile_allocated_tuple_count << std:: endl;

	old_tile_active_tuple_count = tile->GetActiveTupleCount();
	std::cout << "old tile active tuple count: " << old_tile_active_tuple_count << std:: endl;
	old_tile_active_tuple_count = 3;

	old_tile_tuple_size = old_tile_size / old_tile_allocated_tuple_count;
	std::cout << "size of each tuple in old tile: " << old_tile_tuple_size << std::endl;

	old_schema = tile->GetSchema();
	old_tile_is_inlined = old_schema->IsInlined();
	std::cout << "Is the entire old tile inlined? " << (old_tile_is_inlined? "true" : "false") << std::endl;

	Pool *old_pool = tile->GetPool();
	std::cout << "Pool associated with old tile is at address: " << static_cast<void *>(old_pool) << std::endl;

	int64_t old_pool_size = old_pool->GetAllocatedMemory();
	std::cout << "size of old pool: " << old_pool_size << std::endl;

	/*
	 * Create a new tile from the old tile
	 */
	std::vector<catalog::ColumnInfo> new_columns = old_schema->GetColumns();
	const catalog::Schema *new_schema = new catalog::Schema(columns);

	storage::AbstractBackend *new_backend = new storage::VMBackend();
	storage::TileGroupHeader *new_header = new storage::TileGroupHeader(new_backend, tuple_count);
	storage::Tile *new_tile = storage::TileFactory::GetTile(INVALID_OID, INVALID_OID, INVALID_OID, INVALID_OID,
											  new_header, new_backend, *new_schema, nullptr, old_tile_allocated_tuple_count);
	Pool *new_pool = new_tile->GetPool();

	//::memcpy(new_pool,old_pool,old_pool_size);
	//::memcpy(static_cast<void *>(new_tile), static_cast<void *>(tile), old_tile_size);

	storage::Tuple *old_tuple;

	for(int old_tup_itr=0; old_tup_itr<old_tile_active_tuple_count; old_tup_itr++)
	{
		old_tuple = tile->GetTuple(old_tup_itr);
		new_tile->InsertTuple(old_tup_itr,old_tuple);
	}

	/*
	 * Print details of new tile
	 */

	bool new_tile_is_inlined;
	uint16_t new_tile_allocated_tuple_count, new_tile_active_tuple_count;
	uint32_t new_tile_size;
	uint32_t new_tile_tuple_size;

	std::cout << "-------------------" << std::endl;
	std::cout << "Details of new tile" << std::endl;
	std::cout << "-------------------" << std::endl;

	std::cout << "base address of new tile: " << static_cast<void *>(new_tile) << std::endl;

	new_tile_size = new_tile->GetInlinedSize();
	std::cout << "new tile size: " << new_tile_size << std:: endl;

	new_tile_allocated_tuple_count = tile->GetAllocatedTupleCount();
	std::cout << "new tile allocated tuple count: " << new_tile_allocated_tuple_count << std:: endl;

	new_tile_active_tuple_count = tile->GetActiveTupleCount();
	std::cout << "new tile active tuple count: " << new_tile_active_tuple_count << std:: endl;
	new_tile_active_tuple_count = 3;

	new_tile_tuple_size = new_tile_size / new_tile_allocated_tuple_count;
	std::cout << "size of each tuple in new tile: " << new_tile_tuple_size << std::endl;

	new_schema = new_tile->GetSchema();
	new_tile_is_inlined = new_schema->IsInlined();
	std::cout << "Is the entire new tile inlined? " << (new_tile_is_inlined? "true" : "false") << std::endl;

	std::cout << "Pool associated with new tile is at address: " << static_cast<void *>(new_pool) << std::endl;

	int64_t new_pool_size = new_pool->GetAllocatedMemory();
	std::cout << "size of new pool: " << new_pool_size << std::endl;

	std::cout << "------------------------------------" << std:: endl;
	std::cout << "In case some columns are not inlined" << std:: endl;
	std::cout << "------------------------------------" << std:: endl;

	//std::cout << (*new_tile);

	/*
	 * Iterate over the tile and print the tuples
	 */
	//storage::TileIterator tile_itr(new_tile);
	//storage::Tuple *new_tuple = new storage::Tuple(old_schema, true);
	//storage::Tuple& new_tuple_ref = *new_tuple;

/*
	while(tile_itr.Next(new_tuple_ref) == true)
	{
		std::cout << (new_tuple_ref);
		tile_itr++;
	}
*/

	if(!new_tile_is_inlined)
	{
		//int col_cnt = old_schema->GetColumnCount();
		//std::cout << "total column count: " << col_cnt << std::endl;

		int uninlined_col_cnt = new_schema->GetUninlinedColumnCount();
		//std::cout << "uninlined column count: " << uninlined_col_cnt << std::endl;

		int uninlined_col_index;
		Value uninlined_col_value, new_uninlined_col_value;
		storage::Tuple *new_tuple;

		for(int col_itr=0; col_itr<uninlined_col_cnt; col_itr++) {

			uninlined_col_index = new_schema->GetUninlinedColumnIndex(col_itr);
			std::cout << "----------------------------------" << std::endl;
			std::cout << "index of next uninlined column: " << uninlined_col_index << std::endl;
			std::cout << "----------------------------------" << std::endl  << std::endl;

			for(int tup_itr=0; tup_itr<new_tile_active_tuple_count; tup_itr++) {

				std::cout << "\t -----------------------------------------------------" + tup_itr << std::endl;
				std::cout << "\t Before associating new pool to new data for tuple: " + tup_itr << std::endl;
				std::cout << "\t -----------------------------------------------------" + tup_itr << std::endl;

				new_tuple = new_tile->GetTuple(tup_itr);
				std::cout << "\t address of new_tuple: " << static_cast<void *>(new_tuple) << std::endl << std::endl;

				uninlined_col_value = new_tile->GetValue(tup_itr,uninlined_col_index);
				std::cout << "\t uninlined column value: " << uninlined_col_value << std::endl;

				size_t uninlined_col_object_len = ValuePeeker::PeekObjectLength(uninlined_col_value);
				std::cout << "\t size of uninlined column object: " << uninlined_col_object_len << std::endl;

				unsigned char* uninlined_col_object_ptr = static_cast<unsigned char *>(ValuePeeker::PeekObjectValue(uninlined_col_value));
				std::cout << "\t uninlined column object pointer: " << static_cast<void *>(uninlined_col_object_ptr) << std::endl;

				std::string uninlined_varchar_str(reinterpret_cast<char const*>(uninlined_col_object_ptr), uninlined_col_object_len);
				std::cout << "\t the data stored uninlined is: " << uninlined_varchar_str << std::endl << std::endl;

				//char *xyz = new_tuple->GetData();
				//tile->GetValue(tup_itr,next_uninlined_col_index);

				// std::string copy_uninlined_varchar_str;
				// Create a new Value object with the uninlined string w.r.t. the new pool
				Value new_val = ValueFactory::GetStringValue(uninlined_varchar_str, new_pool);
				// Set the newly created value object to the tuple
				// new_tuple->SetValue(uninlined_col_index, uninlined_col_value);
				new_tile->SetValue(new_val, tup_itr, uninlined_col_index);

				std::cout << "\t ---------------------------------------------" + tup_itr << std::endl;
				std::cout << "\t Associated new pool to new data for tuple: " + tup_itr << std::endl;
				std::cout << "\t ---------------------------------------------" + tup_itr << std::endl;

				new_uninlined_col_value = new_tile->GetValue(tup_itr,uninlined_col_index);
				std::cout << "\t new uninlined column value: " << new_uninlined_col_value << std::endl;

				size_t new_uninlined_col_object_len = ValuePeeker::PeekObjectLength(new_uninlined_col_value);
				std::cout << "\t size of uninlined column object: " << new_uninlined_col_object_len << std::endl;

				unsigned char* new_uninlined_col_object_ptr = static_cast<unsigned char *>(ValuePeeker::PeekObjectValue(new_uninlined_col_value));
				std::cout << "\t new uninlined column object pointer: " << static_cast<void *>(new_uninlined_col_object_ptr) << std::endl;

				std::string new_uninlined_varchar_str( reinterpret_cast<char const*>(new_uninlined_col_object_ptr), uninlined_col_object_len);
				std::cout << "\t the new data stored uninlined is: " << new_uninlined_varchar_str << std::endl << std::endl;
			}
		}

		delete new_tuple;
	}

	if(tile==new_tile)
			std::cout << "old and new tiles are the same ..." << std::endl;

	std::string str1 = "hello world";
	std::string str2 = str1;

	std::cout << "add of str1: " << &str1 << std::endl;
	std::cout << "add of str2: " << &str2 << std::endl;

	delete tuple1;
	delete tuple2;
	delete tuple3;
	delete tile;
	delete header;
	delete schema;
	delete backend;
}

} // End test namespace
} // End peloton namespace

<commit_msg>minor cleanup<commit_after>/*-------------------------------------------------------------------------
*
* tile_test.cpp
* file description
*
* Copyright(c) 2015, CMU
*
* /n-store/test/tile_test.cpp
*
*-------------------------------------------------------------------------
*/

#include "gtest/gtest.h"

#include "backend/storage/tile.h"
#include "backend/storage/tile_group.h"
#include "backend/storage/tile_iterator.h"

namespace peloton {
namespace test {

//===--------------------------------------------------------------------===//
// Tile Tests
//===--------------------------------------------------------------------===//

TEST(TileTests, BasicTest) {

	std::vector<catalog::ColumnInfo> columns;

	catalog::ColumnInfo column1(VALUE_TYPE_INTEGER, GetTypeSize(VALUE_TYPE_INTEGER), "A", true);
	catalog::ColumnInfo column2(VALUE_TYPE_INTEGER, GetTypeSize(VALUE_TYPE_INTEGER), "B", true);
	catalog::ColumnInfo column3(VALUE_TYPE_TINYINT, GetTypeSize(VALUE_TYPE_TINYINT), "C", true);
	catalog::ColumnInfo column4(VALUE_TYPE_VARCHAR, 25, "D", false);
	catalog::ColumnInfo column5(VALUE_TYPE_VARCHAR, 25, "E", false);

	columns.push_back(column1);
	columns.push_back(column2);
	columns.push_back(column3);
	columns.push_back(column4);
	columns.push_back(column4);

	catalog::Schema *schema = new catalog::Schema(columns);

	std::vector<std::string> column_names;

	column_names.push_back("COL 1");
	column_names.push_back("COL 2");
	column_names.push_back("COL 3");
	column_names.push_back("COL 4");
	column_names.push_back("COL 5");

	const int tuple_count = 6;

	storage::AbstractBackend *backend = new storage::VMBackend();
	storage::TileGroupHeader *header = new storage::TileGroupHeader(backend, tuple_count);

	storage::Tile *tile = storage::TileFactory::GetTile(INVALID_OID, INVALID_OID, INVALID_OID, INVALID_OID,
													  	  header, backend, *schema, nullptr, tuple_count);

	storage::Tuple *tuple1 = new storage::Tuple(schema, true);
	storage::Tuple *tuple2 = new storage::Tuple(schema, true);
	storage::Tuple *tuple3 = new storage::Tuple(schema, true);

	tuple1->SetValue(0, ValueFactory::GetIntegerValue(1));
	tuple1->SetValue(1, ValueFactory::GetIntegerValue(1));
	tuple1->SetValue(2, ValueFactory::GetTinyIntValue(1));
	tuple1->SetValue(3, ValueFactory::GetStringValue("vivek sengupta", tile->GetPool()));
	tuple1->SetValue(4, ValueFactory::GetStringValue("vivek sengupta again", tile->GetPool()));

	tuple2->SetValue(0, ValueFactory::GetIntegerValue(2));
	tuple2->SetValue(1, ValueFactory::GetIntegerValue(2));
	tuple2->SetValue(2, ValueFactory::GetTinyIntValue(2));
	tuple2->SetValue(3, ValueFactory::GetStringValue("ming fang", tile->GetPool()));
	tuple2->SetValue(4, ValueFactory::GetStringValue("ming fang again", tile->GetPool()));

	tuple3->SetValue(0, ValueFactory::GetIntegerValue(3));
	tuple3->SetValue(1, ValueFactory::GetIntegerValue(3));
	tuple3->SetValue(2, ValueFactory::GetTinyIntValue(3));
	tuple3->SetValue(3, ValueFactory::GetStringValue("jinwoong kim", tile->GetPool()));
	tuple3->SetValue(4, ValueFactory::GetStringValue("jinwoong kim again", tile->GetPool()));

	tile->InsertTuple(0, tuple1);
	tile->InsertTuple(1, tuple2);
	tile->InsertTuple(2, tuple3);

	//std::cout << (*tile);

	//tile->InsertTuple(2, tuple1);

	//std::cout << (*tile);

	/*
	 * Print details of old tile
	 */
	const catalog::Schema *old_schema;
	bool old_tile_is_inlined;
	uint16_t old_tile_allocated_tuple_count, old_tile_active_tuple_count;
	uint32_t old_tile_size;
	uint32_t old_tile_tuple_size;

	std::cout << "-------------------" << std::endl;
	std::cout << "Details of old tile" << std::endl;
	std::cout << "-------------------" << std::endl;

	std::cout << "base address of old tile: " << static_cast<void *>(tile) << std::endl;

	old_tile_size = tile->GetInlinedSize();
	std::cout << "old tile size: " << old_tile_size << std:: endl;

	old_tile_allocated_tuple_count = tile->GetAllocatedTupleCount();
	std::cout << "old tile allocated tuple count: " << old_tile_allocated_tuple_count << std:: endl;

	old_tile_active_tuple_count = tile->GetActiveTupleCount();
	std::cout << "old tile active tuple count: " << old_tile_active_tuple_count << std:: endl;
	old_tile_active_tuple_count = 3;

	old_tile_tuple_size = old_tile_size / old_tile_allocated_tuple_count;
	std::cout << "size of each tuple in old tile: " << old_tile_tuple_size << std::endl;

	old_schema = tile->GetSchema();
	old_tile_is_inlined = old_schema->IsInlined();
	std::cout << "Is the entire old tile inlined? " << (old_tile_is_inlined? "true" : "false") << std::endl;

	Pool *old_pool = tile->GetPool();
	std::cout << "Pool associated with old tile is at address: " << static_cast<void *>(old_pool) << std::endl;

	int64_t old_pool_size = old_pool->GetAllocatedMemory();
	std::cout << "size of old pool: " << old_pool_size << std::endl;

	/*
	 * Create a new tile from the old tile
	 */
	std::vector<catalog::ColumnInfo> new_columns = old_schema->GetColumns();
	const catalog::Schema *new_schema = new catalog::Schema(columns);

	storage::AbstractBackend *new_backend = new storage::VMBackend();
	storage::TileGroupHeader *new_header = new storage::TileGroupHeader(new_backend, tuple_count);
	storage::Tile *new_tile = storage::TileFactory::GetTile(INVALID_OID, INVALID_OID, INVALID_OID, INVALID_OID,
											  new_header, new_backend, *new_schema, nullptr, old_tile_allocated_tuple_count);
	Pool *new_pool = new_tile->GetPool();

	storage::Tuple *old_tuple;

	for(int old_tup_itr=0; old_tup_itr<old_tile_active_tuple_count; old_tup_itr++)
	{
		old_tuple = tile->GetTuple(old_tup_itr);
		new_tile->InsertTuple(old_tup_itr,old_tuple);
	}

	/*
	 * Print details of new tile
	 */
	bool new_tile_is_inlined;
	uint16_t new_tile_allocated_tuple_count, new_tile_active_tuple_count;
	uint32_t new_tile_size;
	uint32_t new_tile_tuple_size;

	std::cout << "-------------------" << std::endl;
	std::cout << "Details of new tile" << std::endl;
	std::cout << "-------------------" << std::endl;

	std::cout << "base address of new tile: " << static_cast<void *>(new_tile) << std::endl;

	new_tile_size = new_tile->GetInlinedSize();
	std::cout << "new tile size: " << new_tile_size << std:: endl;

	new_tile_allocated_tuple_count = tile->GetAllocatedTupleCount();
	std::cout << "new tile allocated tuple count: " << new_tile_allocated_tuple_count << std:: endl;

	new_tile_active_tuple_count = tile->GetActiveTupleCount();
	std::cout << "new tile active tuple count: " << new_tile_active_tuple_count << std:: endl;
	new_tile_active_tuple_count = 3;

	new_tile_tuple_size = new_tile_size / new_tile_allocated_tuple_count;
	std::cout << "size of each tuple in new tile: " << new_tile_tuple_size << std::endl;

	new_schema = new_tile->GetSchema();
	new_tile_is_inlined = new_schema->IsInlined();
	std::cout << "Is the entire new tile inlined? " << (new_tile_is_inlined? "true" : "false") << std::endl;

	std::cout << "Pool associated with new tile is at address: " << static_cast<void *>(new_pool) << std::endl;

	int64_t new_pool_size = new_pool->GetAllocatedMemory();
	std::cout << "size of new pool: " << new_pool_size << std::endl;

	std::cout << "------------------------------------" << std:: endl;
	std::cout << "In case some columns are not inlined" << std:: endl;
	std::cout << "------------------------------------" << std:: endl;

	if(!new_tile_is_inlined)
	{
		int uninlined_col_cnt = new_schema->GetUninlinedColumnCount();

		int uninlined_col_index;
		Value uninlined_col_value, new_uninlined_col_value;
		storage::Tuple *new_tuple;

		for(int col_itr=0; col_itr<uninlined_col_cnt; col_itr++) {

			uninlined_col_index = new_schema->GetUninlinedColumnIndex(col_itr);
			std::cout << " ----------------------------------" << std::endl;
			std::cout << " index of next uninlined column: " << uninlined_col_index << std::endl;
			std::cout << " ----------------------------------" << std::endl << std::endl;

			for(int tup_itr=0; tup_itr<new_tile_active_tuple_count; tup_itr++) {

				std::cout << "\t -----------------------------------------------------" << std::endl;
				std::cout << "\t Before associating new pool to new data for tuple: " << tup_itr << std::endl;
				std::cout << "\t -----------------------------------------------------" << std::endl;

				new_tuple = new_tile->GetTuple(tup_itr);
				std::cout << "\t address of new_tuple: " << static_cast<void *>(new_tuple) << std::endl << std::endl;

				uninlined_col_value = new_tile->GetValue(tup_itr,uninlined_col_index);
				std::cout << "\t uninlined column value: " << uninlined_col_value << std::endl;

				size_t uninlined_col_object_len = ValuePeeker::PeekObjectLength(uninlined_col_value);
				std::cout << "\t size of uninlined column object: " << uninlined_col_object_len << std::endl;

				unsigned char* uninlined_col_object_ptr = static_cast<unsigned char *>(ValuePeeker::PeekObjectValue(uninlined_col_value));
				std::cout << "\t uninlined column object pointer: " << static_cast<void *>(uninlined_col_object_ptr) << std::endl;

				std::string uninlined_varchar_str(reinterpret_cast<char const*>(uninlined_col_object_ptr), uninlined_col_object_len);
				std::cout << "\t the data stored uninlined is: " << uninlined_varchar_str << std::endl << std::endl;

				// Create a new Value object with the uninlined string w.r.t. the new pool
				Value new_val = ValueFactory::GetStringValue(uninlined_varchar_str, new_pool);
				// Set the newly created value object to the tuple
				new_tile->SetValue(new_val, tup_itr, uninlined_col_index);

				std::cout << "\t ---------------------------------------------" << std::endl;
				std::cout << "\t Associated new pool to new data for tuple: " << tup_itr << std::endl;
				std::cout << "\t ---------------------------------------------" << std::endl;

				new_uninlined_col_value = new_tile->GetValue(tup_itr,uninlined_col_index);
				std::cout << "\t new uninlined column value: " << new_uninlined_col_value << std::endl;

				size_t new_uninlined_col_object_len = ValuePeeker::PeekObjectLength(new_uninlined_col_value);
				std::cout << "\t size of uninlined column object: " << new_uninlined_col_object_len << std::endl;

				unsigned char* new_uninlined_col_object_ptr = static_cast<unsigned char *>(ValuePeeker::PeekObjectValue(new_uninlined_col_value));
				std::cout << "\t new uninlined column object pointer: " << static_cast<void *>(new_uninlined_col_object_ptr) << std::endl;

				std::string new_uninlined_varchar_str( reinterpret_cast<char const*>(new_uninlined_col_object_ptr), uninlined_col_object_len);
				std::cout << "\t the new data stored uninlined is: " << new_uninlined_varchar_str << std::endl << std::endl;
			}
		}

		delete new_tuple;
	}

	delete tuple1;
	delete tuple2;
	delete tuple3;
	delete tile;
	delete header;
	delete schema;
	delete backend;
}

} // End test namespace
} // End peloton namespace

<|endoftext|>


<commit_before>#include "stringify.h"

namespace mahjong {

static long parse_tiles_impl(const char *str, tile_t *tiles, long max_cnt, long *out_tile_cnt) {
    //if (strspn(str, "123456789mpsESWNCFP") != strlen(str)) {
    //    return PARSE_ERROR_ILLEGAL_CHARACTER;
    //}

    long tile_cnt = 0;

#define SET_SUIT_FOR_NUMBERED(value_)       \
    for (long i = tile_cnt; i > 0;) {       \
        if (tiles[--i] & 0xF0) break;       \
        tiles[i] |= value_;                 \
        } (void)0

    const char *p = str;
    for (; tile_cnt < max_cnt && *p != '\0'; ++p) {
        char c = *p;
        switch (c) {
        case '1': tiles[tile_cnt++] = 1; break;
        case '2': tiles[tile_cnt++] = 2; break;
        case '3': tiles[tile_cnt++] = 3; break;
        case '4': tiles[tile_cnt++] = 4; break;
        case '5': tiles[tile_cnt++] = 5; break;
        case '6': tiles[tile_cnt++] = 6; break;
        case '7': tiles[tile_cnt++] = 7; break;
        case '8': tiles[tile_cnt++] = 8; break;
        case '9': tiles[tile_cnt++] = 9; break;
        case 'm': SET_SUIT_FOR_NUMBERED(0x10); break;
        case 's': SET_SUIT_FOR_NUMBERED(0x20); break;
        case 'p': SET_SUIT_FOR_NUMBERED(0x30); break;
        case 'E': tiles[tile_cnt++] = TILE_E; break;
        case 'S': tiles[tile_cnt++] = TILE_S; break;
        case 'W': tiles[tile_cnt++] = TILE_W; break;
        case 'N': tiles[tile_cnt++] = TILE_N; break;
        case 'C': tiles[tile_cnt++] = TILE_C; break;
        case 'F': tiles[tile_cnt++] = TILE_F; break;
        case 'P': tiles[tile_cnt++] = TILE_P; break;
        default: goto parse_finish;
        }
    }

parse_finish:
    if (tile_cnt > 0 && !(tiles[tile_cnt - 1] & 0xF0)) {
        bool hasSuffix = false;
        for (; !hasSuffix && *p != '\0'; ++p) {
            char c = *p;
            switch (c) {
            case 'm': SET_SUIT_FOR_NUMBERED(0x10); hasSuffix = true; break;
            case 's': SET_SUIT_FOR_NUMBERED(0x20); hasSuffix = true; break;
            case 'p': SET_SUIT_FOR_NUMBERED(0x30); hasSuffix = true; break;
            default: break;
            }
        }

        if (!hasSuffix) {
            return PARSE_ERROR_NO_SUFFIX_AFTER_DIGIT;
        }
    }

#undef SET_SUIT_FOR_NUMBERED

    if (out_tile_cnt != nullptr) {
        *out_tile_cnt = tile_cnt;
    }
    return (p - str);
}

long parse_tiles(const char *str, tile_t *tiles, long max_cnt) {
    long tile_cnt;
    if (parse_tiles_impl(str, tiles, max_cnt, &tile_cnt) > 0) {
        return tile_cnt;
    }
    return 0;
}

static long make_fixed_pack(const tile_t *tiles, long tile_cnt, pack_t *pack) {
    if (tile_cnt > 0) {
        if (tile_cnt != 3 && tile_cnt != 4) {
            return PARSE_ERROR_TOO_MANY_TILES_FOR_FIXED_SET;
        }
        if (tile_cnt == 3) {
            if (tiles[0] == tiles[1] && tiles[1] == tiles[2]) {
                *pack = make_pack(true, PACK_TYPE_PUNG, tiles[0]);
            }
            else {
                tile_t temp[3] = { tiles[0], tiles[1], tiles[2] };
                std::sort(std::begin(temp), std::end(temp));
                if (temp[0] + 1 == temp[1] && temp[1] + 1 == temp[2]) {
                    *pack = make_pack(true, PACK_TYPE_CHOW, temp[1]);
                }
                else {
                    return PARSE_ERROR_CANNOT_MAKE_FIXED_SET;
                }
            }
        }
        else {
            if (tiles[0] != tiles[1] || tiles[1] != tiles[2] || tiles[2] != tiles[3]) {
                return PARSE_ERROR_CANNOT_MAKE_FIXED_SET;
            }
            *pack = make_pack(true, PACK_TYPE_KONG, tiles[0]);
        }
        return 1;
    }
    return 0;
}

long string_to_tiles(const char *str, hand_tiles_t *hand_tiles) {
    pack_t packs[4];
    long pack_cnt = 0;
    bool is_concealed_kong = false;
    tile_t tiles[13];
    long tile_cnt = 0;

    const char *p = str;
    while (char c = *p) {
        const char *q;
        switch (c) {
        case ' ': {
            if (pack_cnt > 4) {
                return PARSE_ERROR_TOO_MANY_FIXED_SET;
            }
            long ret = make_fixed_pack(tiles, tile_cnt, &packs[pack_cnt]);
            if (ret < 0) {
                return ret;
            }
            pack_cnt += ret;
            q = ++p;
            tile_cnt = 0;
            break;
        }
        case '[': {
            if (pack_cnt > 4) {
                return PARSE_ERROR_TOO_MANY_FIXED_SET;
            }
            long ret = make_fixed_pack(tiles, tile_cnt, &packs[pack_cnt]);
            if (ret < 0) {
                return ret;
            }
            pack_cnt += ret;
            q = ++p;
            is_concealed_kong = true;
            break;
        }
        case ']':
            if (!is_concealed_kong) {
                return PARSE_ERROR_ILLEGAL_CHARACTER;
            }
            if (tile_cnt != 4) {
                return PARSE_ERROR_TOO_MANY_TILES_FOR_FIXED_SET;
            }
            q = ++p;
            packs[pack_cnt] = make_pack(false, PACK_TYPE_KONG, tiles[0]);
            is_concealed_kong = false;
            ++pack_cnt;
            tile_cnt = 0;
            break;
        default: {
                long ret = parse_tiles_impl(p, tiles, 13, &tile_cnt);
                if (ret <= 0) {
                    return ret;
                }
                q = p + ret;
            }
            break;
        }
        p = q;
    }

    memcpy(hand_tiles->fixed_packs, packs, pack_cnt * sizeof(pack_t));
    hand_tiles->pack_count = pack_cnt;
    memcpy(hand_tiles->standing_tiles, tiles, tile_cnt * sizeof(tile_t));
    hand_tiles->tile_count = tile_cnt;

    return PARSE_NO_ERROR;
}

}

<commit_msg>修复解析字符串逻辑错误<commit_after>#include "stringify.h"

namespace mahjong {

static long parse_tiles_impl(const char *str, tile_t *tiles, long max_cnt, long *out_tile_cnt) {
    //if (strspn(str, "123456789mpsESWNCFP") != strlen(str)) {
    //    return PARSE_ERROR_ILLEGAL_CHARACTER;
    //}

    long tile_cnt = 0;

#define SET_SUIT_FOR_NUMBERED(value_)       \
    for (long i = tile_cnt; i > 0;) {       \
        if (tiles[--i] & 0xF0) break;       \
        tiles[i] |= value_;                 \
        } (void)0

    const char *p = str;
    for (; tile_cnt < max_cnt && *p != '\0'; ++p) {
        char c = *p;
        switch (c) {
        case '1': tiles[tile_cnt++] = 1; break;
        case '2': tiles[tile_cnt++] = 2; break;
        case '3': tiles[tile_cnt++] = 3; break;
        case '4': tiles[tile_cnt++] = 4; break;
        case '5': tiles[tile_cnt++] = 5; break;
        case '6': tiles[tile_cnt++] = 6; break;
        case '7': tiles[tile_cnt++] = 7; break;
        case '8': tiles[tile_cnt++] = 8; break;
        case '9': tiles[tile_cnt++] = 9; break;
        case 'm': SET_SUIT_FOR_NUMBERED(0x10); break;
        case 's': SET_SUIT_FOR_NUMBERED(0x20); break;
        case 'p': SET_SUIT_FOR_NUMBERED(0x30); break;
        case 'E': tiles[tile_cnt++] = TILE_E; break;
        case 'S': tiles[tile_cnt++] = TILE_S; break;
        case 'W': tiles[tile_cnt++] = TILE_W; break;
        case 'N': tiles[tile_cnt++] = TILE_N; break;
        case 'C': tiles[tile_cnt++] = TILE_C; break;
        case 'F': tiles[tile_cnt++] = TILE_F; break;
        case 'P': tiles[tile_cnt++] = TILE_P; break;
        default: goto parse_finish;
        }
    }

parse_finish:
    if (tile_cnt > 0 && !(tiles[tile_cnt - 1] & 0xF0)) {
        bool hasSuffix = false;
        for (; !hasSuffix && *p != '\0'; ++p) {
            char c = *p;
            switch (c) {
            case 'm': SET_SUIT_FOR_NUMBERED(0x10); hasSuffix = true; break;
            case 's': SET_SUIT_FOR_NUMBERED(0x20); hasSuffix = true; break;
            case 'p': SET_SUIT_FOR_NUMBERED(0x30); hasSuffix = true; break;
            default: break;
            }
        }

        if (!hasSuffix) {
            return PARSE_ERROR_NO_SUFFIX_AFTER_DIGIT;
        }
    }

#undef SET_SUIT_FOR_NUMBERED

    if (out_tile_cnt != nullptr) {
        *out_tile_cnt = tile_cnt;
    }
    return (p - str);
}

long parse_tiles(const char *str, tile_t *tiles, long max_cnt) {
    long tile_cnt;
    if (parse_tiles_impl(str, tiles, max_cnt, &tile_cnt) > 0) {
        return tile_cnt;
    }
    return 0;
}

static long make_fixed_pack(const tile_t *tiles, long tile_cnt, pack_t *pack) {
    if (tile_cnt > 0) {
        if (tile_cnt != 3 && tile_cnt != 4) {
            return PARSE_ERROR_TOO_MANY_TILES_FOR_FIXED_SET;
        }
        if (tile_cnt == 3) {
            if (tiles[0] == tiles[1] && tiles[1] == tiles[2]) {
                *pack = make_pack(true, PACK_TYPE_PUNG, tiles[0]);
            }
            else {
                tile_t temp[3] = { tiles[0], tiles[1], tiles[2] };
                std::sort(std::begin(temp), std::end(temp));
                if (temp[0] + 1 == temp[1] && temp[1] + 1 == temp[2]) {
                    *pack = make_pack(true, PACK_TYPE_CHOW, temp[1]);
                }
                else {
                    return PARSE_ERROR_CANNOT_MAKE_FIXED_SET;
                }
            }
        }
        else {
            if (tiles[0] != tiles[1] || tiles[1] != tiles[2] || tiles[2] != tiles[3]) {
                return PARSE_ERROR_CANNOT_MAKE_FIXED_SET;
            }
            *pack = make_pack(true, PACK_TYPE_KONG, tiles[0]);
        }
        return 1;
    }
    return 0;
}

long string_to_tiles(const char *str, hand_tiles_t *hand_tiles) {
    pack_t packs[4];
    long pack_cnt = 0;
    bool is_concealed_kong = false;
    tile_t tiles[13];
    long tile_cnt = 0;

    const char *p = str;
    while (char c = *p) {
        const char *q;
        switch (c) {
        case ' ': {
            if (pack_cnt > 4) {
                return PARSE_ERROR_TOO_MANY_FIXED_SET;
            }
            long ret = make_fixed_pack(tiles, tile_cnt, &packs[pack_cnt]);
            if (ret < 0) {
                return ret;
            }
            pack_cnt += ret;
            q = ++p;
            tile_cnt = 0;
            break;
        }
        case '[': {
            if (pack_cnt > 4) {
                return PARSE_ERROR_TOO_MANY_FIXED_SET;
            }
            long ret = make_fixed_pack(tiles, tile_cnt, &packs[pack_cnt]);
            if (ret < 0) {
                return ret;
            }
            pack_cnt += ret;
            q = ++p;
            is_concealed_kong = true;
            break;
        }
        case ']':
            if (!is_concealed_kong) {
                return PARSE_ERROR_ILLEGAL_CHARACTER;
            }
            if (tile_cnt != 4) {
                return PARSE_ERROR_TOO_MANY_TILES_FOR_FIXED_SET;
            }
            q = ++p;
            packs[pack_cnt] = make_pack(false, PACK_TYPE_KONG, tiles[0]);
            is_concealed_kong = false;
            ++pack_cnt;
            tile_cnt = 0;
            break;
        default: {
                long ret = parse_tiles_impl(p, tiles, 13, &tile_cnt);
                if (ret < 0) {
                    return ret;
                }
                if (ret == 0) {
                    return PARSE_ERROR_ILLEGAL_CHARACTER;
                }
                q = p + ret;
            }
            break;
        }
        p = q;
    }

    memcpy(hand_tiles->fixed_packs, packs, pack_cnt * sizeof(pack_t));
    hand_tiles->pack_count = pack_cnt;
    memcpy(hand_tiles->standing_tiles, tiles, tile_cnt * sizeof(tile_t));
    hand_tiles->tile_count = tile_cnt;

    return PARSE_NO_ERROR;
}

}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: servicehandler.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 01:21:51 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

//_________________________________________________________________________________________________________________
//  my own includes
//_________________________________________________________________________________________________________________

#ifndef __FRAMEWORK_DISPATCH_SERVICEHANDLER_HXX_
#include <dispatch/servicehandler.hxx>
#endif

#ifndef __FRAMEWORK_THREADHELP_READGUARD_HXX_
#include <threadhelp/readguard.hxx>
#endif

#ifndef __FRAMEWORK_GENERAL_H_
#include <general.h>
#endif

#ifndef __FRAMEWORK_SERVICES_H_
#include <services.h>
#endif

//_________________________________________________________________________________________________________________
//  interface includes
//_________________________________________________________________________________________________________________

#ifndef _COM_SUN_STAR_FRAME_DISPATCHRESULTSTATE_HPP_
#include <com/sun/star/frame/DispatchResultState.hpp>
#endif

#ifndef _COM_SUN_STAR_TASK_XJOBEXECUTOR_HPP_
#include <com/sun/star/task/XJobExecutor.hpp>
#endif

//_________________________________________________________________________________________________________________
//  includes of other projects
//_________________________________________________________________________________________________________________

#include <vcl/svapp.hxx>

//_________________________________________________________________________________________________________________
//  namespace
//_________________________________________________________________________________________________________________

namespace framework{

//_________________________________________________________________________________________________________________
//  non exported const
//_________________________________________________________________________________________________________________

#define PROTOCOL_VALUE      "service:"
#define PROTOCOL_LENGTH     8

//_________________________________________________________________________________________________________________
//  non exported definitions
//_________________________________________________________________________________________________________________

//_________________________________________________________________________________________________________________
//  declarations
//_________________________________________________________________________________________________________________

//_________________________________________________________________________________________________________________
// XInterface, XTypeProvider, XServiceInfo

DEFINE_XINTERFACE_5(ServiceHandler                                  ,
                    OWeakObject                                     ,
                    DIRECT_INTERFACE(css::lang::XTypeProvider      ),
                    DIRECT_INTERFACE(css::lang::XServiceInfo       ),
                    DIRECT_INTERFACE(css::frame::XDispatchProvider ),
                    DIRECT_INTERFACE(css::frame::XNotifyingDispatch),
                    DIRECT_INTERFACE(css::frame::XDispatch         ))

DEFINE_XTYPEPROVIDER_5(ServiceHandler                ,
                       css::lang::XTypeProvider      ,
                       css::lang::XServiceInfo       ,
                       css::frame::XDispatchProvider ,
                       css::frame::XNotifyingDispatch,
                       css::frame::XDispatch         )

DEFINE_XSERVICEINFO_MULTISERVICE(ServiceHandler                   ,
                                 ::cppu::OWeakObject              ,
                                 SERVICENAME_PROTOCOLHANDLER      ,
                                 IMPLEMENTATIONNAME_SERVICEHANDLER)

DEFINE_INIT_SERVICE(ServiceHandler,
                    {
                        /*Attention
                            I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
                            to create a new instance of this class by our own supported service factory.
                            see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
                        */
                    }
                   )

//_________________________________________________________________________________________________________________

/**
    @short      standard ctor
    @descr      These initialize a new instance of ths class with needed informations for work.

    @param      xFactory
                reference to uno servicemanager for creation of new services

    @modified   02.05.2002 08:16, as96863
*/
ServiceHandler::ServiceHandler( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory )
        //  Init baseclasses first
        : ThreadHelpBase( &Application::GetSolarMutex() )
        , OWeakObject   (                               )
        // Init member
        , m_xFactory    ( xFactory                      )
{
}

//_________________________________________________________________________________________________________________

/**
    @short      standard dtor
    @descr      -

    @modified   02.05.2002 08:16, as96863
*/
ServiceHandler::~ServiceHandler()
{
    m_xFactory = NULL;
}

//_________________________________________________________________________________________________________________

/**
    @short      decide if this dispatch implementation can be used for requested URL or not
    @descr      A protocol handler is registerd for an URL pattern inside configuration and will
                be asked by the generic dispatch mechanism inside framework, if he can handle this
                special URL wich match his registration. He can agree by returning of a valid dispatch
                instance or disagree by returning <NULL/>.
                We don't create new dispatch instances here realy - we return THIS as result to handle it
                at the same implementation.

    @modified   02.05.2002 15:25, as96863
*/
css::uno::Reference< css::frame::XDispatch > SAL_CALL ServiceHandler::queryDispatch( const css::util::URL&  aURL    ,
                                                                                const ::rtl::OUString& sTarget ,
                                                                                sal_Int32        nFlags  ) throw( css::uno::RuntimeException )
{
    css::uno::Reference< css::frame::XDispatch > xDispatcher;
    if (aURL.Complete.compareToAscii(PROTOCOL_VALUE,PROTOCOL_LENGTH)==0)
        xDispatcher = this;
    return xDispatcher;
}

//_________________________________________________________________________________________________________________

/**
    @short      do the same like dispatch() but for multiple requests at the same time
    @descr      -

    @modified   02.05.2002 15:27, as96863
*/
css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL ServiceHandler::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor ) throw( css::uno::RuntimeException )
{
    sal_Int32 nCount = lDescriptor.getLength();
    css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount );
    for( sal_Int32 i=0; i<nCount; ++i )
    {
        lDispatcher[i] = this->queryDispatch(
                            lDescriptor[i].FeatureURL,
                            lDescriptor[i].FrameName,
                            lDescriptor[i].SearchFlags);
    }
    return lDispatcher;
}

//_________________________________________________________________________________________________________________

/**
    @short      dispatch URL with arguments
    @descr      We use threadsafe internal method to do so. It returns a state value - but we ignore it.
                Because we doesn't support status listener notifications here.

    @param      aURL
                    uno URL which should be executed
    @param      lArguments
                    list of optional arguments for this request

    @modified   02.05.2002 08:19, as96863
*/
void SAL_CALL ServiceHandler::dispatch( const css::util::URL&                                  aURL       ,
                                    const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException )
{
    // dispatch() is an [oneway] call ... and may our user release his reference to us immediatly.
    // So we should hold us self alive till this call ends.
    css::uno::Reference< css::frame::XNotifyingDispatch > xSelfHold(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
    implts_dispatch(aURL,lArguments);
    // No notification for status listener!
}

//_________________________________________________________________________________________________________________

/**
    @short      dispatch with guaranteed notifications about success
    @descr      We use threadsafe internal method to do so. Return state of this function will be used
                for notification if an optional listener is given.

    @param      aURL
                    uno URL which should be executed
    @param      lArguments
                    list of optional arguments for this request
    @param      xListener
                    optional listener for state events

    @modified   30.04.2002 14:49, as96863
*/
void SAL_CALL ServiceHandler::dispatchWithNotification( const css::util::URL&                                             aURL      ,
                                                        const css::uno::Sequence< css::beans::PropertyValue >&            lArguments,
                                                        const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) throw( css::uno::RuntimeException )
{
    // This class was designed to die by reference. And if user release his reference to us immediatly after calling this method
    // we can run into some problems. So we hold us self alive till this method ends.
    // Another reason: We can use this reference as source of sending event at the end too.
    css::uno::Reference< css::frame::XNotifyingDispatch > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);

    css::uno::Reference< css::uno::XInterface > xService = implts_dispatch(aURL,lArguments);
    if (xListener.is())
    {
        css::frame::DispatchResultEvent aEvent;
        if (xService.is())
            aEvent.State = css::frame::DispatchResultState::SUCCESS;
        else
            aEvent.State = css::frame::DispatchResultState::FAILURE;
        aEvent.Result <<= xService; // may NULL for state=FAILED!
        aEvent.Source = xThis;

        xListener->dispatchFinished( aEvent );
    }
}

//_________________________________________________________________________________________________________________

/**
    @short      threadsafe helper for dispatch calls
    @descr      We support two interfaces for the same process - dispatch URLs. That the reason for this internal
                function. It implements the real dispatch operation and returns a state value which inform caller
                about success. He can notify listener then by using this return value.

    @param      aURL
                    uno URL which should be executed
    @param      lArguments
                    list of optional arguments for this request

    @return     <NULL/> if requested service couldn't be created successullfy;
                a valid reference otherwise. This return value can be used to indicate,
                if dispatch was successfully or not.

    @modified   02.05.2002 10:51, as96863
*/
css::uno::Reference< css::uno::XInterface > ServiceHandler::implts_dispatch( const css::util::URL&                                  aURL       ,
                                                                             const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException )
{
    /* SAFE */
    ReadGuard aReadLock( m_aLock );
    css::uno::Reference< css::lang::XMultiServiceFactory > xFactory = m_xFactory;
    aReadLock.unlock();
    /* SAFE */

    if (!xFactory.is())
        return css::uno::Reference< css::uno::XInterface >();

    // extract service name and may optional given parameters from given URL
    // and use it to create and start the component
    ::rtl::OUString sServiceAndArguments = aURL.Complete.copy(PROTOCOL_LENGTH);
    ::rtl::OUString sServiceName;
    ::rtl::OUString sArguments  ;

    sal_Int32 nArgStart = sServiceAndArguments.indexOf('?',0);
    if (nArgStart!=-1)
    {
        sServiceName = sServiceAndArguments.copy(0,nArgStart);
        ++nArgStart; // ignore '?'!
        sArguments   = sServiceAndArguments.copy(nArgStart);
    }
    else
    {
        sServiceName = sServiceAndArguments;
    }

    if (!sServiceName.getLength())
        return css::uno::Reference< css::uno::XInterface >();

    // If a service doesnt support an optional job executor interface - he can't get
    // any given parameters!
    // Because we can't know if we must call createInstanceWithArguments() or XJobExecutor::trigger() ...

    css::uno::Reference< css::uno::XInterface > xService;
    try
    {
        // => a) a service starts running inside his own ctor and we create it only
        xService = xFactory->createInstance(sServiceName);
        // or b) he implements the right interface and starts there (may with optional parameters)
        css::uno::Reference< css::task::XJobExecutor > xExecuteable(xService, css::uno::UNO_QUERY);
        if (xExecuteable.is())
            xExecuteable->trigger(sArguments);
    }
    // ignore all errors - inclusive runtime errors!
    // E.g. a script based service (written in phyton) could not be executed
    // because it contains syntax errors, which was detected at runtime ...
    catch(const css::uno::Exception&)
        { xService.clear(); }

    return xService;
}

//_________________________________________________________________________________________________________________

/**
    @short      add/remove listener for state events
    @descr      We use an internal container to hold such registered listener. This container lives if we live.
                And if call pas registration as non breakable transaction - we can accept the request without
                any explicit lock. Because we share our mutex with this container.

    @param      xListener
                    reference to a valid listener for state events
    @param      aURL
                    URL about listener will be informed, if something occured

    @modified   30.04.2002 14:49, as96863
*/
void SAL_CALL ServiceHandler::addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xListener ,
                                                 const css::util::URL&                                     aURL      ) throw( css::uno::RuntimeException )
{
    // not suported yet
}

//_________________________________________________________________________________________________________________

void SAL_CALL ServiceHandler::removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xListener ,
                                                    const css::util::URL&                                     aURL      ) throw( css::uno::RuntimeException )
{
    // not suported yet
}

}       //  namespace framework
<commit_msg>INTEGRATION: CWS warnings01 (1.6.32); FILE MERGED 2005/11/16 13:10:35 pl 1.6.32.1: #i55991# removed warnings<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: servicehandler.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 11:16:53 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

//_________________________________________________________________________________________________________________
//  my own includes
//_________________________________________________________________________________________________________________

#ifndef __FRAMEWORK_DISPATCH_SERVICEHANDLER_HXX_
#include <dispatch/servicehandler.hxx>
#endif

#ifndef __FRAMEWORK_THREADHELP_READGUARD_HXX_
#include <threadhelp/readguard.hxx>
#endif

#ifndef __FRAMEWORK_GENERAL_H_
#include <general.h>
#endif

#ifndef __FRAMEWORK_SERVICES_H_
#include <services.h>
#endif

//_________________________________________________________________________________________________________________
//  interface includes
//_________________________________________________________________________________________________________________

#ifndef _COM_SUN_STAR_FRAME_DISPATCHRESULTSTATE_HPP_
#include <com/sun/star/frame/DispatchResultState.hpp>
#endif

#ifndef _COM_SUN_STAR_TASK_XJOBEXECUTOR_HPP_
#include <com/sun/star/task/XJobExecutor.hpp>
#endif

//_________________________________________________________________________________________________________________
//  includes of other projects
//_________________________________________________________________________________________________________________

#include <vcl/svapp.hxx>

//_________________________________________________________________________________________________________________
//  namespace
//_________________________________________________________________________________________________________________

namespace framework{

//_________________________________________________________________________________________________________________
//  non exported const
//_________________________________________________________________________________________________________________

#define PROTOCOL_VALUE      "service:"
#define PROTOCOL_LENGTH     8

//_________________________________________________________________________________________________________________
//  non exported definitions
//_________________________________________________________________________________________________________________

//_________________________________________________________________________________________________________________
//  declarations
//_________________________________________________________________________________________________________________

//_________________________________________________________________________________________________________________
// XInterface, XTypeProvider, XServiceInfo

DEFINE_XINTERFACE_5(ServiceHandler                                  ,
                    OWeakObject                                     ,
                    DIRECT_INTERFACE(css::lang::XTypeProvider      ),
                    DIRECT_INTERFACE(css::lang::XServiceInfo       ),
                    DIRECT_INTERFACE(css::frame::XDispatchProvider ),
                    DIRECT_INTERFACE(css::frame::XNotifyingDispatch),
                    DIRECT_INTERFACE(css::frame::XDispatch         ))

DEFINE_XTYPEPROVIDER_5(ServiceHandler                ,
                       css::lang::XTypeProvider      ,
                       css::lang::XServiceInfo       ,
                       css::frame::XDispatchProvider ,
                       css::frame::XNotifyingDispatch,
                       css::frame::XDispatch         )

DEFINE_XSERVICEINFO_MULTISERVICE(ServiceHandler                   ,
                                 ::cppu::OWeakObject              ,
                                 SERVICENAME_PROTOCOLHANDLER      ,
                                 IMPLEMENTATIONNAME_SERVICEHANDLER)

DEFINE_INIT_SERVICE(ServiceHandler,
                    {
                        /*Attention
                            I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
                            to create a new instance of this class by our own supported service factory.
                            see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
                        */
                    }
                   )

//_________________________________________________________________________________________________________________

/**
    @short      standard ctor
    @descr      These initialize a new instance of ths class with needed informations for work.

    @param      xFactory
                reference to uno servicemanager for creation of new services

    @modified   02.05.2002 08:16, as96863
*/
ServiceHandler::ServiceHandler( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory )
        //  Init baseclasses first
        : ThreadHelpBase( &Application::GetSolarMutex() )
        , OWeakObject   (                               )
        // Init member
        , m_xFactory    ( xFactory                      )
{
}

//_________________________________________________________________________________________________________________

/**
    @short      standard dtor
    @descr      -

    @modified   02.05.2002 08:16, as96863
*/
ServiceHandler::~ServiceHandler()
{
    m_xFactory = NULL;
}

//_________________________________________________________________________________________________________________

/**
    @short      decide if this dispatch implementation can be used for requested URL or not
    @descr      A protocol handler is registerd for an URL pattern inside configuration and will
                be asked by the generic dispatch mechanism inside framework, if he can handle this
                special URL wich match his registration. He can agree by returning of a valid dispatch
                instance or disagree by returning <NULL/>.
                We don't create new dispatch instances here realy - we return THIS as result to handle it
                at the same implementation.

    @modified   02.05.2002 15:25, as96863
*/
css::uno::Reference< css::frame::XDispatch > SAL_CALL ServiceHandler::queryDispatch( const css::util::URL&  aURL    ,
                                                                                const ::rtl::OUString& /*sTarget*/ ,
                                                                                sal_Int32        /*nFlags*/  ) throw( css::uno::RuntimeException )
{
    css::uno::Reference< css::frame::XDispatch > xDispatcher;
    if (aURL.Complete.compareToAscii(PROTOCOL_VALUE,PROTOCOL_LENGTH)==0)
        xDispatcher = this;
    return xDispatcher;
}

//_________________________________________________________________________________________________________________

/**
    @short      do the same like dispatch() but for multiple requests at the same time
    @descr      -

    @modified   02.05.2002 15:27, as96863
*/
css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL ServiceHandler::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor ) throw( css::uno::RuntimeException )
{
    sal_Int32 nCount = lDescriptor.getLength();
    css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount );
    for( sal_Int32 i=0; i<nCount; ++i )
    {
        lDispatcher[i] = this->queryDispatch(
                            lDescriptor[i].FeatureURL,
                            lDescriptor[i].FrameName,
                            lDescriptor[i].SearchFlags);
    }
    return lDispatcher;
}

//_________________________________________________________________________________________________________________

/**
    @short      dispatch URL with arguments
    @descr      We use threadsafe internal method to do so. It returns a state value - but we ignore it.
                Because we doesn't support status listener notifications here.

    @param      aURL
                    uno URL which should be executed
    @param      lArguments
                    list of optional arguments for this request

    @modified   02.05.2002 08:19, as96863
*/
void SAL_CALL ServiceHandler::dispatch( const css::util::URL&                                  aURL       ,
                                    const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException )
{
    // dispatch() is an [oneway] call ... and may our user release his reference to us immediatly.
    // So we should hold us self alive till this call ends.
    css::uno::Reference< css::frame::XNotifyingDispatch > xSelfHold(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);
    implts_dispatch(aURL,lArguments);
    // No notification for status listener!
}

//_________________________________________________________________________________________________________________

/**
    @short      dispatch with guaranteed notifications about success
    @descr      We use threadsafe internal method to do so. Return state of this function will be used
                for notification if an optional listener is given.

    @param      aURL
                    uno URL which should be executed
    @param      lArguments
                    list of optional arguments for this request
    @param      xListener
                    optional listener for state events

    @modified   30.04.2002 14:49, as96863
*/
void SAL_CALL ServiceHandler::dispatchWithNotification( const css::util::URL&                                             aURL      ,
                                                        const css::uno::Sequence< css::beans::PropertyValue >&            lArguments,
                                                        const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) throw( css::uno::RuntimeException )
{
    // This class was designed to die by reference. And if user release his reference to us immediatly after calling this method
    // we can run into some problems. So we hold us self alive till this method ends.
    // Another reason: We can use this reference as source of sending event at the end too.
    css::uno::Reference< css::frame::XNotifyingDispatch > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY);

    css::uno::Reference< css::uno::XInterface > xService = implts_dispatch(aURL,lArguments);
    if (xListener.is())
    {
        css::frame::DispatchResultEvent aEvent;
        if (xService.is())
            aEvent.State = css::frame::DispatchResultState::SUCCESS;
        else
            aEvent.State = css::frame::DispatchResultState::FAILURE;
        aEvent.Result <<= xService; // may NULL for state=FAILED!
        aEvent.Source = xThis;

        xListener->dispatchFinished( aEvent );
    }
}

//_________________________________________________________________________________________________________________

/**
    @short      threadsafe helper for dispatch calls
    @descr      We support two interfaces for the same process - dispatch URLs. That the reason for this internal
                function. It implements the real dispatch operation and returns a state value which inform caller
                about success. He can notify listener then by using this return value.

    @param      aURL
                    uno URL which should be executed
    @param      lArguments
                    list of optional arguments for this request

    @return     <NULL/> if requested service couldn't be created successullfy;
                a valid reference otherwise. This return value can be used to indicate,
                if dispatch was successfully or not.

    @modified   02.05.2002 10:51, as96863
*/
css::uno::Reference< css::uno::XInterface > ServiceHandler::implts_dispatch( const css::util::URL&                                  aURL       ,
                                                                             const css::uno::Sequence< css::beans::PropertyValue >& /*lArguments*/ ) throw( css::uno::RuntimeException )
{
    /* SAFE */
    ReadGuard aReadLock( m_aLock );
    css::uno::Reference< css::lang::XMultiServiceFactory > xFactory = m_xFactory;
    aReadLock.unlock();
    /* SAFE */

    if (!xFactory.is())
        return css::uno::Reference< css::uno::XInterface >();

    // extract service name and may optional given parameters from given URL
    // and use it to create and start the component
    ::rtl::OUString sServiceAndArguments = aURL.Complete.copy(PROTOCOL_LENGTH);
    ::rtl::OUString sServiceName;
    ::rtl::OUString sArguments  ;

    sal_Int32 nArgStart = sServiceAndArguments.indexOf('?',0);
    if (nArgStart!=-1)
    {
        sServiceName = sServiceAndArguments.copy(0,nArgStart);
        ++nArgStart; // ignore '?'!
        sArguments   = sServiceAndArguments.copy(nArgStart);
    }
    else
    {
        sServiceName = sServiceAndArguments;
    }

    if (!sServiceName.getLength())
        return css::uno::Reference< css::uno::XInterface >();

    // If a service doesnt support an optional job executor interface - he can't get
    // any given parameters!
    // Because we can't know if we must call createInstanceWithArguments() or XJobExecutor::trigger() ...

    css::uno::Reference< css::uno::XInterface > xService;
    try
    {
        // => a) a service starts running inside his own ctor and we create it only
        xService = xFactory->createInstance(sServiceName);
        // or b) he implements the right interface and starts there (may with optional parameters)
        css::uno::Reference< css::task::XJobExecutor > xExecuteable(xService, css::uno::UNO_QUERY);
        if (xExecuteable.is())
            xExecuteable->trigger(sArguments);
    }
    // ignore all errors - inclusive runtime errors!
    // E.g. a script based service (written in phyton) could not be executed
    // because it contains syntax errors, which was detected at runtime ...
    catch(const css::uno::Exception&)
        { xService.clear(); }

    return xService;
}

//_________________________________________________________________________________________________________________

/**
    @short      add/remove listener for state events
    @descr      We use an internal container to hold such registered listener. This container lives if we live.
                And if call pas registration as non breakable transaction - we can accept the request without
                any explicit lock. Because we share our mutex with this container.

    @param      xListener
                    reference to a valid listener for state events
    @param      aURL
                    URL about listener will be informed, if something occured

    @modified   30.04.2002 14:49, as96863
*/
void SAL_CALL ServiceHandler::addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/ ,
                                                 const css::util::URL&                                     /*aURL*/      ) throw( css::uno::RuntimeException )
{
    // not suported yet
}

//_________________________________________________________________________________________________________________

void SAL_CALL ServiceHandler::removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/ ,
                                                    const css::util::URL&                                     /*aURL*/      ) throw( css::uno::RuntimeException )
{
    // not suported yet
}

}       //  namespace framework
<|endoftext|>