<commit_before>//===- EarlyCSE.cpp - Simple and fast CSE pass ----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass performs a simple dominator tree walk that eliminates trivially
// redundant instructions.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "early-cse"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Instructions.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/RecyclingAllocator.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/Statistic.h"
using namespace llvm;

STATISTIC(NumSimplify, "Number of instructions simplified or DCE'd");
STATISTIC(NumCSE,      "Number of instructions CSE'd");
STATISTIC(NumCSELoad,  "Number of load instructions CSE'd");
STATISTIC(NumCSECall,  "Number of call instructions CSE'd");

static unsigned getHash(const void *V) {
  return DenseMapInfo<const void*>::getHashValue(V);
}

//===----------------------------------------------------------------------===//
// SimpleValue
//===----------------------------------------------------------------------===//

namespace {
  /// SimpleValue - Instances of this struct represent available values in the
  /// scoped hash table.
  struct SimpleValue {
    Instruction *Inst;

    SimpleValue(Instruction *I) : Inst(I) {
      assert((isSentinel() || canHandle(I)) && "Inst can't be handled!");
    }

    bool isSentinel() const {
      return Inst == DenseMapInfo<Instruction*>::getEmptyKey() ||
             Inst == DenseMapInfo<Instruction*>::getTombstoneKey();
    }

    static bool canHandle(Instruction *Inst) {
      return isa<CastInst>(Inst) || isa<BinaryOperator>(Inst) ||
             isa<GetElementPtrInst>(Inst) || isa<CmpInst>(Inst) ||
             isa<SelectInst>(Inst) || isa<ExtractElementInst>(Inst) ||
             isa<InsertElementInst>(Inst) || isa<ShuffleVectorInst>(Inst) ||
             isa<ExtractValueInst>(Inst) || isa<InsertValueInst>(Inst);
    }
  };
}

namespace llvm {
// SimpleValue is POD.
template<> struct isPodLike<SimpleValue> {
  static const bool value = true;
};

template<> struct DenseMapInfo<SimpleValue> {
  static inline SimpleValue getEmptyKey() {
    return DenseMapInfo<Instruction*>::getEmptyKey();
  }
  static inline SimpleValue getTombstoneKey() {
    return DenseMapInfo<Instruction*>::getTombstoneKey();
  }
  static unsigned getHashValue(SimpleValue Val);
  static bool isEqual(SimpleValue LHS, SimpleValue RHS);
};
}

unsigned DenseMapInfo<SimpleValue>::getHashValue(SimpleValue Val) {
  Instruction *Inst = Val.Inst;

  // Hash in all of the operands as pointers.
  unsigned Res = 0;
  for (unsigned i = 0, e = Inst->getNumOperands(); i != e; ++i)
    Res ^= getHash(Inst->getOperand(i)) << i;

  if (CastInst *CI = dyn_cast<CastInst>(Inst))
    Res ^= getHash(CI->getType());
  else if (CmpInst *CI = dyn_cast<CmpInst>(Inst))
    Res ^= CI->getPredicate();
  else if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(Inst)) {
    for (ExtractValueInst::idx_iterator I = EVI->idx_begin(),
         E = EVI->idx_end(); I != E; ++I)
      Res ^= *I;
  } else if (const InsertValueInst *IVI = dyn_cast<InsertValueInst>(Inst)) {
    for (InsertValueInst::idx_iterator I = IVI->idx_begin(),
         E = IVI->idx_end(); I != E; ++I)
      Res ^= *I;
  } else {
    // nothing extra to hash in.
    assert((isa<BinaryOperator>(Inst) || isa<GetElementPtrInst>(Inst) ||
            isa<SelectInst>(Inst) || isa<ExtractElementInst>(Inst) ||
            isa<InsertElementInst>(Inst) || isa<ShuffleVectorInst>(Inst)) &&
           "Invalid/unknown instruction");
  }

  // Mix in the opcode.
  return (Res << 1) ^ Inst->getOpcode();
}

bool DenseMapInfo<SimpleValue>::isEqual(SimpleValue LHS, SimpleValue RHS) {
  Instruction *LHSI = LHS.Inst, *RHSI = RHS.Inst;

  if (LHS.isSentinel() || RHS.isSentinel())
    return LHSI == RHSI;

  if (LHSI->getOpcode() != RHSI->getOpcode()) return false;
  return LHSI->isIdenticalTo(RHSI);
}

//===----------------------------------------------------------------------===//
// CallValue
//===----------------------------------------------------------------------===//

namespace {
  /// CallValue - Instances of this struct represent available call values in
  /// the scoped hash table.
  struct CallValue {
    Instruction *Inst;

    CallValue(Instruction *I) : Inst(I) {
      assert((isSentinel() || canHandle(I)) && "Inst can't be handled!");
    }

    bool isSentinel() const {
      return Inst == DenseMapInfo<Instruction*>::getEmptyKey() ||
             Inst == DenseMapInfo<Instruction*>::getTombstoneKey();
    }

    static bool canHandle(Instruction *Inst) {
      if (CallInst *CI = dyn_cast<CallInst>(Inst))
        return CI->onlyReadsMemory();
      return false;
    }
  };
}

namespace llvm {
  // CallValue is POD.
  template<> struct isPodLike<CallValue> {
    static const bool value = true;
  };

  template<> struct DenseMapInfo<CallValue> {
    static inline CallValue getEmptyKey() {
      return DenseMapInfo<Instruction*>::getEmptyKey();
    }
    static inline CallValue getTombstoneKey() {
      return DenseMapInfo<Instruction*>::getTombstoneKey();
    }
    static unsigned getHashValue(CallValue Val);
    static bool isEqual(CallValue LHS, CallValue RHS);
  };
}
unsigned DenseMapInfo<CallValue>::getHashValue(CallValue Val) {
  Instruction *Inst = Val.Inst;
  // Hash in all of the operands as pointers.
  unsigned Res = 0;
  for (unsigned i = 0, e = Inst->getNumOperands(); i != e; ++i)
    Res ^= getHash(Inst->getOperand(i)) << i;
  // Mix in the opcode.
  return (Res << 1) ^ Inst->getOpcode();
}

bool DenseMapInfo<CallValue>::isEqual(CallValue LHS, CallValue RHS) {
  Instruction *LHSI = LHS.Inst, *RHSI = RHS.Inst;
  if (LHS.isSentinel() || RHS.isSentinel())
    return LHSI == RHSI;
  return LHSI->isIdenticalTo(RHSI);
}

//===----------------------------------------------------------------------===//
// EarlyCSE pass.
//===----------------------------------------------------------------------===//

namespace {

/// EarlyCSE - This pass does a simple depth-first walk over the dominator
/// tree, eliminating trivially redundant instructions and using instsimplify
/// to canonicalize things as it goes.  It is intended to be fast and catch
/// obvious cases so that instcombine and other passes are more effective.  It
/// is expected that a later pass of GVN will catch the interesting/hard
/// cases.
class EarlyCSE : public FunctionPass {
public:
  const TargetData *TD;
  DominatorTree *DT;
  typedef RecyclingAllocator<BumpPtrAllocator,
                      ScopedHashTableVal<SimpleValue, Value*> > AllocatorTy;
  typedef ScopedHashTable<SimpleValue, Value*, DenseMapInfo<SimpleValue>,
                          AllocatorTy> ScopedHTType;

  /// AvailableValues - This scoped hash table contains the current values of
  /// all of our simple scalar expressions.  As we walk down the domtree, we
  /// look to see if instructions are in this: if so, we replace them with what
  /// we find, otherwise we insert them so that dominated values can succeed in
  /// their lookup.
  ScopedHTType *AvailableValues;

  /// AvailableLoads - This scoped hash table contains the current values
  /// of loads.  This allows us to get efficient access to dominating loads when
  /// we have a fully redundant load.  In addition to the most recent load, we
  /// keep track of a generation count of the read, which is compared against
  /// the current generation count.  The current generation count is
  /// incremented after every possibly writing memory operation, which ensures
  /// that we only CSE loads with other loads that have no intervening store.
  typedef ScopedHashTable<Value*, std::pair<Value*, unsigned> > LoadHTType;
  LoadHTType *AvailableLoads;

  /// AvailableCalls - This scoped hash table contains the current values
  /// of read-only call values.  It uses the same generation count as loads.
  typedef ScopedHashTable<CallValue, std::pair<Value*, unsigned> > CallHTType;
  CallHTType *AvailableCalls;

  /// CurrentGeneration - This is the current generation of the memory value.
  unsigned CurrentGeneration;

  static char ID;
  explicit EarlyCSE() : FunctionPass(ID) {
    initializeEarlyCSEPass(*PassRegistry::getPassRegistry());
  }

  bool runOnFunction(Function &F);

private:

  bool processNode(DomTreeNode *Node);

  // This transformation requires dominator postdominator info
  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequired<DominatorTree>();
    AU.setPreservesCFG();
  }
};
}

char EarlyCSE::ID = 0;

// createEarlyCSEPass - The public interface to this file.
FunctionPass *llvm::createEarlyCSEPass() {
  return new EarlyCSE();
}

INITIALIZE_PASS_BEGIN(EarlyCSE, "early-cse", "Early CSE", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTree)
INITIALIZE_PASS_END(EarlyCSE, "early-cse", "Early CSE", false, false)

bool EarlyCSE::processNode(DomTreeNode *Node) {
  // Define a scope in the scoped hash table.  When we are done processing this
  // domtree node and recurse back up to our parent domtree node, this will pop
  // off all the values we install.
  ScopedHTType::ScopeTy Scope(*AvailableValues);

  // Define a scope for the load values so that anything we add will get
  // popped when we recurse back up to our parent domtree node.
  LoadHTType::ScopeTy LoadScope(*AvailableLoads);

  // Define a scope for the call values so that anything we add will get
  // popped when we recurse back up to our parent domtree node.
  CallHTType::ScopeTy CallScope(*AvailableCalls);

  BasicBlock *BB = Node->getBlock();

  // If this block has a single predecessor, then the predecessor is the parent
  // of the domtree node and all of the live out memory values are still current
  // in this block.  If this block has multiple predecessors, then they could
  // have invalidated the live-out memory values of our parent value.  For now,
  // just be conservative and invalidate memory if this block has multiple
  // predecessors.
  if (BB->getSinglePredecessor() == 0)
    ++CurrentGeneration;

  bool Changed = false;

  // See if any instructions in the block can be eliminated.  If so, do it.  If
  // not, add them to AvailableValues.
  for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) {
    Instruction *Inst = I++;

    // Dead instructions should just be removed.
    if (isInstructionTriviallyDead(Inst)) {
      DEBUG(dbgs() << "EarlyCSE DCE: " << *Inst << '\n');
      Inst->eraseFromParent();
      Changed = true;
      ++NumSimplify;
      continue;
    }

    // If the instruction can be simplified (e.g. X+0 = X) then replace it with
    // its simpler value.
    if (Value *V = SimplifyInstruction(Inst, TD, DT)) {
      DEBUG(dbgs() << "EarlyCSE Simplify: " << *Inst << "  to: " << *V << '\n');
      Inst->replaceAllUsesWith(V);
      Inst->eraseFromParent();
      Changed = true;
      ++NumSimplify;
      continue;
    }

    // If this is a simple instruction that we can value number, process it.
    if (SimpleValue::canHandle(Inst)) {
      // See if the instruction has an available value.  If so, use it.
      if (Value *V = AvailableValues->lookup(Inst)) {
        DEBUG(dbgs() << "EarlyCSE CSE: " << *Inst << "  to: " << *V << '\n');
        Inst->replaceAllUsesWith(V);
        Inst->eraseFromParent();
        Changed = true;
        ++NumCSE;
        continue;
      }

      // Otherwise, just remember that this value is available.
      AvailableValues->insert(Inst, Inst);
      continue;
    }

    // If this is a non-volatile load, process it.
    if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
      // Ignore volatile loads.
      if (LI->isVolatile()) continue;

      // If we have an available version of this load, and if it is the right
      // generation, replace this instruction.
      std::pair<Value*, unsigned> InVal =
        AvailableLoads->lookup(Inst->getOperand(0));
      if (InVal.first != 0 && InVal.second == CurrentGeneration) {
        DEBUG(dbgs() << "EarlyCSE CSE LOAD: " << *Inst << "  to: "
              << *InVal.first << '\n');
        if (!Inst->use_empty()) Inst->replaceAllUsesWith(InVal.first);
        Inst->eraseFromParent();
        Changed = true;
        ++NumCSELoad;
        continue;
      }

      // Otherwise, remember that we have this instruction.
      AvailableLoads->insert(Inst->getOperand(0),
                          std::pair<Value*, unsigned>(Inst, CurrentGeneration));
      continue;
    }

    // If this is a read-only call, process it.
    if (CallValue::canHandle(Inst)) {
      // If we have an available version of this call, and if it is the right
      // generation, replace this instruction.
      std::pair<Value*, unsigned> InVal = AvailableCalls->lookup(Inst);
      if (InVal.first != 0 && InVal.second == CurrentGeneration) {
        DEBUG(dbgs() << "EarlyCSE CSE CALL: " << *Inst << "  to: "
                     << *InVal.first << '\n');
        if (!Inst->use_empty()) Inst->replaceAllUsesWith(InVal.first);
        Inst->eraseFromParent();
        Changed = true;
        ++NumCSECall;
        continue;
      }

      // Otherwise, remember that we have this instruction.
      AvailableCalls->insert(Inst,
                         std::pair<Value*, unsigned>(Inst, CurrentGeneration));
      continue;
    }

    // Okay, this isn't something we can CSE at all.  Check to see if it is
    // something that could modify memory.  If so, our available memory values
    // cannot be used so bump the generation count.
    if (Inst->mayWriteToMemory()) {
      ++CurrentGeneration;

      // Okay, we just invalidated anything we knew about loaded values.  Try to
      // salvage *something* by remembering that the stored value is a live
      // version of the pointer.  It is safe to forward from volatile stores to
      // non-volatile loads, so we don't have to check for volatility of the
      // store.
      if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
        AvailableLoads->insert(SI->getPointerOperand(),
         std::pair<Value*, unsigned>(SI->getValueOperand(), CurrentGeneration));
      }
    }
  }

  unsigned LiveOutGeneration = CurrentGeneration;
  for (DomTreeNode::iterator I = Node->begin(), E = Node->end(); I != E; ++I) {
    Changed |= processNode(*I);
    // Pop any generation changes off the stack from the recursive walk.
    CurrentGeneration = LiveOutGeneration;
  }
  return Changed;
}

bool EarlyCSE::runOnFunction(Function &F) {
  TD = getAnalysisIfAvailable<TargetData>();
  DT = &getAnalysis<DominatorTree>();

  // Tables that the pass uses when walking the domtree.
  ScopedHTType AVTable;
  AvailableValues = &AVTable;
  LoadHTType LoadTable;
  AvailableLoads = &LoadTable;
  CallHTType CallTable;
  AvailableCalls = &CallTable;

  CurrentGeneration = 0;
  return processNode(DT->getRootNode());
}
<commit_msg>switch the load table to use a recycling bump pointer allocator, speeding earlycse up by 6%.<commit_after>//===- EarlyCSE.cpp - Simple and fast CSE pass ----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass performs a simple dominator tree walk that eliminates trivially
// redundant instructions.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "early-cse"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Instructions.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/RecyclingAllocator.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/ADT/Statistic.h"
using namespace llvm;

STATISTIC(NumSimplify, "Number of instructions simplified or DCE'd");
STATISTIC(NumCSE,      "Number of instructions CSE'd");
STATISTIC(NumCSELoad,  "Number of load instructions CSE'd");
STATISTIC(NumCSECall,  "Number of call instructions CSE'd");

static unsigned getHash(const void *V) {
  return DenseMapInfo<const void*>::getHashValue(V);
}

//===----------------------------------------------------------------------===//
// SimpleValue
//===----------------------------------------------------------------------===//

namespace {
  /// SimpleValue - Instances of this struct represent available values in the
  /// scoped hash table.
  struct SimpleValue {
    Instruction *Inst;

    SimpleValue(Instruction *I) : Inst(I) {
      assert((isSentinel() || canHandle(I)) && "Inst can't be handled!");
    }

    bool isSentinel() const {
      return Inst == DenseMapInfo<Instruction*>::getEmptyKey() ||
             Inst == DenseMapInfo<Instruction*>::getTombstoneKey();
    }

    static bool canHandle(Instruction *Inst) {
      return isa<CastInst>(Inst) || isa<BinaryOperator>(Inst) ||
             isa<GetElementPtrInst>(Inst) || isa<CmpInst>(Inst) ||
             isa<SelectInst>(Inst) || isa<ExtractElementInst>(Inst) ||
             isa<InsertElementInst>(Inst) || isa<ShuffleVectorInst>(Inst) ||
             isa<ExtractValueInst>(Inst) || isa<InsertValueInst>(Inst);
    }
  };
}

namespace llvm {
// SimpleValue is POD.
template<> struct isPodLike<SimpleValue> {
  static const bool value = true;
};

template<> struct DenseMapInfo<SimpleValue> {
  static inline SimpleValue getEmptyKey() {
    return DenseMapInfo<Instruction*>::getEmptyKey();
  }
  static inline SimpleValue getTombstoneKey() {
    return DenseMapInfo<Instruction*>::getTombstoneKey();
  }
  static unsigned getHashValue(SimpleValue Val);
  static bool isEqual(SimpleValue LHS, SimpleValue RHS);
};
}

unsigned DenseMapInfo<SimpleValue>::getHashValue(SimpleValue Val) {
  Instruction *Inst = Val.Inst;

  // Hash in all of the operands as pointers.
  unsigned Res = 0;
  for (unsigned i = 0, e = Inst->getNumOperands(); i != e; ++i)
    Res ^= getHash(Inst->getOperand(i)) << i;

  if (CastInst *CI = dyn_cast<CastInst>(Inst))
    Res ^= getHash(CI->getType());
  else if (CmpInst *CI = dyn_cast<CmpInst>(Inst))
    Res ^= CI->getPredicate();
  else if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(Inst)) {
    for (ExtractValueInst::idx_iterator I = EVI->idx_begin(),
         E = EVI->idx_end(); I != E; ++I)
      Res ^= *I;
  } else if (const InsertValueInst *IVI = dyn_cast<InsertValueInst>(Inst)) {
    for (InsertValueInst::idx_iterator I = IVI->idx_begin(),
         E = IVI->idx_end(); I != E; ++I)
      Res ^= *I;
  } else {
    // nothing extra to hash in.
    assert((isa<BinaryOperator>(Inst) || isa<GetElementPtrInst>(Inst) ||
            isa<SelectInst>(Inst) || isa<ExtractElementInst>(Inst) ||
            isa<InsertElementInst>(Inst) || isa<ShuffleVectorInst>(Inst)) &&
           "Invalid/unknown instruction");
  }

  // Mix in the opcode.
  return (Res << 1) ^ Inst->getOpcode();
}

bool DenseMapInfo<SimpleValue>::isEqual(SimpleValue LHS, SimpleValue RHS) {
  Instruction *LHSI = LHS.Inst, *RHSI = RHS.Inst;

  if (LHS.isSentinel() || RHS.isSentinel())
    return LHSI == RHSI;

  if (LHSI->getOpcode() != RHSI->getOpcode()) return false;
  return LHSI->isIdenticalTo(RHSI);
}

//===----------------------------------------------------------------------===//
// CallValue
//===----------------------------------------------------------------------===//

namespace {
  /// CallValue - Instances of this struct represent available call values in
  /// the scoped hash table.
  struct CallValue {
    Instruction *Inst;

    CallValue(Instruction *I) : Inst(I) {
      assert((isSentinel() || canHandle(I)) && "Inst can't be handled!");
    }

    bool isSentinel() const {
      return Inst == DenseMapInfo<Instruction*>::getEmptyKey() ||
             Inst == DenseMapInfo<Instruction*>::getTombstoneKey();
    }

    static bool canHandle(Instruction *Inst) {
      if (CallInst *CI = dyn_cast<CallInst>(Inst))
        return CI->onlyReadsMemory();
      return false;
    }
  };
}

namespace llvm {
  // CallValue is POD.
  template<> struct isPodLike<CallValue> {
    static const bool value = true;
  };

  template<> struct DenseMapInfo<CallValue> {
    static inline CallValue getEmptyKey() {
      return DenseMapInfo<Instruction*>::getEmptyKey();
    }
    static inline CallValue getTombstoneKey() {
      return DenseMapInfo<Instruction*>::getTombstoneKey();
    }
    static unsigned getHashValue(CallValue Val);
    static bool isEqual(CallValue LHS, CallValue RHS);
  };
}
unsigned DenseMapInfo<CallValue>::getHashValue(CallValue Val) {
  Instruction *Inst = Val.Inst;
  // Hash in all of the operands as pointers.
  unsigned Res = 0;
  for (unsigned i = 0, e = Inst->getNumOperands(); i != e; ++i)
    Res ^= getHash(Inst->getOperand(i)) << i;
  // Mix in the opcode.
  return (Res << 1) ^ Inst->getOpcode();
}

bool DenseMapInfo<CallValue>::isEqual(CallValue LHS, CallValue RHS) {
  Instruction *LHSI = LHS.Inst, *RHSI = RHS.Inst;
  if (LHS.isSentinel() || RHS.isSentinel())
    return LHSI == RHSI;
  return LHSI->isIdenticalTo(RHSI);
}

//===----------------------------------------------------------------------===//
// EarlyCSE pass.
//===----------------------------------------------------------------------===//

namespace {

/// EarlyCSE - This pass does a simple depth-first walk over the dominator
/// tree, eliminating trivially redundant instructions and using instsimplify
/// to canonicalize things as it goes.  It is intended to be fast and catch
/// obvious cases so that instcombine and other passes are more effective.  It
/// is expected that a later pass of GVN will catch the interesting/hard
/// cases.
class EarlyCSE : public FunctionPass {
public:
  const TargetData *TD;
  DominatorTree *DT;
  typedef RecyclingAllocator<BumpPtrAllocator,
                      ScopedHashTableVal<SimpleValue, Value*> > AllocatorTy;
  typedef ScopedHashTable<SimpleValue, Value*, DenseMapInfo<SimpleValue>,
                          AllocatorTy> ScopedHTType;

  /// AvailableValues - This scoped hash table contains the current values of
  /// all of our simple scalar expressions.  As we walk down the domtree, we
  /// look to see if instructions are in this: if so, we replace them with what
  /// we find, otherwise we insert them so that dominated values can succeed in
  /// their lookup.
  ScopedHTType *AvailableValues;

  /// AvailableLoads - This scoped hash table contains the current values
  /// of loads.  This allows us to get efficient access to dominating loads when
  /// we have a fully redundant load.  In addition to the most recent load, we
  /// keep track of a generation count of the read, which is compared against
  /// the current generation count.  The current generation count is
  /// incremented after every possibly writing memory operation, which ensures
  /// that we only CSE loads with other loads that have no intervening store.
  typedef RecyclingAllocator<BumpPtrAllocator,
    ScopedHashTableVal<Value*, std::pair<Value*, unsigned> > > LoadMapAllocator;
  typedef ScopedHashTable<Value*, std::pair<Value*, unsigned>,
                          DenseMapInfo<Value*>, LoadMapAllocator> LoadHTType;
  LoadHTType *AvailableLoads;

  /// AvailableCalls - This scoped hash table contains the current values
  /// of read-only call values.  It uses the same generation count as loads.
  typedef ScopedHashTable<CallValue, std::pair<Value*, unsigned> > CallHTType;
  CallHTType *AvailableCalls;

  /// CurrentGeneration - This is the current generation of the memory value.
  unsigned CurrentGeneration;

  static char ID;
  explicit EarlyCSE() : FunctionPass(ID) {
    initializeEarlyCSEPass(*PassRegistry::getPassRegistry());
  }

  bool runOnFunction(Function &F);

private:

  bool processNode(DomTreeNode *Node);

  // This transformation requires dominator postdominator info
  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequired<DominatorTree>();
    AU.setPreservesCFG();
  }
};
}

char EarlyCSE::ID = 0;

// createEarlyCSEPass - The public interface to this file.
FunctionPass *llvm::createEarlyCSEPass() {
  return new EarlyCSE();
}

INITIALIZE_PASS_BEGIN(EarlyCSE, "early-cse", "Early CSE", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTree)
INITIALIZE_PASS_END(EarlyCSE, "early-cse", "Early CSE", false, false)

bool EarlyCSE::processNode(DomTreeNode *Node) {
  // Define a scope in the scoped hash table.  When we are done processing this
  // domtree node and recurse back up to our parent domtree node, this will pop
  // off all the values we install.
  ScopedHTType::ScopeTy Scope(*AvailableValues);

  // Define a scope for the load values so that anything we add will get
  // popped when we recurse back up to our parent domtree node.
  LoadHTType::ScopeTy LoadScope(*AvailableLoads);

  // Define a scope for the call values so that anything we add will get
  // popped when we recurse back up to our parent domtree node.
  CallHTType::ScopeTy CallScope(*AvailableCalls);

  BasicBlock *BB = Node->getBlock();

  // If this block has a single predecessor, then the predecessor is the parent
  // of the domtree node and all of the live out memory values are still current
  // in this block.  If this block has multiple predecessors, then they could
  // have invalidated the live-out memory values of our parent value.  For now,
  // just be conservative and invalidate memory if this block has multiple
  // predecessors.
  if (BB->getSinglePredecessor() == 0)
    ++CurrentGeneration;

  bool Changed = false;

  // See if any instructions in the block can be eliminated.  If so, do it.  If
  // not, add them to AvailableValues.
  for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ) {
    Instruction *Inst = I++;

    // Dead instructions should just be removed.
    if (isInstructionTriviallyDead(Inst)) {
      DEBUG(dbgs() << "EarlyCSE DCE: " << *Inst << '\n');
      Inst->eraseFromParent();
      Changed = true;
      ++NumSimplify;
      continue;
    }

    // If the instruction can be simplified (e.g. X+0 = X) then replace it with
    // its simpler value.
    if (Value *V = SimplifyInstruction(Inst, TD, DT)) {
      DEBUG(dbgs() << "EarlyCSE Simplify: " << *Inst << "  to: " << *V << '\n');
      Inst->replaceAllUsesWith(V);
      Inst->eraseFromParent();
      Changed = true;
      ++NumSimplify;
      continue;
    }

    // If this is a simple instruction that we can value number, process it.
    if (SimpleValue::canHandle(Inst)) {
      // See if the instruction has an available value.  If so, use it.
      if (Value *V = AvailableValues->lookup(Inst)) {
        DEBUG(dbgs() << "EarlyCSE CSE: " << *Inst << "  to: " << *V << '\n');
        Inst->replaceAllUsesWith(V);
        Inst->eraseFromParent();
        Changed = true;
        ++NumCSE;
        continue;
      }

      // Otherwise, just remember that this value is available.
      AvailableValues->insert(Inst, Inst);
      continue;
    }

    // If this is a non-volatile load, process it.
    if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
      // Ignore volatile loads.
      if (LI->isVolatile()) continue;

      // If we have an available version of this load, and if it is the right
      // generation, replace this instruction.
      std::pair<Value*, unsigned> InVal =
        AvailableLoads->lookup(Inst->getOperand(0));
      if (InVal.first != 0 && InVal.second == CurrentGeneration) {
        DEBUG(dbgs() << "EarlyCSE CSE LOAD: " << *Inst << "  to: "
              << *InVal.first << '\n');
        if (!Inst->use_empty()) Inst->replaceAllUsesWith(InVal.first);
        Inst->eraseFromParent();
        Changed = true;
        ++NumCSELoad;
        continue;
      }

      // Otherwise, remember that we have this instruction.
      AvailableLoads->insert(Inst->getOperand(0),
                          std::pair<Value*, unsigned>(Inst, CurrentGeneration));
      continue;
    }

    // If this is a read-only call, process it.
    if (CallValue::canHandle(Inst)) {
      // If we have an available version of this call, and if it is the right
      // generation, replace this instruction.
      std::pair<Value*, unsigned> InVal = AvailableCalls->lookup(Inst);
      if (InVal.first != 0 && InVal.second == CurrentGeneration) {
        DEBUG(dbgs() << "EarlyCSE CSE CALL: " << *Inst << "  to: "
                     << *InVal.first << '\n');
        if (!Inst->use_empty()) Inst->replaceAllUsesWith(InVal.first);
        Inst->eraseFromParent();
        Changed = true;
        ++NumCSECall;
        continue;
      }

      // Otherwise, remember that we have this instruction.
      AvailableCalls->insert(Inst,
                         std::pair<Value*, unsigned>(Inst, CurrentGeneration));
      continue;
    }

    // Okay, this isn't something we can CSE at all.  Check to see if it is
    // something that could modify memory.  If so, our available memory values
    // cannot be used so bump the generation count.
    if (Inst->mayWriteToMemory()) {
      ++CurrentGeneration;

      // Okay, we just invalidated anything we knew about loaded values.  Try to
      // salvage *something* by remembering that the stored value is a live
      // version of the pointer.  It is safe to forward from volatile stores to
      // non-volatile loads, so we don't have to check for volatility of the
      // store.
      if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
        AvailableLoads->insert(SI->getPointerOperand(),
         std::pair<Value*, unsigned>(SI->getValueOperand(), CurrentGeneration));
      }
    }
  }

  unsigned LiveOutGeneration = CurrentGeneration;
  for (DomTreeNode::iterator I = Node->begin(), E = Node->end(); I != E; ++I) {
    Changed |= processNode(*I);
    // Pop any generation changes off the stack from the recursive walk.
    CurrentGeneration = LiveOutGeneration;
  }
  return Changed;
}

bool EarlyCSE::runOnFunction(Function &F) {
  TD = getAnalysisIfAvailable<TargetData>();
  DT = &getAnalysis<DominatorTree>();

  // Tables that the pass uses when walking the domtree.
  ScopedHTType AVTable;
  AvailableValues = &AVTable;
  LoadHTType LoadTable;
  AvailableLoads = &LoadTable;
  CallHTType CallTable;
  AvailableCalls = &CallTable;

  CurrentGeneration = 0;
  return processNode(DT->getRootNode());
}
<|endoftext|>


<commit_before>//
//  fiber.hpp
//  fibio
//
//  Created by Chen Xu on 14-3-4.
//  Copyright (c) 2014 0d0a.com. All rights reserved.
//

#ifndef fibio_fiber_hpp
#define fibio_fiber_hpp

#include <fibio/fibers/fiber.hpp>
#include <fibio/fibers/mutex.hpp>
#include <fibio/fibers/condition_variable.hpp>
#include <fibio/fibers/fss.hpp>

#endif
<commit_msg>fiberize<commit_after>//
//  fiber.hpp
//  fibio
//
//  Created by Chen Xu on 14-3-4.
//  Copyright (c) 2014 0d0a.com. All rights reserved.
//

#ifndef fibio_fiber_hpp
#define fibio_fiber_hpp

#include <fibio/fibers/fiber.hpp>
#include <fibio/fibers/mutex.hpp>
#include <fibio/fibers/condition_variable.hpp>
#include <fibio/fibers/fss.hpp>
#include <fibio/fibers/fiberize.hpp>

#endif
<|endoftext|>


<commit_before>#pragma once

#include <vector>

namespace fsbb
{
//----------------------------------------------------------------

template
<
    typename t_state_id,
    typename t_state
>
struct state_and_id
{
    t_state_id id;
    t_state state;
};

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

template
<
    typename t_state_id,
    typename t_state
>
class state_registry
{
public:
    typedef std::vector<state_and_id<t_state_id, t_state>> states_vector;

    bool register_state( t_state_id id, t_state state )
    {
        if ( find_state( id ) != 0 )
            return false;

        state_and_id<t_state_id, t_state> s;
        s.id = id;
        s.state = state;
        m_states.push_back( s );

        return true;
    }

    state_and_id<t_state_id, t_state>* find_state( t_state_id id )
    {
        for ( size_t i = 0; i < m_states.size(); ++i )
        {
            if ( m_states[i].id == id )
                return &m_states[i];
        }

        return 0;
    }

    states_vector & get_states() { return m_states; }

protected:
    states_vector m_states;
};

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

template<typename T>
struct context_holder
{
    context_holder( T t )
        : m_context(t)
    {
    }

    T m_context;
};

template<>
struct context_holder<void>
{
    context_holder()
    {
    }
};

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

template
<
    typename t_state_id,
    typename t_state,
    typename t_state_container_interface,
    typename t_state_manipulator_interface
>
class fsm :
    public state_registry<t_state_id, t_state>,
    public t_state_container_interface,
    public t_state_manipulator_interface
{
public:
    fsm()
        : t_state_container_interface( m_state_container )
        , t_state_manipulator_interface( m_state_manipulator )
        , m_state_manipulator( m_state_container, *this )
    {}

protected:
    typename t_state_container_interface::t_impl m_state_container;
    typename t_state_manipulator_interface::t_impl m_state_manipulator;
};

//----------------------------------------------------------------
// Enter/Exit policies
//----------------------------------------------------------------

struct enter_exit_policy_default
{
    template<typename t_state_id, typename t_state, typename t_context = void>
    static void on_enter( state_and_id<t_state_id, t_state>& state, context_holder<t_context>& ctx ) {}

    template<typename t_state_id, typename t_state, typename t_context = void>
    static void on_exit( state_and_id<t_state_id, t_state>& state, context_holder<t_context>& ctx ) {}
};

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

struct enter_exit_policy_notify
{
    template<typename t_state_id, typename t_state, typename t_context>
    static void on_enter( state_and_id<t_state_id, t_state>& state, context_holder<t_context>& ctx ) { state.state->on_enter( ctx.m_context ); }

    template<typename t_state_id, typename t_state>
    static void on_enter( state_and_id<t_state_id, t_state>& state, context_holder<void>& ctx ) { state.state->on_enter(); }

    template<typename t_state_id, typename t_state, typename t_context>
    static void on_exit( state_and_id<t_state_id, t_state>& state, context_holder<t_context>& ctx ) { state.state->on_exit( ctx.m_context ); }

    template<typename t_state_id, typename t_state>
    static void on_exit( state_and_id<t_state_id, t_state>& state, context_holder<void>& ctx ) { state.state->on_exit(); }
};

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

struct enter_exit_policy_call
{
    template<typename t_state_id, typename t_state, typename t_context>
    static void on_enter( state_and_id<t_state_id, t_state>& state, context_holder<t_context>& ctx ) { state.state( ctx.m_context ); }

    template<typename t_state_id, typename t_state, typename t_context>
    static void on_enter( state_and_id<t_state_id, t_state>& state, context_holder<void>& ctx ) { state.state(); }

    template<typename t_state_id, typename t_state, typename t_context = void>
    static void on_exit( state_and_id<t_state_id, t_state>& state, context_holder<t_context>& ctx ) {}
};

//----------------------------------------------------------------
}
<commit_msg>small fix<commit_after>#pragma once

#include <vector>

namespace fsbb
{
//----------------------------------------------------------------

template
<
    typename t_state_id,
    typename t_state
>
struct state_and_id
{
    t_state_id id;
    t_state state;
};

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

template
<
    typename t_state_id,
    typename t_state
>
class state_registry
{
public:
    typedef std::vector<state_and_id<t_state_id, t_state> > states_vector;

    bool register_state( t_state_id id, t_state state )
    {
        if ( find_state( id ) != 0 )
            return false;

        state_and_id<t_state_id, t_state> s;
        s.id = id;
        s.state = state;
        m_states.push_back( s );

        return true;
    }

    state_and_id<t_state_id, t_state>* find_state( t_state_id id )
    {
        for ( size_t i = 0; i < m_states.size(); ++i )
        {
            if ( m_states[i].id == id )
                return &m_states[i];
        }

        return 0;
    }

    states_vector & get_states() { return m_states; }

protected:
    states_vector m_states;
};

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

template<typename T>
struct context_holder
{
    context_holder( T t )
        : m_context(t)
    {
    }

    T m_context;
};

template<>
struct context_holder<void>
{
    context_holder()
    {
    }
};

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

template
<
    typename t_state_id,
    typename t_state,
    typename t_state_container_interface,
    typename t_state_manipulator_interface
>
class fsm :
    public state_registry<t_state_id, t_state>,
    public t_state_container_interface,
    public t_state_manipulator_interface
{
public:
    fsm()
        : t_state_container_interface( m_state_container )
        , t_state_manipulator_interface( m_state_manipulator )
        , m_state_manipulator( m_state_container, *this )
    {}

protected:
    typename t_state_container_interface::t_impl m_state_container;
    typename t_state_manipulator_interface::t_impl m_state_manipulator;
};

//----------------------------------------------------------------
// Enter/Exit policies
//----------------------------------------------------------------

struct enter_exit_policy_default
{
    template<typename t_state_id, typename t_state, typename t_context = void>
    static void on_enter( state_and_id<t_state_id, t_state>& state, context_holder<t_context>& ctx ) {}

    template<typename t_state_id, typename t_state, typename t_context = void>
    static void on_exit( state_and_id<t_state_id, t_state>& state, context_holder<t_context>& ctx ) {}
};

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

struct enter_exit_policy_notify
{
    template<typename t_state_id, typename t_state, typename t_context>
    static void on_enter( state_and_id<t_state_id, t_state>& state, context_holder<t_context>& ctx ) { state.state->on_enter( ctx.m_context ); }

    template<typename t_state_id, typename t_state>
    static void on_enter( state_and_id<t_state_id, t_state>& state, context_holder<void>& ctx ) { state.state->on_enter(); }

    template<typename t_state_id, typename t_state, typename t_context>
    static void on_exit( state_and_id<t_state_id, t_state>& state, context_holder<t_context>& ctx ) { state.state->on_exit( ctx.m_context ); }

    template<typename t_state_id, typename t_state>
    static void on_exit( state_and_id<t_state_id, t_state>& state, context_holder<void>& ctx ) { state.state->on_exit(); }
};

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

struct enter_exit_policy_call
{
    template<typename t_state_id, typename t_state, typename t_context>
    static void on_enter( state_and_id<t_state_id, t_state>& state, context_holder<t_context>& ctx ) { state.state( ctx.m_context ); }

    template<typename t_state_id, typename t_state, typename t_context>
    static void on_enter( state_and_id<t_state_id, t_state>& state, context_holder<void>& ctx ) { state.state(); }

    template<typename t_state_id, typename t_state, typename t_context = void>
    static void on_exit( state_and_id<t_state_id, t_state>& state, context_holder<t_context>& ctx ) {}
};

//----------------------------------------------------------------
}
<|endoftext|>


<commit_before>#include "gbwt_helper.hpp"

#include <stack>

namespace vg {

// Stores haplotype-consistent traversal of the graph and the corresponding sequence.
struct GBWTTraversal {
    // The traversal as a sequence of (begin, length) pairs.
    std::vector<std::pair<pos_t, size_t>> traversal;
    // The sequence.
    std::string seq;
    // GBWT search state at the end of the traversal.
    gbwt::SearchState state;
};

void extend_traversals(const HandleGraph& graph, const gbwt::GBWT& haplotypes,
                       std::stack<GBWTTraversal>& kmers, size_t target_length, size_t minimum_length,
                       const function<void(const std::vector<std::pair<pos_t, size_t>>&, const std::string&)>& lambda) {
    while (!kmers.empty()) {
        GBWTTraversal curr = kmers.top(); kmers.pop();
        // Report the full kmer.
        if (curr.seq.length() >= target_length) {
            lambda(curr.traversal, curr.seq);
            continue;
        }

        // Try to extend the kmer to all successor nodes.
        // We are using undocumented parts of the GBWT interface --Jouni
        bool extend_success = false;
        gbwt::CompressedRecord record = haplotypes.record(curr.state.node);
        for (gbwt::rank_type outrank = 0; outrank < record.outdegree(); outrank++) {
            gbwt::node_type next_node = record.successor(outrank);
            if (next_node == gbwt::ENDMARKER) {
                continue;
            }
            gbwt::range_type range = record.LF(curr.state.range, next_node);
            if (gbwt::Range::empty(range)) {
                continue;
            }
            id_t id = gbwt::Node::id(next_node);
            bool is_reverse = gbwt::Node::is_reverse(next_node);
            std::string seq = graph.get_sequence(gbwt_to_handle(graph, next_node));
            pos_t begin = make_pos_t(id, is_reverse, 0);
            size_t length = std::min(seq.length(), target_length - curr.seq.length());
            GBWTTraversal next = curr;
            next.traversal.emplace_back(std::make_pair(begin, length));
            next.seq.append(seq, offset(begin), length);
            next.state.node = next_node;
            next.state.range = range;
            kmers.push(next);
            extend_success = true;
        }

        // Report sufficiently long kmers that cannot be extended.
        if (!extend_success && curr.seq.length() >= minimum_length) {
            lambda(curr.traversal, curr.seq);
        }
    }
}

void for_each_kmer(const HandleGraph& graph, const gbwt::GBWT& haplotypes, size_t k,
                   const function<void(const std::vector<std::pair<pos_t, size_t>>&, const std::string&)>& lambda,
                   bool parallel) {

    // Traverse all starting nodes in parallel.
    graph.for_each_handle([&](const handle_t& h) {
        // Initialize the stack with all starting positions in the current node.
        std::stack<GBWTTraversal> kmers;
        for (bool is_reverse : { false, true }) {
            handle_t handle = (is_reverse ? graph.flip(h) : h);
            gbwt::SearchState state = haplotypes.find(handle_to_gbwt(graph, handle));
            if (state.empty()) {
                continue;
            }
            id_t id = graph.get_id(handle);
            std::string seq = graph.get_sequence(handle);
            for (size_t i = 0; i < seq.length(); i++) {
                pos_t begin = make_pos_t(id, is_reverse, i);
                size_t length = std::min(seq.length() - i, k);
                GBWTTraversal kmer;
                kmer.traversal.emplace_back(std::make_pair(begin, length));
                kmer.seq = seq.substr(offset(begin), length);
                kmer.state = state;
                kmers.push(kmer);
            }
        }

        // Extend with target length and minimum length k.
        extend_traversals(graph, haplotypes, kmers, k, k, lambda);
    }, parallel);
}

void for_each_window(const HandleGraph& graph, const gbwt::GBWT& haplotypes, size_t window_size,
                    const function<void(const std::vector<std::pair<pos_t, size_t>>&, const std::string&)>& lambda,
                    bool parallel) {

    // Traverse all starting nodes in parallel.
    graph.for_each_handle([&](const handle_t& h) {
        // Initialize the stack with both orientations.
        std::stack<GBWTTraversal> kmers;
        id_t id = graph.get_id(h);
        size_t node_length = graph.get_length(h);
        for (bool is_reverse : { false, true }) {
            handle_t handle = (is_reverse ? graph.flip(h) : h);
            gbwt::SearchState state = haplotypes.find(handle_to_gbwt(graph, handle));
            if (state.empty()) {
                continue;
            }
            GBWTTraversal kmer;
            kmer.traversal.emplace_back(std::make_pair(make_pos_t(id, is_reverse, 0), node_length));
            kmer.seq = graph.get_sequence(handle);
            kmer.state = state;
            kmers.push(kmer);
        }

        // Extend the windows.
        extend_traversals(graph, haplotypes, kmers, node_length + window_size - 1, window_size, lambda);
    }, parallel);
}

void for_each_window(const HandleGraph& graph, size_t window_size,
                     const function<void(const std::vector<std::pair<pos_t, size_t>>&, const std::string&)>& lambda,
                     bool parallel) {

    // Traverse all starting nodes in parallel.
    graph.for_each_handle([&](const handle_t& h) {
        // Initialize the stack with both orientations.
        std::stack<GBWTTraversal> windows;
        id_t id = graph.get_id(h);
        size_t node_length = graph.get_length(h);
        for (bool is_reverse : { false, true }) {
            handle_t handle = (is_reverse ? graph.flip(h) : h);
            GBWTTraversal window;
            window.traversal.emplace_back(std::make_pair(make_pos_t(id, is_reverse, 0), node_length));
            window.seq = graph.get_sequence(handle);
            windows.push(window);
        }

        // Extend the windows.
        size_t target_length = node_length + window_size - 1;
        while (!windows.empty()) {
            GBWTTraversal window = windows.top(); windows.pop();
            // Report the full window.
            if (window.seq.length() >= target_length) {
                lambda(window.traversal, window.seq);
                continue;
            }

            // Extend the window to all successors.
            bool extend_success = false;
            handle_t curr = graph.get_handle(vg::id(window.traversal.back().first), is_rev(window.traversal.back().first));
            graph.follow_edges(curr, false, [&](const handle_t& next) {
                std::string seq = graph.get_sequence(next);
                pos_t begin = make_pos_t(graph.get_id(next), graph.get_is_reverse(next), 0);
                size_t length = std::min(seq.length(), target_length - window.seq.length());
                GBWTTraversal next_window = window;
                next_window.traversal.emplace_back(std::make_pair(begin, length));
                next_window.seq.append(seq, offset(begin), length);
                windows.push(next_window);
                extend_success = true;
            });

            // Report sufficiently long windows that cannot be extended.
            if (!extend_success && window.seq.length() >= window_size) {
                lambda(window.traversal, window.seq);
            }
        }
    }, parallel);
}

gbwt::GBWT get_gbwt(const std::vector<gbwt::vector_type>& paths) {
    gbwt::size_type node_width = 1, total_length = 0;
    for (auto& path : paths) {
        for (auto node : path) {
            node_width = std::max(node_width, gbwt::bit_length(gbwt::Node::encode(node, true)));
        }
        total_length += 2 * (path.size() + 1);
    }

    gbwt::Verbosity::set(gbwt::Verbosity::SILENT);
    gbwt::GBWTBuilder builder(node_width, total_length);
    for (auto& path : paths) {
        builder.insert(path, true);
    }
    builder.finish();

    std::string filename = temp_file::create("gbwt");
    sdsl::store_to_file(builder.index, filename);
    gbwt::GBWT gbwt_index;
    sdsl::load_from_file(gbwt_index, filename);
    temp_file::remove(filename);

    return gbwt_index;
}

} // namespace vg
<commit_msg>for_each_handle() expects bool-valued functions. Weird that it works with void<commit_after>#include "gbwt_helper.hpp"

#include <stack>

namespace vg {

// Stores haplotype-consistent traversal of the graph and the corresponding sequence.
struct GBWTTraversal {
    // The traversal as a sequence of (begin, length) pairs.
    std::vector<std::pair<pos_t, size_t>> traversal;
    // The sequence.
    std::string seq;
    // GBWT search state at the end of the traversal.
    gbwt::SearchState state;
};

void extend_traversals(const HandleGraph& graph, const gbwt::GBWT& haplotypes,
                       std::stack<GBWTTraversal>& kmers, size_t target_length, size_t minimum_length,
                       const function<void(const std::vector<std::pair<pos_t, size_t>>&, const std::string&)>& lambda) {
    while (!kmers.empty()) {
        GBWTTraversal curr = kmers.top(); kmers.pop();
        // Report the full kmer.
        if (curr.seq.length() >= target_length) {
            lambda(curr.traversal, curr.seq);
            continue;
        }

        // Try to extend the kmer to all successor nodes.
        // We are using undocumented parts of the GBWT interface --Jouni
        bool extend_success = false;
        gbwt::CompressedRecord record = haplotypes.record(curr.state.node);
        for (gbwt::rank_type outrank = 0; outrank < record.outdegree(); outrank++) {
            gbwt::node_type next_node = record.successor(outrank);
            if (next_node == gbwt::ENDMARKER) {
                continue;
            }
            gbwt::range_type range = record.LF(curr.state.range, next_node);
            if (gbwt::Range::empty(range)) {
                continue;
            }
            id_t id = gbwt::Node::id(next_node);
            bool is_reverse = gbwt::Node::is_reverse(next_node);
            std::string seq = graph.get_sequence(gbwt_to_handle(graph, next_node));
            pos_t begin = make_pos_t(id, is_reverse, 0);
            size_t length = std::min(seq.length(), target_length - curr.seq.length());
            GBWTTraversal next = curr;
            next.traversal.emplace_back(std::make_pair(begin, length));
            next.seq.append(seq, offset(begin), length);
            next.state.node = next_node;
            next.state.range = range;
            kmers.push(next);
            extend_success = true;
        }

        // Report sufficiently long kmers that cannot be extended.
        if (!extend_success && curr.seq.length() >= minimum_length) {
            lambda(curr.traversal, curr.seq);
        }
    }
}

void for_each_kmer(const HandleGraph& graph, const gbwt::GBWT& haplotypes, size_t k,
                   const function<void(const std::vector<std::pair<pos_t, size_t>>&, const std::string&)>& lambda,
                   bool parallel) {

    // Traverse all starting nodes in parallel.
    graph.for_each_handle([&](const handle_t& h) -> bool {
        // Initialize the stack with all starting positions in the current node.
        std::stack<GBWTTraversal> kmers;
        for (bool is_reverse : { false, true }) {
            handle_t handle = (is_reverse ? graph.flip(h) : h);
            gbwt::SearchState state = haplotypes.find(handle_to_gbwt(graph, handle));
            if (state.empty()) {
                continue;
            }
            id_t id = graph.get_id(handle);
            std::string seq = graph.get_sequence(handle);
            for (size_t i = 0; i < seq.length(); i++) {
                pos_t begin = make_pos_t(id, is_reverse, i);
                size_t length = std::min(seq.length() - i, k);
                GBWTTraversal kmer;
                kmer.traversal.emplace_back(std::make_pair(begin, length));
                kmer.seq = seq.substr(offset(begin), length);
                kmer.state = state;
                kmers.push(kmer);
            }
        }

        // Extend with target length and minimum length k.
        extend_traversals(graph, haplotypes, kmers, k, k, lambda);
        return true;
    }, parallel);
}

void for_each_window(const HandleGraph& graph, const gbwt::GBWT& haplotypes, size_t window_size,
                    const function<void(const std::vector<std::pair<pos_t, size_t>>&, const std::string&)>& lambda,
                    bool parallel) {

    // Traverse all starting nodes in parallel.
    graph.for_each_handle([&](const handle_t& h) -> bool {
        // Initialize the stack with both orientations.
        std::stack<GBWTTraversal> kmers;
        id_t id = graph.get_id(h);
        size_t node_length = graph.get_length(h);
        for (bool is_reverse : { false, true }) {
            handle_t handle = (is_reverse ? graph.flip(h) : h);
            gbwt::SearchState state = haplotypes.find(handle_to_gbwt(graph, handle));
            if (state.empty()) {
                continue;
            }
            GBWTTraversal kmer;
            kmer.traversal.emplace_back(std::make_pair(make_pos_t(id, is_reverse, 0), node_length));
            kmer.seq = graph.get_sequence(handle);
            kmer.state = state;
            kmers.push(kmer);
        }

        // Extend the windows.
        extend_traversals(graph, haplotypes, kmers, node_length + window_size - 1, window_size, lambda);
        return true;
    }, parallel);
}

void for_each_window(const HandleGraph& graph, size_t window_size,
                     const function<void(const std::vector<std::pair<pos_t, size_t>>&, const std::string&)>& lambda,
                     bool parallel) {

    // Traverse all starting nodes in parallel.
    graph.for_each_handle([&](const handle_t& h) -> bool {
        // Initialize the stack with both orientations.
        std::stack<GBWTTraversal> windows;
        id_t id = graph.get_id(h);
        size_t node_length = graph.get_length(h);
        for (bool is_reverse : { false, true }) {
            handle_t handle = (is_reverse ? graph.flip(h) : h);
            GBWTTraversal window;
            window.traversal.emplace_back(std::make_pair(make_pos_t(id, is_reverse, 0), node_length));
            window.seq = graph.get_sequence(handle);
            windows.push(window);
        }

        // Extend the windows.
        size_t target_length = node_length + window_size - 1;
        while (!windows.empty()) {
            GBWTTraversal window = windows.top(); windows.pop();
            // Report the full window.
            if (window.seq.length() >= target_length) {
                lambda(window.traversal, window.seq);
                continue;
            }

            // Extend the window to all successors.
            bool extend_success = false;
            handle_t curr = graph.get_handle(vg::id(window.traversal.back().first), is_rev(window.traversal.back().first));
            graph.follow_edges(curr, false, [&](const handle_t& next) {
                std::string seq = graph.get_sequence(next);
                pos_t begin = make_pos_t(graph.get_id(next), graph.get_is_reverse(next), 0);
                size_t length = std::min(seq.length(), target_length - window.seq.length());
                GBWTTraversal next_window = window;
                next_window.traversal.emplace_back(std::make_pair(begin, length));
                next_window.seq.append(seq, offset(begin), length);
                windows.push(next_window);
                extend_success = true;
            });

            // Report sufficiently long windows that cannot be extended.
            if (!extend_success && window.seq.length() >= window_size) {
                lambda(window.traversal, window.seq);
            }
        }

        return true;
    }, parallel);
}

gbwt::GBWT get_gbwt(const std::vector<gbwt::vector_type>& paths) {
    gbwt::size_type node_width = 1, total_length = 0;
    for (auto& path : paths) {
        for (auto node : path) {
            node_width = std::max(node_width, gbwt::bit_length(gbwt::Node::encode(node, true)));
        }
        total_length += 2 * (path.size() + 1);
    }

    gbwt::Verbosity::set(gbwt::Verbosity::SILENT);
    gbwt::GBWTBuilder builder(node_width, total_length);
    for (auto& path : paths) {
        builder.insert(path, true);
    }
    builder.finish();

    std::string filename = temp_file::create("gbwt");
    sdsl::store_to_file(builder.index, filename);
    gbwt::GBWT gbwt_index;
    sdsl::load_from_file(gbwt_index, filename);
    temp_file::remove(filename);

    return gbwt_index;
}

} // namespace vg
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_RULE_HPP
#define MAPNIK_RULE_HPP

// mapnik
#include <mapnik/line_symbolizer.hpp>
#include <mapnik/line_pattern_symbolizer.hpp>
#include <mapnik/polygon_symbolizer.hpp>
#include <mapnik/polygon_pattern_symbolizer.hpp>
#include <mapnik/point_symbolizer.hpp>
#include <mapnik/raster_symbolizer.hpp>
#include <mapnik/shield_symbolizer.hpp>
#include <mapnik/text_symbolizer.hpp>
#include <mapnik/markers_symbolizer.hpp>
#include <mapnik/glyph_symbolizer.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/filter_factory.hpp>
#include <mapnik/expression_string.hpp>

// boost
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/variant.hpp>

// stl
#include <string>
#include <vector>

namespace mapnik
{
inline bool operator==(point_symbolizer const& lhs,
                       point_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}
inline bool operator==(line_symbolizer const& lhs,
                       line_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}
inline bool operator==(line_pattern_symbolizer const& lhs,
                       line_pattern_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(polygon_symbolizer const& lhs,
                       polygon_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(polygon_pattern_symbolizer const& lhs,
                       polygon_pattern_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(raster_symbolizer const& lhs,
                       raster_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(text_symbolizer const& lhs,
                       text_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(shield_symbolizer const& lhs,
                       shield_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(building_symbolizer const& lhs,
                       building_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(markers_symbolizer const& lhs,
                       markers_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(glyph_symbolizer const& lhs,
                       glyph_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}
typedef boost::variant<point_symbolizer,
                       line_symbolizer,
                       line_pattern_symbolizer,
                       polygon_symbolizer,
                       polygon_pattern_symbolizer,
                       raster_symbolizer,
                       shield_symbolizer,
                       text_symbolizer,
                       building_symbolizer,
                       markers_symbolizer,
                       glyph_symbolizer> symbolizer;

class rule
{
public:
    typedef std::vector<symbolizer> symbolizers;
private:

    std::string name_;
    double min_scale_;
    double max_scale_;
    symbolizers syms_;
    expression_ptr filter_;
    bool else_filter_;
    bool also_filter_;
public:
    rule()
        : name_(),
          min_scale_(0),
          max_scale_(std::numeric_limits<double>::infinity()),
          syms_(),
          filter_(boost::make_shared<mapnik::expr_node>(true)),
          else_filter_(false),
          also_filter_(false) {}

    rule(const std::string& name,
         double min_scale_denominator=0,
         double max_scale_denominator=std::numeric_limits<double>::infinity())
        : name_(name),
          min_scale_(min_scale_denominator),
          max_scale_(max_scale_denominator),
          syms_(),
          filter_(boost::make_shared<mapnik::expr_node>(true)),
          else_filter_(false),
          also_filter_(false)  {}

    rule(const rule& rhs, bool deep_copy = false)
        : name_(rhs.name_),
          min_scale_(rhs.min_scale_),
          max_scale_(rhs.max_scale_),
          syms_(rhs.syms_),
          filter_(rhs.filter_),
          else_filter_(rhs.else_filter_),
          also_filter_(rhs.also_filter_)
    {
        if (deep_copy) {
            //std::string expr = to_expression_string(rhs.filter_);
            //filter_ = parse_expression(expr,"utf8");

            symbolizers::iterator it  = syms_.begin(),
                                  end = syms_.end();

            // FIXME - metawriter_ptr?

            for(; it != end; ++it) {

                /*if (polygon_symbolizer *sym = boost::get<polygon_symbolizer>(&(*it))) {
                    // no shared pointers
                } else if (line_symbolizer *sym = boost::get<line_symbolizer>(&(*it))) {
                    // no shared pointers
                } else if (building_symbolizer *sym = boost::get<building_symbolizer>(&(*it))) {
                    // no shared pointers
                }*/

                if (markers_symbolizer *sym = boost::get<markers_symbolizer>(&(*it))) {
                    copy_path_ptr(sym);
                } else if (point_symbolizer *sym = boost::get<point_symbolizer>(&(*it))) {
                    copy_path_ptr(sym);
                } else if (polygon_pattern_symbolizer *sym = boost::get<polygon_pattern_symbolizer>(&(*it))) {
                    copy_path_ptr(sym);
                } else if (line_pattern_symbolizer *sym = boost::get<line_pattern_symbolizer>(&(*it))) {
                    copy_path_ptr(sym);
                } else if (raster_symbolizer *sym = boost::get<raster_symbolizer>(&(*it))) {
                    raster_colorizer_ptr old_colorizer = sym->get_colorizer(),
                                         new_colorizer = raster_colorizer_ptr();

                    new_colorizer->set_stops( old_colorizer->get_stops());
                    new_colorizer->set_default_mode( old_colorizer->get_default_mode() );
                    new_colorizer->set_default_color( old_colorizer->get_default_color() );
                    new_colorizer->set_epsilon( old_colorizer->get_epsilon() );

                    sym->set_colorizer(new_colorizer);
                } else if (shield_symbolizer *sym = boost::get<shield_symbolizer>(&(*it))) {
                    copy_path_ptr(sym);
                    copy_text_ptr(sym);
                } else if (text_symbolizer *sym = boost::get<text_symbolizer>(&(*it))) {
                    copy_text_ptr(sym);
                }
            }
        }
    }

    rule& operator=(rule const& rhs)
    {
        rule tmp(rhs);
        swap(tmp);
        return *this;
    }
    bool operator==(rule const& other)
    {
        return  (this == &other);
    }

    void set_max_scale(double scale)
    {
        max_scale_=scale;
    }

    double get_max_scale() const
    {
        return max_scale_;
    }

    void set_min_scale(double scale)
    {
        min_scale_=scale;
    }

    double get_min_scale() const
    {
        return min_scale_;
    }

    void set_name(std::string const& name)
    {
        name_=name;
    }

    std::string const& get_name() const
    {
        return name_;
    }

    void append(const symbolizer& sym)
    {
        syms_.push_back(sym);
    }

    void remove_at(size_t index)
    {
        if (index < syms_.size())
        {
            syms_.erase(syms_.begin()+index);
        }
    }

    const symbolizers& get_symbolizers() const
    {
        return syms_;
    }

    symbolizers::const_iterator begin() const
    {
        return syms_.begin();
    }

    symbolizers::const_iterator end() const
    {
        return syms_.end();
    }

    symbolizers::iterator begin()
    {
        return syms_.begin();
    }

    symbolizers::iterator end()
    {
        return syms_.end();
    }

    void set_filter(const expression_ptr& filter)
    {
        filter_=filter;
    }

    expression_ptr const& get_filter() const
    {
        return filter_;
    }

    void set_else(bool else_filter)
    {
        else_filter_=else_filter;
    }

    bool has_else_filter() const
    {
        return else_filter_;
    }

    void set_also(bool also_filter)
    {
        also_filter_=also_filter;
    }

    bool has_also_filter() const
    {
        return also_filter_;
    }

    bool active(double scale) const
    {
        return ( scale >= min_scale_ - 1e-6 && scale < max_scale_ + 1e-6);
    }

private:

    void swap(rule& rhs) throw()
    {
        name_=rhs.name_;
        min_scale_=rhs.min_scale_;
        max_scale_=rhs.max_scale_;
        syms_=rhs.syms_;
        filter_=rhs.filter_;
        else_filter_=rhs.else_filter_;
        also_filter_=rhs.also_filter_;
    }

    template <class T>
    void copy_path_ptr(T* sym)
    {
        std::string path = path_processor_type::to_string(*sym->get_filename());
        sym->set_filename( parse_path(path) );
    }

    template <class T>
    void copy_text_ptr(T* sym)
    {
        std::string name = to_expression_string(*sym->get_name());
        sym->set_name( parse_expression(name) );

        // FIXME - orientation doesn't appear to be initialized in constructor?
        //std::string orientation = to_expression_string(*sym->get_orientation());
        //sym->set_orientation( parse_expression(orientation) );

        float text_size = sym->get_text_size();
        position displace = sym->get_displacement();
        vertical_alignment_e valign = sym->get_vertical_alignment();
        horizontal_alignment_e halign = sym->get_horizontal_alignment();
        justify_alignment_e jalign = sym->get_justify_alignment();

        text_placements_ptr placements = text_placements_ptr(boost::make_shared<text_placements_dummy>());
        sym->set_placement_options( placements );

        sym->set_text_size(text_size);
        sym->set_displacement(displace);
        sym->set_vertical_alignment(valign);
        sym->set_horizontal_alignment(halign);
        sym->set_justify_alignment(jalign);
    }
};

}

#endif // MAPNIK_RULE_HPP
<commit_msg>refactor symbolizer deepcopy semantics into internal structure<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_RULE_HPP
#define MAPNIK_RULE_HPP

// mapnik
#include <mapnik/line_symbolizer.hpp>
#include <mapnik/line_pattern_symbolizer.hpp>
#include <mapnik/polygon_symbolizer.hpp>
#include <mapnik/polygon_pattern_symbolizer.hpp>
#include <mapnik/point_symbolizer.hpp>
#include <mapnik/raster_symbolizer.hpp>
#include <mapnik/shield_symbolizer.hpp>
#include <mapnik/text_symbolizer.hpp>
#include <mapnik/markers_symbolizer.hpp>
#include <mapnik/glyph_symbolizer.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/filter_factory.hpp>
#include <mapnik/expression_string.hpp>

// boost
#include <boost/concept_check.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/variant.hpp>

// stl
#include <string>
#include <vector>

namespace mapnik
{
inline bool operator==(point_symbolizer const& lhs,
                       point_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}
inline bool operator==(line_symbolizer const& lhs,
                       line_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}
inline bool operator==(line_pattern_symbolizer const& lhs,
                       line_pattern_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(polygon_symbolizer const& lhs,
                       polygon_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(polygon_pattern_symbolizer const& lhs,
                       polygon_pattern_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(raster_symbolizer const& lhs,
                       raster_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(text_symbolizer const& lhs,
                       text_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(shield_symbolizer const& lhs,
                       shield_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(building_symbolizer const& lhs,
                       building_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(markers_symbolizer const& lhs,
                       markers_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}

inline bool operator==(glyph_symbolizer const& lhs,
                       glyph_symbolizer const& rhs)
{
    return (&lhs == &rhs);
}
typedef boost::variant<point_symbolizer,
                       line_symbolizer,
                       line_pattern_symbolizer,
                       polygon_symbolizer,
                       polygon_pattern_symbolizer,
                       raster_symbolizer,
                       shield_symbolizer,
                       text_symbolizer,
                       building_symbolizer,
                       markers_symbolizer,
                       glyph_symbolizer> symbolizer;

class rule
{
public:
    typedef std::vector<symbolizer> symbolizers;
private:

    std::string name_;
    double min_scale_;
    double max_scale_;
    symbolizers syms_;
    expression_ptr filter_;
    bool else_filter_;
    bool also_filter_;

    struct deepcopy_symbolizer : public boost::static_visitor<>
    {

        void operator () (markers_symbolizer & sym) const
        {
            copy_path_ptr(sym);
        }

        void operator () (point_symbolizer & sym) const
        {
            copy_path_ptr(sym);
        }

        void operator () (polygon_pattern_symbolizer & sym) const
        {
            copy_path_ptr(sym);
        }

        void operator () (line_pattern_symbolizer & sym) const
        {
            copy_path_ptr(sym);
        }

        void operator () (raster_symbolizer & sym) const
        {
            raster_colorizer_ptr old_colorizer = sym.get_colorizer();
            raster_colorizer_ptr new_colorizer = raster_colorizer_ptr();
            new_colorizer->set_stops(old_colorizer->get_stops());
            new_colorizer->set_default_mode(old_colorizer->get_default_mode());
            new_colorizer->set_default_color(old_colorizer->get_default_color());
            new_colorizer->set_epsilon(old_colorizer->get_epsilon());
            sym.set_colorizer(new_colorizer);
        }

        void operator () (text_symbolizer & sym) const
        {
            copy_text_ptr(sym);
        }

        void operator () (shield_symbolizer & sym) const
        {
            copy_path_ptr(sym);
            copy_text_ptr(sym);
        }

        void operator () (building_symbolizer & sym) const
        {
            copy_height_ptr(sym);
        }

        template <typename T> void operator () (T &sym) const
        {
            boost::ignore_unused_variable_warning(sym);
        }

    private:
        template <class T>
        void copy_path_ptr(T & sym) const
        {
            std::string path = path_processor_type::to_string(*sym.get_filename());
            sym.set_filename( parse_path(path) );
        }

        template <class T>
        void copy_text_ptr(T & sym) const
        {
            std::string name = to_expression_string(*sym.get_name());
            sym.set_name( parse_expression(name) );

            // FIXME - orientation doesn't appear to be initialized in constructor?
            //std::string orientation = to_expression_string(*sym->get_orientation());
            //sym->set_orientation( parse_expression(orientation) );

            float text_size = sym.get_text_size();
            position displace = sym.get_displacement();
            vertical_alignment_e valign = sym.get_vertical_alignment();
            horizontal_alignment_e halign = sym.get_horizontal_alignment();
            justify_alignment_e jalign = sym.get_justify_alignment();

            text_placements_ptr placements = text_placements_ptr(boost::make_shared<text_placements_dummy>());
            sym.set_placement_options( placements );
            sym.set_text_size(text_size);
            sym.set_displacement(displace);
            sym.set_vertical_alignment(valign);
            sym.set_horizontal_alignment(halign);
            sym.set_justify_alignment(jalign);
        }

        template <class T>
        void copy_height_ptr(T & sym) const
        {
            std::string height_expr = to_expression_string(sym.height());
            sym.set_height(parse_expression(height_expr,"utf8"));
        }
    };

public:
    rule()
        : name_(),
          min_scale_(0),
          max_scale_(std::numeric_limits<double>::infinity()),
          syms_(),
          filter_(boost::make_shared<mapnik::expr_node>(true)),
          else_filter_(false),
          also_filter_(false) {}

    rule(const std::string& name,
         double min_scale_denominator=0,
         double max_scale_denominator=std::numeric_limits<double>::infinity())
        : name_(name),
          min_scale_(min_scale_denominator),
          max_scale_(max_scale_denominator),
          syms_(),
          filter_(boost::make_shared<mapnik::expr_node>(true)),
          else_filter_(false),
          also_filter_(false)  {}

    rule(const rule& rhs, bool deep_copy = false)
        : name_(rhs.name_),
          min_scale_(rhs.min_scale_),
          max_scale_(rhs.max_scale_),
          syms_(rhs.syms_),
          filter_(rhs.filter_),
          else_filter_(rhs.else_filter_),
          also_filter_(rhs.also_filter_)
    {
        if (deep_copy) {

            std::string expr = to_expression_string(rhs.filter_);
            filter_ = parse_expression(expr,"utf8");

            symbolizers::iterator it  = syms_.begin(),
                                  end = syms_.end();

            // FIXME - metawriter_ptr?

            for(; it != end; ++it)
            {
                boost::apply_visitor(deepcopy_symbolizer(),*it);
            }
        }
    }

    rule& operator=(rule const& rhs)
    {
        rule tmp(rhs);
        swap(tmp);
        return *this;
    }
    bool operator==(rule const& other)
    {
        return  (this == &other);
    }

    void set_max_scale(double scale)
    {
        max_scale_=scale;
    }

    double get_max_scale() const
    {
        return max_scale_;
    }

    void set_min_scale(double scale)
    {
        min_scale_=scale;
    }

    double get_min_scale() const
    {
        return min_scale_;
    }

    void set_name(std::string const& name)
    {
        name_=name;
    }

    std::string const& get_name() const
    {
        return name_;
    }

    void append(const symbolizer& sym)
    {
        syms_.push_back(sym);
    }

    void remove_at(size_t index)
    {
        if (index < syms_.size())
        {
            syms_.erase(syms_.begin()+index);
        }
    }

    const symbolizers& get_symbolizers() const
    {
        return syms_;
    }

    symbolizers::const_iterator begin() const
    {
        return syms_.begin();
    }

    symbolizers::const_iterator end() const
    {
        return syms_.end();
    }

    symbolizers::iterator begin()
    {
        return syms_.begin();
    }

    symbolizers::iterator end()
    {
        return syms_.end();
    }

    void set_filter(const expression_ptr& filter)
    {
        filter_=filter;
    }

    expression_ptr const& get_filter() const
    {
        return filter_;
    }

    void set_else(bool else_filter)
    {
        else_filter_=else_filter;
    }

    bool has_else_filter() const
    {
        return else_filter_;
    }

    void set_also(bool also_filter)
    {
        also_filter_=also_filter;
    }

    bool has_also_filter() const
    {
        return also_filter_;
    }

    bool active(double scale) const
    {
        return ( scale >= min_scale_ - 1e-6 && scale < max_scale_ + 1e-6);
    }

private:

    void swap(rule& rhs) throw()
    {
        name_=rhs.name_;
        min_scale_=rhs.min_scale_;
        max_scale_=rhs.max_scale_;
        syms_=rhs.syms_;
        filter_=rhs.filter_;
        else_filter_=rhs.else_filter_;
        also_filter_=rhs.also_filter_;
    }
};

}

#endif // MAPNIK_RULE_HPP
<|endoftext|>