<commit_before>//===---- BDCE.cpp - Bit-tracking dead code elimination -------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Bit-Tracking Dead Code Elimination pass. Some
// instructions (shifts, some ands, ors, etc.) kill some of their input bits.
// We track these dead bits and remove instructions that compute only these
// dead bits.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

#define DEBUG_TYPE "bdce"

STATISTIC(NumRemoved, "Number of instructions removed (unused)");
STATISTIC(NumSimplified, "Number of instructions trivialized (dead bits)");

namespace {
struct BDCE : public FunctionPass {
  static char ID; // Pass identification, replacement for typeid
  BDCE() : FunctionPass(ID) {
    initializeBDCEPass(*PassRegistry::getPassRegistry());
  }

  bool runOnFunction(Function& F) override;

  void getAnalysisUsage(AnalysisUsage& AU) const override {
    AU.setPreservesCFG();
    AU.addRequired<AssumptionCacheTracker>();
    AU.addRequired<DominatorTreeWrapperPass>();
  }

  void determineLiveOperandBits(const Instruction *UserI,
                                const Instruction *I, unsigned OperandNo,
                                const APInt &AOut, APInt &AB,
                                APInt &KnownZero, APInt &KnownOne,
                                APInt &KnownZero2, APInt &KnownOne2);

  AssumptionCache *AC;
  const DataLayout *DL;
  DominatorTree *DT;
};
}

char BDCE::ID = 0;
INITIALIZE_PASS_BEGIN(BDCE, "bdce", "Bit-Tracking Dead Code Elimination",
                      false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_END(BDCE, "bdce", "Bit-Tracking Dead Code Elimination",
                    false, false)

static bool isAlwaysLive(Instruction *I) {
  return isa<TerminatorInst>(I) || isa<DbgInfoIntrinsic>(I) ||
         isa<LandingPadInst>(I) || I->mayHaveSideEffects();
}

void BDCE::determineLiveOperandBits(const Instruction *UserI,
                                    const Instruction *I, unsigned OperandNo,
                                    const APInt &AOut, APInt &AB,
                                    APInt &KnownZero, APInt &KnownOne,
                                    APInt &KnownZero2, APInt &KnownOne2) {
  unsigned BitWidth = AB.getBitWidth();

  // We're called once per operand, but for some instructions, we need to
  // compute known bits of both operands in order to determine the live bits of
  // either (when both operands are instructions themselves). We don't,
  // however, want to do this twice, so we cache the result in APInts that live
  // in the caller. For the two-relevant-operands case, both operand values are
  // provided here.
  auto ComputeKnownBits = [&](unsigned BitWidth, const Value *V1,
                              const Value *V2) {
    KnownZero = APInt(BitWidth, 0);
    KnownOne =  APInt(BitWidth, 0);
    computeKnownBits(const_cast<Value*>(V1), KnownZero, KnownOne, DL, 0, AC,
                     UserI, DT);

    if (V2) {
      KnownZero2 = APInt(BitWidth, 0);
      KnownOne2 =  APInt(BitWidth, 0);
      computeKnownBits(const_cast<Value*>(V2), KnownZero2, KnownOne2, DL, 0, AC,
                       UserI, DT);
    }
  };

  switch (UserI->getOpcode()) {
  default: break;
  case Instruction::Call:
  case Instruction::Invoke:
    if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(UserI))
      switch (II->getIntrinsicID()) {
      default: break;
      case Intrinsic::bswap:
        // The alive bits of the input are the swapped alive bits of
        // the output.
        AB = AOut.byteSwap();
        break;
      case Intrinsic::ctlz:
        if (OperandNo == 0) {
          // We need some output bits, so we need all bits of the
          // input to the left of, and including, the leftmost bit
          // known to be one.
          ComputeKnownBits(BitWidth, I, nullptr);
          AB = APInt::getHighBitsSet(BitWidth,
                 std::min(BitWidth, KnownOne.countLeadingZeros()+1));
        }
        break;
      case Intrinsic::cttz:
        if (OperandNo == 0) {
          // We need some output bits, so we need all bits of the
          // input to the right of, and including, the rightmost bit
          // known to be one.
          ComputeKnownBits(BitWidth, I, nullptr);
          AB = APInt::getLowBitsSet(BitWidth,
                 std::min(BitWidth, KnownOne.countTrailingZeros()+1));
        }
        break;
      }
    break;
  case Instruction::Add:
  case Instruction::Sub:
    // Find the highest live output bit. We don't need any more input
    // bits than that (adds, and thus subtracts, ripple only to the
    // left).
    AB = APInt::getLowBitsSet(BitWidth, AOut.getActiveBits());
    break;
  case Instruction::Shl:
    if (OperandNo == 0)
      if (ConstantInt *CI =
            dyn_cast<ConstantInt>(UserI->getOperand(1))) {
        uint64_t ShiftAmt = CI->getLimitedValue(BitWidth-1);
        AB = AOut.lshr(ShiftAmt);

        // If the shift is nuw/nsw, then the high bits are not dead
        // (because we've promised that they *must* be zero).
        const ShlOperator *S = cast<ShlOperator>(UserI);
        if (S->hasNoSignedWrap())
          AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt+1);
        else if (S->hasNoUnsignedWrap())
          AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt);
      }
    break;
  case Instruction::LShr:
    if (OperandNo == 0)
      if (ConstantInt *CI =
            dyn_cast<ConstantInt>(UserI->getOperand(1))) {
        uint64_t ShiftAmt = CI->getLimitedValue(BitWidth-1);
        AB = AOut.shl(ShiftAmt);

        // If the shift is exact, then the low bits are not dead
        // (they must be zero).
        if (cast<LShrOperator>(UserI)->isExact())
          AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt);
      }
    break;
  case Instruction::AShr:
    if (OperandNo == 0)
      if (ConstantInt *CI =
            dyn_cast<ConstantInt>(UserI->getOperand(1))) {
        uint64_t ShiftAmt = CI->getLimitedValue(BitWidth-1);
        AB = AOut.shl(ShiftAmt);
        // Because the high input bit is replicated into the
        // high-order bits of the result, if we need any of those
        // bits, then we must keep the highest input bit.
        if ((AOut & APInt::getHighBitsSet(BitWidth, ShiftAmt))
            .getBoolValue())
          AB.setBit(BitWidth-1);

        // If the shift is exact, then the low bits are not dead
        // (they must be zero).
        if (cast<AShrOperator>(UserI)->isExact())
          AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt);
      }
    break;
  case Instruction::And:
    AB = AOut;

    // For bits that are known zero, the corresponding bits in the
    // other operand are dead (unless they're both zero, in which
    // case they can't both be dead, so just mark the LHS bits as
    // dead).
    if (OperandNo == 0) {
      ComputeKnownBits(BitWidth, I, UserI->getOperand(1));
      AB &= ~KnownZero2;
    } else {
      if (!isa<Instruction>(UserI->getOperand(0)))
        ComputeKnownBits(BitWidth, UserI->getOperand(0), I);
      AB &= ~(KnownZero & ~KnownZero2);
    }
    break;
  case Instruction::Or:
    AB = AOut;

    // For bits that are known one, the corresponding bits in the
    // other operand are dead (unless they're both one, in which
    // case they can't both be dead, so just mark the LHS bits as
    // dead).
    if (OperandNo == 0) {
      ComputeKnownBits(BitWidth, I, UserI->getOperand(1));
      AB &= ~KnownOne2;
    } else {
      if (!isa<Instruction>(UserI->getOperand(0)))
        ComputeKnownBits(BitWidth, UserI->getOperand(0), I);
      AB &= ~(KnownOne & ~KnownOne2);
    }
    break;
  case Instruction::Xor:
  case Instruction::PHI:
    AB = AOut;
    break;
  case Instruction::Trunc:
    AB = AOut.zext(BitWidth);
    break;
  case Instruction::ZExt:
    AB = AOut.trunc(BitWidth);
    break;
  case Instruction::SExt:
    AB = AOut.trunc(BitWidth);
    // Because the high input bit is replicated into the
    // high-order bits of the result, if we need any of those
    // bits, then we must keep the highest input bit.
    if ((AOut & APInt::getHighBitsSet(AOut.getBitWidth(),
                                      AOut.getBitWidth() - BitWidth))
        .getBoolValue())
      AB.setBit(BitWidth-1);
    break;
  case Instruction::Select:
    if (OperandNo != 0)
      AB = AOut;
    break;
  }
}

bool BDCE::runOnFunction(Function& F) {
  if (skipOptnoneFunction(F))
    return false;

  AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
  DL = F.getParent()->getDataLayout();
  DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();

  DenseMap<Instruction *, APInt> AliveBits;
  SmallVector<Instruction*, 128> Worklist;

  // The set of visited instructions (non-integer-typed only).
  SmallPtrSet<Instruction*, 128> Visited;

  // Collect the set of "root" instructions that are known live.
  for (Instruction &I : inst_range(F)) {
    if (!isAlwaysLive(&I))
      continue;

    DEBUG(dbgs() << "BDCE: Root: " << I);
    // For integer-valued instructions, set up an initial empty set of alive
    // bits and add the instruction to the work list. For other instructions
    // add their operands to the work list (for integer values operands, mark
    // all bits as live).
    if (IntegerType *IT = dyn_cast<IntegerType>(I.getType())) {
      if (!AliveBits.count(&I)) {
        AliveBits[&I] = APInt(IT->getBitWidth(), 0);
        Worklist.push_back(&I);
      }

      continue;
    }

    // Non-integer-typed instructions...
    for (Use &OI : I.operands()) {
      if (Instruction *J = dyn_cast<Instruction>(OI)) {
        if (IntegerType *IT = dyn_cast<IntegerType>(J->getType()))
          AliveBits[J] = APInt::getAllOnesValue(IT->getBitWidth());
        Worklist.push_back(J);
      }
    }
    // To save memory, we don't add I to the Visited set here. Instead, we
    // check isAlwaysLive on every instruction when searching for dead
    // instructions later (we need to check isAlwaysLive for the
    // integer-typed instructions anyway).
  }

  // Propagate liveness backwards to operands.
  while (!Worklist.empty()) {
    Instruction *UserI = Worklist.pop_back_val();

    DEBUG(dbgs() << "BDCE: Visiting: " << *UserI);
    APInt AOut;
    if (UserI->getType()->isIntegerTy()) {
      AOut = AliveBits[UserI];
      DEBUG(dbgs() << " Alive Out: " << AOut);
    }
    DEBUG(dbgs() << "\n");

    if (!UserI->getType()->isIntegerTy())
      Visited.insert(UserI);

    APInt KnownZero, KnownOne, KnownZero2, KnownOne2;
    // Compute the set of alive bits for each operand. These are anded into the
    // existing set, if any, and if that changes the set of alive bits, the
    // operand is added to the work-list.
    for (Use &OI : UserI->operands()) {
      if (Instruction *I = dyn_cast<Instruction>(OI)) {
        if (IntegerType *IT = dyn_cast<IntegerType>(I->getType())) {
          unsigned BitWidth = IT->getBitWidth();
          APInt AB = APInt::getAllOnesValue(BitWidth);
          if (UserI->getType()->isIntegerTy() && !AOut &&
              !isAlwaysLive(UserI)) {
            AB = APInt(BitWidth, 0);
          } else {
            // If all bits of the output are dead, then all bits of the input
            // Bits of each operand that are used to compute alive bits of the
            // output are alive, all others are dead.
            determineLiveOperandBits(UserI, I, OI.getOperandNo(), AOut, AB,
                                     KnownZero, KnownOne,
                                     KnownZero2, KnownOne2);
          }

          // If we've added to the set of alive bits (or the operand has not
          // been previously visited), then re-queue the operand to be visited
          // again.
          APInt ABPrev(BitWidth, 0);
          auto ABI = AliveBits.find(I);
          if (ABI != AliveBits.end())
            ABPrev = ABI->second;

          APInt ABNew = AB | ABPrev;
          if (ABNew != ABPrev || ABI == AliveBits.end()) {
            AliveBits[I] = std::move(ABNew);
            Worklist.push_back(I);
          }
        } else if (!Visited.count(I)) {
          Worklist.push_back(I);
        }
      }
    }
  }

  bool Changed = false;
  // The inverse of the live set is the dead set.  These are those instructions
  // which have no side effects and do not influence the control flow or return
  // value of the function, and may therefore be deleted safely.
  // NOTE: We reuse the Worklist vector here for memory efficiency.
  for (Instruction &I : inst_range(F)) {
    // For live instructions that have all dead bits, first make them dead by
    // replacing all uses with something else. Then, if they don't need to
    // remain live (because they have side effects, etc.) we can remove them.
    if (I.getType()->isIntegerTy()) {
      auto ABI = AliveBits.find(&I);
      if (ABI != AliveBits.end()) {
        if (ABI->second.getBoolValue())
          continue;

        DEBUG(dbgs() << "BDCE: Trivializing: " << I << " (all bits dead)\n");
        // FIXME: In theory we could substitute undef here instead of zero.
        // This should be reconsidered once we settle on the semantics of
        // undef, poison, etc.
        Value *Zero = ConstantInt::get(I.getType(), 0);
        ++NumSimplified;
        I.replaceAllUsesWith(Zero);
        Changed = true;
      }
    } else if (Visited.count(&I)) {
      continue;
    }

    if (isAlwaysLive(&I))
      continue;

    Worklist.push_back(&I);
    I.dropAllReferences();
    Changed = true;
  }

  for (Instruction *&I : Worklist) {
    ++NumRemoved;
    I->eraseFromParent();
  }

  return Changed;
}

FunctionPass *llvm::createBitTrackingDCEPass() {
  return new BDCE();
}

<commit_msg>add newline for easier reading; NFC<commit_after>//===---- BDCE.cpp - Bit-tracking dead code elimination -------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Bit-Tracking Dead Code Elimination pass. Some
// instructions (shifts, some ands, ors, etc.) kill some of their input bits.
// We track these dead bits and remove instructions that compute only these
// dead bits.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

#define DEBUG_TYPE "bdce"

STATISTIC(NumRemoved, "Number of instructions removed (unused)");
STATISTIC(NumSimplified, "Number of instructions trivialized (dead bits)");

namespace {
struct BDCE : public FunctionPass {
  static char ID; // Pass identification, replacement for typeid
  BDCE() : FunctionPass(ID) {
    initializeBDCEPass(*PassRegistry::getPassRegistry());
  }

  bool runOnFunction(Function& F) override;

  void getAnalysisUsage(AnalysisUsage& AU) const override {
    AU.setPreservesCFG();
    AU.addRequired<AssumptionCacheTracker>();
    AU.addRequired<DominatorTreeWrapperPass>();
  }

  void determineLiveOperandBits(const Instruction *UserI,
                                const Instruction *I, unsigned OperandNo,
                                const APInt &AOut, APInt &AB,
                                APInt &KnownZero, APInt &KnownOne,
                                APInt &KnownZero2, APInt &KnownOne2);

  AssumptionCache *AC;
  const DataLayout *DL;
  DominatorTree *DT;
};
}

char BDCE::ID = 0;
INITIALIZE_PASS_BEGIN(BDCE, "bdce", "Bit-Tracking Dead Code Elimination",
                      false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_END(BDCE, "bdce", "Bit-Tracking Dead Code Elimination",
                    false, false)

static bool isAlwaysLive(Instruction *I) {
  return isa<TerminatorInst>(I) || isa<DbgInfoIntrinsic>(I) ||
         isa<LandingPadInst>(I) || I->mayHaveSideEffects();
}

void BDCE::determineLiveOperandBits(const Instruction *UserI,
                                    const Instruction *I, unsigned OperandNo,
                                    const APInt &AOut, APInt &AB,
                                    APInt &KnownZero, APInt &KnownOne,
                                    APInt &KnownZero2, APInt &KnownOne2) {
  unsigned BitWidth = AB.getBitWidth();

  // We're called once per operand, but for some instructions, we need to
  // compute known bits of both operands in order to determine the live bits of
  // either (when both operands are instructions themselves). We don't,
  // however, want to do this twice, so we cache the result in APInts that live
  // in the caller. For the two-relevant-operands case, both operand values are
  // provided here.
  auto ComputeKnownBits = [&](unsigned BitWidth, const Value *V1,
                              const Value *V2) {
    KnownZero = APInt(BitWidth, 0);
    KnownOne =  APInt(BitWidth, 0);
    computeKnownBits(const_cast<Value*>(V1), KnownZero, KnownOne, DL, 0, AC,
                     UserI, DT);

    if (V2) {
      KnownZero2 = APInt(BitWidth, 0);
      KnownOne2 =  APInt(BitWidth, 0);
      computeKnownBits(const_cast<Value*>(V2), KnownZero2, KnownOne2, DL, 0, AC,
                       UserI, DT);
    }
  };

  switch (UserI->getOpcode()) {
  default: break;
  case Instruction::Call:
  case Instruction::Invoke:
    if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(UserI))
      switch (II->getIntrinsicID()) {
      default: break;
      case Intrinsic::bswap:
        // The alive bits of the input are the swapped alive bits of
        // the output.
        AB = AOut.byteSwap();
        break;
      case Intrinsic::ctlz:
        if (OperandNo == 0) {
          // We need some output bits, so we need all bits of the
          // input to the left of, and including, the leftmost bit
          // known to be one.
          ComputeKnownBits(BitWidth, I, nullptr);
          AB = APInt::getHighBitsSet(BitWidth,
                 std::min(BitWidth, KnownOne.countLeadingZeros()+1));
        }
        break;
      case Intrinsic::cttz:
        if (OperandNo == 0) {
          // We need some output bits, so we need all bits of the
          // input to the right of, and including, the rightmost bit
          // known to be one.
          ComputeKnownBits(BitWidth, I, nullptr);
          AB = APInt::getLowBitsSet(BitWidth,
                 std::min(BitWidth, KnownOne.countTrailingZeros()+1));
        }
        break;
      }
    break;
  case Instruction::Add:
  case Instruction::Sub:
    // Find the highest live output bit. We don't need any more input
    // bits than that (adds, and thus subtracts, ripple only to the
    // left).
    AB = APInt::getLowBitsSet(BitWidth, AOut.getActiveBits());
    break;
  case Instruction::Shl:
    if (OperandNo == 0)
      if (ConstantInt *CI =
            dyn_cast<ConstantInt>(UserI->getOperand(1))) {
        uint64_t ShiftAmt = CI->getLimitedValue(BitWidth-1);
        AB = AOut.lshr(ShiftAmt);

        // If the shift is nuw/nsw, then the high bits are not dead
        // (because we've promised that they *must* be zero).
        const ShlOperator *S = cast<ShlOperator>(UserI);
        if (S->hasNoSignedWrap())
          AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt+1);
        else if (S->hasNoUnsignedWrap())
          AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt);
      }
    break;
  case Instruction::LShr:
    if (OperandNo == 0)
      if (ConstantInt *CI =
            dyn_cast<ConstantInt>(UserI->getOperand(1))) {
        uint64_t ShiftAmt = CI->getLimitedValue(BitWidth-1);
        AB = AOut.shl(ShiftAmt);

        // If the shift is exact, then the low bits are not dead
        // (they must be zero).
        if (cast<LShrOperator>(UserI)->isExact())
          AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt);
      }
    break;
  case Instruction::AShr:
    if (OperandNo == 0)
      if (ConstantInt *CI =
            dyn_cast<ConstantInt>(UserI->getOperand(1))) {
        uint64_t ShiftAmt = CI->getLimitedValue(BitWidth-1);
        AB = AOut.shl(ShiftAmt);
        // Because the high input bit is replicated into the
        // high-order bits of the result, if we need any of those
        // bits, then we must keep the highest input bit.
        if ((AOut & APInt::getHighBitsSet(BitWidth, ShiftAmt))
            .getBoolValue())
          AB.setBit(BitWidth-1);

        // If the shift is exact, then the low bits are not dead
        // (they must be zero).
        if (cast<AShrOperator>(UserI)->isExact())
          AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt);
      }
    break;
  case Instruction::And:
    AB = AOut;

    // For bits that are known zero, the corresponding bits in the
    // other operand are dead (unless they're both zero, in which
    // case they can't both be dead, so just mark the LHS bits as
    // dead).
    if (OperandNo == 0) {
      ComputeKnownBits(BitWidth, I, UserI->getOperand(1));
      AB &= ~KnownZero2;
    } else {
      if (!isa<Instruction>(UserI->getOperand(0)))
        ComputeKnownBits(BitWidth, UserI->getOperand(0), I);
      AB &= ~(KnownZero & ~KnownZero2);
    }
    break;
  case Instruction::Or:
    AB = AOut;

    // For bits that are known one, the corresponding bits in the
    // other operand are dead (unless they're both one, in which
    // case they can't both be dead, so just mark the LHS bits as
    // dead).
    if (OperandNo == 0) {
      ComputeKnownBits(BitWidth, I, UserI->getOperand(1));
      AB &= ~KnownOne2;
    } else {
      if (!isa<Instruction>(UserI->getOperand(0)))
        ComputeKnownBits(BitWidth, UserI->getOperand(0), I);
      AB &= ~(KnownOne & ~KnownOne2);
    }
    break;
  case Instruction::Xor:
  case Instruction::PHI:
    AB = AOut;
    break;
  case Instruction::Trunc:
    AB = AOut.zext(BitWidth);
    break;
  case Instruction::ZExt:
    AB = AOut.trunc(BitWidth);
    break;
  case Instruction::SExt:
    AB = AOut.trunc(BitWidth);
    // Because the high input bit is replicated into the
    // high-order bits of the result, if we need any of those
    // bits, then we must keep the highest input bit.
    if ((AOut & APInt::getHighBitsSet(AOut.getBitWidth(),
                                      AOut.getBitWidth() - BitWidth))
        .getBoolValue())
      AB.setBit(BitWidth-1);
    break;
  case Instruction::Select:
    if (OperandNo != 0)
      AB = AOut;
    break;
  }
}

bool BDCE::runOnFunction(Function& F) {
  if (skipOptnoneFunction(F))
    return false;

  AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
  DL = F.getParent()->getDataLayout();
  DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();

  DenseMap<Instruction *, APInt> AliveBits;
  SmallVector<Instruction*, 128> Worklist;

  // The set of visited instructions (non-integer-typed only).
  SmallPtrSet<Instruction*, 128> Visited;

  // Collect the set of "root" instructions that are known live.
  for (Instruction &I : inst_range(F)) {
    if (!isAlwaysLive(&I))
      continue;

    DEBUG(dbgs() << "BDCE: Root: " << I << "\n");
    // For integer-valued instructions, set up an initial empty set of alive
    // bits and add the instruction to the work list. For other instructions
    // add their operands to the work list (for integer values operands, mark
    // all bits as live).
    if (IntegerType *IT = dyn_cast<IntegerType>(I.getType())) {
      if (!AliveBits.count(&I)) {
        AliveBits[&I] = APInt(IT->getBitWidth(), 0);
        Worklist.push_back(&I);
      }

      continue;
    }

    // Non-integer-typed instructions...
    for (Use &OI : I.operands()) {
      if (Instruction *J = dyn_cast<Instruction>(OI)) {
        if (IntegerType *IT = dyn_cast<IntegerType>(J->getType()))
          AliveBits[J] = APInt::getAllOnesValue(IT->getBitWidth());
        Worklist.push_back(J);
      }
    }
    // To save memory, we don't add I to the Visited set here. Instead, we
    // check isAlwaysLive on every instruction when searching for dead
    // instructions later (we need to check isAlwaysLive for the
    // integer-typed instructions anyway).
  }

  // Propagate liveness backwards to operands.
  while (!Worklist.empty()) {
    Instruction *UserI = Worklist.pop_back_val();

    DEBUG(dbgs() << "BDCE: Visiting: " << *UserI);
    APInt AOut;
    if (UserI->getType()->isIntegerTy()) {
      AOut = AliveBits[UserI];
      DEBUG(dbgs() << " Alive Out: " << AOut);
    }
    DEBUG(dbgs() << "\n");

    if (!UserI->getType()->isIntegerTy())
      Visited.insert(UserI);

    APInt KnownZero, KnownOne, KnownZero2, KnownOne2;
    // Compute the set of alive bits for each operand. These are anded into the
    // existing set, if any, and if that changes the set of alive bits, the
    // operand is added to the work-list.
    for (Use &OI : UserI->operands()) {
      if (Instruction *I = dyn_cast<Instruction>(OI)) {
        if (IntegerType *IT = dyn_cast<IntegerType>(I->getType())) {
          unsigned BitWidth = IT->getBitWidth();
          APInt AB = APInt::getAllOnesValue(BitWidth);
          if (UserI->getType()->isIntegerTy() && !AOut &&
              !isAlwaysLive(UserI)) {
            AB = APInt(BitWidth, 0);
          } else {
            // If all bits of the output are dead, then all bits of the input
            // Bits of each operand that are used to compute alive bits of the
            // output are alive, all others are dead.
            determineLiveOperandBits(UserI, I, OI.getOperandNo(), AOut, AB,
                                     KnownZero, KnownOne,
                                     KnownZero2, KnownOne2);
          }

          // If we've added to the set of alive bits (or the operand has not
          // been previously visited), then re-queue the operand to be visited
          // again.
          APInt ABPrev(BitWidth, 0);
          auto ABI = AliveBits.find(I);
          if (ABI != AliveBits.end())
            ABPrev = ABI->second;

          APInt ABNew = AB | ABPrev;
          if (ABNew != ABPrev || ABI == AliveBits.end()) {
            AliveBits[I] = std::move(ABNew);
            Worklist.push_back(I);
          }
        } else if (!Visited.count(I)) {
          Worklist.push_back(I);
        }
      }
    }
  }

  bool Changed = false;
  // The inverse of the live set is the dead set.  These are those instructions
  // which have no side effects and do not influence the control flow or return
  // value of the function, and may therefore be deleted safely.
  // NOTE: We reuse the Worklist vector here for memory efficiency.
  for (Instruction &I : inst_range(F)) {
    // For live instructions that have all dead bits, first make them dead by
    // replacing all uses with something else. Then, if they don't need to
    // remain live (because they have side effects, etc.) we can remove them.
    if (I.getType()->isIntegerTy()) {
      auto ABI = AliveBits.find(&I);
      if (ABI != AliveBits.end()) {
        if (ABI->second.getBoolValue())
          continue;

        DEBUG(dbgs() << "BDCE: Trivializing: " << I << " (all bits dead)\n");
        // FIXME: In theory we could substitute undef here instead of zero.
        // This should be reconsidered once we settle on the semantics of
        // undef, poison, etc.
        Value *Zero = ConstantInt::get(I.getType(), 0);
        ++NumSimplified;
        I.replaceAllUsesWith(Zero);
        Changed = true;
      }
    } else if (Visited.count(&I)) {
      continue;
    }

    if (isAlwaysLive(&I))
      continue;

    Worklist.push_back(&I);
    I.dropAllReferences();
    Changed = true;
  }

  for (Instruction *&I : Worklist) {
    ++NumRemoved;
    I->eraseFromParent();
  }

  return Changed;
}

FunctionPass *llvm::createBitTrackingDCEPass() {
  return new BDCE();
}

<|endoftext|>


<commit_before>#ifndef SD_UNO_DRAW_VIEW_HXX
#define SD_UNO_DRAW_VIEW_HXX

#ifndef SD_DRAW_CONTROLLER_HXX
#include "DrawController.hxx"
#endif
#ifndef _COM_SUN_STAR_DRAWING_XDRAWVIEW_HPP_
#include <com/sun/star/drawing/XDrawView.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_VIEW_XSELECTIONSUPPLIER_HPP_
#include <com/sun/star/view/XSelectionSupplier.hpp>
#endif
#ifndef _COM_SUN_STAR_DRAWING_XLAYER_HPP_
#include <com/sun/star/drawing/XLayer.hpp>
#endif

#ifndef _SFX_SFXBASECONTROLLER_HXX_
#include <sfx2/sfxbasecontroller.hxx>
#endif

#ifndef _CPPUHELPER_PROPSHLP_HXX
#include <cppuhelper/propshlp.hxx>
#endif

#ifndef _CPPUHELPER_PROPTYPEHLP_HXX
#include <cppuhelper/proptypehlp.hxx>
#endif

#ifndef _CPPUHELPER_INTERFACECONTAINER_H_
#include <cppuhelper/interfacecontainer.h>
#endif

#ifndef _SVX_UNOSHAPE_HXX
#include <svx/unoshape.hxx>
#endif

class SdXImpressDocument;
class SdPage;

namespace sd {

class DrawViewShell;

/**
 * This class implements the view component for a SdDrawViewShell
 */
class SdUnoDrawView
    : public DrawController
{
public:
    enum properties
    {
        PROPERTY_FIRST = DrawController::PROPERTY_FIRST_FREE,
        PROPERTY_CURRENTPAGE = PROPERTY_FIRST,
        PROPERTY_MASTERPAGEMODE,
        PROPERTY_LAYERMODE,
        PROPERTY_ACTIVE_LAYER,
        PROPERTY_ZOOMTYPE,
        PROPERTY_ZOOMVALUE,
        PROPERTY_VIEWOFFSET,
        PROPERTY_FIRST_FREE
    };

    SdUnoDrawView (
        ViewShellBase& rBase,
        ViewShell& rViewShell,
        View& rView) throw();
    virtual ~SdUnoDrawView (void) throw();

    virtual void FireChangeEditMode (bool bMasterPageMode) throw();
    virtual void FireChangeLayerMode (bool bLayerMode) throw();
    virtual void FireSwitchCurrentPage (SdPage* pCurrentPage) throw();

    // XTypeProvider
    virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId(  ) throw(::com::sun::star::uno::RuntimeException);

    // XServiceInfo
    virtual ::rtl::OUString SAL_CALL getImplementationName() throw(::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw(::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw(::com::sun::star::uno::RuntimeException);

    // XSelectionSupplier
    virtual sal_Bool SAL_CALL select( const ::com::sun::star::uno::Any& aSelection ) throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Any SAL_CALL getSelection(  ) throw(::com::sun::star::uno::RuntimeException);

    // XDrawView
    virtual void SAL_CALL setCurrentPage( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& xPage ) throw(::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage > SAL_CALL getCurrentPage(  ) throw(::com::sun::star::uno::RuntimeException);

protected:
    virtual void FillPropertyTable (
        ::std::vector< ::com::sun::star::beans::Property>& rProperties);

    /**
     * Converted the value rValue and return the result in rConvertedValue and the
     * old value in rOldValue. A IllegalArgumentException is thrown.
     * The method is not implemented in this class. After this call the vetoable
     * listeners are notified.
     *
     * @param rConvertedValue the converted value. Only set if return is true.
     * @param rOldValue the old value. Only set if return is true.
     * @param nHandle the handle of the proberty.
     * @return true if the value converted.
     */
    virtual sal_Bool SAL_CALL convertFastPropertyValue(
        ::com::sun::star::uno::Any & rConvertedValue,
        ::com::sun::star::uno::Any & rOldValue,
        sal_Int32 nHandle,
        const ::com::sun::star::uno::Any& rValue )
        throw (::com::sun::star::lang::IllegalArgumentException);
    /**
     * The same as setFastProperyValue, but no exception is thrown and nHandle
     * is always valid. You must not broadcast the changes in this method.

     * You type is correct you need't test it.
     */
    virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
        sal_Int32 nHandle,
        const ::com::sun::star::uno::Any& rValue )
        throw (::com::sun::star::uno::Exception);
    /**
     * The same as getFastProperyValue, but return the value through
     * rValue and nHandle is always valid.
     */
    virtual void SAL_CALL getFastPropertyValue(
        ::com::sun::star::uno::Any& rValue,
        sal_Int32 nHandle ) const;

    sal_Bool getMasterPageMode(void) const throw();
    void setMasterPageMode(sal_Bool MasterPageMode_) throw();
    sal_Bool getLayerMode(void) const throw();
    void setLayerMode(sal_Bool LayerMode_) throw();

    /** Return a reference to the active layer object.
        @return
            The returned value may be empty when the internal state of this
            view is not valid (like during destruction.)
    */
    ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XLayer> getActiveLayer (void) throw ();

    /** Make the specified object the active layer.
        @param rxLayer
            The new layer object.
    */
    void setActiveLayer (const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XLayer>& rxLayer) throw ();

    void SetZoom( sal_Int16 nZoom );
    sal_Int16 GetZoom(void) const;

    void SetViewOffset(const com::sun::star::awt::Point& rWinPos );
    com::sun::star::awt::Point GetViewOffset() const;

    void SetZoomType( sal_Int16 nType );

private:
    bool mbOldMasterPageMode;
    bool mbOldLayerMode;
    SdPage* mpCurrentPage;

    /** This is a shortcut for accessing the view shell data member of
        the base class casted to the correct class.
    */
    DrawViewShell& GetDrawViewShell (void) const;
};

} // end of namespace sd

#endif
<commit_msg>INTEGRATION: CWS impress2 (1.8.12); FILE MERGED 2004/07/01 11:18:14 af 1.8.12.1: #i22705# Renamed property enums.<commit_after>#ifndef SD_UNO_DRAW_VIEW_HXX
#define SD_UNO_DRAW_VIEW_HXX

#ifndef SD_DRAW_CONTROLLER_HXX
#include "DrawController.hxx"
#endif
#ifndef _COM_SUN_STAR_DRAWING_XDRAWVIEW_HPP_
#include <com/sun/star/drawing/XDrawView.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_VIEW_XSELECTIONSUPPLIER_HPP_
#include <com/sun/star/view/XSelectionSupplier.hpp>
#endif
#ifndef _COM_SUN_STAR_DRAWING_XLAYER_HPP_
#include <com/sun/star/drawing/XLayer.hpp>
#endif

#ifndef _SFX_SFXBASECONTROLLER_HXX_
#include <sfx2/sfxbasecontroller.hxx>
#endif

#ifndef _CPPUHELPER_PROPSHLP_HXX
#include <cppuhelper/propshlp.hxx>
#endif

#ifndef _CPPUHELPER_PROPTYPEHLP_HXX
#include <cppuhelper/proptypehlp.hxx>
#endif

#ifndef _CPPUHELPER_INTERFACECONTAINER_H_
#include <cppuhelper/interfacecontainer.h>
#endif

#ifndef _SVX_UNOSHAPE_HXX
#include <svx/unoshape.hxx>
#endif

class SdXImpressDocument;
class SdPage;

namespace sd {

class DrawViewShell;

/**
 * This class implements the view component for a SdDrawViewShell
 */
class SdUnoDrawView
    : public DrawController
{
public:
    enum properties
    {
        PROPERTY__BEGIN = DrawController::PROPERTY__BEGIN,
        PROPERTY_CURRENTPAGE = PROPERTY__BEGIN,
        PROPERTY_MASTERPAGEMODE,
        PROPERTY_LAYERMODE,
        PROPERTY_ACTIVE_LAYER,
        PROPERTY_ZOOMTYPE,
        PROPERTY_ZOOMVALUE,
        PROPERTY_VIEWOFFSET,
        PROPERTY__END
    };

    SdUnoDrawView (
        ViewShellBase& rBase,
        ViewShell& rViewShell,
        View& rView) throw();
    virtual ~SdUnoDrawView (void) throw();

    virtual void FireChangeEditMode (bool bMasterPageMode) throw();
    virtual void FireChangeLayerMode (bool bLayerMode) throw();
    virtual void FireSwitchCurrentPage (SdPage* pCurrentPage) throw();

    // XTypeProvider
    virtual ::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId(  ) throw(::com::sun::star::uno::RuntimeException);

    // XServiceInfo
    virtual ::rtl::OUString SAL_CALL getImplementationName() throw(::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw(::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw(::com::sun::star::uno::RuntimeException);

    // XSelectionSupplier
    virtual sal_Bool SAL_CALL select( const ::com::sun::star::uno::Any& aSelection ) throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Any SAL_CALL getSelection(  ) throw(::com::sun::star::uno::RuntimeException);

    // XDrawView
    virtual void SAL_CALL setCurrentPage( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& xPage ) throw(::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage > SAL_CALL getCurrentPage(  ) throw(::com::sun::star::uno::RuntimeException);

protected:
    virtual void FillPropertyTable (
        ::std::vector< ::com::sun::star::beans::Property>& rProperties);

    /**
     * Converted the value rValue and return the result in rConvertedValue and the
     * old value in rOldValue. A IllegalArgumentException is thrown.
     * The method is not implemented in this class. After this call the vetoable
     * listeners are notified.
     *
     * @param rConvertedValue the converted value. Only set if return is true.
     * @param rOldValue the old value. Only set if return is true.
     * @param nHandle the handle of the proberty.
     * @return true if the value converted.
     */
    virtual sal_Bool SAL_CALL convertFastPropertyValue(
        ::com::sun::star::uno::Any & rConvertedValue,
        ::com::sun::star::uno::Any & rOldValue,
        sal_Int32 nHandle,
        const ::com::sun::star::uno::Any& rValue )
        throw (::com::sun::star::lang::IllegalArgumentException);
    /**
     * The same as setFastProperyValue, but no exception is thrown and nHandle
     * is always valid. You must not broadcast the changes in this method.

     * You type is correct you need't test it.
     */
    virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
        sal_Int32 nHandle,
        const ::com::sun::star::uno::Any& rValue )
        throw (::com::sun::star::uno::Exception);
    /**
     * The same as getFastProperyValue, but return the value through
     * rValue and nHandle is always valid.
     */
    virtual void SAL_CALL getFastPropertyValue(
        ::com::sun::star::uno::Any& rValue,
        sal_Int32 nHandle ) const;

    sal_Bool getMasterPageMode(void) const throw();
    void setMasterPageMode(sal_Bool MasterPageMode_) throw();
    sal_Bool getLayerMode(void) const throw();
    void setLayerMode(sal_Bool LayerMode_) throw();

    /** Return a reference to the active layer object.
        @return
            The returned value may be empty when the internal state of this
            view is not valid (like during destruction.)
    */
    ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XLayer> getActiveLayer (void) throw ();

    /** Make the specified object the active layer.
        @param rxLayer
            The new layer object.
    */
    void setActiveLayer (const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XLayer>& rxLayer) throw ();

    void SetZoom( sal_Int16 nZoom );
    sal_Int16 GetZoom(void) const;

    void SetViewOffset(const com::sun::star::awt::Point& rWinPos );
    com::sun::star::awt::Point GetViewOffset() const;

    void SetZoomType( sal_Int16 nType );

private:
    bool mbOldMasterPageMode;
    bool mbOldLayerMode;
    SdPage* mpCurrentPage;

    /** This is a shortcut for accessing the view shell data member of
        the base class casted to the correct class.
    */
    DrawViewShell& GetDrawViewShell (void) const;
};

} // end of namespace sd

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: WindowUpdater.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 05:21:28 $
 *
 *  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
 *
 ************************************************************************/

#ifndef SD_OUTPUT_DEVICE_UPDATER_HXX
#define SD_OUTPUT_DEVICE_UPDATER_HXX

#ifndef _SFXLSTNER_HXX
#include <svtools/lstner.hxx>
#endif
#ifndef _SVTOOLS_CTLOPTIONS_HXX
#include <svtools/ctloptions.hxx>
#endif

#ifndef INCLUDED_SDDLLAPI_H
#include "sddllapi.h"
#endif

#ifndef INCLUDED_VECTOR
#include <vector>
#define INCLUDED_VECTOR
#endif

class Window;
class OutputDevice;
class SdDrawDocument;

namespace sd {

class ViewShell;

/** The purpose of the <type>WindowUpdater</type> is to update output
    devices to take care of modified global values.  These values are
    monitored for changes.  At the moment this is
    the digit language that defines the glyphs to use to render digits.
    Other values may be added in the future.

The methods of this class have not been included into the
    <type>ViewShell</type> class in order to not clutter its interface any
    further.  This class accesses some of <type>ViewShell</type> data
    members directly and thus is declared as its friend.

Windows that are to be kept up-to-date have to be registered via the
    <member>RegisterWindow()</member> method.  When a document is given then
    this document is reformatted when the monitored option changes.

*/
class SD_DLLPUBLIC WindowUpdater
    : public SfxListener
{
public:
    explicit WindowUpdater (void);
    virtual ~WindowUpdater (void) throw();

    /** Add the given device to the list of devices which will be updated
        when one of the monitored values changes.
        @param pWindow
            This device is added to the device list if it is not <null/> and
            when it is not already a member of that list.
    */
    void RegisterWindow (::Window* pWindow);

    /** Remove the given device from the list of devices which will be updated
        when one of the monitored values changes.
        @param pWindow
            This device is removed from the device list when it is a member
            of that list.
    */
    void UnregisterWindow (::Window* pWindow);

    /** Set the view shell whose output devices shall be kept up to date.
        It is used to clear the master page cache so that a redraw affects
        the master page content as well.
    */
    void SetViewShell (ViewShell& rViewShell);

    /** Set the document so that it is reformatted when one of the monitored
        values changes.
        @param pDocument
            When <null/> is given document reformatting will not take
            place in the future.
    */
    void SetDocument (SdDrawDocument* pDocument);

    /** Update the given output device and update all text objects of the
        view shell if not told otherwise.
        @param pWindow
            The device to update.  When the given pointer is NULL then
            nothing is done.
        @param pDocument
            When given a pointer to a document then tell it to reformat all
            text objects.  This refromatting is necessary for the new values
            to take effect.
    */
    void Update (OutputDevice* pDevice, SdDrawDocument* pDocument=0) const;

    /** Callback that waits for notifications of a
        <type>SvtCTLOptions</type> object.
    */
    virtual void Notify (SfxBroadcaster& rBC, const SfxHint& rHint);

private:
    /// Options to monitor for changes.
    SvtCTLOptions maCTLOptions;

    /// Keep the output devices of this view shell up to date.
    ViewShell* mpViewShell;

    /// The document rendered in the output devices.
    SdDrawDocument* mpDocument;

    /// Copy constructor not supported.
    WindowUpdater (const WindowUpdater& rUpdater);

    /// Assignment operator not supported.
    WindowUpdater operator= (const WindowUpdater& rUpdater);

    /** Type and data member for a list of devices that have to be kept
        up-to-date.
    */
    typedef ::std::vector< ::Window*> tWindowList;
    tWindowList maWindowList;

    /** The central method of this class.  Update the given output device.
        It is the task of the caller to initiate a refrormatting of the
        document that is rendered on this device to reflect the changes.
        @param pWindow
            The output device to update.  When it is <null/> then the call
            is ignored.
    */
    SD_DLLPRIVATE void UpdateWindow (OutputDevice* pDevice) const;
};

} // end of namespace sd

#endif
<commit_msg>INTEGRATION: CWS changefileheader (1.6.624); FILE MERGED 2008/04/01 15:35:20 thb 1.6.624.3: #i85898# Stripping all external header guards 2008/04/01 12:39:03 thb 1.6.624.2: #i85898# Stripping all external header guards 2008/03/31 13:58:12 rt 1.6.624.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: WindowUpdater.hxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef SD_OUTPUT_DEVICE_UPDATER_HXX
#define SD_OUTPUT_DEVICE_UPDATER_HXX

#include <svtools/lstner.hxx>
#include <svtools/ctloptions.hxx>
#include "sddllapi.h"

#ifndef INCLUDED_VECTOR
#include <vector>
#define INCLUDED_VECTOR
#endif

class Window;
class OutputDevice;
class SdDrawDocument;

namespace sd {

class ViewShell;

/** The purpose of the <type>WindowUpdater</type> is to update output
    devices to take care of modified global values.  These values are
    monitored for changes.  At the moment this is
    the digit language that defines the glyphs to use to render digits.
    Other values may be added in the future.

The methods of this class have not been included into the
    <type>ViewShell</type> class in order to not clutter its interface any
    further.  This class accesses some of <type>ViewShell</type> data
    members directly and thus is declared as its friend.

Windows that are to be kept up-to-date have to be registered via the
    <member>RegisterWindow()</member> method.  When a document is given then
    this document is reformatted when the monitored option changes.

*/
class SD_DLLPUBLIC WindowUpdater
    : public SfxListener
{
public:
    explicit WindowUpdater (void);
    virtual ~WindowUpdater (void) throw();

    /** Add the given device to the list of devices which will be updated
        when one of the monitored values changes.
        @param pWindow
            This device is added to the device list if it is not <null/> and
            when it is not already a member of that list.
    */
    void RegisterWindow (::Window* pWindow);

    /** Remove the given device from the list of devices which will be updated
        when one of the monitored values changes.
        @param pWindow
            This device is removed from the device list when it is a member
            of that list.
    */
    void UnregisterWindow (::Window* pWindow);

    /** Set the view shell whose output devices shall be kept up to date.
        It is used to clear the master page cache so that a redraw affects
        the master page content as well.
    */
    void SetViewShell (ViewShell& rViewShell);

    /** Set the document so that it is reformatted when one of the monitored
        values changes.
        @param pDocument
            When <null/> is given document reformatting will not take
            place in the future.
    */
    void SetDocument (SdDrawDocument* pDocument);

    /** Update the given output device and update all text objects of the
        view shell if not told otherwise.
        @param pWindow
            The device to update.  When the given pointer is NULL then
            nothing is done.
        @param pDocument
            When given a pointer to a document then tell it to reformat all
            text objects.  This refromatting is necessary for the new values
            to take effect.
    */
    void Update (OutputDevice* pDevice, SdDrawDocument* pDocument=0) const;

    /** Callback that waits for notifications of a
        <type>SvtCTLOptions</type> object.
    */
    virtual void Notify (SfxBroadcaster& rBC, const SfxHint& rHint);

private:
    /// Options to monitor for changes.
    SvtCTLOptions maCTLOptions;

    /// Keep the output devices of this view shell up to date.
    ViewShell* mpViewShell;

    /// The document rendered in the output devices.
    SdDrawDocument* mpDocument;

    /// Copy constructor not supported.
    WindowUpdater (const WindowUpdater& rUpdater);

    /// Assignment operator not supported.
    WindowUpdater operator= (const WindowUpdater& rUpdater);

    /** Type and data member for a list of devices that have to be kept
        up-to-date.
    */
    typedef ::std::vector< ::Window*> tWindowList;
    tWindowList maWindowList;

    /** The central method of this class.  Update the given output device.
        It is the task of the caller to initiate a refrormatting of the
        document that is rendered on this device to reflect the changes.
        @param pWindow
            The output device to update.  When it is <null/> then the call
            is ignored.
    */
    SD_DLLPRIVATE void UpdateWindow (OutputDevice* pDevice) const;
};

} // end of namespace sd

#endif
<|endoftext|>


<commit_before>#include "AgentsConfig.h"
#include "Tools.h"
#include "sc2utils/sc2_manage_process.h"
#include "sc2utils/sc2_scan_directory.h"
#define RAPIDJSON_HAS_STDSTRING 1
#include "rapidjson.h"
#include "document.h"

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

AgentsConfig::AgentsConfig(LadderConfig *InLadderConfig)
    : Config(InLadderConfig),
      PlayerIds(nullptr),
      EnablePlayerIds(false)
{
	if (Config == nullptr)
	{
		return;
	}
	std::string PlayerIdFile = Config->GetStringValue("PlayerIdFile");
	if (PlayerIdFile.length() > 0)
	{
		PlayerIds = new LadderConfig(PlayerIdFile);
		EnablePlayerIds = true;
	}
	if (Config->GetStringValue("BotConfigFile") != "")
	{
		LoadAgents("", Config->GetStringValue("BotConfigFile"));
	}
	else if (Config->GetStringValue("BaseBotDirectory") != "")
	{
		ReadBotDirectories(Config->GetStringValue("BaseBotDirectory"));
	}

}

void AgentsConfig::ReadBotDirectories(const std::string &BaseDirectory)
{
	std::vector<std::string> directories;
	sc2::scan_directory(BaseDirectory.c_str(), directories, true, true);
	for (const std::string  &Directory : directories)
	{
		std::string CurrentConfigFile = Directory + "/ladderbots.json";
		LoadAgents(Directory, CurrentConfigFile);
	}

}

void AgentsConfig::LoadAgents(const std::string &BaseDirectory, const std::string &BotConfigFile)
{
	if (BotConfigFile.length() < 1)
	{
		return;
	}
	std::ifstream t(BotConfigFile);
	std::stringstream buffer;
	buffer << t.rdbuf();
	std::string BotConfigString = buffer.str();
	rapidjson::Document doc;
	bool parsingFailed = doc.Parse(BotConfigString.c_str()).HasParseError();
	if (parsingFailed)
	{
		std::cerr << "Unable to parse bot config file: " << BotConfigFile << std::endl;
		return;
	}
	if (doc.HasMember("Bots") && doc["Bots"].IsObject())
	{
		const rapidjson::Value & Bots = doc["Bots"];
        for (auto itr = Bots.MemberBegin(); itr != Bots.MemberEnd(); ++itr)
        {
            BotConfig NewBot;
            NewBot.BotName = itr->name.GetString();
            const rapidjson::Value &val = itr->value;

            if (val.HasMember("Race") && val["Race"].IsString())
            {
                NewBot.Race = GetRaceFromString(val["Race"].GetString());
            }
            else
            {
                std::cerr << "Unable to parse race for bot " << NewBot.BotName << std::endl;
                continue;
            }
            if (val.HasMember("Type") && val["Type"].IsString())
            {
                NewBot.Type = GetTypeFromString(val["Type"].GetString());
            }
            else
            {
                std::cerr << "Unable to parse type for bot " << NewBot.BotName << std::endl;
                continue;
            }
            if (val.HasMember("RootPath") && val["RootPath"].IsString())
            {
                NewBot.RootPath = BaseDirectory;
                if (NewBot.RootPath.back() != '/')
                {
                    NewBot.RootPath += '/';
                }
                NewBot.RootPath = NewBot.RootPath + val["RootPath"].GetString();
                if (NewBot.RootPath.back() != '/')
                {
                    NewBot.RootPath += '/';
                }
            }
            else
            {
                std::cerr << "Unable to parse root path for bot " << NewBot.BotName << std::endl;
                continue;
            }
            if (val.HasMember("FileName") && val["FileName"].IsString())
            {
                NewBot.FileName = val["FileName"].GetString();
            }
            else
            {
                std::cerr << "Unable to parse file name for bot " << NewBot.BotName << std::endl;
                continue;
            }
            if (!sc2::DoesFileExist(NewBot.RootPath + NewBot.FileName))
            {
                std::cerr << "Unable to parse bot " << NewBot.BotName << std::endl;
                std::cerr << "Is the path " << NewBot.RootPath << " correct?" << std::endl;
                continue;
            }
            const std::string dataLocation = NewBot.RootPath + "/data";
            MakeDirectory(dataLocation); // If a directory exists this just fails and does nothing.
            if (val.HasMember("Args") && val["Args"].IsString())
            {
                NewBot.Args = val["Args"].GetString();
            }
            if (val.HasMember("Debug") && val["Debug"].IsBool()) {
                NewBot.Debug = val["Debug"].GetBool();
            }

            if (val.HasMember("SurrenderPhrase") && val["SurrenderPhrase"].IsString()) {
                NewBot.SurrenderPhrase = val["SurrenderPhrase"].GetString();
            }

            if (EnablePlayerIds)
            {
                NewBot.PlayerId = PlayerIds->GetStringValue(NewBot.BotName);
                if (NewBot.PlayerId.empty())
                {
                    NewBot.PlayerId = GerneratePlayerId(PLAYER_ID_LENGTH);
                    PlayerIds->AddValue(NewBot.BotName, NewBot.PlayerId);
                    PlayerIds->WriteConfig();
                }
            }

            std::string OutCmdLine = "";
            switch (NewBot.Type)
            {
            case Python:
            {
                OutCmdLine = Config->GetStringValue("PythonBinary") + " " + NewBot.FileName;
                break;
            }
            case Wine:
            {
                OutCmdLine = "wine " + NewBot.FileName;
                break;
            }
            case Mono:
            {
                OutCmdLine = "mono " + NewBot.FileName;
                break;
            }
            case DotNetCore:
            {
                OutCmdLine = "dotnet " + NewBot.FileName;
                break;
            }
            case CommandCenter:
            {
                OutCmdLine = Config->GetStringValue("CommandCenterPath") + " --ConfigFile " + NewBot.FileName;
                break;
            }
            case BinaryCpp:
            {
                OutCmdLine = NewBot.RootPath + NewBot.FileName;
                break;
            }
            case Java:
            {
                OutCmdLine = "java -jar " + NewBot.FileName;
                break;
            }
            case NodeJS:
            {
                OutCmdLine = Config->GetStringValue("NodeJSBinary") + " " + NewBot.FileName;
                break;
            }
            }

            if (NewBot.Args != "")
            {
                OutCmdLine += " " + NewBot.Args;
            }

            NewBot.executeCommand = OutCmdLine;
            BotConfig SavedBot;
            if (FindBot(NewBot.BotName, SavedBot))
            {
                NewBot.CheckSum = SavedBot.CheckSum;
                BotConfigs[NewBot.BotName] = NewBot;
            }
            else
            {
                BotConfigs.insert(std::make_pair(std::string(NewBot.BotName), NewBot));
            }

        }
	}

}

void AgentsConfig::SaveBotConfig(const BotConfig& Agent)
{
    BotConfig SavedBot;
    if (FindBot(Agent.BotName, SavedBot))
    {
        BotConfigs[Agent.BotName] = Agent;
    }
    else
    {
        BotConfigs.insert(std::make_pair(std::string(Agent.BotName), Agent));
    }
}

bool AgentsConfig::FindBot(const std::string &BotName, BotConfig &ReturnBot)
{
	auto ThisBot = BotConfigs.find(BotName);
	if (ThisBot != BotConfigs.end())
	{
		ReturnBot = ThisBot->second;
		return true;
	}
	return false;
}

bool AgentsConfig::CheckDiactivatedBots()
{
	std::string BotCheckLocation = Config->GetStringValue("BotInfoLocation");
	if (BotCheckLocation.empty())
	{
		return false;
	}
	std::vector<std::string> arguments;
	std::string result = PerformRestRequest(BotCheckLocation, arguments);
	if (result.empty())
	{
		return false;
	}
	rapidjson::Document doc;
	bool parsingFailed = doc.Parse(result.c_str()).HasParseError();
	if (parsingFailed)
	{
		std::cerr << "Unable to parse incoming bot config: " << BotCheckLocation << std::endl;
		return false;
	}
	if (doc.HasMember("Bots") && doc["Bots"].IsArray())
	{
		const rapidjson::Value & Units = doc["Bots"];
		for (const auto& val : Units.GetArray())
		{
			if (val.HasMember("name") && val["name"].IsString())
			{
				auto ThisBot = BotConfigs.find(val["name"].GetString());
				if (ThisBot != BotConfigs.end())
				{
					if (val.HasMember("deactivated") && val.HasMember("deleted") && val["deactivated"].IsBool() && val["deleted"].IsBool())
					{
						if ((val["deactivated"].GetBool() || val["deleted"].GetBool()) && ThisBot->second.Enabled)
						{
							// Set bot to disabled
							PrintThread{} << "Deactivating bot " << ThisBot->second.BotName << std::endl;
							ThisBot->second.Enabled = false;

						}
						else if (val["deactivated"].GetBool() == false && val["deleted"].GetBool() == false && ThisBot->second.Enabled == false)
						{
							// reenable a bot
							PrintThread{} << "Activating bot " << ThisBot->second.BotName;
							ThisBot->second.Enabled = true;
						}
					}
					if (val.HasMember("elo") && val["elo"].IsString())
					{
						ThisBot->second.ELO = std::stoi(val["elo"].GetString());
					}
				}

			}
		}
		return true;
	}
	return false;
}

std::string AgentsConfig::GerneratePlayerId(size_t Length)
{
	static const char hexdigit[16] = { '0', '1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
	std::string outstring;
	if (Length < 1)
	{
		return outstring;

	}
	--Length;
	for (int i = 0; i < Length; ++i)
	{
		outstring.append(1, hexdigit[rand() % sizeof hexdigit]);
	}
	return outstring;
}
<commit_msg>Update AgentsConfig.cpp<commit_after>#include "AgentsConfig.h"
#include "Tools.h"
#include "sc2utils/sc2_manage_process.h"
#include "sc2utils/sc2_scan_directory.h"
#define RAPIDJSON_HAS_STDSTRING 1
#include "rapidjson.h"
#include "document.h"

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

AgentsConfig::AgentsConfig(LadderConfig *InLadderConfig)
    : Config(InLadderConfig),
      PlayerIds(nullptr),
      EnablePlayerIds(false)
{
	if (Config == nullptr)
	{
		return;
	}
	std::string PlayerIdFile = Config->GetStringValue("PlayerIdFile");
	if (PlayerIdFile.length() > 0)
	{
		PlayerIds = new LadderConfig(PlayerIdFile);
        PlayerIds->ParseConfig();
		EnablePlayerIds = true;
	}
	if (Config->GetStringValue("BotConfigFile") != "")
	{
		LoadAgents("", Config->GetStringValue("BotConfigFile"));
	}
	else if (Config->GetStringValue("BaseBotDirectory") != "")
	{
		ReadBotDirectories(Config->GetStringValue("BaseBotDirectory"));
	}

}

void AgentsConfig::ReadBotDirectories(const std::string &BaseDirectory)
{
	std::vector<std::string> directories;
	sc2::scan_directory(BaseDirectory.c_str(), directories, true, true);
	for (const std::string  &Directory : directories)
	{
		std::string CurrentConfigFile = Directory + "/ladderbots.json";
		LoadAgents(Directory, CurrentConfigFile);
	}

}

void AgentsConfig::LoadAgents(const std::string &BaseDirectory, const std::string &BotConfigFile)
{
	if (BotConfigFile.length() < 1)
	{
		return;
	}
	std::ifstream t(BotConfigFile);
	std::stringstream buffer;
	buffer << t.rdbuf();
	std::string BotConfigString = buffer.str();
	rapidjson::Document doc;
	bool parsingFailed = doc.Parse(BotConfigString.c_str()).HasParseError();
	if (parsingFailed)
	{
		std::cerr << "Unable to parse bot config file: " << BotConfigFile << std::endl;
		return;
	}
	if (doc.HasMember("Bots") && doc["Bots"].IsObject())
	{
		const rapidjson::Value & Bots = doc["Bots"];
        for (auto itr = Bots.MemberBegin(); itr != Bots.MemberEnd(); ++itr)
        {
            BotConfig NewBot;
            NewBot.BotName = itr->name.GetString();
            const rapidjson::Value &val = itr->value;

            if (val.HasMember("Race") && val["Race"].IsString())
            {
                NewBot.Race = GetRaceFromString(val["Race"].GetString());
            }
            else
            {
                std::cerr << "Unable to parse race for bot " << NewBot.BotName << std::endl;
                continue;
            }
            if (val.HasMember("Type") && val["Type"].IsString())
            {
                NewBot.Type = GetTypeFromString(val["Type"].GetString());
            }
            else
            {
                std::cerr << "Unable to parse type for bot " << NewBot.BotName << std::endl;
                continue;
            }
            if (val.HasMember("RootPath") && val["RootPath"].IsString())
            {
                NewBot.RootPath = BaseDirectory;
                if (NewBot.RootPath.back() != '/')
                {
                    NewBot.RootPath += '/';
                }
                NewBot.RootPath = NewBot.RootPath + val["RootPath"].GetString();
                if (NewBot.RootPath.back() != '/')
                {
                    NewBot.RootPath += '/';
                }
            }
            else
            {
                std::cerr << "Unable to parse root path for bot " << NewBot.BotName << std::endl;
                continue;
            }
            if (val.HasMember("FileName") && val["FileName"].IsString())
            {
                NewBot.FileName = val["FileName"].GetString();
            }
            else
            {
                std::cerr << "Unable to parse file name for bot " << NewBot.BotName << std::endl;
                continue;
            }
            if (!sc2::DoesFileExist(NewBot.RootPath + NewBot.FileName))
            {
                std::cerr << "Unable to parse bot " << NewBot.BotName << std::endl;
                std::cerr << "Is the path " << NewBot.RootPath << " correct?" << std::endl;
                continue;
            }
            const std::string dataLocation = NewBot.RootPath + "/data";
            MakeDirectory(dataLocation); // If a directory exists this just fails and does nothing.
            if (val.HasMember("Args") && val["Args"].IsString())
            {
                NewBot.Args = val["Args"].GetString();
            }
            if (val.HasMember("Debug") && val["Debug"].IsBool()) {
                NewBot.Debug = val["Debug"].GetBool();
            }

            if (val.HasMember("SurrenderPhrase") && val["SurrenderPhrase"].IsString()) {
                NewBot.SurrenderPhrase = val["SurrenderPhrase"].GetString();
            }

            if (EnablePlayerIds)
            {
                NewBot.PlayerId = PlayerIds->GetStringValue(NewBot.BotName);
                if (NewBot.PlayerId.empty())
                {
                    NewBot.PlayerId = GerneratePlayerId(PLAYER_ID_LENGTH);
                    PlayerIds->AddValue(NewBot.BotName, NewBot.PlayerId);
                    PlayerIds->WriteConfig();
                }
            }

            std::string OutCmdLine = "";
            switch (NewBot.Type)
            {
            case Python:
            {
                OutCmdLine = Config->GetStringValue("PythonBinary") + " " + NewBot.FileName;
                break;
            }
            case Wine:
            {
                OutCmdLine = "wine " + NewBot.FileName;
                break;
            }
            case Mono:
            {
                OutCmdLine = "mono " + NewBot.FileName;
                break;
            }
            case DotNetCore:
            {
                OutCmdLine = "dotnet " + NewBot.FileName;
                break;
            }
            case CommandCenter:
            {
                OutCmdLine = Config->GetStringValue("CommandCenterPath") + " --ConfigFile " + NewBot.FileName;
                break;
            }
            case BinaryCpp:
            {
                OutCmdLine = NewBot.RootPath + NewBot.FileName;
                break;
            }
            case Java:
            {
                OutCmdLine = "java -jar " + NewBot.FileName;
                break;
            }
            case NodeJS:
            {
                OutCmdLine = Config->GetStringValue("NodeJSBinary") + " " + NewBot.FileName;
                break;
            }
            }

            if (NewBot.Args != "")
            {
                OutCmdLine += " " + NewBot.Args;
            }

            NewBot.executeCommand = OutCmdLine;
            BotConfig SavedBot;
            if (FindBot(NewBot.BotName, SavedBot))
            {
                NewBot.CheckSum = SavedBot.CheckSum;
                BotConfigs[NewBot.BotName] = NewBot;
            }
            else
            {
                BotConfigs.insert(std::make_pair(std::string(NewBot.BotName), NewBot));
            }

        }
	}

}

void AgentsConfig::SaveBotConfig(const BotConfig& Agent)
{
    BotConfig SavedBot;
    if (FindBot(Agent.BotName, SavedBot))
    {
        BotConfigs[Agent.BotName] = Agent;
    }
    else
    {
        BotConfigs.insert(std::make_pair(std::string(Agent.BotName), Agent));
    }
}

bool AgentsConfig::FindBot(const std::string &BotName, BotConfig &ReturnBot)
{
	auto ThisBot = BotConfigs.find(BotName);
	if (ThisBot != BotConfigs.end())
	{
		ReturnBot = ThisBot->second;
		return true;
	}
	return false;
}

bool AgentsConfig::CheckDiactivatedBots()
{
	std::string BotCheckLocation = Config->GetStringValue("BotInfoLocation");
	if (BotCheckLocation.empty())
	{
		return false;
	}
	std::vector<std::string> arguments;
	std::string result = PerformRestRequest(BotCheckLocation, arguments);
	if (result.empty())
	{
		return false;
	}
	rapidjson::Document doc;
	bool parsingFailed = doc.Parse(result.c_str()).HasParseError();
	if (parsingFailed)
	{
		std::cerr << "Unable to parse incoming bot config: " << BotCheckLocation << std::endl;
		return false;
	}
	if (doc.HasMember("Bots") && doc["Bots"].IsArray())
	{
		const rapidjson::Value & Units = doc["Bots"];
		for (const auto& val : Units.GetArray())
		{
			if (val.HasMember("name") && val["name"].IsString())
			{
				auto ThisBot = BotConfigs.find(val["name"].GetString());
				if (ThisBot != BotConfigs.end())
				{
					if (val.HasMember("deactivated") && val.HasMember("deleted") && val["deactivated"].IsBool() && val["deleted"].IsBool())
					{
						if ((val["deactivated"].GetBool() || val["deleted"].GetBool()) && ThisBot->second.Enabled)
						{
							// Set bot to disabled
							PrintThread{} << "Deactivating bot " << ThisBot->second.BotName << std::endl;
							ThisBot->second.Enabled = false;

						}
						else if (val["deactivated"].GetBool() == false && val["deleted"].GetBool() == false && ThisBot->second.Enabled == false)
						{
							// reenable a bot
							PrintThread{} << "Activating bot " << ThisBot->second.BotName;
							ThisBot->second.Enabled = true;
						}
					}
					if (val.HasMember("elo") && val["elo"].IsString())
					{
						ThisBot->second.ELO = std::stoi(val["elo"].GetString());
					}
				}

			}
		}
		return true;
	}
	return false;
}

std::string AgentsConfig::GerneratePlayerId(size_t Length)
{
	static const char hexdigit[16] = { '0', '1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
	std::string outstring;
	if (Length < 1)
	{
		return outstring;

	}
	--Length;
	for (int i = 0; i < Length; ++i)
	{
		outstring.append(1, hexdigit[rand() % sizeof hexdigit]);
	}
	return outstring;
}
<|endoftext|>


<commit_before>#include "exon.h"

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <cassert>
#include <cstdio>

exon::exon(const string &s)
{
	parse(s);
}

exon::exon(const string &_transcript_id, const string &_gene_id, int32_t _start, int32_t _end, int32_t _expression)
	: seqname("chr1"), source("simulation"), start(_start), end(_end), transcript_id(_transcript_id),
	gene_id(_gene_id), expression(_expression), feature("exon"), score(1000), strand('+'), frame(0)
{
}

int exon::parse(const string &s)
{
	char buf[10240];
	stringstream sstr(s);
	sstr>>buf;
	seqname.assign(buf);
	sstr>>buf;
	source.assign(buf);
	sstr>>buf;
	feature.assign(buf);
	sstr>>start>>end;
	end++;			// TODO check gtf end is inclusive
	sstr>>buf;
	if(buf[0] == '.') score = -1;
	else score = atof(buf);
	sstr>>buf;
	strand = buf[0];
	sstr>>buf;
	frame = buf[0];

	char buf2[10240];
	while(sstr.eof() == false)
	{
		sstr>>buf;
		sstr.getline(buf2, 10240, '"');
		sstr.getline(buf2, 10240, '"');
		string v(buf2);
		if(string(buf) == "" || v == "") break;

		//printf(" |%s|%s|%lu|%lu|\n", buf, k.c_str(), p1, p2);

		if(string(buf) == "transcript_id") transcript_id = v;
		else if(string(buf) == "gene_id") gene_id = v;
		else if(string(buf) == "expression") expression = atoi(v.c_str());

		sstr.getline(buf2, 10240, ';');
	}

	return 0;
}

int exon::print() const
{
	printf("%s\t%s\t%s\t%d\t%d\t%.1lf\t%c\t%c\ttranscript_id \"%s\"; gene_id \"%s\"; expression \"%d\"\n",
			seqname.c_str(), source.c_str(), feature.c_str(), start, end, score, strand, frame,
			transcript_id.c_str(), gene_id.c_str(), expression);
	return 0;
}

bool exon::operator<(const exon &ge) const
{
	if(start < ge.start) return true;
	else return false;
}

int exon::length() const
{
	assert(end > start);
	return end - start;
}
<commit_msg>adjust gtf, starting from 0, [)<commit_after>#include "exon.h"

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <cassert>
#include <cstdio>

exon::exon(const string &s)
{
	parse(s);
}

exon::exon(const string &_transcript_id, const string &_gene_id, int32_t _start, int32_t _end, int32_t _expression)
	: seqname("chr1"), source("simulation"), start(_start), end(_end), transcript_id(_transcript_id),
	gene_id(_gene_id), expression(_expression), feature("exon"), score(1000), strand('+'), frame(0)
{
}

int exon::parse(const string &s)
{
	char buf[10240];
	stringstream sstr(s);
	sstr>>buf;
	seqname.assign(buf);
	sstr>>buf;
	source.assign(buf);
	sstr>>buf;
	feature.assign(buf);
	sstr>>start>>end;
	start--;			// gtf: (from 1, both inclusive)
	sstr>>buf;
	if(buf[0] == '.') score = -1;
	else score = atof(buf);
	sstr>>buf;
	strand = buf[0];
	sstr>>buf;
	frame = buf[0];

	char buf2[10240];
	while(sstr.eof() == false)
	{
		sstr>>buf;
		sstr.getline(buf2, 10240, '"');
		sstr.getline(buf2, 10240, '"');
		string v(buf2);
		if(string(buf) == "" || v == "") break;

		//printf(" |%s|%s|%lu|%lu|\n", buf, k.c_str(), p1, p2);

		if(string(buf) == "transcript_id") transcript_id = v;
		else if(string(buf) == "gene_id") gene_id = v;
		else if(string(buf) == "expression") expression = atoi(v.c_str());

		sstr.getline(buf2, 10240, ';');
	}

	return 0;
}

int exon::print() const
{
	printf("%s\t%s\t%s\t%d\t%d\t%.1lf\t%c\t%c\ttranscript_id \"%s\"; gene_id \"%s\"; expression \"%d\"\n",
			seqname.c_str(), source.c_str(), feature.c_str(), start, end, score, strand, frame,
			transcript_id.c_str(), gene_id.c_str(), expression);
	return 0;
}

bool exon::operator<(const exon &ge) const
{
	if(start < ge.start) return true;
	else return false;
}

int exon::length() const
{
	assert(end > start);
	return end - start;
}
<|endoftext|>


<commit_before>/* This file is part of QJson
 *
 * Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "json_driver.h"
#include "json_driver_p.h"
#include "json_parser.hh"

#include <QtCore/QBuffer>
#include <QtCore/QStringList>
#include <QtCore/QTextStream>
#include <QtCore/QDebug>

JSonDriverPrivate::JSonDriverPrivate() :
    m_scanner(0)
  , m_negate(false)
  , m_error(false)
{
}

JSonDriverPrivate::~JSonDriverPrivate()
{
  delete m_scanner;
}

void JSonDriverPrivate::setError(QString errorMsg, int errorLine) {
  m_error = true;
  m_errorMsg = errorMsg;
  m_errorLine = errorLine;
}

JSonDriver::JSonDriver() :
    d(new JSonDriverPrivate)
{
}

JSonDriver::~JSonDriver()
{
  delete d;
}

QVariant JSonDriver::parse (QIODevice* io, bool* ok)
{
  d->m_errorMsg.clear();
  delete d->m_scanner;
  d->m_scanner = 0;

  if (!io->isOpen()) {
    if (!io->open(QIODevice::ReadOnly)) {
      if (ok != 0)
        *ok = false;
      qFatal ("Error opening device");
      return QVariant();
    }
  }

  if (!io->isReadable()) {
    if (ok != 0)
      *ok = false;
    qFatal ("Device is not readable");
    io->close();
    return QVariant();
  }

  d->m_scanner = new JSonScanner (io);
  yy::json_parser parser (d);
  parser.parse ();

  delete d->m_scanner;
  d->m_scanner = 0;

  if (ok != 0)
    *ok = !d->m_error;

  io->close();
  return d->m_result;
}

QVariant JSonDriver::parse(const QString& jsonString, bool* ok) {
  QBuffer buffer;
  buffer.open(QBuffer::ReadWrite);
  buffer.write(jsonString.toAscii());
  buffer.seek(0);
  return parse (&buffer, ok);
}

void JSonDriver::serialize( const QVariant& v, QIODevice* io, bool* ok )
{
  if (!io->isOpen()) {
    if (!io->open(QIODevice::WriteOnly)) {
      if ( ok != 0 )
        *ok = false;
      qFatal ("Error opening device");
      return;
    }
  }

  if (!io->isWritable()) {
    if (ok != 0)
      *ok = false;
    qFatal ("Device is not readable");
    io->close();
    return;
  }

  bool error = false;
  const QString str = serialize( v );
  if ( !str.isNull() ) {
    QTextStream stream( io );
    stream << str;
  } else {
    if ( ok )
      *ok = error;
  }
}

static QString sanitizeString( const QString& s )
{
  return QLatin1String("\"") + s + QLatin1String("\"");
}

const QString JSonDriver::serialize( const QVariant &v )
{
  if ( !v.isValid() )
    return QString(""); // no parse error
  QString str;
  bool error = false;

  // two major cases, either it's an array or ... not
  if ( v.canConvert<QVariantList>() ) {
    const QVariantList list = v.toList();
    QStringList values;
    Q_FOREACH( const QVariant& v, list ) {
      values << serialize( v );
    }
    str = QLatin1String("[ ") + values.join(", ") + QLatin1String(" ]");
  } else {
    // not a list, so it must be an object
    if ( !v.canConvert<QVariantMap>() ) {
      // not a map, so it must be a value
      if ( v.type() == QVariant::String )
        str = sanitizeString( v.toString() );
      else
        str = v.toString();
    } else {
      const QVariantMap vmap = v.toMap();
      QStringList values;
      QMapIterator<QString, QVariant> it( vmap );
      while ( it.hasNext() ) {
        it.next();
        QString value = it.value().toString();
        if ( it.value().type() == QVariant::String )
          value = sanitizeString( value );
      }
      str = QLatin1String("{ ") + values.join(", ") + QLatin1String(" }");
    }
  }
  if ( !error )
    return str;
  else
    return QString();
}

QString JSonDriver::error() const
{
  return d->m_errorMsg;
}

int JSonDriver::errorLine() const
{
  return d->m_errorLine;
}
<commit_msg>replaced qFatal with qCritical<commit_after>/* This file is part of QJson
 *
 * Copyright (C) 2008 Flavio Castelli <flavio.castelli@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "json_driver.h"
#include "json_driver_p.h"
#include "json_parser.hh"

#include <QtCore/QBuffer>
#include <QtCore/QStringList>
#include <QtCore/QTextStream>
#include <QtCore/QDebug>

JSonDriverPrivate::JSonDriverPrivate() :
    m_scanner(0)
  , m_negate(false)
  , m_error(false)
{
}

JSonDriverPrivate::~JSonDriverPrivate()
{
  delete m_scanner;
}

void JSonDriverPrivate::setError(QString errorMsg, int errorLine) {
  m_error = true;
  m_errorMsg = errorMsg;
  m_errorLine = errorLine;
}

JSonDriver::JSonDriver() :
    d(new JSonDriverPrivate)
{
}

JSonDriver::~JSonDriver()
{
  delete d;
}

QVariant JSonDriver::parse (QIODevice* io, bool* ok)
{
  d->m_errorMsg.clear();
  delete d->m_scanner;
  d->m_scanner = 0;

  if (!io->isOpen()) {
    if (!io->open(QIODevice::ReadOnly)) {
      if (ok != 0)
        *ok = false;
      qCritical ("Error opening device");
      return QVariant();
    }
  }

  if (!io->isReadable()) {
    if (ok != 0)
      *ok = false;
    qCritical ("Device is not readable");
    io->close();
    return QVariant();
  }

  d->m_scanner = new JSonScanner (io);
  yy::json_parser parser (d);
  parser.parse ();

  delete d->m_scanner;
  d->m_scanner = 0;

  if (ok != 0)
    *ok = !d->m_error;

  io->close();
  return d->m_result;
}

QVariant JSonDriver::parse(const QString& jsonString, bool* ok) {
  QBuffer buffer;
  buffer.open(QBuffer::ReadWrite);
  buffer.write(jsonString.toAscii());
  buffer.seek(0);
  return parse (&buffer, ok);
}

void JSonDriver::serialize( const QVariant& v, QIODevice* io, bool* ok )
{
  if (!io->isOpen()) {
    if (!io->open(QIODevice::WriteOnly)) {
      if ( ok != 0 )
        *ok = false;
      qCritical ("Error opening device");
      return;
    }
  }

  if (!io->isWritable()) {
    if (ok != 0)
      *ok = false;
    qCritical ("Device is not readable");
    io->close();
    return;
  }

  bool error = false;
  const QString str = serialize( v );
  if ( !str.isNull() ) {
    QTextStream stream( io );
    stream << str;
  } else {
    if ( ok )
      *ok = error;
  }
}

static QString sanitizeString( const QString& s )
{
  return QLatin1String("\"") + s + QLatin1String("\"");
}

const QString JSonDriver::serialize( const QVariant &v )
{
  if ( !v.isValid() )
    return QString(""); // no parse error
  QString str;
  bool error = false;

  // two major cases, either it's an array or ... not
  if ( v.canConvert<QVariantList>() ) {
    const QVariantList list = v.toList();
    QStringList values;
    Q_FOREACH( const QVariant& v, list ) {
      values << serialize( v );
    }
    str = QLatin1String("[ ") + values.join(", ") + QLatin1String(" ]");
  } else {
    // not a list, so it must be an object
    if ( !v.canConvert<QVariantMap>() ) {
      // not a map, so it must be a value
      if ( v.type() == QVariant::String )
        str = sanitizeString( v.toString() );
      else
        str = v.toString();
    } else {
      const QVariantMap vmap = v.toMap();
      QStringList values;
      QMapIterator<QString, QVariant> it( vmap );
      while ( it.hasNext() ) {
        it.next();
        QString value = it.value().toString();
        if ( it.value().type() == QVariant::String )
          value = sanitizeString( value );
      }
      str = QLatin1String("{ ") + values.join(", ") + QLatin1String(" }");
    }
  }
  if ( !error )
    return str;
  else
    return QString();
}

QString JSonDriver::error() const
{
  return d->m_errorMsg;
}

int JSonDriver::errorLine() const
{
  return d->m_errorLine;
}
<|endoftext|>


<commit_before>//
// Allocate objects smaller than a page.
//

#include "types.h"
#include "mmu.h"
#include "kernel.hh"
#include "spinlock.h"
#include "kalloc.hh"
#include "mtrace.h"
#include "cpu.hh"
#include "kstream.hh"

// allocate in power-of-two sizes up to 2^KMMAX (PGSIZE)
#define KMMAX 12

struct header {
  struct header *next;
};

struct freelist {
  versioned<vptr48<header*>> buckets[KMMAX+1];
  char name[MAXNAME];
};

struct freelist freelists[NCPU];

void
kminit(void)
{
  for (int c = 0; c < NCPU; c++) {
    freelists[c].name[0] = (char) c + '0';
    safestrcpy(freelists[c].name+1, "freelist", MAXNAME-1);
  }
}

// get more space for freelists[c].buckets[b]
static int
morecore(int c, int b)
{
  char *p = kalloc("kmalloc");
  if(p == 0)
    return -1;

  if (ALLOC_MEMSET)
    memset(p, 3, PGSIZE);

  int sz = 1 << b;
  assert(sz >= sizeof(header));
  for(char *q = p; q + sz <= p + PGSIZE; q += sz){
    struct header *h = (struct header *) q;
    for (;;) {
      auto headptr = freelists[c].buckets[b].load();
      h->next = headptr.ptr();
      if (freelists[c].buckets[b].compare_exchange(headptr, h))
        break;
    }
  }

  return 0;
}

static int
bucket(u64 nbytes)
{
  static int bucketmap[] = {
    6,
    7,
    8,  8,
    9,  9,  9,  9,
    10, 10, 10, 10, 10, 10, 10, 10,
    11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
    12,
  };

  assert(nbytes <= PGSIZE);
  int b = bucketmap[nbytes >> 6];
  assert((1<<b) >= nbytes);
  return b;
}

void *
kmalloc(u64 nbytes, const char *name)
{
  int b = bucket(nbytes);

  struct header *h;
  int c = mycpu()->id;

  for (;;) {
    auto headptr = freelists[c].buckets[b].load();
    h = headptr.ptr();
    if (!h) {
      if (morecore(c, b) < 0) {
        cprintf("kmalloc(%d) failed\n", (int) nbytes);
        return 0;
      }
    } else {
      header *nxt = h->next;
      if (freelists[c].buckets[b].compare_exchange(headptr, nxt)) {
        if (h->next != nxt)
          panic("kmalloc: aba race");
        break;
      }
    }
  }

  mtlabel(mtrace_label_heap, (void*) h, nbytes, name, strlen(name));

  if (ALLOC_MEMSET) {
    char* chk = (char*)(h + 1);
    for (int i = 0; i < (1<<b)-sizeof(*h); i++)
      if (chk[i] != 3) {
        console.print(shexdump(chk, nbytes));
        panic("kmalloc: free memory was overwritten %p+%x", chk, i);
      }
    memset(h, 4, (1<<b));
  }

  return h;
}

void
kmfree(void *ap, u64 nbytes)
{
  int b = bucket(nbytes);

  struct header *h = (struct header *) ap;
  if (ALLOC_MEMSET)
    memset(ap, 3, (1<<b));

  mtunlabel(mtrace_label_heap, ap);

  int c = mycpu()->id;
  for (;;) {
    auto headptr = freelists[c].buckets[b].load();
    h->next = headptr.ptr();
    if (freelists[c].buckets[b].compare_exchange(headptr, h))
      break;
  }
}

int
kmalign(void **p, int align, u64 size, const char *name)
{
  void *mem = kmalloc(size + (align-1) + sizeof(void*), name);
  char *amem = ((char*)mem) + sizeof(void*);
  amem += align - ((uptr)amem & (align - 1));
  ((void**)amem)[-1] = mem;
  *p = amem;
  return 0;
}

void kmalignfree(void *mem, int align, u64 size)
{
  u64 msz = size + (align-1) + sizeof(void*);
  kmfree(((void**)mem)[-1], msz);
}
<commit_msg>kmalloc: Allow large allocations<commit_after>//
// Allocate objects smaller than a page.
//

#include "types.h"
#include "mmu.h"
#include "kernel.hh"
#include "spinlock.h"
#include "kalloc.hh"
#include "mtrace.h"
#include "cpu.hh"
#include "kstream.hh"
#include "log2.hh"

// allocate in power-of-two sizes up to 2^KMMAX (PGSIZE)
#define KMMAX 12

struct header {
  struct header *next;
};

struct freelist {
  versioned<vptr48<header*>> buckets[KMMAX+1];
  char name[MAXNAME];
};

struct freelist freelists[NCPU];

void
kminit(void)
{
  for (int c = 0; c < NCPU; c++) {
    freelists[c].name[0] = (char) c + '0';
    safestrcpy(freelists[c].name+1, "freelist", MAXNAME-1);
  }
}

// get more space for freelists[c].buckets[b]
static int
morecore(int c, int b)
{
  char *p = kalloc("kmalloc");
  if(p == 0)
    return -1;

  if (ALLOC_MEMSET)
    memset(p, 3, PGSIZE);

  int sz = 1 << b;
  assert(sz >= sizeof(header));
  for(char *q = p; q + sz <= p + PGSIZE; q += sz){
    struct header *h = (struct header *) q;
    for (;;) {
      auto headptr = freelists[c].buckets[b].load();
      h->next = headptr.ptr();
      if (freelists[c].buckets[b].compare_exchange(headptr, h))
        break;
    }
  }

  return 0;
}

static int
bucket(u64 nbytes)
{
  int b = ceil_log2(nbytes);
  if (b < 6)
    b = 6;
  assert((1<<b) >= nbytes);
  return b;
}

static void *
kmalloc_small(size_t b, const char *name)
{
  struct header *h;
  int c = mycpu()->id;

  for (;;) {
    auto headptr = freelists[c].buckets[b].load();
    h = headptr.ptr();
    if (!h) {
      if (morecore(c, b) < 0) {
        cprintf("kmalloc(%d) failed\n", 1 << b);
        return 0;
      }
    } else {
      header *nxt = h->next;
      if (freelists[c].buckets[b].compare_exchange(headptr, nxt)) {
        if (h->next != nxt)
          panic("kmalloc: aba race");
        break;
      }
    }
  }

  return h;
}

void *
kmalloc(u64 nbytes, const char *name)
{
  void *h;
  int b = bucket(nbytes);

  if (b >= PGSHIFT)
    h = kalloc(name, (size_t)1 << b);
  else
    h = kmalloc_small(b, name);
  if (!h)
    return nullptr;

  mtlabel(mtrace_label_heap, (void*) h, nbytes, name, strlen(name));

  if (ALLOC_MEMSET) {
    char* chk = (char*)h + sizeof(struct header);
    for (int i = 0; i < (1<<b)-sizeof(struct header); i++)
      if (chk[i] != 3) {
        console.print(shexdump(chk, nbytes));
        panic("kmalloc: free memory was overwritten %p+%x", chk, i);
      }
    memset(h, 4, (1<<b));
  }

  return h;
}

void
kmfree(void *ap, u64 nbytes)
{
  int b = bucket(nbytes);

  struct header *h = (struct header *) ap;
  if (ALLOC_MEMSET)
    memset(ap, 3, (1<<b));

  mtunlabel(mtrace_label_heap, ap);

  if (b >= PGSHIFT) {
    kfree(ap, (size_t)1 << b);
  } else {
    int c = mycpu()->id;
    for (;;) {
      auto headptr = freelists[c].buckets[b].load();
      h->next = headptr.ptr();
      if (freelists[c].buckets[b].compare_exchange(headptr, h))
        break;
    }
  }
}

int
kmalign(void **p, int align, u64 size, const char *name)
{
  void *mem = kmalloc(size + (align-1) + sizeof(void*), name);
  char *amem = ((char*)mem) + sizeof(void*);
  amem += align - ((uptr)amem & (align - 1));
  ((void**)amem)[-1] = mem;
  *p = amem;
  return 0;
}

void kmalignfree(void *mem, int align, u64 size)
{
  u64 msz = size + (align-1) + sizeof(void*);
  kmfree(((void**)mem)[-1], msz);
}
<|endoftext|>