<commit_before>//===-- GCSE.cpp - SSA based Global Common Subexpr Elimination ------------===//
//
// This pass is designed to be a very quick global transformation that
// eliminates global common subexpressions from a function.  It does this by
// examining the SSA value graph of the function, instead of doing slow, dense,
// bit-vector computations.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/InstrTypes.h"
#include "llvm/iMemory.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Support/InstVisitor.h"
#include "llvm/Support/InstIterator.h"
#include "llvm/Support/CFG.h"
#include "Support/StatisticReporter.h"
#include <algorithm>
using std::set;
using std::map;

static Statistic<> NumInstRemoved("gcse\t\t- Number of instructions removed");
static Statistic<> NumLoadRemoved("gcse\t\t- Number of loads removed");

namespace {
  class GCSE : public FunctionPass, public InstVisitor<GCSE, bool> {
    set<Instruction*>       WorkList;
    DominatorSet           *DomSetInfo;
    ImmediateDominators    *ImmDominator;
    AliasAnalysis          *AA;

  public:
    virtual bool runOnFunction(Function &F);

    // Visitation methods, these are invoked depending on the type of
    // instruction being checked.  They should return true if a common
    // subexpression was folded.
    //
    bool visitBinaryOperator(Instruction &I);
    bool visitGetElementPtrInst(GetElementPtrInst &I);
    bool visitCastInst(CastInst &I);
    bool visitShiftInst(ShiftInst &I) {
      return visitBinaryOperator((Instruction&)I);
    }
    bool visitLoadInst(LoadInst &LI);
    bool visitInstruction(Instruction &) { return false; }

  private:
    void ReplaceInstWithInst(Instruction *First, BasicBlock::iterator SI);
    bool CommonSubExpressionFound(Instruction *I, Instruction *Other);

    // TryToRemoveALoad - Try to remove one of L1 or L2.  The problem with
    // removing loads is that intervening stores might make otherwise identical
    // load's yield different values.  To ensure that this is not the case, we
    // check that there are no intervening stores or calls between the
    // instructions.
    //
    bool TryToRemoveALoad(LoadInst *L1, LoadInst *L2);

    // CheckForInvalidatingInst - Return true if BB or any of the predecessors
    // of BB (until DestBB) contain an instruction that might invalidate Ptr.
    //
    bool CheckForInvalidatingInst(BasicBlock *BB, BasicBlock *DestBB,
                                  Value *Ptr, set<BasicBlock*> &VisitedSet);

    // This transformation requires dominator and immediate dominator info
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.preservesCFG();
      AU.addRequired<DominatorSet>();
      AU.addRequired<ImmediateDominators>();
      AU.addRequired<AliasAnalysis>();
    }
  };

  RegisterOpt<GCSE> X("gcse", "Global Common Subexpression Elimination");
}

// createGCSEPass - The public interface to this file...
Pass *createGCSEPass() { return new GCSE(); }

// GCSE::runOnFunction - This is the main transformation entry point for a
// function.
//
bool GCSE::runOnFunction(Function &F) {
  bool Changed = false;

  // Get pointers to the analysis results that we will be using...
  DomSetInfo = &getAnalysis<DominatorSet>();
  ImmDominator = &getAnalysis<ImmediateDominators>();
  AA = &getAnalysis<AliasAnalysis>();

  // Step #1: Add all instructions in the function to the worklist for
  // processing.  All of the instructions are considered to be our
  // subexpressions to eliminate if possible.
  //
  WorkList.insert(inst_begin(F), inst_end(F));

  // Step #2: WorkList processing.  Iterate through all of the instructions,
  // checking to see if there are any additionally defined subexpressions in the
  // program.  If so, eliminate them!
  //
  while (!WorkList.empty()) {
    Instruction &I = **WorkList.begin(); // Get an instruction from the worklist
    WorkList.erase(WorkList.begin());

    // Visit the instruction, dispatching to the correct visit function based on
    // the instruction type.  This does the checking.
    //
    Changed |= visit(I);
  }

  // When the worklist is empty, return whether or not we changed anything...
  return Changed;
}

// ReplaceInstWithInst - Destroy the instruction pointed to by SI, making all
// uses of the instruction use First now instead.
//
void GCSE::ReplaceInstWithInst(Instruction *First, BasicBlock::iterator SI) {
  Instruction &Second = *SI;

  //cerr << "DEL " << (void*)Second << Second;

  // Add the first instruction back to the worklist
  WorkList.insert(First);

  // Add all uses of the second instruction to the worklist
  for (Value::use_iterator UI = Second.use_begin(), UE = Second.use_end();
       UI != UE; ++UI)
    WorkList.insert(cast<Instruction>(*UI));

  // Make all users of 'Second' now use 'First'
  Second.replaceAllUsesWith(First);

  // Erase the second instruction from the program
  Second.getParent()->getInstList().erase(SI);
}

// CommonSubExpressionFound - The two instruction I & Other have been found to
// be common subexpressions.  This function is responsible for eliminating one
// of them, and for fixing the worklist to be correct.
//
bool GCSE::CommonSubExpressionFound(Instruction *I, Instruction *Other) {
  assert(I != Other);

  WorkList.erase(I);
  WorkList.erase(Other); // Other may not actually be on the worklist anymore...

  ++NumInstRemoved;   // Keep track of number of instructions eliminated

  // Handle the easy case, where both instructions are in the same basic block
  BasicBlock *BB1 = I->getParent(), *BB2 = Other->getParent();
  if (BB1 == BB2) {
    // Eliminate the second occuring instruction.  Add all uses of the second
    // instruction to the worklist.
    //
    // Scan the basic block looking for the "first" instruction
    BasicBlock::iterator BI = BB1->begin();
    while (&*BI != I && &*BI != Other) {
      ++BI;
      assert(BI != BB1->end() && "Instructions not found in parent BB!");
    }

    // Keep track of which instructions occurred first & second
    Instruction *First = BI;
    Instruction *Second = I != First ? I : Other; // Get iterator to second inst
    BI = Second;

    // Destroy Second, using First instead.
    ReplaceInstWithInst(First, BI);

    // Otherwise, the two instructions are in different basic blocks.  If one
    // dominates the other instruction, we can simply use it
    //
  } else if (DomSetInfo->dominates(BB1, BB2)) {    // I dom Other?
    ReplaceInstWithInst(I, Other);
  } else if (DomSetInfo->dominates(BB2, BB1)) {    // Other dom I?
    ReplaceInstWithInst(Other, I);
  } else {
    // This code is disabled because it has several problems:
    // One, the actual assumption is wrong, as shown by this code:
    // int "test"(int %X, int %Y) {
    //         %Z = add int %X, %Y
    //         ret int %Z
    // Unreachable:
    //         %Q = add int %X, %Y
    //         ret int %Q
    // }
    //
    // Here there are no shared dominators.  Additionally, this had the habit of
    // moving computations where they were not always computed.  For example, in
    // a cast like this:
    //  if (c) {
    //    if (d)  ...
    //    else ... X+Y ...
    //  } else {
    //    ... X+Y ...
    //  }
    //
    // In thiscase, the expression would be hoisted to outside the 'if' stmt,
    // causing the expression to be evaluated, even for the if (d) path, which
    // could cause problems, if, for example, it caused a divide by zero.  In
    // general the problem this case is trying to solve is better addressed with
    // PRE than GCSE.
    //
    return false;

#if 0
    // Handle the most general case now.  In this case, neither I dom Other nor
    // Other dom I.  Because we are in SSA form, we are guaranteed that the
    // operands of the two instructions both dominate the uses, so we _know_
    // that there must exist a block that dominates both instructions (if the
    // operands of the instructions are globals or constants, worst case we
    // would get the entry node of the function).  Search for this block now.
    //

    // Search up the immediate dominator chain of BB1 for the shared dominator
    BasicBlock *SharedDom = (*ImmDominator)[BB1];
    while (!DomSetInfo->dominates(SharedDom, BB2))
      SharedDom = (*ImmDominator)[SharedDom];

    // At this point, shared dom must dominate BOTH BB1 and BB2...
    assert(SharedDom && DomSetInfo->dominates(SharedDom, BB1) &&
           DomSetInfo->dominates(SharedDom, BB2) && "Dominators broken!");

    // Rip 'I' out of BB1, and move it to the end of SharedDom.
    BB1->getInstList().remove(I);
    SharedDom->getInstList().insert(--SharedDom->end(), I);

    // Eliminate 'Other' now.
    ReplaceInstWithInst(I, Other);
#endif
  }
  return true;
}

//===----------------------------------------------------------------------===//
//
// Visitation methods, these are invoked depending on the type of instruction
// being checked.  They should return true if a common subexpression was folded.
//
//===----------------------------------------------------------------------===//

bool GCSE::visitCastInst(CastInst &CI) {
  Instruction &I = (Instruction&)CI;
  Value *Op = I.getOperand(0);
  Function *F = I.getParent()->getParent();

  for (Value::use_iterator UI = Op->use_begin(), UE = Op->use_end();
       UI != UE; ++UI)
    if (Instruction *Other = dyn_cast<Instruction>(*UI))
      // Check to see if this new cast is not I, but has the same operand...
      if (Other != &I && Other->getOpcode() == I.getOpcode() &&
          Other->getOperand(0) == Op &&     // Is the operand the same?
          // Is it embeded in the same function?  (This could be false if LHS
          // is a constant or global!)
          Other->getParent()->getParent() == F &&

          // Check that the types are the same, since this code handles casts...
          Other->getType() == I.getType()) {

        // These instructions are identical.  Handle the situation.
        if (CommonSubExpressionFound(&I, Other))
          return true;   // One instruction eliminated!
      }

  return false;
}

// isIdenticalBinaryInst - Return true if the two binary instructions are
// identical.
//
static inline bool isIdenticalBinaryInst(const Instruction &I1,
                                         const Instruction *I2) {
  // Is it embeded in the same function?  (This could be false if LHS
  // is a constant or global!)
  if (I1.getOpcode() != I2->getOpcode() ||
      I1.getParent()->getParent() != I2->getParent()->getParent())
    return false;

  // They are identical if both operands are the same!
  if (I1.getOperand(0) == I2->getOperand(0) &&
      I1.getOperand(1) == I2->getOperand(1))
    return true;

  // If the instruction is commutative and associative, the instruction can
  // match if the operands are swapped!
  //
  if ((I1.getOperand(0) == I2->getOperand(1) &&
       I1.getOperand(1) == I2->getOperand(0)) &&
      (I1.getOpcode() == Instruction::Add ||
       I1.getOpcode() == Instruction::Mul ||
       I1.getOpcode() == Instruction::And ||
       I1.getOpcode() == Instruction::Or  ||
       I1.getOpcode() == Instruction::Xor))
    return true;

  return false;
}

bool GCSE::visitBinaryOperator(Instruction &I) {
  Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
  Function *F = I.getParent()->getParent();

  for (Value::use_iterator UI = LHS->use_begin(), UE = LHS->use_end();
       UI != UE; ++UI)
    if (Instruction *Other = dyn_cast<Instruction>(*UI))
      // Check to see if this new binary operator is not I, but same operand...
      if (Other != &I && isIdenticalBinaryInst(I, Other)) {
        // These instructions are identical.  Handle the situation.
        if (CommonSubExpressionFound(&I, Other))
          return true;   // One instruction eliminated!
      }

  return false;
}

// IdenticalComplexInst - Return true if the two instructions are the same, by
// using a brute force comparison.
//
static bool IdenticalComplexInst(const Instruction *I1, const Instruction *I2) {
  assert(I1->getOpcode() == I2->getOpcode());
  // Equal if they are in the same function...
  return I1->getParent()->getParent() == I2->getParent()->getParent() &&
    // And return the same type...
    I1->getType() == I2->getType() &&
    // And have the same number of operands...
    I1->getNumOperands() == I2->getNumOperands() &&
    // And all of the operands are equal.
    std::equal(I1->op_begin(), I1->op_end(), I2->op_begin());
}

bool GCSE::visitGetElementPtrInst(GetElementPtrInst &I) {
  Value *Op = I.getOperand(0);
  Function *F = I.getParent()->getParent();

  for (Value::use_iterator UI = Op->use_begin(), UE = Op->use_end();
       UI != UE; ++UI)
    if (GetElementPtrInst *Other = dyn_cast<GetElementPtrInst>(*UI))
      // Check to see if this new getelementptr is not I, but same operand...
      if (Other != &I && IdenticalComplexInst(&I, Other)) {
        // These instructions are identical.  Handle the situation.
        if (CommonSubExpressionFound(&I, Other))
          return true;   // One instruction eliminated!
      }

  return false;
}

bool GCSE::visitLoadInst(LoadInst &LI) {
  Value *Op = LI.getOperand(0);
  Function *F = LI.getParent()->getParent();

  for (Value::use_iterator UI = Op->use_begin(), UE = Op->use_end();
       UI != UE; ++UI)
    if (LoadInst *Other = dyn_cast<LoadInst>(*UI))
      // Check to see if this new load is not LI, but has the same operands...
      if (Other != &LI && IdenticalComplexInst(&LI, Other) &&
          TryToRemoveALoad(&LI, Other))
        return true;   // An instruction was eliminated!

  return false;
}

// TryToRemoveALoad - Try to remove one of L1 or L2.  The problem with removing
// loads is that intervening stores might make otherwise identical load's yield
// different values.  To ensure that this is not the case, we check that there
// are no intervening stores or calls between the instructions.
//
bool GCSE::TryToRemoveALoad(LoadInst *L1, LoadInst *L2) {
  // Figure out which load dominates the other one.  If neither dominates the
  // other we cannot eliminate one...
  //
  if (DomSetInfo->dominates(L2, L1))
    std::swap(L1, L2);   // Make L1 dominate L2
  else if (!DomSetInfo->dominates(L1, L2))
    return false;  // Neither instruction dominates the other one...

  BasicBlock *BB1 = L1->getParent(), *BB2 = L2->getParent();
  Value *LoadAddress = L1->getOperand(0);

  // L1 now dominates L2.  Check to see if the intervening instructions between
  // the two loads include a store or call...
  //
  if (BB1 == BB2) {  // In same basic block?
    // In this degenerate case, no checking of global basic blocks has to occur
    // just check the instructions BETWEEN L1 & L2...
    //
    if (AA->canInstructionRangeModify(*L1, *L2, LoadAddress))
      return false;   // Cannot eliminate load

    ++NumLoadRemoved;
    if (CommonSubExpressionFound(L1, L2))
      return true;
  } else {
    // Make sure that there are no store instructions between L1 and the end of
    // it's basic block...
    //
    if (AA->canInstructionRangeModify(*L1, *BB1->getTerminator(), LoadAddress))
      return false;   // Cannot eliminate load

    // Make sure that there are no store instructions between the start of BB2
    // and the second load instruction...
    //
    if (AA->canInstructionRangeModify(BB2->front(), *L2, LoadAddress))
      return false;   // Cannot eliminate load

    // Do a depth first traversal of the inverse CFG starting at L2's block,
    // looking for L1's block.  The inverse CFG is made up of the predecessor
    // nodes of a block... so all of the edges in the graph are "backward".
    //
    set<BasicBlock*> VisitedSet;
    for (pred_iterator PI = pred_begin(BB2), PE = pred_end(BB2); PI != PE; ++PI)
      if (CheckForInvalidatingInst(*PI, BB1, LoadAddress, VisitedSet))
        return false;

    ++NumLoadRemoved;
    return CommonSubExpressionFound(L1, L2);
  }
  return false;
}

// CheckForInvalidatingInst - Return true if BB or any of the predecessors of BB
// (until DestBB) contain an instruction that might invalidate Ptr.
//
bool GCSE::CheckForInvalidatingInst(BasicBlock *BB, BasicBlock *DestBB,
                                    Value *Ptr, set<BasicBlock*> &VisitedSet) {
  // Found the termination point!
  if (BB == DestBB || VisitedSet.count(BB)) return false;

  // Avoid infinite recursion!
  VisitedSet.insert(BB);

  // Can this basic block modify Ptr?
  if (AA->canBasicBlockModify(*BB, Ptr))
    return true;

  // Check all of our predecessor blocks...
  for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE; ++PI)
    if (CheckForInvalidatingInst(*PI, DestBB, Ptr, VisitedSet))
      return true;

  // None of our predecessor blocks contain a store, and we don't either!
  return false;
}
<commit_msg>  - GCSE now no longer counts instructions not removed (due to no common     dominator as being removed)   - GCSE now uses new Value #'ing interface, instead of dealing with AA itself   - GCSE worklist implementation much simpler, class cleaned up.<commit_after>//===-- GCSE.cpp - SSA based Global Common Subexpr Elimination ------------===//
//
// This pass is designed to be a very quick global transformation that
// eliminates global common subexpressions from a function.  It does this by
// examining the SSA value graph of the function, instead of doing slow, dense,
// bit-vector computations.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/InstrTypes.h"
#include "llvm/iMemory.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/ValueNumbering.h"
#include "llvm/Support/InstIterator.h"
#include "llvm/Support/CFG.h"
#include "llvm/Type.h"
#include "Support/StatisticReporter.h"
#include <algorithm>
using std::set;
using std::map;

namespace {
  Statistic<> NumInstRemoved("gcse\t\t- Number of instructions removed");
  Statistic<> NumLoadRemoved("gcse\t\t- Number of loads removed");
  Statistic<> NumNonInsts   ("gcse\t\t- Number of instructions removed due "
                             "to non-instruction values");

  class GCSE : public FunctionPass {
    set<Instruction*>       WorkList;
    DominatorSet           *DomSetInfo;
#if 0
    ImmediateDominators    *ImmDominator;
#endif
    ValueNumbering         *VN;
  public:
    virtual bool runOnFunction(Function &F);

  private:
    bool EliminateRedundancies(Instruction *I,std::vector<Value*> &EqualValues);
    Instruction *EliminateCSE(Instruction *I, Instruction *Other);
    void ReplaceInstWithInst(Instruction *First, BasicBlock::iterator SI);

    // This transformation requires dominator and immediate dominator info
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.preservesCFG();
      AU.addRequired<DominatorSet>();
      AU.addRequired<ImmediateDominators>();
      AU.addRequired<ValueNumbering>();
    }
  };

  RegisterOpt<GCSE> X("gcse", "Global Common Subexpression Elimination");
}

// createGCSEPass - The public interface to this file...
Pass *createGCSEPass() { return new GCSE(); }

// GCSE::runOnFunction - This is the main transformation entry point for a
// function.
//
bool GCSE::runOnFunction(Function &F) {
  bool Changed = false;

  // Get pointers to the analysis results that we will be using...
  DomSetInfo = &getAnalysis<DominatorSet>();
#if 0
  ImmDominator = &getAnalysis<ImmediateDominators>();
#endif
  VN = &getAnalysis<ValueNumbering>();

  // Step #1: Add all instructions in the function to the worklist for
  // processing.  All of the instructions are considered to be our
  // subexpressions to eliminate if possible.
  //
  WorkList.insert(inst_begin(F), inst_end(F));

  // Step #2: WorkList processing.  Iterate through all of the instructions,
  // checking to see if there are any additionally defined subexpressions in the
  // program.  If so, eliminate them!
  //
  while (!WorkList.empty()) {
    Instruction &I = **WorkList.begin(); // Get an instruction from the worklist
    WorkList.erase(WorkList.begin());

    // If this instruction computes a value, try to fold together common
    // instructions that compute it.
    //
    if (I.getType() != Type::VoidTy) {
      std::vector<Value*> EqualValues;
      VN->getEqualNumberNodes(&I, EqualValues);

      if (!EqualValues.empty())
        Changed |= EliminateRedundancies(&I, EqualValues);
    }
  }

  // When the worklist is empty, return whether or not we changed anything...
  return Changed;
}

bool GCSE::EliminateRedundancies(Instruction *I,
                                 std::vector<Value*> &EqualValues) {
  // If the EqualValues set contains any non-instruction values, then we know
  // that all of the instructions can be replaced with the non-instruction value
  // because it is guaranteed to dominate all of the instructions in the
  // function.  We only have to do hard work if all we have are instructions.
  //
  for (unsigned i = 0, e = EqualValues.size(); i != e; ++i)
    if (!isa<Instruction>(EqualValues[i])) {
      // Found a non-instruction.  Replace all instructions with the
      // non-instruction.
      //
      Value *Replacement = EqualValues[i];

      // Make sure we get I as well...
      EqualValues[i] = I;

      // Replace all instructions with the Replacement value.
      for (i = 0; i != e; ++i)
        if (Instruction *I = dyn_cast<Instruction>(EqualValues[i])) {
          // Change all users of I to use Replacement.
          I->replaceAllUsesWith(Replacement);

          if (isa<LoadInst>(I))
            ++NumLoadRemoved; // Keep track of loads eliminated
          ++NumInstRemoved;   // Keep track of number of instructions eliminated
          ++NumNonInsts;      // Keep track of number of insts repl with values

          // Erase the instruction from the program.
          I->getParent()->getInstList().erase(I);
        }

      return true;
    }

  // Remove duplicate entries from EqualValues...
  std::sort(EqualValues.begin(), EqualValues.end());
  EqualValues.erase(std::unique(EqualValues.begin(), EqualValues.end()),
                    EqualValues.end());

  // From this point on, EqualValues is logically a vector of instructions.
  //
  bool Changed = false;
  EqualValues.push_back(I); // Make sure I is included...
  while (EqualValues.size() > 1) {
    // FIXME, this could be done better than simple iteration!
    Instruction *Test = cast<Instruction>(EqualValues.back());
    EqualValues.pop_back();

    for (unsigned i = 0, e = EqualValues.size(); i != e; ++i)
      if (Instruction *Ret = EliminateCSE(Test,
                                          cast<Instruction>(EqualValues[i]))) {
        if (Ret == Test)          // Eliminated EqualValues[i]
          EqualValues[i] = Test;  // Make sure that we reprocess I at some point
        Changed = true;
        break;
      }
  }
  return Changed;
}

// ReplaceInstWithInst - Destroy the instruction pointed to by SI, making all
// uses of the instruction use First now instead.
//
void GCSE::ReplaceInstWithInst(Instruction *First, BasicBlock::iterator SI) {
  Instruction &Second = *SI;

  //cerr << "DEL " << (void*)Second << Second;

  // Add the first instruction back to the worklist
  WorkList.insert(First);

  // Add all uses of the second instruction to the worklist
  for (Value::use_iterator UI = Second.use_begin(), UE = Second.use_end();
       UI != UE; ++UI)
    WorkList.insert(cast<Instruction>(*UI));

  // Make all users of 'Second' now use 'First'
  Second.replaceAllUsesWith(First);

  // Erase the second instruction from the program
  Second.getParent()->getInstList().erase(SI);
}

// EliminateCSE - The two instruction I & Other have been found to be common
// subexpressions.  This function is responsible for eliminating one of them,
// and for fixing the worklist to be correct.  The instruction that is preserved
// is returned from the function if the other is eliminated, otherwise null is
// returned.
//
Instruction *GCSE::EliminateCSE(Instruction *I, Instruction *Other) {
  assert(I != Other);

  WorkList.erase(I);
  WorkList.erase(Other); // Other may not actually be on the worklist anymore...

  // Handle the easy case, where both instructions are in the same basic block
  BasicBlock *BB1 = I->getParent(), *BB2 = Other->getParent();
  Instruction *Ret = 0;

  if (BB1 == BB2) {
    // Eliminate the second occuring instruction.  Add all uses of the second
    // instruction to the worklist.
    //
    // Scan the basic block looking for the "first" instruction
    BasicBlock::iterator BI = BB1->begin();
    while (&*BI != I && &*BI != Other) {
      ++BI;
      assert(BI != BB1->end() && "Instructions not found in parent BB!");
    }

    // Keep track of which instructions occurred first & second
    Instruction *First = BI;
    Instruction *Second = I != First ? I : Other; // Get iterator to second inst
    BI = Second;

    // Destroy Second, using First instead.
    ReplaceInstWithInst(First, BI);
    Ret = First;

    // Otherwise, the two instructions are in different basic blocks.  If one
    // dominates the other instruction, we can simply use it
    //
  } else if (DomSetInfo->dominates(BB1, BB2)) {    // I dom Other?
    ReplaceInstWithInst(I, Other);
    Ret = I;
  } else if (DomSetInfo->dominates(BB2, BB1)) {    // Other dom I?
    ReplaceInstWithInst(Other, I);
    Ret = Other;
  } else {
    // This code is disabled because it has several problems:
    // One, the actual assumption is wrong, as shown by this code:
    // int "test"(int %X, int %Y) {
    //         %Z = add int %X, %Y
    //         ret int %Z
    // Unreachable:
    //         %Q = add int %X, %Y
    //         ret int %Q
    // }
    //
    // Here there are no shared dominators.  Additionally, this had the habit of
    // moving computations where they were not always computed.  For example, in
    // a cast like this:
    //  if (c) {
    //    if (d)  ...
    //    else ... X+Y ...
    //  } else {
    //    ... X+Y ...
    //  }
    //
    // In thiscase, the expression would be hoisted to outside the 'if' stmt,
    // causing the expression to be evaluated, even for the if (d) path, which
    // could cause problems, if, for example, it caused a divide by zero.  In
    // general the problem this case is trying to solve is better addressed with
    // PRE than GCSE.
    //
    return 0;

#if 0
    // Handle the most general case now.  In this case, neither I dom Other nor
    // Other dom I.  Because we are in SSA form, we are guaranteed that the
    // operands of the two instructions both dominate the uses, so we _know_
    // that there must exist a block that dominates both instructions (if the
    // operands of the instructions are globals or constants, worst case we
    // would get the entry node of the function).  Search for this block now.
    //

    // Search up the immediate dominator chain of BB1 for the shared dominator
    BasicBlock *SharedDom = (*ImmDominator)[BB1];
    while (!DomSetInfo->dominates(SharedDom, BB2))
      SharedDom = (*ImmDominator)[SharedDom];

    // At this point, shared dom must dominate BOTH BB1 and BB2...
    assert(SharedDom && DomSetInfo->dominates(SharedDom, BB1) &&
           DomSetInfo->dominates(SharedDom, BB2) && "Dominators broken!");

    // Rip 'I' out of BB1, and move it to the end of SharedDom.
    BB1->getInstList().remove(I);
    SharedDom->getInstList().insert(--SharedDom->end(), I);

    // Eliminate 'Other' now.
    ReplaceInstWithInst(I, Other);
#endif
  }

  if (isa<LoadInst>(Ret))
    ++NumLoadRemoved;  // Keep track of loads eliminated
  ++NumInstRemoved;   // Keep track of number of instructions eliminated

  // Add all users of Ret to the worklist...
  for (Value::use_iterator I = Ret->use_begin(), E = Ret->use_end(); I != E;++I)
    if (Instruction *Inst = dyn_cast<Instruction>(*I))
      WorkList.insert(Inst);

  return Ret;
}
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "../lest/include/lest/lest.hpp"
#include "../../api/net/tcp/write_buffer.hpp"

using namespace net::tcp;

const lest::test test_tcp_write_buffer[] =
{
  SCENARIO("Creating a WriteBuffer and operate it")
  {
    GIVEN("An WriteBuffer with a buffer_t of 1000 bytes")
    {
      const uint32_t len = 1000;
      WriteBuffer wb { new_shared_buffer(len), len, true };

      EXPECT( wb.length() == len );
      EXPECT( not wb.done() );

      EXPECT( wb.pos() == wb.begin() );
      EXPECT( wb.pos() != wb.end() );

      WHEN("Advanced with 300 bytes")
      {
        bool advanced = wb.advance(300);
        EXPECT( advanced );

        THEN("The buffer is advanced forward but the length is constant")
        {
          EXPECT( wb.pos() != wb.begin() );
          EXPECT( wb.pos() != wb.end() );

          EXPECT( wb.length() == len );
          EXPECT( not wb.done() );

        }
        WHEN("Advanced with additional 700 bytes")
        {
          advanced = wb.advance(700);
          EXPECT( advanced );

          THEN("The buffer is at the end, but still not fully done")
          {
            EXPECT( wb.pos() == wb.end() );
            EXPECT( wb.remaining == 0 );

            EXPECT( not wb.done() );
          }
          WHEN("Acknowledged with 1000 bytes")
          {
            wb.acknowledge(1000);

            THEN("The buffer is done")
            {
              EXPECTS( wb.done() );
            }
          }
          WHEN("Acknowledged with 1200 bytes")
          {
            auto acked = wb.acknowledge(1200);

            THEN("The buffer is done, but no more than 1000 bytes is acked")
            {
              EXPECT( wb.done() );
              EXPECT( acked == len );
              EXPECT( wb.acknowledged == wb.length() );
            }
          }
        }
      }

    }
  }; // < SCENARIO #1
}

int main(int argc, char * argv[])
{
  int res = lest::run(test_tcp_write_buffer, argc, argv);

  return res;
}
<commit_msg>test: unit test for tcp::WriteBuffer now passes<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "../../lest/include/lest/lest.hpp"
#include <net/tcp/write_buffer.hpp>

using namespace net::tcp;

const lest::test test_tcp_write_buffer[] =
{
  SCENARIO("Creating a WriteBuffer and operate it")
  {
    GIVEN("An WriteBuffer with a buffer_t of 1000 bytes")
    {
      const uint32_t len = 1000;
      WriteBuffer wb { new_shared_buffer(len), len, true };

      EXPECT( wb.length() == len );
      EXPECT( not wb.done() );

      EXPECT( wb.pos() == wb.begin() );
      EXPECT( wb.pos() != wb.end() );

      WHEN("Advanced with 300 bytes")
      {
        bool advanced = wb.advance(300);
        EXPECT( advanced );

        THEN("The buffer is advanced forward, and the length is constant")
        {
          EXPECT( wb.pos() != wb.begin() );
          EXPECT( wb.pos() != wb.end() );

          EXPECT( wb.length() == len );

          EXPECT( wb.remaining == 700 );

          WHEN("Advanced with additional 700 bytes")
          {
            advanced = wb.advance(700);
            EXPECT( advanced );

            THEN("The buffer is at the end, but still not fully done")
            {
              EXPECT( wb.pos() == wb.end() );
              EXPECT( wb.remaining == 0 );

              EXPECT( not wb.done() );

              WHEN("Acknowledged with 1200 bytes")
              {
                auto acked = wb.acknowledge(1200);

                THEN("The buffer is done, but no more than 1000 bytes is acked")
                {
                  EXPECT( wb.done() );
                  EXPECT( acked == len );
                  EXPECT( wb.acknowledged == wb.length() );
                }
              } // < Acknowledge 1200
            } // < THEN
          } // < Advance 700
        } // < THEN
      } // < Advance 300
    } // < GIVEN
  } // < SCENARIO #1
};

#ifndef HAVE_LEST_MAIN

int main(int argc, char * argv[])
{
  int res = lest::run(test_tcp_write_buffer, argc, argv);

  return res;
}

#endif
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
// Class header file.
#include "XNumber.hpp"

#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/DoubleSupport.hpp>

#include "XObjectTypeCallback.hpp"

XNumber::XNumber(
			XPathEnvSupport&	envSupport,
			XPathSupport&		support,
			double				val) :
	XObject(&envSupport, &support),
	m_value(val)
{
}

XNumber::XNumber(const XNumber&		source) :
	XObject(source),
	m_value(source.m_value)
{
}

XNumber::~XNumber()
{
}

XNumber::eObjectType
XNumber::getType() const
{
	return eTypeNumber;
}

XalanDOMString
XNumber::getTypeString() const
{
	return XALAN_STATIC_UCODE_STRING("#NUMBER");
}

double
XNumber::num() const
{
	return m_value;
}

bool
XNumber::boolean() const
{
	return m_value == 0.0 ? false : true;
}

XalanDOMString
XNumber::str() const
{
	return DoubleToDOMString(m_value);
}

const ResultTreeFragBase&
XNumber::rtree() const
{
	error("Can't cast XNumber to ResultTreeFragBase");

	// error will throw, so this is just a dummy
	// value to satisfy the compiler.
	return *static_cast<ResultTreeFragBase*>(0);
}

ResultTreeFragBase&
XNumber::rtree()
{
	error("Can't cast XNumber to ResultTreeFragBase");

	// error will throw, so this is just a dummy
	// value to satisfy the compiler.
	return *static_cast<ResultTreeFragBase*>(0);
}

const NodeRefListBase&
XNumber::nodeset() const
{
	error("Can't cast XNumber to NodeRefListBase");

	// error will throw, so this is just a dummy
	// value to satisfy the compiler.
	return *static_cast<NodeRefListBase*>(0);
}

const MutableNodeRefList&
XNumber::mutableNodeset() const
{
	error("Can't cast XNumber to MutableNodeRefList");

	// error will throw, so this is just a dummy
	// value to satisfy the compiler.
	return *static_cast<MutableNodeRefList*>(0);
}

MutableNodeRefList&
XNumber::mutableNodeset()
{
	error("Can't cast XNumber to MutableNodeRefList");

	// error will throw, so this is just a dummy
	// value to satisfy the compiler.
	return *static_cast<MutableNodeRefList*>(0);
}

void
XNumber::ProcessXObjectTypeCallback(XObjectTypeCallback&	theCallbackObject)
{
	theCallbackObject.Number(*this,
							 num());
}

void
XNumber::ProcessXObjectTypeCallback(XObjectTypeCallback&	theCallbackObject) const
{
	theCallbackObject.Number(*this,
							 num());
}
<commit_msg>Fixed bug with boolean() function and NaN.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
// Class header file.
#include "XNumber.hpp"

#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/DoubleSupport.hpp>

#include "XObjectTypeCallback.hpp"

XNumber::XNumber(
			XPathEnvSupport&	envSupport,
			XPathSupport&		support,
			double				val) :
	XObject(&envSupport, &support),
	m_value(val)
{
}

XNumber::XNumber(const XNumber&		source) :
	XObject(source),
	m_value(source.m_value)
{
}

XNumber::~XNumber()
{
}

XNumber::eObjectType
XNumber::getType() const
{
	return eTypeNumber;
}

XalanDOMString
XNumber::getTypeString() const
{
	return XALAN_STATIC_UCODE_STRING("#NUMBER");
}

double
XNumber::num() const
{
	return m_value;
}

bool
XNumber::boolean() const
{
	return DoubleSupport::isNaN(m_value) || DoubleSupport::equal(m_value, 0.0) ? false : true;
}

XalanDOMString
XNumber::str() const
{
	return DoubleToDOMString(m_value);
}

const ResultTreeFragBase&
XNumber::rtree() const
{
	error("Can't cast XNumber to ResultTreeFragBase");

	// error will throw, so this is just a dummy
	// value to satisfy the compiler.
	return *static_cast<ResultTreeFragBase*>(0);
}

ResultTreeFragBase&
XNumber::rtree()
{
	error("Can't cast XNumber to ResultTreeFragBase");

	// error will throw, so this is just a dummy
	// value to satisfy the compiler.
	return *static_cast<ResultTreeFragBase*>(0);
}

const NodeRefListBase&
XNumber::nodeset() const
{
	error("Can't cast XNumber to NodeRefListBase");

	// error will throw, so this is just a dummy
	// value to satisfy the compiler.
	return *static_cast<NodeRefListBase*>(0);
}

const MutableNodeRefList&
XNumber::mutableNodeset() const
{
	error("Can't cast XNumber to MutableNodeRefList");

	// error will throw, so this is just a dummy
	// value to satisfy the compiler.
	return *static_cast<MutableNodeRefList*>(0);
}

MutableNodeRefList&
XNumber::mutableNodeset()
{
	error("Can't cast XNumber to MutableNodeRefList");

	// error will throw, so this is just a dummy
	// value to satisfy the compiler.
	return *static_cast<MutableNodeRefList*>(0);
}

void
XNumber::ProcessXObjectTypeCallback(XObjectTypeCallback&	theCallbackObject)
{
	theCallbackObject.Number(*this,
							 num());
}

void
XNumber::ProcessXObjectTypeCallback(XObjectTypeCallback&	theCallbackObject) const
{
	theCallbackObject.Number(*this,
							 num());
}
<|endoftext|>


<commit_before>// @(#)root/gui:$Name:  $:$Id: TGWindow.cxx,v 1.16 2004/09/11 16:27:09 brun Exp $
// Author: Fons Rademakers   28/12/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
/**************************************************************************

    This source is based on Xclass95, a Win95-looking GUI toolkit.
    Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.

    Xclass95 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.

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

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGWindow                                                             //
//                                                                      //
// ROOT GUI Window base class.                                          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGWindow.h"
#include "TMath.h"
#include "Riostream.h"

ClassImp(TGWindow)
ClassImp(TGUnknownWindowHandler)

Int_t TGWindow::fgCounter = 0;

//______________________________________________________________________________
TGWindow::TGWindow(const TGWindow *p, Int_t x, Int_t y, UInt_t w, UInt_t h,
                   UInt_t border, Int_t depth, UInt_t clss, void *visual,
                   SetWindowAttributes_t *attr, UInt_t wtype)
{
   // Create a new window. Parent p must exist otherwise the root window
   // is taken as parent. No arguments specified results in values from
   // parent to be taken (or defaults).

   // this can only happen when libGui was loaded at program startup
   // but not initialized because application is in batch mode
   if (!gClient) new TGClient();

   UInt_t type = wtype;

   if (!p && gClient) {
      p = gClient->GetRoot();
   }

   if (p) {
      fClient = p->fClient;
      if (fClient->IsEditable()) type = wtype & ~1;

      fParent = p;
      fId = gVirtualX->CreateWindow(fParent->fId, x, y,
                                    TMath::Max(w, (UInt_t) 1),
                                    TMath::Max(h, (UInt_t) 1), border,
                                    depth, clss, visual, attr, type);
      fClient->RegisterWindow(this);
      fNeedRedraw = kFALSE;

      // name will be used in SavePrimitive methods
      fgCounter++;
      fName = "frame";
      fName += fgCounter;
   }
   fEditDisabled = (fId != gVirtualX->GetDefaultRootWindow()) && fParent ?
                    fParent->fEditDisabled : kFALSE;

   SetWindowName();
}

//______________________________________________________________________________
TGWindow::TGWindow(TGClient *c, Window_t id, const TGWindow *parent)
{
   // Create a copy of a window.

   fClient = c;
   fId     = id;
   fParent = parent;
   fClient->RegisterWindow(this);
   fNeedRedraw = kFALSE;
   fEditDisabled = (fId != gVirtualX->GetDefaultRootWindow()) && fParent ?
                    fParent->fEditDisabled : kFALSE;

   // name used in SavePrimitive methods
   fgCounter++;
   fName = "frame";
   fName += fgCounter;
}

//______________________________________________________________________________
TGWindow::~TGWindow()
{
   // Window destructor. Unregisters the window.

   if (fClient) {
      if (fParent == fClient->GetDefaultRoot()) DestroyWindow();
      fClient->UnregisterWindow(this);
   }
}

//______________________________________________________________________________
void TGWindow::SetWindowName(const char *name)
{
   // Set window name.

   TString wname = name;

   if (!name) {
      wname = ClassName();
      wname += "::" + fName;
   }
   gVirtualX->SetWindowName(fId, (char *)wname.Data());
}

//______________________________________________________________________________
const TGWindow *TGWindow::GetMainFrame() const
{
   // Returns top level main frame.

   return (fParent == fClient->GetDefaultRoot()) ? this : fParent->GetMainFrame();
}

//______________________________________________________________________________
void TGWindow::ReparentWindow(const TGWindow *p, Int_t x, Int_t y)
{
   // Reparent window, make p the new parent and position the window at
   // position (x,y) in new parent.

   if (p == fParent) return;

   if (p) gVirtualX->ReparentWindow(fId, p->GetId(), x, y);
   fParent = p;
}

//______________________________________________________________________________
void TGWindow::Move(Int_t x, Int_t y)
{
   // Move the window.

   gVirtualX->MoveWindow(fId, x, y);
}

//______________________________________________________________________________
void TGWindow::Resize(UInt_t w, UInt_t h)
{
   // Resize the window.

   gVirtualX->ResizeWindow(fId, TMath::Max(w, (UInt_t)1), TMath::Max(h, (UInt_t)1));
}

//______________________________________________________________________________
void TGWindow::MoveResize(Int_t x, Int_t y, UInt_t w, UInt_t h)
{
   // Move and resize the window.

   gVirtualX->MoveResizeWindow(fId, x, y, TMath::Max(w, (UInt_t)1), TMath::Max(h, (UInt_t)1));
}

//______________________________________________________________________________
Bool_t TGWindow::IsMapped()
{
   // Returns kTRUE if window is mapped on screen, kFALSE otherwise.

   WindowAttributes_t attr;

   gVirtualX->GetWindowAttributes(fId, attr);
   return (attr.fMapState != kIsUnmapped);
}

//______________________________________________________________________________
void TGWindow::Print(Option_t *) const
{
   // Print window id.

   cout << ClassName() << ":\t" << fId << endl;
}

//______________________________________________________________________________
Int_t TGWindow::GetCounter()
{
   // Return global window counter (total number of created windows).

   return fgCounter;
}
<commit_msg>smal optimization in SetWindowName().<commit_after>// @(#)root/gui:$Name:  $:$Id: TGWindow.cxx,v 1.17 2004/09/12 10:55:26 brun Exp $
// Author: Fons Rademakers   28/12/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
/**************************************************************************

    This source is based on Xclass95, a Win95-looking GUI toolkit.
    Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.

    Xclass95 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.

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

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGWindow                                                             //
//                                                                      //
// ROOT GUI Window base class.                                          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGWindow.h"
#include "TMath.h"
#include "Riostream.h"

ClassImp(TGWindow)
ClassImp(TGUnknownWindowHandler)

Int_t TGWindow::fgCounter = 0;

//______________________________________________________________________________
TGWindow::TGWindow(const TGWindow *p, Int_t x, Int_t y, UInt_t w, UInt_t h,
                   UInt_t border, Int_t depth, UInt_t clss, void *visual,
                   SetWindowAttributes_t *attr, UInt_t wtype)
{
   // Create a new window. Parent p must exist otherwise the root window
   // is taken as parent. No arguments specified results in values from
   // parent to be taken (or defaults).

   // this can only happen when libGui was loaded at program startup
   // but not initialized because application is in batch mode
   if (!gClient) new TGClient();

   UInt_t type = wtype;

   if (!p && gClient) {
      p = gClient->GetRoot();
   }

   if (p) {
      fClient = p->fClient;
      if (fClient->IsEditable()) type = wtype & ~1;

      fParent = p;
      fId = gVirtualX->CreateWindow(fParent->fId, x, y,
                                    TMath::Max(w, (UInt_t) 1),
                                    TMath::Max(h, (UInt_t) 1), border,
                                    depth, clss, visual, attr, type);
      fClient->RegisterWindow(this);
      fNeedRedraw = kFALSE;

      // name will be used in SavePrimitive methods
      fgCounter++;
      fName = "frame";
      fName += fgCounter;
   }
   fEditDisabled = (fId != gVirtualX->GetDefaultRootWindow()) && fParent ?
                    fParent->fEditDisabled : kFALSE;

   SetWindowName();
}

//______________________________________________________________________________
TGWindow::TGWindow(TGClient *c, Window_t id, const TGWindow *parent)
{
   // Create a copy of a window.

   fClient = c;
   fId     = id;
   fParent = parent;
   fClient->RegisterWindow(this);
   fNeedRedraw = kFALSE;
   fEditDisabled = (fId != gVirtualX->GetDefaultRootWindow()) && fParent ?
                    fParent->fEditDisabled : kFALSE;

   // name used in SavePrimitive methods
   fgCounter++;
   fName = "frame";
   fName += fgCounter;
}

//______________________________________________________________________________
TGWindow::~TGWindow()
{
   // Window destructor. Unregisters the window.

   if (fClient) {
      if (fParent == fClient->GetDefaultRoot()) DestroyWindow();
      fClient->UnregisterWindow(this);
   }
}

//______________________________________________________________________________
void TGWindow::SetWindowName(const char *name)
{
   // Set window name.

   TString wname;

   if (!name) {
      wname = ClassName();
      wname += "::" + fName;
   } else {
      wname = name;
   }

   gVirtualX->SetWindowName(fId, (char *)wname.Data());
}

//______________________________________________________________________________
const TGWindow *TGWindow::GetMainFrame() const
{
   // Returns top level main frame.

   return (fParent == fClient->GetDefaultRoot()) ? this : fParent->GetMainFrame();
}

//______________________________________________________________________________
void TGWindow::ReparentWindow(const TGWindow *p, Int_t x, Int_t y)
{
   // Reparent window, make p the new parent and position the window at
   // position (x,y) in new parent.

   if (p == fParent) return;

   if (p) gVirtualX->ReparentWindow(fId, p->GetId(), x, y);
   fParent = p;
}

//______________________________________________________________________________
void TGWindow::Move(Int_t x, Int_t y)
{
   // Move the window.

   gVirtualX->MoveWindow(fId, x, y);
}

//______________________________________________________________________________
void TGWindow::Resize(UInt_t w, UInt_t h)
{
   // Resize the window.

   gVirtualX->ResizeWindow(fId, TMath::Max(w, (UInt_t)1), TMath::Max(h, (UInt_t)1));
}

//______________________________________________________________________________
void TGWindow::MoveResize(Int_t x, Int_t y, UInt_t w, UInt_t h)
{
   // Move and resize the window.

   gVirtualX->MoveResizeWindow(fId, x, y, TMath::Max(w, (UInt_t)1), TMath::Max(h, (UInt_t)1));
}

//______________________________________________________________________________
Bool_t TGWindow::IsMapped()
{
   // Returns kTRUE if window is mapped on screen, kFALSE otherwise.

   WindowAttributes_t attr;

   gVirtualX->GetWindowAttributes(fId, attr);
   return (attr.fMapState != kIsUnmapped);
}

//______________________________________________________________________________
void TGWindow::Print(Option_t *) const
{
   // Print window id.

   cout << ClassName() << ":\t" << fId << endl;
}

//______________________________________________________________________________
Int_t TGWindow::GetCounter()
{
   // Return global window counter (total number of created windows).

   return fgCounter;
}
<|endoftext|>


<commit_before>#include "expanderbutton.h"

#include <QDialog>
#include <QIcon>
#include <QImage>
#include <QDebug>

ExpanderButton::ExpanderButton(QWidget *parent) :
	QPushButton(parent)
{
    _expanded = false;
    _expandedIcon = QIcon(QString(":/images/expander-arrow-down.png"));
    _contractedIcon = QIcon(QString(":/images/expander-arrow-up.png"));

	setCheckable(true);
	setIcon(_contractedIcon);

#ifdef __APPLE__
	setStyleSheet(QString("QPushButton { text-align: left ; }"));
#else
	setStyleSheet(QString("QPushButton { text-align: left ; padding: 3px 9px ; }"));
#endif

}

void ExpanderButton::nextCheckState()
{
	_expanded = !_expanded;
	setIcon(_expanded ? _expandedIcon : _contractedIcon);

	QObjectList siblings = this->parentWidget()->children();

	for (QObjectList::Iterator itr = siblings.begin(); itr != siblings.end(); itr++) {
		QWidget* w = dynamic_cast<QWidget*>(*itr);
        if (w != NULL && w != this)
			w->setVisible(_expanded);
	}
}
<commit_msg>Removed focus from expander button<commit_after>#include "expanderbutton.h"

#include <QDialog>
#include <QIcon>
#include <QImage>
#include <QDebug>

ExpanderButton::ExpanderButton(QWidget *parent) :
	QPushButton(parent)
{
    _expanded = false;
    _expandedIcon = QIcon(QString(":/images/expander-arrow-down.png"));
    _contractedIcon = QIcon(QString(":/images/expander-arrow-up.png"));

	setCheckable(true);
	setIcon(_contractedIcon);

	setFocusPolicy(Qt::NoFocus);

#ifdef __APPLE__
	setStyleSheet(QString("QPushButton { text-align: left ; }"));
#else
	setStyleSheet(QString("QPushButton { text-align: left ; padding: 3px 9px ; }"));
#endif

}

void ExpanderButton::nextCheckState()
{
	_expanded = !_expanded;
	setIcon(_expanded ? _expandedIcon : _contractedIcon);

	QObjectList siblings = this->parentWidget()->children();

	for (QObjectList::Iterator itr = siblings.begin(); itr != siblings.end(); itr++) {
		QWidget* w = dynamic_cast<QWidget*>(*itr);
        if (w != NULL && w != this)
			w->setVisible(_expanded);
	}
}
<|endoftext|>


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

#include <gtest/gtest.h>

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/registration/ia_fpcs.h>

#include "test_fpcs_ia_data.h"

using namespace pcl;
using namespace pcl::io;
using namespace pcl::registration;
using namespace std;

PointCloud<PointXYZ> cloud_source, cloud_target;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST (PCL, FPCSInitialAlignment)
{
  // transform the source cloud by a large amount
  Eigen::Vector3f initial_offset (1.f, 0.f, 0.f);
  float angle = static_cast<float> (M_PI) / 2.f;
  Eigen::Quaternionf initial_rotation (cos (angle / 2.f), 0, 0, sin (angle / 2.f));
  PointCloud<PointXYZ> cloud_source_transformed;
  transformPointCloud (cloud_source, cloud_source_transformed, initial_offset, initial_rotation);

  // create shared pointers
  PointCloud<PointXYZ>::Ptr cloud_source_ptr, cloud_target_ptr;
  cloud_source_ptr = cloud_source_transformed.makeShared ();
  cloud_target_ptr = cloud_target.makeShared ();

  // initialize fpcs
  PointCloud <PointXYZ> source_aligned;
  FPCSInitialAlignment <PointXYZ, PointXYZ> fpcs_ia;
  fpcs_ia.setInputSource (cloud_source_ptr);
  fpcs_ia.setInputTarget (cloud_target_ptr);

  fpcs_ia.setNumberOfThreads (nr_threads);
  fpcs_ia.setApproxOverlap (approx_overlap);
  fpcs_ia.setDelta (delta, true);
  fpcs_ia.setNumberOfSamples (nr_samples);

  // align
  fpcs_ia.align (source_aligned);
  EXPECT_EQ (static_cast <int> (source_aligned.points.size ()), static_cast <int> (cloud_source.points.size ()));

  // check for correct coarse transformation marix
  //Eigen::Matrix4f transform_res_from_fpcs = fpcs_ia.getFinalTransformation ();
  //for (int i = 0; i < 4; ++i)
  //  for (int j = 0; j < 4; ++j)
  //    EXPECT_NEAR (transform_res_from_fpcs (i,j), transform_from_fpcs[i][j], 0.5);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int
main (int argc, char** argv)
{
  if (argc < 3)
  {
    std::cerr << "No test files given. Please download `bun0.pcd` and `bun4.pcd` pass their path to the test." << std::endl;
    return (-1);
  }

  // Input
  if (loadPCDFile (argv[1], cloud_source) < 0)
  {
    std::cerr << "Failed to read test file. Please download `bun0.pcd` and pass its path to the test." << std::endl;
    return (-1);
  }
  if (loadPCDFile (argv[2], cloud_target) < 0)
  {
    std::cerr << "Failed to read test file. Please download `bun4.pcd` and pass its path to the test." << std::endl;
    return (-1);
  }

  testing::InitGoogleTest (&argc, argv);
  return (RUN_ALL_TESTS ());
}

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

#include <gtest/gtest.h>

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/registration/ia_fpcs.h>

#include "test_fpcs_ia_data.h"

using namespace pcl;
using namespace pcl::io;
using namespace pcl::registration;
using namespace std;

PointCloud<PointXYZ> cloud_source, cloud_target;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST (PCL, FPCSInitialAlignment)
{
  // transform the source cloud by a large amount
  Eigen::Vector3f initial_offset (1.f, 0.f, 0.f);
  float angle = static_cast<float> (M_PI) / 2.f;
  Eigen::Quaternionf initial_rotation (cos (angle / 2.f), 0, 0, sin (angle / 2.f));
  PointCloud<PointXYZ> cloud_source_transformed;
  transformPointCloud (cloud_source, cloud_source_transformed, initial_offset, initial_rotation);

  // create shared pointers
  PointCloud<PointXYZ>::Ptr cloud_source_ptr, cloud_target_ptr;
  cloud_source_ptr = cloud_source_transformed.makeShared ();
  cloud_target_ptr = cloud_target.makeShared ();

  // initialize fpcs
  PointCloud <PointXYZ> source_aligned;
  FPCSInitialAlignment <PointXYZ, PointXYZ> fpcs_ia;
  fpcs_ia.setInputSource (cloud_source_ptr);
  fpcs_ia.setInputTarget (cloud_target_ptr);

  fpcs_ia.setNumberOfThreads (nr_threads);
  fpcs_ia.setApproxOverlap (approx_overlap);
  fpcs_ia.setDelta (delta, true);
  fpcs_ia.setNumberOfSamples (nr_samples);

  // align
  fpcs_ia.align (source_aligned);
  EXPECT_EQ (static_cast <int> (source_aligned.points.size ()), static_cast <int> (cloud_source.points.size ()));

  // check for correct coarse transformation marix
  //Eigen::Matrix4f transform_res_from_fpcs = fpcs_ia.getFinalTransformation ();
  //for (int i = 0; i < 4; ++i)
  //  for (int j = 0; j < 4; ++j)
  //    EXPECT_NEAR (transform_res_from_fpcs (i,j), transform_from_fpcs[i][j], 0.5);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int
main (int argc, char** argv)
{
  if (argc < 3)
  {
    std::cerr << "No test files given. Please download `bun0.pcd` and `bun4.pcd` pass their path to the test." << std::endl;
    return (-1);
  }

  // Input
  if (loadPCDFile (argv[1], cloud_source) < 0)
  {
    std::cerr << "Failed to read test file. Please download `bun0.pcd` and pass its path to the test." << std::endl;
    return (-1);
  }
  if (loadPCDFile (argv[2], cloud_target) < 0)
  {
    std::cerr << "Failed to read test file. Please download `bun4.pcd` and pass its path to the test." << std::endl;
    return (-1);
  }

  testing::InitGoogleTest (&argc, argv);
  return (RUN_ALL_TESTS ());
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>#include "thethingsiOClient.h"

#define TOKEN_SIZE 43

//byte thethingsiOClient::server[] = {77, 73, 82, 243};
char thethingsiOClient::server[] = "api.devices.thethings.io";
bool  firstValue = true;

thethingsiOClient::thethingsiOClient(Client *regular, Client *subscription) {
    this->regular_client = regular;
    this->subscription_client = subscription;
    this->token = "";
    this->data = "";
}

thethingsiOClient::thethingsiOClient(Client *regular, Client *subscription, String &token) {
    this->regular_client = regular;
    this->subscription_client = subscription;
    this->token = token;
    this->data = "";
}

String thethingsiOClient::activate(String productId, String activationCode) {
    token = "";
    String body = "";
    String find_token = "thingToken\":\"";
    int start;
    char c;
    if (POST(regular_client, "/v2/things/", "{\"activationCode\":\"" + activationCode + "\",\"productId\":\"" + productId + "\"}")) {
        delay(1000);
        while (regular_client->available() && (c = (char)regular_client->read()) != '{');
        if (c == '{') {
            while (regular_client->available() && (c = (char)regular_client->read()) != '\n') body.concat(c);
            if ((start = body.indexOf(find_token)) >= 0) {
                start = start + find_token.length();
                token = body.substring(start, start + TOKEN_SIZE);
            }
        }
    }
    return token;
}

String thethingsiOClient::getToken() {
    return token;
}

void thethingsiOClient::setToken(String &token) {
    this->token = token;
}

bool thethingsiOClient::isGeo(double lon, double lat) {
    return lon >= -180  && lon <= 180 && lat >= -90 && lat <= 90;
}

String thethingsiOClient::geoJSON(double lon, double lat) {
    return "\"geo\":{\"lat\":" + String(lat, 7) + ",\"long\":" + String(lon, 7) + "}";
}

void thethingsiOClient::addValue(String key, String value, double lon, double lat) {
	if (firstValue == true) {
		firstValue = false;
	  data.concat(
	              "{\"key\":\"" + key + "\",\"value\":\"" + value + "\"" +
	              (isGeo(lon, lat) ? "," + geoJSON(lon, lat) : "") +
	              "}"
	          );
	}
	else
	{
		data.concat(
	              ",{\"key\":\"" + key + "\",\"value\":\"" + value + "\"" +
	              (isGeo(lon, lat) ? "," + geoJSON(lon, lat) : "") +
	              "}"
	          );
	}
}

void thethingsiOClient::addValue(String key, double value, double lon, double lat) {
	if (firstValue == true) {
		firstValue = false;
	  data.concat(
	              "{\"key\":\"" + key + "\",\"value\":\"" + value + "\"" +
	              (isGeo(lon, lat) ? "," + geoJSON(lon, lat) : "") +
	              "}"
	          );
	}
	else
	{
		data.concat(
	              ",{\"key\":\"" + key + "\",\"value\":\"" + value + "\"" +
	              (isGeo(lon, lat) ? "," + geoJSON(lon, lat) : "") +
	              "}"
	          );
	}
}

String thethingsiOClient::send() {
    String received = "";
    if (POST(regular_client, "/v2/things/" + token, "{\"values\":[" + data + "]}")) {
        data = "";
        delay(1000);
        while (regular_client->available()) {
            char c = (char)regular_client->read();
            received.concat(c);
        }
    }
    return received;
}

bool thethingsiOClient::POST(Client *client, String url, String &data) {
    client->flush();
    client->stop();
    if (client->connected() || client->connect(server, 80)) {
        client->print("POST " + url + " HTTP/1.1\n");
        client->print("Host: api.devices.thethings.io\n");
        client->print("Connection: close\n");
        client->print("Content-Type: application/json\n");
        client->print("Content-Length: ");
        client->print(data.length());
        client->print("\n\n");
        client->print(data);
    }
    return client->connected();
}

bool thethingsiOClient::GET(Client *client, String &data) {
    client->flush();
    if (client->connected() || client->connect(server, 80)) {
        client->print("GET " + data + " HTTP/1.1\n");
        client->print("Host: api.devices.thethings.io\n");
        client->print("Accept: application/json\n\n");
    }
    return client->connected();
}

String thethingsiOClient::read(String key) {
    return read(key, 10);
}

String thethingsiOClient::read(String key, int limit) {
    String received = "";
    if (regular_client->connect(server, 80)) {
        GET(regular_client, "/v2/things/" + token + "/resources/" + key + "?limit=" + String(limit));
        delay(1000);
        while (regular_client->available())
            received.concat((char)regular_client->read());
        regular_client->stop();
    }
    return received;
}

//Costum Function To Retrieve Date Time From Server
String thethingsiOClient::readTime(String format) {
	int start;
	int end;
	String received = "";

    if (regular_client->connect(server, 80)) {
        GET(regular_client, "/v2/utils/date?thingToken=" + token + "&format=" + format);
        delay(1000);
        while (regular_client->available())
            received.concat((char)regular_client->read());
        regular_client->stop();
    }

//Retrieve the Time from Response
	String dummy = "value";
	dummy.concat('"');
	dummy.concat(':');
	start = received.lastIndexOf(dummy) + dummy.length();
	end	  = received.lastIndexOf("]") - 1;
	received = received.substring(start,end);

//
    return received;
}

void thethingsiOClient::subscribe(int const keep_alive) {
    subscription_client->stop();
    GET(subscription_client, "/v2/things/" + token + "?keepAlive=" + String(keep_alive));
}

bool thethingsiOClient::subscribed() {
    return subscription_client->connected();
}

int thethingsiOClient::available() {
    return subscription_client->available();
}

String thethingsiOClient::read() {
    String received = "";
    if (subscription_client->connected()) {
        while (subscription_client->available())
            received.concat((char)subscription_client->read());
    }
    return received;
}
<commit_msg>corrected addValue & send<commit_after>#include "thethingsiOClient.h"

#define TOKEN_SIZE 43

//byte thethingsiOClient::server[] = {77, 73, 82, 243};
char thethingsiOClient::server[] = "api.devices.thethings.io";

thethingsiOClient::thethingsiOClient(Client *regular, Client *subscription)
{
    this->regular_client = regular;
    this->subscription_client = subscription;
    this->token = "";
    this->data = "";
}

thethingsiOClient::thethingsiOClient(Client *regular, Client *subscription, String &token)
{
    this->regular_client = regular;
    this->subscription_client = subscription;
    this->token = token;
    this->data = "";
}

String thethingsiOClient::activate(String productId, String activationCode)
{
    token = "";
    String body = "";
    String find_token = "thingToken\":\"";
    int start;
    char c;
    if (POST(regular_client, "/v2/things/", "{\"activationCode\":\"" + activationCode + "\",\"productId\":\"" + productId + "\"}"))
    {
        delay(1000);
        while (regular_client->available() && (c = (char)regular_client->read()) != '{')
            ;
        if (c == '{')
        {
            while (regular_client->available() && (c = (char)regular_client->read()) != '\n')
                body.concat(c);
            if ((start = body.indexOf(find_token)) >= 0)
            {
                start = start + find_token.length();
                token = body.substring(start, start + TOKEN_SIZE);
            }
        }
    }
    return token;
}

String thethingsiOClient::getToken()
{
    return token;
}

void thethingsiOClient::setToken(String &token)
{
    this->token = token;
}

bool thethingsiOClient::isGeo(double lon, double lat)
{
    return lon >= -180 && lon <= 180 && lat >= -90 && lat <= 90;
}

String thethingsiOClient::geoJSON(double lon, double lat)
{
    return "\"geo\":{\"lat\":" + String(lat, 7) + ",\"long\":" + String(lon, 7) + "}";
}

void thethingsiOClient::addValue(String key, String value, double lon, double lat)
{
    data.concat(
        String(data == "" ? "" : ",") + "{\"key\":\"" + key + "\",\"value\":\"" + value + "\"" + (isGeo(lon, lat) ? "," + geoJSON(lon, lat) : "") + "}");
}

void thethingsiOClient::addValue(String key, double value, double lon, double lat)
{
    data.concat(
        String(data == "" ? "" : ",") + "{\"key\":\"" + key + "\",\"value\":\"" + value + "\"" + (isGeo(lon, lat) ? "," + geoJSON(lon, lat) : "") + "}");
}

String thethingsiOClient::send()
{
    String received = "";
    if (POST(regular_client, "/v2/things/" + token, "{\"values\":[" + data + "]}"))
    {
        delay(1000);
        while (regular_client->available())
        {
            char c = (char)regular_client->read();
            received.concat(c);
        }
    }
    data = "";
    return received;
}

bool thethingsiOClient::POST(Client *client, String url, String &data)
{
    client->flush();
    client->stop();
    if (client->connected() || client->connect(server, 80))
    {
        client->print("POST " + url + " HTTP/1.1\n");
        client->print("Host: api.devices.thethings.io\n");
        client->print("Connection: close\n");
        client->print("Content-Type: application/json\n");
        client->print("Content-Length: ");
        client->print(data.length());
        client->print("\n\n");
        client->print(data);
    }
    return client->connected();
}

bool thethingsiOClient::GET(Client *client, String &data)
{
    client->flush();
    if (client->connected() || client->connect(server, 80))
    {
        client->print("GET " + data + " HTTP/1.1\n");
        client->print("Host: api.devices.thethings.io\n");
        client->print("Accept: application/json\n\n");
    }
    return client->connected();
}

String thethingsiOClient::read(String key)
{
    return read(key, 10);
}

String thethingsiOClient::read(String key, int limit)
{
    String received = "";
    if (regular_client->connect(server, 80))
    {
        GET(regular_client, "/v2/things/" + token + "/resources/" + key + "?limit=" + String(limit));
        delay(1000);
        while (regular_client->available())
            received.concat((char)regular_client->read());
        regular_client->stop();
    }
    return received;
}

//Costum Function To Retrieve Date Time From Server
String thethingsiOClient::readTime(String format)
{
    int start;
    int end;
    String received = "";

    if (regular_client->connect(server, 80))
    {
        GET(regular_client, "/v2/utils/date?thingToken=" + token + "&format=" + format);
        delay(1000);
        while (regular_client->available())
            received.concat((char)regular_client->read());
        regular_client->stop();
    }

    //Retrieve the Time from Response
    String dummy = "value";
    dummy.concat('"');
    dummy.concat(':');
    start = received.lastIndexOf(dummy) + dummy.length();
    end = received.lastIndexOf("]") - 1;
    received = received.substring(start, end);

    //
    return received;
}

void thethingsiOClient::subscribe(int const keep_alive)
{
    subscription_client->stop();
    GET(subscription_client, "/v2/things/" + token + "?keepAlive=" + String(keep_alive));
}

bool thethingsiOClient::subscribed()
{
    return subscription_client->connected();
}

int thethingsiOClient::available()
{
    return subscription_client->available();
}

String thethingsiOClient::read()
{
    String received = "";
    if (subscription_client->connected())
    {
        while (subscription_client->available())
            received.concat((char)subscription_client->read());
    }
    return received;
}
<|endoftext|>