<commit_before>//===-- LiveRangeEdit.cpp - Basic tools for editing a register live range -===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The LiveRangeEdit class represents changes done to a virtual register when it
// is spilled or split.
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "regalloc"
#include "llvm/CodeGen/LiveRangeEdit.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/CalcSpillWeights.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/VirtRegMap.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"

using namespace llvm;

STATISTIC(NumDCEDeleted,     "Number of instructions deleted by DCE");
STATISTIC(NumDCEFoldedLoads, "Number of single use loads folded after DCE");
STATISTIC(NumFracRanges,     "Number of live ranges fractured by DCE");

void LiveRangeEdit::Delegate::anchor() { }

LiveInterval &LiveRangeEdit::createFrom(unsigned OldReg) {
  unsigned VReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg));
  if (VRM) {
    VRM->grow();
    VRM->setIsSplitFromReg(VReg, VRM->getOriginal(OldReg));
  }
  LiveInterval &LI = LIS.getOrCreateInterval(VReg);
  NewRegs.push_back(&LI);
  return LI;
}

bool LiveRangeEdit::checkRematerializable(VNInfo *VNI,
                                          const MachineInstr *DefMI,
                                          AliasAnalysis *aa) {
  assert(DefMI && "Missing instruction");
  ScannedRemattable = true;
  if (!TII.isTriviallyReMaterializable(DefMI, aa))
    return false;
  Remattable.insert(VNI);
  return true;
}

void LiveRangeEdit::scanRemattable(AliasAnalysis *aa) {
  for (LiveInterval::vni_iterator I = getParent().vni_begin(),
       E = getParent().vni_end(); I != E; ++I) {
    VNInfo *VNI = *I;
    if (VNI->isUnused())
      continue;
    MachineInstr *DefMI = LIS.getInstructionFromIndex(VNI->def);
    if (!DefMI)
      continue;
    checkRematerializable(VNI, DefMI, aa);
  }
  ScannedRemattable = true;
}

bool LiveRangeEdit::anyRematerializable(AliasAnalysis *aa) {
  if (!ScannedRemattable)
    scanRemattable(aa);
  return !Remattable.empty();
}

/// allUsesAvailableAt - Return true if all registers used by OrigMI at
/// OrigIdx are also available with the same value at UseIdx.
bool LiveRangeEdit::allUsesAvailableAt(const MachineInstr *OrigMI,
                                       SlotIndex OrigIdx,
                                       SlotIndex UseIdx) const {
  OrigIdx = OrigIdx.getRegSlot(true);
  UseIdx = UseIdx.getRegSlot(true);
  for (unsigned i = 0, e = OrigMI->getNumOperands(); i != e; ++i) {
    const MachineOperand &MO = OrigMI->getOperand(i);
    if (!MO.isReg() || !MO.getReg() || !MO.readsReg())
      continue;

    // We can't remat physreg uses, unless it is a constant.
    if (TargetRegisterInfo::isPhysicalRegister(MO.getReg())) {
      if (MRI.isConstantPhysReg(MO.getReg(), *OrigMI->getParent()->getParent()))
        continue;
      return false;
    }

    LiveInterval &li = LIS.getInterval(MO.getReg());
    const VNInfo *OVNI = li.getVNInfoAt(OrigIdx);
    if (!OVNI)
      continue;

    // Don't allow rematerialization immediately after the original def.
    // It would be incorrect if OrigMI redefines the register.
    // See PR14098.
    if (SlotIndex::isSameInstr(OrigIdx, UseIdx))
      return false;

    if (OVNI != li.getVNInfoAt(UseIdx))
      return false;
  }
  return true;
}

bool LiveRangeEdit::canRematerializeAt(Remat &RM,
                                       SlotIndex UseIdx,
                                       bool cheapAsAMove) {
  assert(ScannedRemattable && "Call anyRematerializable first");

  // Use scanRemattable info.
  if (!Remattable.count(RM.ParentVNI))
    return false;

  // No defining instruction provided.
  SlotIndex DefIdx;
  if (RM.OrigMI)
    DefIdx = LIS.getInstructionIndex(RM.OrigMI);
  else {
    DefIdx = RM.ParentVNI->def;
    RM.OrigMI = LIS.getInstructionFromIndex(DefIdx);
    assert(RM.OrigMI && "No defining instruction for remattable value");
  }

  // If only cheap remats were requested, bail out early.
  if (cheapAsAMove && !RM.OrigMI->isAsCheapAsAMove())
    return false;

  // Verify that all used registers are available with the same values.
  if (!allUsesAvailableAt(RM.OrigMI, DefIdx, UseIdx))
    return false;

  return true;
}

SlotIndex LiveRangeEdit::rematerializeAt(MachineBasicBlock &MBB,
                                         MachineBasicBlock::iterator MI,
                                         unsigned DestReg,
                                         const Remat &RM,
                                         const TargetRegisterInfo &tri,
                                         bool Late) {
  assert(RM.OrigMI && "Invalid remat");
  TII.reMaterialize(MBB, MI, DestReg, 0, RM.OrigMI, tri);
  Rematted.insert(RM.ParentVNI);
  return LIS.getSlotIndexes()->insertMachineInstrInMaps(--MI, Late)
           .getRegSlot();
}

void LiveRangeEdit::eraseVirtReg(unsigned Reg) {
  if (TheDelegate && TheDelegate->LRE_CanEraseVirtReg(Reg))
    LIS.removeInterval(Reg);
}

bool LiveRangeEdit::foldAsLoad(LiveInterval *LI,
                               SmallVectorImpl<MachineInstr*> &Dead) {
  MachineInstr *DefMI = 0, *UseMI = 0;

  // Check that there is a single def and a single use.
  for (MachineRegisterInfo::reg_nodbg_iterator I = MRI.reg_nodbg_begin(LI->reg),
       E = MRI.reg_nodbg_end(); I != E; ++I) {
    MachineOperand &MO = I.getOperand();
    MachineInstr *MI = MO.getParent();
    if (MO.isDef()) {
      if (DefMI && DefMI != MI)
        return false;
      if (!MI->canFoldAsLoad())
        return false;
      DefMI = MI;
    } else if (!MO.isUndef()) {
      if (UseMI && UseMI != MI)
        return false;
      // FIXME: Targets don't know how to fold subreg uses.
      if (MO.getSubReg())
        return false;
      UseMI = MI;
    }
  }
  if (!DefMI || !UseMI)
    return false;

  // Since we're moving the DefMI load, make sure we're not extending any live
  // ranges.
  if (!allUsesAvailableAt(DefMI,
                          LIS.getInstructionIndex(DefMI),
                          LIS.getInstructionIndex(UseMI)))
    return false;

  // We also need to make sure it is safe to move the load.
  // Assume there are stores between DefMI and UseMI.
  bool SawStore = true;
  if (!DefMI->isSafeToMove(&TII, 0, SawStore))
    return false;

  DEBUG(dbgs() << "Try to fold single def: " << *DefMI
               << "       into single use: " << *UseMI);

  SmallVector<unsigned, 8> Ops;
  if (UseMI->readsWritesVirtualRegister(LI->reg, &Ops).second)
    return false;

  MachineInstr *FoldMI = TII.foldMemoryOperand(UseMI, Ops, DefMI);
  if (!FoldMI)
    return false;
  DEBUG(dbgs() << "                folded: " << *FoldMI);
  LIS.ReplaceMachineInstrInMaps(UseMI, FoldMI);
  UseMI->eraseFromParent();
  DefMI->addRegisterDead(LI->reg, 0);
  Dead.push_back(DefMI);
  ++NumDCEFoldedLoads;
  return true;
}

/// Find all live intervals that need to shrink, then remove the instruction.
void LiveRangeEdit::eliminateDeadDef(MachineInstr *MI, ToShrinkSet &ToShrink) {
  assert(MI->allDefsAreDead() && "Def isn't really dead");
  SlotIndex Idx = LIS.getInstructionIndex(MI).getRegSlot();

  // Never delete inline asm.
  if (MI->isInlineAsm()) {
    DEBUG(dbgs() << "Won't delete: " << Idx << '\t' << *MI);
    return;
  }

  // Use the same criteria as DeadMachineInstructionElim.
  bool SawStore = false;
  if (!MI->isSafeToMove(&TII, 0, SawStore)) {
    DEBUG(dbgs() << "Can't delete: " << Idx << '\t' << *MI);
    return;
  }

  DEBUG(dbgs() << "Deleting dead def " << Idx << '\t' << *MI);

  // Collect virtual registers to be erased after MI is gone.
  SmallVector<unsigned, 8> RegsToErase;
  bool ReadsPhysRegs = false;

  // Check for live intervals that may shrink
  for (MachineInstr::mop_iterator MOI = MI->operands_begin(),
         MOE = MI->operands_end(); MOI != MOE; ++MOI) {
    if (!MOI->isReg())
      continue;
    unsigned Reg = MOI->getReg();
    if (!TargetRegisterInfo::isVirtualRegister(Reg)) {
      // Check if MI reads any unreserved physregs.
      if (Reg && MOI->readsReg() && !MRI.isReserved(Reg))
        ReadsPhysRegs = true;
      else if (MOI->isDef()) {
        for (MCRegUnitIterator Units(Reg, MRI.getTargetRegisterInfo());
             Units.isValid(); ++Units) {
          if (LiveInterval *LI = LIS.getCachedRegUnit(*Units)) {
            if (VNInfo *VNI = LI->getVNInfoAt(Idx))
              LI->removeValNo(VNI);
          }
        }
      }
      continue;
    }
    LiveInterval &LI = LIS.getInterval(Reg);

    // Shrink read registers, unless it is likely to be expensive and
    // unlikely to change anything. We typically don't want to shrink the
    // PIC base register that has lots of uses everywhere.
    // Always shrink COPY uses that probably come from live range splitting.
    if (MI->readsVirtualRegister(Reg) &&
        (MI->isCopy() || MOI->isDef() || MRI.hasOneNonDBGUse(Reg) ||
         LI.killedAt(Idx)))
      ToShrink.insert(&LI);

    // Remove defined value.
    if (MOI->isDef()) {
      if (VNInfo *VNI = LI.getVNInfoAt(Idx)) {
        if (TheDelegate)
          TheDelegate->LRE_WillShrinkVirtReg(LI.reg);
        LI.removeValNo(VNI);
        if (LI.empty())
          RegsToErase.push_back(Reg);
      }
    }
  }

  // Currently, we don't support DCE of physreg live ranges. If MI reads
  // any unreserved physregs, don't erase the instruction, but turn it into
  // a KILL instead. This way, the physreg live ranges don't end up
  // dangling.
  // FIXME: It would be better to have something like shrinkToUses() for
  // physregs. That could potentially enable more DCE and it would free up
  // the physreg. It would not happen often, though.
  if (ReadsPhysRegs) {
    MI->setDesc(TII.get(TargetOpcode::KILL));
    // Remove all operands that aren't physregs.
    for (unsigned i = MI->getNumOperands(); i; --i) {
      const MachineOperand &MO = MI->getOperand(i-1);
      if (MO.isReg() && TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
        continue;
      MI->RemoveOperand(i-1);
    }
    DEBUG(dbgs() << "Converted physregs to:\t" << *MI);
  } else {
    if (TheDelegate)
      TheDelegate->LRE_WillEraseInstruction(MI);
    LIS.RemoveMachineInstrFromMaps(MI);
    MI->eraseFromParent();
    ++NumDCEDeleted;
  }

  // Erase any virtregs that are now empty and unused. There may be <undef>
  // uses around. Keep the empty live range in that case.
  for (unsigned i = 0, e = RegsToErase.size(); i != e; ++i) {
    unsigned Reg = RegsToErase[i];
    if (LIS.hasInterval(Reg) && MRI.reg_nodbg_empty(Reg)) {
      ToShrink.remove(&LIS.getInterval(Reg));
      eraseVirtReg(Reg);
    }
  }
}

void LiveRangeEdit::eliminateDeadDefs(SmallVectorImpl<MachineInstr*> &Dead,
                                      ArrayRef<unsigned> RegsBeingSpilled) {
  ToShrinkSet ToShrink;

  for (;;) {
    // Erase all dead defs.
    while (!Dead.empty())
      eliminateDeadDef(Dead.pop_back_val(), ToShrink);

    if (ToShrink.empty())
      break;

    // Shrink just one live interval. Then delete new dead defs.
    LiveInterval *LI = ToShrink.back();
    ToShrink.pop_back();
    if (foldAsLoad(LI, Dead))
      continue;
    if (TheDelegate)
      TheDelegate->LRE_WillShrinkVirtReg(LI->reg);
    if (!LIS.shrinkToUses(LI, &Dead))
      continue;

    // Don't create new intervals for a register being spilled.
    // The new intervals would have to be spilled anyway so its not worth it.
    // Also they currently aren't spilled so creating them and not spilling
    // them results in incorrect code.
    bool BeingSpilled = false;
    for (unsigned i = 0, e = RegsBeingSpilled.size(); i != e; ++i) {
      if (LI->reg == RegsBeingSpilled[i]) {
        BeingSpilled = true;
        break;
      }
    }

    if (BeingSpilled) continue;

    // LI may have been separated, create new intervals.
    LI->RenumberValues(LIS);
    ConnectedVNInfoEqClasses ConEQ(LIS);
    unsigned NumComp = ConEQ.Classify(LI);
    if (NumComp <= 1)
      continue;
    ++NumFracRanges;
    bool IsOriginal = VRM && VRM->getOriginal(LI->reg) == LI->reg;
    DEBUG(dbgs() << NumComp << " components: " << *LI << '\n');
    SmallVector<LiveInterval*, 8> Dups(1, LI);
    for (unsigned i = 1; i != NumComp; ++i) {
      Dups.push_back(&createFrom(LI->reg));
      // If LI is an original interval that hasn't been split yet, make the new
      // intervals their own originals instead of referring to LI. The original
      // interval must contain all the split products, and LI doesn't.
      if (IsOriginal)
        VRM->setIsSplitFromReg(Dups.back()->reg, 0);
      if (TheDelegate)
        TheDelegate->LRE_DidCloneVirtReg(Dups.back()->reg, LI->reg);
    }
    ConEQ.Distribute(&Dups[0], MRI);
    DEBUG({
      for (unsigned i = 0; i != NumComp; ++i)
        dbgs() << '\t' << *Dups[i] << '\n';
    });
  }
}

void
LiveRangeEdit::calculateRegClassAndHint(MachineFunction &MF,
                                        const MachineLoopInfo &Loops,
                                        const MachineBlockFrequencyInfo &MBFI) {
  VirtRegAuxInfo VRAI(MF, LIS, Loops, MBFI);
  for (iterator I = begin(), E = end(); I != E; ++I) {
    LiveInterval &LI = **I;
    if (MRI.recomputeRegClass(LI.reg, MF.getTarget()))
      DEBUG(dbgs() << "Inflated " << PrintReg(LI.reg) << " to "
                   << MRI.getRegClass(LI.reg)->getName() << '\n');
    VRAI.CalculateWeightAndHint(LI);
  }
}
<commit_msg>Prevent LiveRangeEdit from deleting bundled instructions.<commit_after>//===-- LiveRangeEdit.cpp - Basic tools for editing a register live range -===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The LiveRangeEdit class represents changes done to a virtual register when it
// is spilled or split.
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "regalloc"
#include "llvm/CodeGen/LiveRangeEdit.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/CalcSpillWeights.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/VirtRegMap.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"

using namespace llvm;

STATISTIC(NumDCEDeleted,     "Number of instructions deleted by DCE");
STATISTIC(NumDCEFoldedLoads, "Number of single use loads folded after DCE");
STATISTIC(NumFracRanges,     "Number of live ranges fractured by DCE");

void LiveRangeEdit::Delegate::anchor() { }

LiveInterval &LiveRangeEdit::createFrom(unsigned OldReg) {
  unsigned VReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg));
  if (VRM) {
    VRM->grow();
    VRM->setIsSplitFromReg(VReg, VRM->getOriginal(OldReg));
  }
  LiveInterval &LI = LIS.getOrCreateInterval(VReg);
  NewRegs.push_back(&LI);
  return LI;
}

bool LiveRangeEdit::checkRematerializable(VNInfo *VNI,
                                          const MachineInstr *DefMI,
                                          AliasAnalysis *aa) {
  assert(DefMI && "Missing instruction");
  ScannedRemattable = true;
  if (!TII.isTriviallyReMaterializable(DefMI, aa))
    return false;
  Remattable.insert(VNI);
  return true;
}

void LiveRangeEdit::scanRemattable(AliasAnalysis *aa) {
  for (LiveInterval::vni_iterator I = getParent().vni_begin(),
       E = getParent().vni_end(); I != E; ++I) {
    VNInfo *VNI = *I;
    if (VNI->isUnused())
      continue;
    MachineInstr *DefMI = LIS.getInstructionFromIndex(VNI->def);
    if (!DefMI)
      continue;
    checkRematerializable(VNI, DefMI, aa);
  }
  ScannedRemattable = true;
}

bool LiveRangeEdit::anyRematerializable(AliasAnalysis *aa) {
  if (!ScannedRemattable)
    scanRemattable(aa);
  return !Remattable.empty();
}

/// allUsesAvailableAt - Return true if all registers used by OrigMI at
/// OrigIdx are also available with the same value at UseIdx.
bool LiveRangeEdit::allUsesAvailableAt(const MachineInstr *OrigMI,
                                       SlotIndex OrigIdx,
                                       SlotIndex UseIdx) const {
  OrigIdx = OrigIdx.getRegSlot(true);
  UseIdx = UseIdx.getRegSlot(true);
  for (unsigned i = 0, e = OrigMI->getNumOperands(); i != e; ++i) {
    const MachineOperand &MO = OrigMI->getOperand(i);
    if (!MO.isReg() || !MO.getReg() || !MO.readsReg())
      continue;

    // We can't remat physreg uses, unless it is a constant.
    if (TargetRegisterInfo::isPhysicalRegister(MO.getReg())) {
      if (MRI.isConstantPhysReg(MO.getReg(), *OrigMI->getParent()->getParent()))
        continue;
      return false;
    }

    LiveInterval &li = LIS.getInterval(MO.getReg());
    const VNInfo *OVNI = li.getVNInfoAt(OrigIdx);
    if (!OVNI)
      continue;

    // Don't allow rematerialization immediately after the original def.
    // It would be incorrect if OrigMI redefines the register.
    // See PR14098.
    if (SlotIndex::isSameInstr(OrigIdx, UseIdx))
      return false;

    if (OVNI != li.getVNInfoAt(UseIdx))
      return false;
  }
  return true;
}

bool LiveRangeEdit::canRematerializeAt(Remat &RM,
                                       SlotIndex UseIdx,
                                       bool cheapAsAMove) {
  assert(ScannedRemattable && "Call anyRematerializable first");

  // Use scanRemattable info.
  if (!Remattable.count(RM.ParentVNI))
    return false;

  // No defining instruction provided.
  SlotIndex DefIdx;
  if (RM.OrigMI)
    DefIdx = LIS.getInstructionIndex(RM.OrigMI);
  else {
    DefIdx = RM.ParentVNI->def;
    RM.OrigMI = LIS.getInstructionFromIndex(DefIdx);
    assert(RM.OrigMI && "No defining instruction for remattable value");
  }

  // If only cheap remats were requested, bail out early.
  if (cheapAsAMove && !RM.OrigMI->isAsCheapAsAMove())
    return false;

  // Verify that all used registers are available with the same values.
  if (!allUsesAvailableAt(RM.OrigMI, DefIdx, UseIdx))
    return false;

  return true;
}

SlotIndex LiveRangeEdit::rematerializeAt(MachineBasicBlock &MBB,
                                         MachineBasicBlock::iterator MI,
                                         unsigned DestReg,
                                         const Remat &RM,
                                         const TargetRegisterInfo &tri,
                                         bool Late) {
  assert(RM.OrigMI && "Invalid remat");
  TII.reMaterialize(MBB, MI, DestReg, 0, RM.OrigMI, tri);
  Rematted.insert(RM.ParentVNI);
  return LIS.getSlotIndexes()->insertMachineInstrInMaps(--MI, Late)
           .getRegSlot();
}

void LiveRangeEdit::eraseVirtReg(unsigned Reg) {
  if (TheDelegate && TheDelegate->LRE_CanEraseVirtReg(Reg))
    LIS.removeInterval(Reg);
}

bool LiveRangeEdit::foldAsLoad(LiveInterval *LI,
                               SmallVectorImpl<MachineInstr*> &Dead) {
  MachineInstr *DefMI = 0, *UseMI = 0;

  // Check that there is a single def and a single use.
  for (MachineRegisterInfo::reg_nodbg_iterator I = MRI.reg_nodbg_begin(LI->reg),
       E = MRI.reg_nodbg_end(); I != E; ++I) {
    MachineOperand &MO = I.getOperand();
    MachineInstr *MI = MO.getParent();
    if (MO.isDef()) {
      if (DefMI && DefMI != MI)
        return false;
      if (!MI->canFoldAsLoad())
        return false;
      DefMI = MI;
    } else if (!MO.isUndef()) {
      if (UseMI && UseMI != MI)
        return false;
      // FIXME: Targets don't know how to fold subreg uses.
      if (MO.getSubReg())
        return false;
      UseMI = MI;
    }
  }
  if (!DefMI || !UseMI)
    return false;

  // Since we're moving the DefMI load, make sure we're not extending any live
  // ranges.
  if (!allUsesAvailableAt(DefMI,
                          LIS.getInstructionIndex(DefMI),
                          LIS.getInstructionIndex(UseMI)))
    return false;

  // We also need to make sure it is safe to move the load.
  // Assume there are stores between DefMI and UseMI.
  bool SawStore = true;
  if (!DefMI->isSafeToMove(&TII, 0, SawStore))
    return false;

  DEBUG(dbgs() << "Try to fold single def: " << *DefMI
               << "       into single use: " << *UseMI);

  SmallVector<unsigned, 8> Ops;
  if (UseMI->readsWritesVirtualRegister(LI->reg, &Ops).second)
    return false;

  MachineInstr *FoldMI = TII.foldMemoryOperand(UseMI, Ops, DefMI);
  if (!FoldMI)
    return false;
  DEBUG(dbgs() << "                folded: " << *FoldMI);
  LIS.ReplaceMachineInstrInMaps(UseMI, FoldMI);
  UseMI->eraseFromParent();
  DefMI->addRegisterDead(LI->reg, 0);
  Dead.push_back(DefMI);
  ++NumDCEFoldedLoads;
  return true;
}

/// Find all live intervals that need to shrink, then remove the instruction.
void LiveRangeEdit::eliminateDeadDef(MachineInstr *MI, ToShrinkSet &ToShrink) {
  assert(MI->allDefsAreDead() && "Def isn't really dead");
  SlotIndex Idx = LIS.getInstructionIndex(MI).getRegSlot();

  // Never delete a bundled instruction.
  if (MI->isBundled()) {
    return;
  }
  // Never delete inline asm.
  if (MI->isInlineAsm()) {
    DEBUG(dbgs() << "Won't delete: " << Idx << '\t' << *MI);
    return;
  }

  // Use the same criteria as DeadMachineInstructionElim.
  bool SawStore = false;
  if (!MI->isSafeToMove(&TII, 0, SawStore)) {
    DEBUG(dbgs() << "Can't delete: " << Idx << '\t' << *MI);
    return;
  }

  DEBUG(dbgs() << "Deleting dead def " << Idx << '\t' << *MI);

  // Collect virtual registers to be erased after MI is gone.
  SmallVector<unsigned, 8> RegsToErase;
  bool ReadsPhysRegs = false;

  // Check for live intervals that may shrink
  for (MachineInstr::mop_iterator MOI = MI->operands_begin(),
         MOE = MI->operands_end(); MOI != MOE; ++MOI) {
    if (!MOI->isReg())
      continue;
    unsigned Reg = MOI->getReg();
    if (!TargetRegisterInfo::isVirtualRegister(Reg)) {
      // Check if MI reads any unreserved physregs.
      if (Reg && MOI->readsReg() && !MRI.isReserved(Reg))
        ReadsPhysRegs = true;
      else if (MOI->isDef()) {
        for (MCRegUnitIterator Units(Reg, MRI.getTargetRegisterInfo());
             Units.isValid(); ++Units) {
          if (LiveInterval *LI = LIS.getCachedRegUnit(*Units)) {
            if (VNInfo *VNI = LI->getVNInfoAt(Idx))
              LI->removeValNo(VNI);
          }
        }
      }
      continue;
    }
    LiveInterval &LI = LIS.getInterval(Reg);

    // Shrink read registers, unless it is likely to be expensive and
    // unlikely to change anything. We typically don't want to shrink the
    // PIC base register that has lots of uses everywhere.
    // Always shrink COPY uses that probably come from live range splitting.
    if (MI->readsVirtualRegister(Reg) &&
        (MI->isCopy() || MOI->isDef() || MRI.hasOneNonDBGUse(Reg) ||
         LI.killedAt(Idx)))
      ToShrink.insert(&LI);

    // Remove defined value.
    if (MOI->isDef()) {
      if (VNInfo *VNI = LI.getVNInfoAt(Idx)) {
        if (TheDelegate)
          TheDelegate->LRE_WillShrinkVirtReg(LI.reg);
        LI.removeValNo(VNI);
        if (LI.empty())
          RegsToErase.push_back(Reg);
      }
    }
  }

  // Currently, we don't support DCE of physreg live ranges. If MI reads
  // any unreserved physregs, don't erase the instruction, but turn it into
  // a KILL instead. This way, the physreg live ranges don't end up
  // dangling.
  // FIXME: It would be better to have something like shrinkToUses() for
  // physregs. That could potentially enable more DCE and it would free up
  // the physreg. It would not happen often, though.
  if (ReadsPhysRegs) {
    MI->setDesc(TII.get(TargetOpcode::KILL));
    // Remove all operands that aren't physregs.
    for (unsigned i = MI->getNumOperands(); i; --i) {
      const MachineOperand &MO = MI->getOperand(i-1);
      if (MO.isReg() && TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
        continue;
      MI->RemoveOperand(i-1);
    }
    DEBUG(dbgs() << "Converted physregs to:\t" << *MI);
  } else {
    if (TheDelegate)
      TheDelegate->LRE_WillEraseInstruction(MI);
    LIS.RemoveMachineInstrFromMaps(MI);
    MI->eraseFromParent();
    ++NumDCEDeleted;
  }

  // Erase any virtregs that are now empty and unused. There may be <undef>
  // uses around. Keep the empty live range in that case.
  for (unsigned i = 0, e = RegsToErase.size(); i != e; ++i) {
    unsigned Reg = RegsToErase[i];
    if (LIS.hasInterval(Reg) && MRI.reg_nodbg_empty(Reg)) {
      ToShrink.remove(&LIS.getInterval(Reg));
      eraseVirtReg(Reg);
    }
  }
}

void LiveRangeEdit::eliminateDeadDefs(SmallVectorImpl<MachineInstr*> &Dead,
                                      ArrayRef<unsigned> RegsBeingSpilled) {
  ToShrinkSet ToShrink;

  for (;;) {
    // Erase all dead defs.
    while (!Dead.empty())
      eliminateDeadDef(Dead.pop_back_val(), ToShrink);

    if (ToShrink.empty())
      break;

    // Shrink just one live interval. Then delete new dead defs.
    LiveInterval *LI = ToShrink.back();
    ToShrink.pop_back();
    if (foldAsLoad(LI, Dead))
      continue;
    if (TheDelegate)
      TheDelegate->LRE_WillShrinkVirtReg(LI->reg);
    if (!LIS.shrinkToUses(LI, &Dead))
      continue;

    // Don't create new intervals for a register being spilled.
    // The new intervals would have to be spilled anyway so its not worth it.
    // Also they currently aren't spilled so creating them and not spilling
    // them results in incorrect code.
    bool BeingSpilled = false;
    for (unsigned i = 0, e = RegsBeingSpilled.size(); i != e; ++i) {
      if (LI->reg == RegsBeingSpilled[i]) {
        BeingSpilled = true;
        break;
      }
    }

    if (BeingSpilled) continue;

    // LI may have been separated, create new intervals.
    LI->RenumberValues(LIS);
    ConnectedVNInfoEqClasses ConEQ(LIS);
    unsigned NumComp = ConEQ.Classify(LI);
    if (NumComp <= 1)
      continue;
    ++NumFracRanges;
    bool IsOriginal = VRM && VRM->getOriginal(LI->reg) == LI->reg;
    DEBUG(dbgs() << NumComp << " components: " << *LI << '\n');
    SmallVector<LiveInterval*, 8> Dups(1, LI);
    for (unsigned i = 1; i != NumComp; ++i) {
      Dups.push_back(&createFrom(LI->reg));
      // If LI is an original interval that hasn't been split yet, make the new
      // intervals their own originals instead of referring to LI. The original
      // interval must contain all the split products, and LI doesn't.
      if (IsOriginal)
        VRM->setIsSplitFromReg(Dups.back()->reg, 0);
      if (TheDelegate)
        TheDelegate->LRE_DidCloneVirtReg(Dups.back()->reg, LI->reg);
    }
    ConEQ.Distribute(&Dups[0], MRI);
    DEBUG({
      for (unsigned i = 0; i != NumComp; ++i)
        dbgs() << '\t' << *Dups[i] << '\n';
    });
  }
}

void
LiveRangeEdit::calculateRegClassAndHint(MachineFunction &MF,
                                        const MachineLoopInfo &Loops,
                                        const MachineBlockFrequencyInfo &MBFI) {
  VirtRegAuxInfo VRAI(MF, LIS, Loops, MBFI);
  for (iterator I = begin(), E = end(); I != E; ++I) {
    LiveInterval &LI = **I;
    if (MRI.recomputeRegClass(LI.reg, MF.getTarget()))
      DEBUG(dbgs() << "Inflated " << PrintReg(LI.reg) << " to "
                   << MRI.getRegClass(LI.reg)->getName() << '\n');
    VRAI.CalculateWeightAndHint(LI);
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, Facebook, Inc.  All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
// This file implements the "bridge" between Java and C++ and enables
// calling c++ rocksdb::Iterator methods from Java side.

#include <stdio.h>
#include <stdlib.h>
#include <jni.h>

#include "include/org_rocksdb_TransactionLogIterator.h"
#include "rocksdb/transaction_log.h"
#include "rocksjni/portal.h"

/*
 * Class:     org_rocksdb_TransactionLogIterator
 * Method:    disposeInternal
 * Signature: (J)V
 */
void Java_org_rocksdb_TransactionLogIterator_disposeInternal(
    JNIEnv* env, jobject jobj, jlong handle) {
  auto* it = reinterpret_cast<rocksdb::TransactionLogIterator*>(handle);
  delete it;
}

/*
 * Class:     org_rocksdb_TransactionLogIterator
 * Method:    isValid
 * Signature: (J)Z
 */
jboolean Java_org_rocksdb_TransactionLogIterator_isValid(
    JNIEnv* env, jobject jobj, jlong handle) {
  return reinterpret_cast<rocksdb::TransactionLogIterator*>(handle)->Valid();
}

/*
 * Class:     org_rocksdb_TransactionLogIterator
 * Method:    next
 * Signature: (J)V
 */
void Java_org_rocksdb_TransactionLogIterator_next(
    JNIEnv* env, jobject jobj, jlong handle) {
  reinterpret_cast<rocksdb::TransactionLogIterator*>(handle)->Next();
}

/*
 * Class:     org_rocksdb_TransactionLogIterator
 * Method:    status
 * Signature: (J)V
 */
void Java_org_rocksdb_TransactionLogIterator_status(
    JNIEnv* env, jobject jobj, jlong handle) {
  rocksdb::Status s = reinterpret_cast<
      rocksdb::TransactionLogIterator*>(handle)->status();
  if (!s.ok()) {
    rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
  }
}

/*
 * Class:     org_rocksdb_TransactionLogIterator
 * Method:    getBatch
 * Signature: (J)Lorg/rocksdb/TransactionLogIterator$BatchResult
 */
jobject Java_org_rocksdb_TransactionLogIterator_getBatch(
    JNIEnv* env, jobject jobj, jlong handle) {
  rocksdb::BatchResult batch_result =
      reinterpret_cast<rocksdb::TransactionLogIterator*>(handle)->GetBatch();
  jclass jclazz = env->FindClass(
      "org/rocksdb/TransactionLogIterator$BatchResult");
  assert(jclazz != nullptr);
  jmethodID mid = env->GetMethodID(
      jclazz, "<init>", "(Lorg/rocksdb/TransactionLogIterator;JJ)V");
  assert(mid != nullptr);
  return env->NewObject(jclazz, mid, jobj,
      batch_result.sequence, batch_result.writeBatchPtr.release());
}
<commit_msg>[RocksJava] GetUpdatesSince support<commit_after>// Copyright (c) 2014, Facebook, Inc.  All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
// This file implements the "bridge" between Java and C++ and enables
// calling c++ rocksdb::Iterator methods from Java side.

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>

#include "include/org_rocksdb_TransactionLogIterator.h"
#include "rocksdb/transaction_log.h"
#include "rocksjni/portal.h"

/*
 * Class:     org_rocksdb_TransactionLogIterator
 * Method:    disposeInternal
 * Signature: (J)V
 */
void Java_org_rocksdb_TransactionLogIterator_disposeInternal(
    JNIEnv* env, jobject jobj, jlong handle) {
  auto* it = reinterpret_cast<rocksdb::TransactionLogIterator*>(handle);
  delete it;
}

/*
 * Class:     org_rocksdb_TransactionLogIterator
 * Method:    isValid
 * Signature: (J)Z
 */
jboolean Java_org_rocksdb_TransactionLogIterator_isValid(
    JNIEnv* env, jobject jobj, jlong handle) {
  return reinterpret_cast<rocksdb::TransactionLogIterator*>(handle)->Valid();
}

/*
 * Class:     org_rocksdb_TransactionLogIterator
 * Method:    next
 * Signature: (J)V
 */
void Java_org_rocksdb_TransactionLogIterator_next(
    JNIEnv* env, jobject jobj, jlong handle) {
  reinterpret_cast<rocksdb::TransactionLogIterator*>(handle)->Next();
}

/*
 * Class:     org_rocksdb_TransactionLogIterator
 * Method:    status
 * Signature: (J)V
 */
void Java_org_rocksdb_TransactionLogIterator_status(
    JNIEnv* env, jobject jobj, jlong handle) {
  rocksdb::Status s = reinterpret_cast<
      rocksdb::TransactionLogIterator*>(handle)->status();
  if (!s.ok()) {
    rocksdb::RocksDBExceptionJni::ThrowNew(env, s);
  }
}

/*
 * Class:     org_rocksdb_TransactionLogIterator
 * Method:    getBatch
 * Signature: (J)Lorg/rocksdb/TransactionLogIterator$BatchResult
 */
jobject Java_org_rocksdb_TransactionLogIterator_getBatch(
    JNIEnv* env, jobject jobj, jlong handle) {
  rocksdb::BatchResult batch_result =
      reinterpret_cast<rocksdb::TransactionLogIterator*>(handle)->GetBatch();
  jclass jclazz = env->FindClass(
      "org/rocksdb/TransactionLogIterator$BatchResult");
  assert(jclazz != nullptr);
  jmethodID mid = env->GetMethodID(
      jclazz, "<init>", "(Lorg/rocksdb/TransactionLogIterator;JJ)V");
  assert(mid != nullptr);
  return env->NewObject(jclazz, mid, jobj,
      batch_result.sequence, batch_result.writeBatchPtr.release());
}
<|endoftext|>


<commit_before><commit_msg>vtk_dump solution<commit_after><|endoftext|>


<commit_before><commit_msg>Backport r851236 by tmcguire from trunk to the 4.1 branch:<commit_after><|endoftext|>


<commit_before>#include "coreplugin.h"
#include "applicationextension.h"
#include "engineextension.h"
#include "componentextension.h"
#include "contextextension.h"
#include <QApplication>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQmlContext>

Q_DECLARE_METATYPE(const QMetaObject*)

namespace RubyQml {

CorePlugin::CorePlugin(QObject *parent) :
    QObject(parent)
{
    qRegisterMetaType<ApplicationExtension *>();
    qRegisterMetaType<EngineExtension *>();
    qRegisterMetaType<ComponentExtension *>();
    qRegisterMetaType<ContextExtension *>();
    qRegisterMetaType<QApplication *>();
    qRegisterMetaType<QCoreApplication *>();
    qRegisterMetaType<QQmlEngine *>();
    qRegisterMetaType<QQmlComponent *>();
    qRegisterMetaType<QQmlContext *>();

    const QMetaObject *metaObjects[] = {
        &staticQtMetaObject,
        &QApplication::staticMetaObject,
        &QQmlEngine::staticMetaObject,
        &QQmlComponent::staticMetaObject,
        &QQmlContext::staticMetaObject};
    for (auto metaobj : metaObjects) {
        mMetaObjects[metaobj->className()] = QVariant::fromValue(metaobj);
    }
}

QApplication *CorePlugin::applicationInstance()
{
    return qApp;
}

QApplication *CorePlugin::createApplication(const QVariantList &args)
{
    static bool created = false;
    static QList<QByteArray> staticArgs;
    static int argc;
    static char **argv;

    if (created) {
        throw std::logic_error("Application already created");
    }

    argc = args.size();
    argv = new char*[argc];

    std::transform(args.begin(), args.end(), std::back_inserter(staticArgs), [](const QVariant &arg) {
        return arg.toString().toUtf8();
    });
    std::transform(staticArgs.begin(), staticArgs.end(), argv, [](QByteArray &ba) {
        return ba.data();
    });
    auto app = new QApplication(argc, argv);
    created = true;
    return app;
}

QQmlEngine *CorePlugin::createEngine()
{
    return new QQmlEngine();
}

QQmlComponent *CorePlugin::createComponent(QQmlEngine *e)
{
    return new QQmlComponent(e);
}

QQmlContext *CorePlugin::createContext(QQmlEngine *engine)
{
    return new QQmlContext(engine);
}

ApplicationExtension *CorePlugin::createApplicationExtension(QApplication *app)
{
    return new ApplicationExtension(app);
}

EngineExtension *CorePlugin::createEngineExtension(QQmlEngine *engine)
{
    return new EngineExtension(engine);
}

ComponentExtension *CorePlugin::createComponentExtension(QQmlComponent *component)
{
    return new ComponentExtension(component);
}

ContextExtension *CorePlugin::createContextExtension(QQmlContext *context)
{
    return new ContextExtension(context);
}

QQmlContext *CorePlugin::contextForObject(QObject *object)
{
    return QQmlEngine::contextForObject(object);
}

} // namespace RubyQml
<commit_msg>Add #include <stdexcept> to coreplugin.cpp<commit_after>#include "coreplugin.h"
#include "applicationextension.h"
#include "engineextension.h"
#include "componentextension.h"
#include "contextextension.h"
#include <QApplication>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQmlContext>
#include <stdexcept>

Q_DECLARE_METATYPE(const QMetaObject*)

namespace RubyQml {

CorePlugin::CorePlugin(QObject *parent) :
    QObject(parent)
{
    qRegisterMetaType<ApplicationExtension *>();
    qRegisterMetaType<EngineExtension *>();
    qRegisterMetaType<ComponentExtension *>();
    qRegisterMetaType<ContextExtension *>();
    qRegisterMetaType<QApplication *>();
    qRegisterMetaType<QCoreApplication *>();
    qRegisterMetaType<QQmlEngine *>();
    qRegisterMetaType<QQmlComponent *>();
    qRegisterMetaType<QQmlContext *>();

    const QMetaObject *metaObjects[] = {
        &staticQtMetaObject,
        &QApplication::staticMetaObject,
        &QQmlEngine::staticMetaObject,
        &QQmlComponent::staticMetaObject,
        &QQmlContext::staticMetaObject};
    for (auto metaobj : metaObjects) {
        mMetaObjects[metaobj->className()] = QVariant::fromValue(metaobj);
    }
}

QApplication *CorePlugin::applicationInstance()
{
    return qApp;
}

QApplication *CorePlugin::createApplication(const QVariantList &args)
{
    static bool created = false;
    static QList<QByteArray> staticArgs;
    static int argc;
    static char **argv;

    if (created) {
        throw std::logic_error("Application already created");
    }

    argc = args.size();
    argv = new char*[argc];

    std::transform(args.begin(), args.end(), std::back_inserter(staticArgs), [](const QVariant &arg) {
        return arg.toString().toUtf8();
    });
    std::transform(staticArgs.begin(), staticArgs.end(), argv, [](QByteArray &ba) {
        return ba.data();
    });
    auto app = new QApplication(argc, argv);
    created = true;
    return app;
}

QQmlEngine *CorePlugin::createEngine()
{
    return new QQmlEngine();
}

QQmlComponent *CorePlugin::createComponent(QQmlEngine *e)
{
    return new QQmlComponent(e);
}

QQmlContext *CorePlugin::createContext(QQmlEngine *engine)
{
    return new QQmlContext(engine);
}

ApplicationExtension *CorePlugin::createApplicationExtension(QApplication *app)
{
    return new ApplicationExtension(app);
}

EngineExtension *CorePlugin::createEngineExtension(QQmlEngine *engine)
{
    return new EngineExtension(engine);
}

ComponentExtension *CorePlugin::createComponentExtension(QQmlComponent *component)
{
    return new ComponentExtension(component);
}

ContextExtension *CorePlugin::createContextExtension(QQmlContext *context)
{
    return new ContextExtension(context);
}

QQmlContext *CorePlugin::contextForObject(QObject *object)
{
    return QQmlEngine::contextForObject(object);
}

} // namespace RubyQml
<|endoftext|>


<commit_before>// Scott Wiedemann
// 05/13/2013
// evenfib.cpp
// Largest prime factor

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

using namespace std;

int main(int argc, char **argv) {
	if (argc!=2) {
		printf("Usage: %s [long to factor]\n", argv[0]);
		return 1;
	}

	long toFactor = atol(argv[1]);
	long k = 2;
	while(k < toFactor) {
		if(toFactor % k == 0) {
			toFactor = toFactor / k--;
		}
		k++;
	}
	printf("Largest prime: %ld\n", toFactor);
	return 0;
}
<commit_msg>typo.<commit_after>// Scott Wiedemann
// 05/13/2013
// largeprimefactor.cpp
// Largest prime factor

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

using namespace std;

int main(int argc, char **argv) {
	if (argc!=2) {
		printf("Usage: %s [long to factor]\n", argv[0]);
		return 1;
	}

	long toFactor = atol(argv[1]);
	long k = 2;
	while(k < toFactor) {
		if(toFactor % k == 0) {
			toFactor = toFactor / k--;
		}
		k++;
	}
	printf("Largest prime: %ld\n", toFactor);
	return 0;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Library
  Module:    Triangle.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Description:
---------------------------------------------------------------------------
This file is part of the Visualization Library. No part of this file
or its contents may be copied, reproduced or altered in any way
without the express written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
#include "Triangle.hh"
#include "Polygon.hh"
#include "Plane.hh"
#include "vlMath.hh"
#include "CellArr.hh"
#include "Line.hh"

int vlTriangle::EvaluatePosition(float x[3], int& subId, float pcoords[3],
                                 float& dist2, float weights[MAX_CELL_SIZE])
{
  int i, j;
  vlPolygon poly;
  float *pt1, *pt2, *pt3, n[3], xProj[3];
  float rhs[2], c1[2], c2[2];
  float closestPoint[3], det;
  vlPlane plane;
  vlMath math;
  float maxComponent;
  int idx, indices[2];

  subId = 0;
  pcoords[0] = pcoords[1] = pcoords[2] = 0.0;
//
// Get normal for triangle
//
  pt1 = this->Points.GetPoint(1);
  pt2 = this->Points.GetPoint(2);
  pt3 = this->Points.GetPoint(0);

  poly.ComputeNormal (pt1, pt2, pt3, n);
//
// Project point to plane
//
  plane.ProjectPoint(x,pt1,n,xProj);
//
// Construct matrices.  Since we have over determined system, need to find
// which 2 out of 3 equations to use to develop equations. (Any 2 should
// work since we've projected point to plane.)
//
  for (maxComponent=0.0, i=0; i<3; i++)
    {
    if (n[i] > maxComponent)
      {
      maxComponent = n[i];
      idx = i;
      }
    }
  for (j=0, i=0; i<3; i++)
    {
    if ( i != idx ) indices[j++] = i;
    }

  for (i=0; i<2; i++)
    {
    rhs[i] = x[indices[i]] - pt3[indices[i]];
    c1[i] = pt1[indices[i]] - pt3[indices[i]];
    c2[i] = pt2[indices[i]] - pt3[indices[i]];
    }

  if ( (det = math.Determinate2x2(c1,c2)) == 0.0 )
    return 0;

  pcoords[0] = math.Determinate2x2 (rhs,c2) / det;
  pcoords[1] = math.Determinate2x2 (c1,rhs) / det;
  pcoords[2] = 1.0 - pcoords[0] - pcoords[1];
//
// Okay, now find closest point to element
//
  if ( pcoords[0] >= 0.0 && pcoords[1] <= 1.0 &&
  pcoords[1] >= 0.0 && pcoords[1] <= 1.0 &&
  pcoords[2] >= 0.0 && pcoords[2] <= 1.0 )
    {
    dist2 = math.Distance2BetweenPoints(xProj,x); //projection distance
    weights[0] = pcoords[2];
    weights[1] = pcoords[0];
    weights[2] = pcoords[1];
    return 1;
    }
  else
    {
    for (i=0; i<2; i++)
      {
      if (pcoords[i] < 0.0) pcoords[i] = 0.0;
      if (pcoords[i] > 1.0) pcoords[i] = 1.0;
      }
    this->EvaluateLocation(subId, pcoords, closestPoint, weights);
    dist2 = math.Distance2BetweenPoints(closestPoint,x);
    return 0;
    }
}

void vlTriangle::EvaluateLocation(int& subId, float pcoords[3], float x[3],
                                  float weights[MAX_CELL_SIZE])
{
  float u3;
  float *pt1, *pt2, *pt3;
  int i;

  pt1 = this->Points.GetPoint(1);
  pt2 = this->Points.GetPoint(2);
  pt3 = this->Points.GetPoint(0);

  u3 = 1.0 - pcoords[0] - pcoords[1];

  for (i=0; i<3; i++)
    {
    x[i] = pt1[i]*pcoords[0] + pt2[i]*pcoords[1] + pt3[i]*u3;
    }

  weights[0] = u3;
  weights[1] = pcoords[0];
  weights[2] = pcoords[1];
}

//
// Marching triangles
//
typedef int EDGE_LIST;
typedef struct {
       EDGE_LIST edges[3];
} LINE_CASES;

static LINE_CASES lineCases[] = {
  {-1, -1, -1},
  {0, 2, -1},
  {1, 0, -1},
  {1, 2, -1},
  {2, 1, -1},
  {0, 1, -1},
  {2, 0, -1},
  {-1, -1, -1}
};

void vlTriangle::Contour(float value, vlFloatScalars *cellScalars,
                         vlFloatPoints *points,
                         vlCellArray *verts, vlCellArray *lines,
                         vlCellArray *polys, vlFloatScalars *scalars)
{
  static int CASE_MASK[3] = {1,2,4};
  LINE_CASES *lineCase;
  EDGE_LIST  *edge;
  int i, j, index, *vert;
  static int edges[3][2] = { {0,1}, {1,2}, {2,0} };
  int pts[2];
  float t, *x1, *x2, x[3];

  // Build the case table
  for ( i=0, index = 0; i < 3; i++)
      if (cellScalars->GetScalar(i) >= value)
          index |= CASE_MASK[i];

  lineCase = lineCases + index;
  edge = lineCase->edges;

  for ( ; edge[0] > -1; edge += 2 )
    {
    for (i=0; i<2; i++) // insert line
      {
      vert = edges[edge[i]];
      t = (value - cellScalars->GetScalar(vert[0])) /
          (cellScalars->GetScalar(vert[1]) - cellScalars->GetScalar(vert[0]));
      x1 = this->Points.GetPoint(vert[0]);
      x2 = this->Points.GetPoint(vert[1]);
      for (j=0; j<3; j++) x[j] = x1[j] + t * (x2[j] - x1[j]);
      pts[i] = points->InsertNextPoint(x);
      scalars->InsertNextScalar(value);
      }
    lines->InsertNextCell(2,pts);
    }
}

vlCell *vlTriangle::GetEdge(int edgeId)
{
  static vlLine line;

  // load point id's
  line.PointIds.SetId(0,this->PointIds.GetId(edgeId));
  line.PointIds.SetId(1,this->PointIds.GetId((edgeId+1) % 3));

  // load coordinates
  line.Points.SetPoint(0,this->Points.GetPoint(edgeId));
  line.Points.SetPoint(1,this->Points.GetPoint((edgeId+1) % 3));

  return &line;
}

<commit_msg>ERR:Fixed bug in pcoords.<commit_after>/*=========================================================================

  Program:   Visualization Library
  Module:    Triangle.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Description:
---------------------------------------------------------------------------
This file is part of the Visualization Library. No part of this file
or its contents may be copied, reproduced or altered in any way
without the express written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
#include "Triangle.hh"
#include "Polygon.hh"
#include "Plane.hh"
#include "vlMath.hh"
#include "CellArr.hh"
#include "Line.hh"

int vlTriangle::EvaluatePosition(float x[3], int& subId, float pcoords[3],
                                 float& dist2, float weights[MAX_CELL_SIZE])
{
  int i, j;
  vlPolygon poly;
  float *pt1, *pt2, *pt3, n[3], xProj[3];
  float rhs[2], c1[2], c2[2];
  float closestPoint[3], det;
  vlPlane plane;
  vlMath math;
  float maxComponent;
  int idx, indices[2];

  subId = 0;
  pcoords[0] = pcoords[1] = pcoords[2] = 0.0;
//
// Get normal for triangle
//
  pt1 = this->Points.GetPoint(1);
  pt2 = this->Points.GetPoint(2);
  pt3 = this->Points.GetPoint(0);

  poly.ComputeNormal (pt1, pt2, pt3, n);
//
// Project point to plane
//
  plane.ProjectPoint(x,pt1,n,xProj);
//
// Construct matrices.  Since we have over determined system, need to find
// which 2 out of 3 equations to use to develop equations. (Any 2 should
// work since we've projected point to plane.)
//
  for (maxComponent=0.0, i=0; i<3; i++)
    {
    if (n[i] > maxComponent)
      {
      maxComponent = n[i];
      idx = i;
      }
    }
  for (j=0, i=0; i<3; i++)
    {
    if ( i != idx ) indices[j++] = i;
    }

  for (i=0; i<2; i++)
    {
    rhs[i] = x[indices[i]] - pt3[indices[i]];
    c1[i] = pt1[indices[i]] - pt3[indices[i]];
    c2[i] = pt2[indices[i]] - pt3[indices[i]];
    }

  if ( (det = math.Determinate2x2(c1,c2)) == 0.0 )
    return 0;

  pcoords[0] = math.Determinate2x2 (rhs,c2) / det;
  pcoords[1] = math.Determinate2x2 (c1,rhs) / det;
  pcoords[2] = 1.0 - pcoords[0] - pcoords[1];
//
// Okay, now find closest point to element
//
  if ( pcoords[0] >= 0.0 && pcoords[1] <= 1.0 &&
  pcoords[1] >= 0.0 && pcoords[1] <= 1.0 &&
  pcoords[2] >= 0.0 && pcoords[2] <= 1.0 )
    {
    dist2 = math.Distance2BetweenPoints(xProj,x); //projection distance
    weights[0] = pcoords[2];
    weights[1] = pcoords[0];
    weights[2] = pcoords[1];
    return 1;
    }
  else
    {
    for (i=0; i<2; i++)
      {
      if (pcoords[i] < 0.0) pcoords[i] = 0.0;
      if (pcoords[i] > 1.0) pcoords[i] = 1.0;
      }
    if ( (1.0 - pcoords[0] - pcoords[1]) < 0.0 )
      {
      float ratio = pcoords[0]/pcoords[1];
      pcoords[1] = 1.0 / (1.0 + ratio);
      pcoords[0] = ratio * pcoords[1];
      }
    this->EvaluateLocation(subId, pcoords, closestPoint, weights);
    dist2 = math.Distance2BetweenPoints(closestPoint,x);
    return 0;
    }
}

void vlTriangle::EvaluateLocation(int& subId, float pcoords[3], float x[3],
                                  float weights[MAX_CELL_SIZE])
{
  float u3;
  float *pt1, *pt2, *pt3;
  int i;

  pt1 = this->Points.GetPoint(1);
  pt2 = this->Points.GetPoint(2);
  pt3 = this->Points.GetPoint(0);

  u3 = 1.0 - pcoords[0] - pcoords[1];

  for (i=0; i<3; i++)
    {
    x[i] = pt1[i]*pcoords[0] + pt2[i]*pcoords[1] + pt3[i]*u3;
    }

  weights[0] = u3;
  weights[1] = pcoords[0];
  weights[2] = pcoords[1];
}

//
// Marching triangles
//
typedef int EDGE_LIST;
typedef struct {
       EDGE_LIST edges[3];
} LINE_CASES;

static LINE_CASES lineCases[] = {
  {-1, -1, -1},
  {0, 2, -1},
  {1, 0, -1},
  {1, 2, -1},
  {2, 1, -1},
  {0, 1, -1},
  {2, 0, -1},
  {-1, -1, -1}
};

void vlTriangle::Contour(float value, vlFloatScalars *cellScalars,
                         vlFloatPoints *points,
                         vlCellArray *verts, vlCellArray *lines,
                         vlCellArray *polys, vlFloatScalars *scalars)
{
  static int CASE_MASK[3] = {1,2,4};
  LINE_CASES *lineCase;
  EDGE_LIST  *edge;
  int i, j, index, *vert;
  static int edges[3][2] = { {0,1}, {1,2}, {2,0} };
  int pts[2];
  float t, *x1, *x2, x[3];

  // Build the case table
  for ( i=0, index = 0; i < 3; i++)
      if (cellScalars->GetScalar(i) >= value)
          index |= CASE_MASK[i];

  lineCase = lineCases + index;
  edge = lineCase->edges;

  for ( ; edge[0] > -1; edge += 2 )
    {
    for (i=0; i<2; i++) // insert line
      {
      vert = edges[edge[i]];
      t = (value - cellScalars->GetScalar(vert[0])) /
          (cellScalars->GetScalar(vert[1]) - cellScalars->GetScalar(vert[0]));
      x1 = this->Points.GetPoint(vert[0]);
      x2 = this->Points.GetPoint(vert[1]);
      for (j=0; j<3; j++) x[j] = x1[j] + t * (x2[j] - x1[j]);
      pts[i] = points->InsertNextPoint(x);
      scalars->InsertNextScalar(value);
      }
    lines->InsertNextCell(2,pts);
    }
}

vlCell *vlTriangle::GetEdge(int edgeId)
{
  static vlLine line;

  // load point id's
  line.PointIds.SetId(0,this->PointIds.GetId(edgeId));
  line.PointIds.SetId(1,this->PointIds.GetId((edgeId+1) % 3));

  // load coordinates
  line.Points.SetPoint(0,this->Points.GetPoint(edgeId));
  line.Points.SetPoint(1,this->Points.GetPoint((edgeId+1) % 3));

  return &line;
}

<|endoftext|>


<commit_before>#include <vector>
#include <boost/filesystem.hpp>
#include <bitcoin/bitcoin.hpp>
#include <obelisk/zmq_message.hpp>
#include "config.hpp"

#define HEARTBEAT_LIVENESS  3       //  3-5 is reasonable
#define HEARTBEAT_INTERVAL  1000    //  msecs

#define LOG_BALANCER "balancer"

using namespace bc;
using namespace obelisk;

typedef data_chunk worker_uuid;

static void s_version_assert(int want_major, int want_minor)
{
    int major, minor, patch;
    zmq_version (&major, &minor, &patch);
    if (major < want_major
    || (major == want_major && minor < want_minor)) {
        std::cout << "Current 0MQ version is " << major << "." << minor << std::endl;
        std::cout << "Application needs at least " << want_major << "." << want_minor
              << " - cannot continue" << std::endl;
        exit (EXIT_FAILURE);
    }
}

//  Return current system clock as milliseconds
static int64_t s_clock(void)
{
#if (defined (__WINDOWS__))
    SYSTEMTIME st;
    GetSystemTime (&st);
    return (int64_t) st.wSecond * 1000 + st.wMilliseconds;
#else
    struct timeval tv;
    gettimeofday (&tv, NULL);
    return (int64_t) (tv.tv_sec * 1000 + tv.tv_usec / 1000);
#endif
}

//  This defines one active worker in our worker queue

typedef struct {
    worker_uuid identity;           //  Address of worker
    int64_t     expiry;             //  Expires at this time
} worker_t;

//  Insert worker at end of queue, reset expiry
//  Worker must not already be in queue
void s_worker_append(std::vector<worker_t>& queue, const worker_uuid& identity)
{
    bool found = false;
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (it->identity == identity)
        {
            std::cout << "E: duplicate worker identity " << identity << std::endl;
            found = true;
            break;
        }
    }
    if (!found)
    {
        worker_t worker;
        worker.identity = identity;
        worker.expiry = s_clock() + HEARTBEAT_INTERVAL * HEARTBEAT_LIVENESS;
        queue.push_back(worker);
    }
}

//  Remove worker from queue, if present
void s_worker_delete(std::vector<worker_t>& queue, const worker_uuid& identity)
{
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (it->identity == identity)
        {
            it = queue.erase(it);
            break;
        }
    }
}

//  Reset worker expiry, worker must be present
void s_worker_refresh(std::vector<worker_t>& queue, const worker_uuid& identity)
{
    bool found = false;
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (it->identity == identity)
        {
           it->expiry = s_clock() + HEARTBEAT_INTERVAL * HEARTBEAT_LIVENESS;
           found = true;
           break;
        }
    }
    if (!found)
    {
       std::cout << "E: worker " << identity << " not ready" << std::endl;
    }
}

//  Pop next available worker off queue, return identity
const worker_uuid s_worker_dequeue(std::vector<worker_t>& queue)
{
    assert(queue.size());
    const worker_uuid identity = queue[0].identity;
    queue.erase(queue.begin());
    return identity;
}

//  Look for & kill expired workers
void s_queue_purge(std::vector<worker_t>& queue)
{
    int64_t clock = s_clock();
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (clock > it->expiry)
        {
           it = queue.erase(it) - 1;
        }
    }
}

typedef std::vector<worker_t> worker_queue;

void forward_request(zmq::socket_t& frontend, zmq::socket_t& backend,
    worker_queue& queue)
{
    // Get client request.
    zmq_message msg_in;
    msg_in.recv(frontend);
    const data_stack& in_parts = msg_in.parts();

    if (in_parts.size() != 6)
    {
        log_warning(LOG_BALANCER) << "Wrong sized message";
        return;
    }
    // First item is client's identity.
    if (in_parts[0].size() != 17)
    {
        log_warning(LOG_BALANCER) << "Client UUID malformed";
        return;
    }
    // Second item is worker identity or nothing.
    if (in_parts[1].size() > 255)
    {
        log_warning(LOG_BALANCER) << "Worker UUID malformed";
        return;
    }

    // We now deconstruct the request message to the backend
    // which looks like:
    //   [CLIENT UUID]
    //   [WORKER UUID]
    //   ...
    // And create a new message that looks like:
    //   [WORKER UUID]
    //   [CLIENT UUID]
    //   ...
    // Before sending it to the worker.

    // This is so the client can specify a worker to send their
    // request specifically to.

    zmq_message msg_out;
    // If second frame is nothing, then we select a random worker.
    if (in_parts[1].empty())
    {
        // Route to next worker
        worker_uuid worker_identity = s_worker_dequeue(queue);
        msg_out.append(worker_identity);
    }
    else
    {
        // Route to client's preferred worker.
        msg_out.append(in_parts[1]);
    }
    msg_out.append(in_parts[0]);
    // Copy the remaining data.
    for (auto it = in_parts.begin() + 2; it != in_parts.end(); ++it)
        msg_out.append(*it);
    msg_out.send(backend);
}

void handle_control_message(const data_stack& in_parts,
    worker_queue& queue, const worker_uuid& identity)
{
    std::string command(in_parts[1].begin(), in_parts[1].end());
    log_info(LOG_BALANCER) << "command: " << command;
    if (command == "READY")
    {
        s_worker_delete(queue, identity);
        s_worker_append(queue, identity);
    }
    else if (command == "HEARTBEAT")
    {
        s_worker_refresh(queue, identity);
    }
    else
        log_error(LOG_BALANCER)
            << "Invalid command from " << identity;
}

void passback_response(zmq::socket_t& backend, zmq::socket_t& frontend,
    worker_queue& queue)
{
    zmq_message msg_in;
    msg_in.recv(backend);
    const data_stack& in_parts = msg_in.parts();
    BITCOIN_ASSERT(in_parts.size() == 2 || in_parts.size() == 6);
    worker_uuid identity = in_parts[0];

    // Return reply to client if it's not a control message
    if (in_parts.size() == 2)
        return handle_control_message(in_parts, queue, identity);

    // We now deconstruct the request message to the frontend
    // which looks like:
    //   [WORKER UUID]
    //   [CLIENT UUID]
    //   ...
    // And create a new message that looks like:
    //   [CLIENT UUID]
    //   [WORKER UUID]
    //   ...
    // Before sending it to the backend.

    // This is so the client will know which worker
    // responded to their request.

    BITCOIN_ASSERT(in_parts.size() == 6);
    zmq_message msg_out;
    BITCOIN_ASSERT(in_parts[1].size() == 17);
    msg_out.append(in_parts[1]);
    BITCOIN_ASSERT(in_parts[0].size() > 0 && in_parts[0].size() < 256);
    msg_out.append(in_parts[0]);
    for (auto it = in_parts.begin() + 2; it != in_parts.end(); ++it)
        msg_out.append(*it);
    BITCOIN_ASSERT(in_parts.size() == msg_out.parts().size());
    msg_out.send(frontend);
    // Add worker back to available pool of workers.
    s_worker_append(queue, identity);
}

int main(int argc, char** argv)
{
    s_version_assert(2, 1);
    config_map_type config;
    if (argc == 2)
    {
        std::cout << "Using config file: " << argv[1] << std::endl;
        load_config(config, argv[1]);
    }
    else
    {
        using boost::filesystem::path;
        path conf_filename = path(SYSCONFDIR) / "obelisk" / "balancer.cfg";
        load_config(config, conf_filename.native());
    }

    // Prepare our context and sockets
    zmq::context_t context(1);
    zmq::socket_t frontend(context, ZMQ_ROUTER);
    zmq::socket_t backend(context, ZMQ_ROUTER);
    // For clients
    frontend.bind(config["frontend"].c_str());
    // For workers
    backend.bind(config["backend"].c_str());

    // Queue of available workers
    worker_queue queue;
    // Send out heartbeats at regular intervals
    int64_t heartbeat_at = s_clock() + HEARTBEAT_INTERVAL;

    while (1)
    {
        zmq::pollitem_t items[] = {
            { backend,  0, ZMQ_POLLIN, 0 },
            { frontend, 0, ZMQ_POLLIN, 0 }
        };

        //  Poll frontend only if we have available workers
        if (queue.size())
            zmq::poll(items, 2, HEARTBEAT_INTERVAL * 1000);
        else
            zmq::poll(items, 1, HEARTBEAT_INTERVAL * 1000);

        // Handle worker activity on backend
        if (items [0].revents & ZMQ_POLLIN)
            passback_response(backend, frontend, queue);
        if (items [1].revents & ZMQ_POLLIN)
            forward_request(frontend, backend, queue);

        //  Send heartbeats to idle workers if it's time
        if (s_clock() > heartbeat_at)
        {
            for (auto it = queue.begin(); it < queue.end(); ++it)
            {
                zmq_message msg;
                msg.append(it->identity);
                std::string command = "HEARTBEAT";
                msg.append(data_chunk(command.begin(), command.end()));
                msg.send(backend);
            }
            heartbeat_at = s_clock() + HEARTBEAT_INTERVAL;
        }
        s_queue_purge(queue);
    }
    //  We never exit the main loop
    //  But pretend to do the right shutdown anyhow
    queue.clear();
    return 0;
}

<commit_msg>recent ZMQ versions change the UUID size from 17 to 5 bytes.<commit_after>#include <vector>
#include <boost/filesystem.hpp>
#include <bitcoin/bitcoin.hpp>
#include <obelisk/zmq_message.hpp>
#include "config.hpp"

#define HEARTBEAT_LIVENESS  3       //  3-5 is reasonable
#define HEARTBEAT_INTERVAL  1000    //  msecs

#define LOG_BALANCER "balancer"

#if ZMQ_VERSION_MAJOR == 4
    constexpr size_t zmq_uuid_size = 5;
#else
    constexpr size_t zmq_uuid_size = 17;
#endif

using namespace bc;
using namespace obelisk;

typedef data_chunk worker_uuid;

static void s_version_assert(int want_major, int want_minor)
{
    int major, minor, patch;
    zmq_version (&major, &minor, &patch);
    if (major < want_major
    || (major == want_major && minor < want_minor)) {
        std::cout << "Current 0MQ version is " << major << "." << minor << std::endl;
        std::cout << "Application needs at least " << want_major << "." << want_minor
              << " - cannot continue" << std::endl;
        exit (EXIT_FAILURE);
    }
}

//  Return current system clock as milliseconds
static int64_t s_clock(void)
{
#if (defined (__WINDOWS__))
    SYSTEMTIME st;
    GetSystemTime (&st);
    return (int64_t) st.wSecond * 1000 + st.wMilliseconds;
#else
    struct timeval tv;
    gettimeofday (&tv, NULL);
    return (int64_t) (tv.tv_sec * 1000 + tv.tv_usec / 1000);
#endif
}

//  This defines one active worker in our worker queue

typedef struct {
    worker_uuid identity;           //  Address of worker
    int64_t     expiry;             //  Expires at this time
} worker_t;

//  Insert worker at end of queue, reset expiry
//  Worker must not already be in queue
void s_worker_append(std::vector<worker_t>& queue, const worker_uuid& identity)
{
    bool found = false;
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (it->identity == identity)
        {
            std::cout << "E: duplicate worker identity " << identity << std::endl;
            found = true;
            break;
        }
    }
    if (!found)
    {
        worker_t worker;
        worker.identity = identity;
        worker.expiry = s_clock() + HEARTBEAT_INTERVAL * HEARTBEAT_LIVENESS;
        queue.push_back(worker);
    }
}

//  Remove worker from queue, if present
void s_worker_delete(std::vector<worker_t>& queue, const worker_uuid& identity)
{
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (it->identity == identity)
        {
            it = queue.erase(it);
            break;
        }
    }
}

//  Reset worker expiry, worker must be present
void s_worker_refresh(std::vector<worker_t>& queue, const worker_uuid& identity)
{
    bool found = false;
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (it->identity == identity)
        {
           it->expiry = s_clock() + HEARTBEAT_INTERVAL * HEARTBEAT_LIVENESS;
           found = true;
           break;
        }
    }
    if (!found)
    {
       std::cout << "E: worker " << identity << " not ready" << std::endl;
    }
}

//  Pop next available worker off queue, return identity
const worker_uuid s_worker_dequeue(std::vector<worker_t>& queue)
{
    assert(queue.size());
    const worker_uuid identity = queue[0].identity;
    queue.erase(queue.begin());
    return identity;
}

//  Look for & kill expired workers
void s_queue_purge(std::vector<worker_t>& queue)
{
    int64_t clock = s_clock();
    for (auto it = queue.begin(); it < queue.end(); ++it)
    {
        if (clock > it->expiry)
        {
           it = queue.erase(it) - 1;
        }
    }
}

typedef std::vector<worker_t> worker_queue;

void forward_request(zmq::socket_t& frontend, zmq::socket_t& backend,
    worker_queue& queue)
{
    // Get client request.
    zmq_message msg_in;
    msg_in.recv(frontend);
    const data_stack& in_parts = msg_in.parts();

    if (in_parts.size() != 6)
    {
        log_warning(LOG_BALANCER) << "Wrong sized message";
        return;
    }
    // First item is client's identity.
    if (in_parts[0].size() != zmq_uuid_size)
    {
        log_warning(LOG_BALANCER) << "Client UUID malformed " << in_parts[0];
        return;
    }
    // Second item is worker identity or nothing.
    if (in_parts[1].size() > 255)
    {
        log_warning(LOG_BALANCER) << "Worker UUID malformed";
        return;
    }

    // We now deconstruct the request message to the backend
    // which looks like:
    //   [CLIENT UUID]
    //   [WORKER UUID]
    //   ...
    // And create a new message that looks like:
    //   [WORKER UUID]
    //   [CLIENT UUID]
    //   ...
    // Before sending it to the worker.

    // This is so the client can specify a worker to send their
    // request specifically to.

    zmq_message msg_out;
    // If second frame is nothing, then we select a random worker.
    if (in_parts[1].empty())
    {
        // Route to next worker
        worker_uuid worker_identity = s_worker_dequeue(queue);
        msg_out.append(worker_identity);
    }
    else
    {
        // Route to client's preferred worker.
        msg_out.append(in_parts[1]);
    }
    msg_out.append(in_parts[0]);
    // Copy the remaining data.
    for (auto it = in_parts.begin() + 2; it != in_parts.end(); ++it)
        msg_out.append(*it);
    msg_out.send(backend);
}

void handle_control_message(const data_stack& in_parts,
    worker_queue& queue, const worker_uuid& identity)
{
    std::string command(in_parts[1].begin(), in_parts[1].end());
    log_info(LOG_BALANCER) << "command: " << command;
    if (command == "READY")
    {
        s_worker_delete(queue, identity);
        s_worker_append(queue, identity);
    }
    else if (command == "HEARTBEAT")
    {
        s_worker_refresh(queue, identity);
    }
    else
        log_error(LOG_BALANCER)
            << "Invalid command from " << identity;
}

void passback_response(zmq::socket_t& backend, zmq::socket_t& frontend,
    worker_queue& queue)
{
    zmq_message msg_in;
    msg_in.recv(backend);
    const data_stack& in_parts = msg_in.parts();
    BITCOIN_ASSERT(in_parts.size() == 2 || in_parts.size() == 6);
    worker_uuid identity = in_parts[0];

    // Return reply to client if it's not a control message
    if (in_parts.size() == 2)
        return handle_control_message(in_parts, queue, identity);

    // We now deconstruct the request message to the frontend
    // which looks like:
    //   [WORKER UUID]
    //   [CLIENT UUID]
    //   ...
    // And create a new message that looks like:
    //   [CLIENT UUID]
    //   [WORKER UUID]
    //   ...
    // Before sending it to the backend.

    // This is so the client will know which worker
    // responded to their request.

    BITCOIN_ASSERT(in_parts.size() == 6);
    zmq_message msg_out;
    BITCOIN_ASSERT(in_parts[1].size() == zmq_uuid_size);
    msg_out.append(in_parts[1]);
    BITCOIN_ASSERT(in_parts[0].size() > 0 && in_parts[0].size() < 256);
    msg_out.append(in_parts[0]);
    for (auto it = in_parts.begin() + 2; it != in_parts.end(); ++it)
        msg_out.append(*it);
    BITCOIN_ASSERT(in_parts.size() == msg_out.parts().size());
    msg_out.send(frontend);
    // Add worker back to available pool of workers.
    s_worker_append(queue, identity);
}

int main(int argc, char** argv)
{
    s_version_assert(2, 1);
    config_map_type config;
    if (argc == 2)
    {
        std::cout << "Using config file: " << argv[1] << std::endl;
        load_config(config, argv[1]);
    }
    else
    {
        using boost::filesystem::path;
        path conf_filename = path(SYSCONFDIR) / "obelisk" / "balancer.cfg";
        load_config(config, conf_filename.native());
    }

    // Prepare our context and sockets
    zmq::context_t context(1);
    zmq::socket_t frontend(context, ZMQ_ROUTER);
    zmq::socket_t backend(context, ZMQ_ROUTER);
    // For clients
    frontend.bind(config["frontend"].c_str());
    // For workers
    backend.bind(config["backend"].c_str());

    // Queue of available workers
    worker_queue queue;
    // Send out heartbeats at regular intervals
    int64_t heartbeat_at = s_clock() + HEARTBEAT_INTERVAL;

    while (1)
    {
        zmq::pollitem_t items[] = {
            { backend,  0, ZMQ_POLLIN, 0 },
            { frontend, 0, ZMQ_POLLIN, 0 }
        };

        //  Poll frontend only if we have available workers
        if (queue.size())
            zmq::poll(items, 2, HEARTBEAT_INTERVAL * 1000);
        else
            zmq::poll(items, 1, HEARTBEAT_INTERVAL * 1000);

        // Handle worker activity on backend
        if (items [0].revents & ZMQ_POLLIN)
            passback_response(backend, frontend, queue);
        if (items [1].revents & ZMQ_POLLIN)
            forward_request(frontend, backend, queue);

        //  Send heartbeats to idle workers if it's time
        if (s_clock() > heartbeat_at)
        {
            for (auto it = queue.begin(); it < queue.end(); ++it)
            {
                zmq_message msg;
                msg.append(it->identity);
                std::string command = "HEARTBEAT";
                msg.append(data_chunk(command.begin(), command.end()));
                msg.send(backend);
            }
            heartbeat_at = s_clock() + HEARTBEAT_INTERVAL;
        }
        s_queue_purge(queue);
    }
    //  We never exit the main loop
    //  But pretend to do the right shutdown anyhow
    queue.clear();
    return 0;
}

<|endoftext|>


<commit_before>#include "CWTableView.h"

using namespace cocos2d;
using namespace cocos2d::ui;

namespace cw {
    TableView::TableView()
    : _vordering(VerticalFillOrder::BOTTOM_UP)
    , _isUsedCellsDirty(false)
    , _delegate(nullptr) {

    }

    TableView::~TableView() {
    }

    TableView *TableView::create() {
        TableView *table = new (std::nothrow) TableView();
        if (table != nullptr && table->init()) {
            table->autorelease();
            return table;
        }
        CC_SAFE_DELETE(table);
        return NULL;
    }

    bool TableView::init() {
        if (!ScrollView::init()) {
            return false;
        }
        _cellsPositions.clear();

        _cellsUsed.clear();
        _cellsFreed.clear();
        _indices.clear();
        _vordering = VerticalFillOrder::BOTTOM_UP;
        this->setDirection(Direction::VERTICAL);

        return true;
    }

    void TableView::onSizeChanged() {
        Size orginSize = _innerContainer->getContentSize();
        Vec2 orginPos = _innerContainer->getPosition();
        ScrollView::onSizeChanged();
        if (orginSize.equals(_innerContainer->getContentSize())) {
            _innerContainer->setPosition(orginPos);
        }
    }

    void TableView::setVerticalFillOrder(VerticalFillOrder fillOrder) {
        if (_vordering != fillOrder) {
            _vordering = fillOrder;
            if (!_cellsUsed.empty()) {
                this->reloadData();
            }
        }
    }

    TableView::VerticalFillOrder TableView::getVerticalFillOrder() {
        return _vordering;
    }

    void TableView::setDirection(Direction dir) {
        switch (_direction) {
        case Direction::NONE:
        case Direction::HORIZONTAL:
        case Direction::VERTICAL:
            _direction = dir;
            break;
        case Direction::BOTH:
            CCAssert(0, "TableView doesn't support both diretion!");
            break;
        default:
            CCAssert(0, "Unknown diretion!");
            break;
        }
    }

    void TableView::reloadData() {
        for (const auto &cell : _cellsUsed) {
            _delegate->tableCellWillRecycle(this, cell);
            _cellsFreed.pushBack(cell);

            cell->reset();
            if (cell->getParent() == _innerContainer) {
                _innerContainer->removeChild(cell, true);
            }
        }

        _indices.clear();
        _cellsUsed.clear();

        ssize_t cellsCount = _delegate->numberOfCellsInTableView(this);
        this->_updateCellPositions(cellsCount);
        this->_updateContentSize(cellsCount);
        if (cellsCount > 0) {
            _scrollViewDidScroll(cellsCount);
            this->processScrollingEvent();
        }
    }

    void TableView::reloadDataInplacement() {
        Vec2 pos = getInnerContainerPosition();
        const Vec2 offset1 = minContainerOffset();

        for (const auto &cell : _cellsUsed) {
            _delegate->tableCellWillRecycle(this, cell);
            _cellsFreed.pushBack(cell);

            cell->reset();
            if (cell->getParent() == _innerContainer) {
                _innerContainer->removeChild(cell, true);
            }
        }

        _indices.clear();
        _cellsUsed.clear();

        ssize_t cellsCount = _delegate->numberOfCellsInTableView(this);
        this->_updateCellPositions(cellsCount);
        this->_updateContentSize(cellsCount);

        const Vec2 offset2 = minContainerOffset();
        if (_direction == Direction::HORIZONTAL) {
            pos.x = std::max(pos.x, offset2.x);
            setInnerContainerPosition(pos);
        }
        else {
            if (_vordering == VerticalFillOrder::BOTTOM_UP) {
                pos.y = std::max(pos.y, offset2.y);
                setInnerContainerPosition(pos);
            }
            else {
                float temp = offset1.y - pos.y;
                pos.y = offset2.y - temp;
                pos.y = std::min(pos.y, 0.0f);
                setInnerContainerPosition(pos);
            }
        }

        if (cellsCount > 0) {
            _scrollViewDidScroll(cellsCount);
            this->processScrollingEvent();
        }
    }

    TableViewCell *TableView::cellAtIndex(ssize_t idx) {
        if (_indices.find(idx) != _indices.end()) {
            for (const auto &cell : _cellsUsed) {
                if (cell->getIdx() == idx) {
                    return cell;
                }
            }
        }

        return nullptr;
    }

    void TableView::updateCellAtIndex(ssize_t idx) {
        if (idx == CC_INVALID_INDEX) {
            return;
        }
        ssize_t countOfItems = _delegate->numberOfCellsInTableView(this);
        if (0 == countOfItems || idx > countOfItems-1) {
            return;
        }

        TableViewCell *cell = this->cellAtIndex(idx);
        if (cell != nullptr) {
            this->_moveCellOutOfSight(cell);
        }
        cell = _delegate->tableCellAtIndex(this, idx);
        this->_setIndexForCell(idx, cell);
        this->_addCellIfNecessary(cell);
    }

    void TableView::insertCellAtIndex(ssize_t idx) {
        if (idx == CC_INVALID_INDEX) {
            return;
        }

        ssize_t countOfItems = _delegate->numberOfCellsInTableView(this);
        if (0 == countOfItems || idx > countOfItems-1) {
            return;
        }

        long newIdx = 0;

        auto cell = cellAtIndex(idx);
        if (cell != nullptr) {
            newIdx = _cellsUsed.getIndex(cell);
            // Move all cells behind the inserted position
            for (ssize_t i = newIdx; i < _cellsUsed.size(); ++i) {
                cell = _cellsUsed.at(i);
                this->_setIndexForCell(cell->getIdx()+1, cell);
            }
        }

        //insert a new cell
        cell = _delegate->tableCellAtIndex(this, idx);
        this->_setIndexForCell(idx, cell);
        this->_addCellIfNecessary(cell);

        this->_updateCellPositions(countOfItems);
        this->_updateContentSize(countOfItems);

        if (countOfItems > 0) {
            _scrollViewDidScroll(countOfItems);
            this->processScrollingEvent();
        }
    }

    void TableView::removeCellAtIndex(ssize_t idx) {
        if (idx == CC_INVALID_INDEX) {
            return;
        }

        ssize_t countOfItems = _delegate->numberOfCellsInTableView(this);
        if (0 == countOfItems || idx + 1 > countOfItems) {
            return;
        }

        TableViewCell* cell = this->cellAtIndex(idx);
        if (cell == nullptr) {
            return;
        }

        ssize_t newIdx = _cellsUsed.getIndex(cell);

        //remove first
        this->_moveCellOutOfSight(cell);

        _indices.erase(idx);
        this->_updateCellPositions(countOfItems);
        this->_updateContentSize(countOfItems);

        for (ssize_t i = _cellsUsed.size() - 1; i > newIdx; --i) {
            cell = _cellsUsed.at(i);
            this->_setIndexForCell(cell->getIdx() - 1, cell);
        }

        if (countOfItems > 0) {
            _scrollViewDidScroll(countOfItems);
            this->processScrollingEvent();
        }
    }

    TableViewCell *TableView::dequeueCell() {
        TableViewCell *cell;
        if (_cellsFreed.empty()) {
            cell = nullptr;
        }
        else {
            cell = _cellsFreed.back();
            cell->retain();
            _cellsFreed.popBack();
            cell->autorelease();
        }
        return cell;
    }

    void TableView::_addCellIfNecessary(TableViewCell *cell) {
        if (cell->getParent() != _innerContainer) {
            _innerContainer->addChild(cell);
        }
        _cellsUsed.pushBack(cell);
        _indices.insert(cell->getIdx());
        _isUsedCellsDirty = true;
    }

    void TableView::_updateContentSize(ssize_t cellsCount) {
        Size size = Size::ZERO;
        if (cellsCount > 0) {
            float maxPosition = _cellsPositions[cellsCount];
            size = _contentSize;
            (_direction == Direction::HORIZONTAL ? size.width : size.height) = maxPosition;
        }

        this->setInnerContainerSize(size);
    }

    Vec2 TableView::_offsetFromIndex(ssize_t index) {
        Vec2 offset = this->__offsetFromIndex(index);

        Size cellSize = _delegate->tableCellSizeForIndex(this, index);
        if (_vordering == VerticalFillOrder::TOP_DOWN) {
            offset.y = _innerContainer->getContentSize().height - offset.y - cellSize.height;
        }
        return offset;
    }

    Vec2 TableView::__offsetFromIndex(ssize_t index) {
        Vec2 offset;
        (_direction == Direction::HORIZONTAL ? offset.x : offset.y) = _cellsPositions[index];
        return offset;
    }

    long TableView::_indexFromOffset(Vec2 offset, ssize_t cellsCount) {
        long index = 0;
        const long maxIdx = cellsCount - 1;

        if (_vordering == VerticalFillOrder::TOP_DOWN) {
            offset.y = _innerContainer->getContentSize().height - offset.y;
        }
        index = this->__indexFromOffset(offset, cellsCount);
        if (index != -1) {
            index = MAX(0, index);
            if (index > maxIdx) {
                index = CC_INVALID_INDEX;
            }
        }

        return index;
    }

    long TableView::__indexFromOffset(const Vec2 &offset, ssize_t cellsCount) {
        long low = 0;
        long high = cellsCount - 1;
        const float search = (_direction == Direction::HORIZONTAL ? offset.x : offset.y);

        // binary search
        while (high >= low) {
            long index = low + (high - low) / 2;
            const float cellStart = _cellsPositions[index];
            const float cellEnd = _cellsPositions[index + 1];

            if (search >= cellStart && search <= cellEnd) {
                return index;
            }
            else if (search < cellStart) {
                high = index - 1;
            }
            else {
                low = index + 1;
            }
        }
        return (low <= 0) ? 0 : -1;
    }

    void TableView::_moveCellOutOfSight(TableViewCell *cell) {
        _delegate->tableCellWillRecycle(this, cell);
        _cellsFreed.pushBack(cell);
        _cellsUsed.eraseObject(cell);
        _isUsedCellsDirty = true;

        _indices.erase(cell->getIdx());
        cell->reset();

        if (cell->getParent() == _innerContainer) {
            _innerContainer->removeChild(cell, true);
        }
    }

    void TableView::_setIndexForCell(ssize_t index, TableViewCell *cell) {
        cell->setAnchorPoint(Vec2(0.0f, 0.0f));
        cell->setPosition(this->_offsetFromIndex(index));
        cell->setIdx(index);
    }

    void TableView::_updateCellPositions(ssize_t cellsCount) {
        _cellsPositions.resize(cellsCount + 1, 0.0f);

        if (cellsCount > 0) {
            float currentPos = 0;
            Size cellSize;
            for (ssize_t i = 0; i < cellsCount; ++i) {
                _cellsPositions[i] = currentPos;
                cellSize = _delegate->tableCellSizeForIndex(this, i);
                currentPos += (_direction == Direction::HORIZONTAL ? cellSize.width : cellSize.height);
            }
            _cellsPositions[cellsCount] = currentPos;//1 extra value allows us to get right/bottom of the last cell
        }
    }

    Vec2 TableView::maxContainerOffset() {
        return Vec2(0, 0);
    }

    Vec2 TableView::minContainerOffset() {
        const Size &contentSize = _innerContainer->getContentSize();
        const Size &viewSize = _contentSize;
        return Vec2(viewSize.width - contentSize.width * _innerContainer->getScaleX(),
                    viewSize.height - contentSize.height * _innerContainer->getScaleY());
    }

    void TableView::_scrollViewDidScroll(ssize_t cellsCount) {
        if (0 == cellsCount) {
            return;
        }

        if (_isUsedCellsDirty) {
            _isUsedCellsDirty = false;
            std::sort(_cellsUsed.begin(), _cellsUsed.end(), [](TableViewCell *a, TableViewCell *b) -> bool{
                return a->getIdx() < b->getIdx();
            });
        }

        ssize_t startIdx = 0, endIdx = 0, idx = 0, maxIdx = 0;
        Vec2 offset = _innerContainer->getPosition();
        Vec2 maxOffset = maxContainerOffset();
        Vec2 minOffset = minContainerOffset();
        offset.x = std::min(maxOffset.x, offset.x);
        offset.x = std::max(minOffset.x, offset.x);
        offset.y = std::min(maxOffset.y, offset.y);
        offset.y = std::max(minOffset.y, offset.y);

        offset.x = -offset.x;
        offset.y = -offset.y;
        maxIdx = std::max((long)cellsCount - 1, 0L);

        if (_vordering == VerticalFillOrder::TOP_DOWN) {
            offset.y = offset.y + _contentSize.height / _innerContainer->getScaleY();
        }
        startIdx = this->_indexFromOffset(offset, cellsCount);
        if (startIdx == CC_INVALID_INDEX) {
            startIdx = cellsCount - 1;
        }

        if (_vordering == VerticalFillOrder::TOP_DOWN) {
            offset.y -= _contentSize.height / _innerContainer->getScaleY();
        }
        else {
            offset.y += _contentSize.height / _innerContainer->getScaleY();
        }
        offset.x += _contentSize.width / _innerContainer->getScaleX();

        endIdx = this->_indexFromOffset(offset, cellsCount);
        if (endIdx == CC_INVALID_INDEX) {
            endIdx = cellsCount - 1;
        }

#if 0 // For Testing.
        int i = 0;
        std::for_each(_cellsUsed.begin(), _cellsUsed.end(), [&i](TableViewCell* pCell) {
            log("cells Used index %d, value = %lu", i, pCell->getIdx());
            ++i;
        });
        log("---------------------------------------");
        i = 0;
        std::for_each(_cellsFreed.begin(), _cellsFreed.end(), [&i](TableViewCell* pCell) {
            log("cells freed index %d, value = %lu", i, pCell->getIdx());
            ++i;
        });
        log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
#endif

        if (!_cellsUsed.empty()) {
            auto cell = _cellsUsed.at(0);
            idx = cell->getIdx();

            while (idx < startIdx) {
                this->_moveCellOutOfSight(cell);
                CC_BREAK_IF(_cellsUsed.empty());
                cell = _cellsUsed.at(0);
                idx = cell->getIdx();
            }
        }
        if (!_cellsUsed.empty()) {
            auto cell = _cellsUsed.back();
            idx = cell->getIdx();

            while (idx <= maxIdx && idx > endIdx) {
                this->_moveCellOutOfSight(cell);
                CC_BREAK_IF(_cellsUsed.empty());
                cell = _cellsUsed.back();
                idx = cell->getIdx();
            }
        }

        for (ssize_t i = startIdx; i <= endIdx; ++i) {
            if (_indices.find(i) == _indices.end()) {
                this->updateCellAtIndex(i);
            }
        }
    }

    void TableView::moveInnerContainer(const Vec2& deltaMove, bool canStartBounceBack) {
        ScrollView::moveInnerContainer(deltaMove, canStartBounceBack);
        ssize_t cellsCount = _delegate->numberOfCellsInTableView(this);
        _scrollViewDidScroll(cellsCount);
    }
}
<commit_msg>MAX->std::max<commit_after>#include "CWTableView.h"

using namespace cocos2d;
using namespace cocos2d::ui;

namespace cw {
    TableView::TableView()
    : _vordering(VerticalFillOrder::BOTTOM_UP)
    , _isUsedCellsDirty(false)
    , _delegate(nullptr) {

    }

    TableView::~TableView() {
    }

    TableView *TableView::create() {
        TableView *table = new (std::nothrow) TableView();
        if (table != nullptr && table->init()) {
            table->autorelease();
            return table;
        }
        CC_SAFE_DELETE(table);
        return NULL;
    }

    bool TableView::init() {
        if (!ScrollView::init()) {
            return false;
        }
        _cellsPositions.clear();

        _cellsUsed.clear();
        _cellsFreed.clear();
        _indices.clear();
        _vordering = VerticalFillOrder::BOTTOM_UP;
        this->setDirection(Direction::VERTICAL);

        return true;
    }

    void TableView::onSizeChanged() {
        Size orginSize = _innerContainer->getContentSize();
        Vec2 orginPos = _innerContainer->getPosition();
        ScrollView::onSizeChanged();
        if (orginSize.equals(_innerContainer->getContentSize())) {
            _innerContainer->setPosition(orginPos);
        }
    }

    void TableView::setVerticalFillOrder(VerticalFillOrder fillOrder) {
        if (_vordering != fillOrder) {
            _vordering = fillOrder;
            if (!_cellsUsed.empty()) {
                this->reloadData();
            }
        }
    }

    TableView::VerticalFillOrder TableView::getVerticalFillOrder() {
        return _vordering;
    }

    void TableView::setDirection(Direction dir) {
        switch (_direction) {
        case Direction::NONE:
        case Direction::HORIZONTAL:
        case Direction::VERTICAL:
            _direction = dir;
            break;
        case Direction::BOTH:
            CCAssert(0, "TableView doesn't support both diretion!");
            break;
        default:
            CCAssert(0, "Unknown diretion!");
            break;
        }
    }

    void TableView::reloadData() {
        for (const auto &cell : _cellsUsed) {
            _delegate->tableCellWillRecycle(this, cell);
            _cellsFreed.pushBack(cell);

            cell->reset();
            if (cell->getParent() == _innerContainer) {
                _innerContainer->removeChild(cell, true);
            }
        }

        _indices.clear();
        _cellsUsed.clear();

        ssize_t cellsCount = _delegate->numberOfCellsInTableView(this);
        this->_updateCellPositions(cellsCount);
        this->_updateContentSize(cellsCount);
        if (cellsCount > 0) {
            _scrollViewDidScroll(cellsCount);
            this->processScrollingEvent();
        }
    }

    void TableView::reloadDataInplacement() {
        Vec2 pos = getInnerContainerPosition();
        const Vec2 offset1 = minContainerOffset();

        for (const auto &cell : _cellsUsed) {
            _delegate->tableCellWillRecycle(this, cell);
            _cellsFreed.pushBack(cell);

            cell->reset();
            if (cell->getParent() == _innerContainer) {
                _innerContainer->removeChild(cell, true);
            }
        }

        _indices.clear();
        _cellsUsed.clear();

        ssize_t cellsCount = _delegate->numberOfCellsInTableView(this);
        this->_updateCellPositions(cellsCount);
        this->_updateContentSize(cellsCount);

        const Vec2 offset2 = minContainerOffset();
        if (_direction == Direction::HORIZONTAL) {
            pos.x = std::max(pos.x, offset2.x);
            setInnerContainerPosition(pos);
        }
        else {
            if (_vordering == VerticalFillOrder::BOTTOM_UP) {
                pos.y = std::max(pos.y, offset2.y);
                setInnerContainerPosition(pos);
            }
            else {
                float temp = offset1.y - pos.y;
                pos.y = offset2.y - temp;
                pos.y = std::min(pos.y, 0.0f);
                setInnerContainerPosition(pos);
            }
        }

        if (cellsCount > 0) {
            _scrollViewDidScroll(cellsCount);
            this->processScrollingEvent();
        }
    }

    TableViewCell *TableView::cellAtIndex(ssize_t idx) {
        if (_indices.find(idx) != _indices.end()) {
            for (const auto &cell : _cellsUsed) {
                if (cell->getIdx() == idx) {
                    return cell;
                }
            }
        }

        return nullptr;
    }

    void TableView::updateCellAtIndex(ssize_t idx) {
        if (idx == CC_INVALID_INDEX) {
            return;
        }
        ssize_t countOfItems = _delegate->numberOfCellsInTableView(this);
        if (0 == countOfItems || idx > countOfItems-1) {
            return;
        }

        TableViewCell *cell = this->cellAtIndex(idx);
        if (cell != nullptr) {
            this->_moveCellOutOfSight(cell);
        }
        cell = _delegate->tableCellAtIndex(this, idx);
        this->_setIndexForCell(idx, cell);
        this->_addCellIfNecessary(cell);
    }

    void TableView::insertCellAtIndex(ssize_t idx) {
        if (idx == CC_INVALID_INDEX) {
            return;
        }

        ssize_t countOfItems = _delegate->numberOfCellsInTableView(this);
        if (0 == countOfItems || idx > countOfItems-1) {
            return;
        }

        long newIdx = 0;

        auto cell = cellAtIndex(idx);
        if (cell != nullptr) {
            newIdx = _cellsUsed.getIndex(cell);
            // Move all cells behind the inserted position
            for (ssize_t i = newIdx; i < _cellsUsed.size(); ++i) {
                cell = _cellsUsed.at(i);
                this->_setIndexForCell(cell->getIdx()+1, cell);
            }
        }

        //insert a new cell
        cell = _delegate->tableCellAtIndex(this, idx);
        this->_setIndexForCell(idx, cell);
        this->_addCellIfNecessary(cell);

        this->_updateCellPositions(countOfItems);
        this->_updateContentSize(countOfItems);

        if (countOfItems > 0) {
            _scrollViewDidScroll(countOfItems);
            this->processScrollingEvent();
        }
    }

    void TableView::removeCellAtIndex(ssize_t idx) {
        if (idx == CC_INVALID_INDEX) {
            return;
        }

        ssize_t countOfItems = _delegate->numberOfCellsInTableView(this);
        if (0 == countOfItems || idx + 1 > countOfItems) {
            return;
        }

        TableViewCell* cell = this->cellAtIndex(idx);
        if (cell == nullptr) {
            return;
        }

        ssize_t newIdx = _cellsUsed.getIndex(cell);

        //remove first
        this->_moveCellOutOfSight(cell);

        _indices.erase(idx);
        this->_updateCellPositions(countOfItems);
        this->_updateContentSize(countOfItems);

        for (ssize_t i = _cellsUsed.size() - 1; i > newIdx; --i) {
            cell = _cellsUsed.at(i);
            this->_setIndexForCell(cell->getIdx() - 1, cell);
        }

        if (countOfItems > 0) {
            _scrollViewDidScroll(countOfItems);
            this->processScrollingEvent();
        }
    }

    TableViewCell *TableView::dequeueCell() {
        TableViewCell *cell;
        if (_cellsFreed.empty()) {
            cell = nullptr;
        }
        else {
            cell = _cellsFreed.back();
            cell->retain();
            _cellsFreed.popBack();
            cell->autorelease();
        }
        return cell;
    }

    void TableView::_addCellIfNecessary(TableViewCell *cell) {
        if (cell->getParent() != _innerContainer) {
            _innerContainer->addChild(cell);
        }
        _cellsUsed.pushBack(cell);
        _indices.insert(cell->getIdx());
        _isUsedCellsDirty = true;
    }

    void TableView::_updateContentSize(ssize_t cellsCount) {
        Size size = Size::ZERO;
        if (cellsCount > 0) {
            float maxPosition = _cellsPositions[cellsCount];
            size = _contentSize;
            (_direction == Direction::HORIZONTAL ? size.width : size.height) = maxPosition;
        }

        this->setInnerContainerSize(size);
    }

    Vec2 TableView::_offsetFromIndex(ssize_t index) {
        Vec2 offset = this->__offsetFromIndex(index);

        Size cellSize = _delegate->tableCellSizeForIndex(this, index);
        if (_vordering == VerticalFillOrder::TOP_DOWN) {
            offset.y = _innerContainer->getContentSize().height - offset.y - cellSize.height;
        }
        return offset;
    }

    Vec2 TableView::__offsetFromIndex(ssize_t index) {
        Vec2 offset;
        (_direction == Direction::HORIZONTAL ? offset.x : offset.y) = _cellsPositions[index];
        return offset;
    }

    long TableView::_indexFromOffset(Vec2 offset, ssize_t cellsCount) {
        long index = 0;
        const long maxIdx = cellsCount - 1;

        if (_vordering == VerticalFillOrder::TOP_DOWN) {
            offset.y = _innerContainer->getContentSize().height - offset.y;
        }
        index = this->__indexFromOffset(offset, cellsCount);
        if (index != -1) {
            index = std::max(0L, index);
            if (index > maxIdx) {
                index = CC_INVALID_INDEX;
            }
        }

        return index;
    }

    long TableView::__indexFromOffset(const Vec2 &offset, ssize_t cellsCount) {
        long low = 0;
        long high = cellsCount - 1;
        const float search = (_direction == Direction::HORIZONTAL ? offset.x : offset.y);

        // binary search
        while (high >= low) {
            long index = low + (high - low) / 2;
            const float cellStart = _cellsPositions[index];
            const float cellEnd = _cellsPositions[index + 1];

            if (search >= cellStart && search <= cellEnd) {
                return index;
            }
            else if (search < cellStart) {
                high = index - 1;
            }
            else {
                low = index + 1;
            }
        }
        return (low <= 0) ? 0 : -1;
    }

    void TableView::_moveCellOutOfSight(TableViewCell *cell) {
        _delegate->tableCellWillRecycle(this, cell);
        _cellsFreed.pushBack(cell);
        _cellsUsed.eraseObject(cell);
        _isUsedCellsDirty = true;

        _indices.erase(cell->getIdx());
        cell->reset();

        if (cell->getParent() == _innerContainer) {
            _innerContainer->removeChild(cell, true);
        }
    }

    void TableView::_setIndexForCell(ssize_t index, TableViewCell *cell) {
        cell->setAnchorPoint(Vec2(0.0f, 0.0f));
        cell->setPosition(this->_offsetFromIndex(index));
        cell->setIdx(index);
    }

    void TableView::_updateCellPositions(ssize_t cellsCount) {
        _cellsPositions.resize(cellsCount + 1, 0.0f);

        if (cellsCount > 0) {
            float currentPos = 0;
            Size cellSize;
            for (ssize_t i = 0; i < cellsCount; ++i) {
                _cellsPositions[i] = currentPos;
                cellSize = _delegate->tableCellSizeForIndex(this, i);
                currentPos += (_direction == Direction::HORIZONTAL ? cellSize.width : cellSize.height);
            }
            _cellsPositions[cellsCount] = currentPos;//1 extra value allows us to get right/bottom of the last cell
        }
    }

    Vec2 TableView::maxContainerOffset() {
        return Vec2(0, 0);
    }

    Vec2 TableView::minContainerOffset() {
        const Size &contentSize = _innerContainer->getContentSize();
        const Size &viewSize = _contentSize;
        return Vec2(viewSize.width - contentSize.width * _innerContainer->getScaleX(),
                    viewSize.height - contentSize.height * _innerContainer->getScaleY());
    }

    void TableView::_scrollViewDidScroll(ssize_t cellsCount) {
        if (0 == cellsCount) {
            return;
        }

        if (_isUsedCellsDirty) {
            _isUsedCellsDirty = false;
            std::sort(_cellsUsed.begin(), _cellsUsed.end(), [](TableViewCell *a, TableViewCell *b) -> bool{
                return a->getIdx() < b->getIdx();
            });
        }

        ssize_t startIdx = 0, endIdx = 0, idx = 0, maxIdx = 0;
        Vec2 offset = _innerContainer->getPosition();
        Vec2 maxOffset = maxContainerOffset();
        Vec2 minOffset = minContainerOffset();
        offset.x = std::min(maxOffset.x, offset.x);
        offset.x = std::max(minOffset.x, offset.x);
        offset.y = std::min(maxOffset.y, offset.y);
        offset.y = std::max(minOffset.y, offset.y);

        offset.x = -offset.x;
        offset.y = -offset.y;
        maxIdx = std::max((long)cellsCount - 1, 0L);

        if (_vordering == VerticalFillOrder::TOP_DOWN) {
            offset.y = offset.y + _contentSize.height / _innerContainer->getScaleY();
        }
        startIdx = this->_indexFromOffset(offset, cellsCount);
        if (startIdx == CC_INVALID_INDEX) {
            startIdx = cellsCount - 1;
        }

        if (_vordering == VerticalFillOrder::TOP_DOWN) {
            offset.y -= _contentSize.height / _innerContainer->getScaleY();
        }
        else {
            offset.y += _contentSize.height / _innerContainer->getScaleY();
        }
        offset.x += _contentSize.width / _innerContainer->getScaleX();

        endIdx = this->_indexFromOffset(offset, cellsCount);
        if (endIdx == CC_INVALID_INDEX) {
            endIdx = cellsCount - 1;
        }

#if 0 // For Testing.
        int i = 0;
        std::for_each(_cellsUsed.begin(), _cellsUsed.end(), [&i](TableViewCell* pCell) {
            log("cells Used index %d, value = %lu", i, pCell->getIdx());
            ++i;
        });
        log("---------------------------------------");
        i = 0;
        std::for_each(_cellsFreed.begin(), _cellsFreed.end(), [&i](TableViewCell* pCell) {
            log("cells freed index %d, value = %lu", i, pCell->getIdx());
            ++i;
        });
        log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
#endif

        if (!_cellsUsed.empty()) {
            auto cell = _cellsUsed.at(0);
            idx = cell->getIdx();

            while (idx < startIdx) {
                this->_moveCellOutOfSight(cell);
                CC_BREAK_IF(_cellsUsed.empty());
                cell = _cellsUsed.at(0);
                idx = cell->getIdx();
            }
        }
        if (!_cellsUsed.empty()) {
            auto cell = _cellsUsed.back();
            idx = cell->getIdx();

            while (idx <= maxIdx && idx > endIdx) {
                this->_moveCellOutOfSight(cell);
                CC_BREAK_IF(_cellsUsed.empty());
                cell = _cellsUsed.back();
                idx = cell->getIdx();
            }
        }

        for (ssize_t i = startIdx; i <= endIdx; ++i) {
            if (_indices.find(i) == _indices.end()) {
                this->updateCellAtIndex(i);
            }
        }
    }

    void TableView::moveInnerContainer(const Vec2& deltaMove, bool canStartBounceBack) {
        ScrollView::moveInnerContainer(deltaMove, canStartBounceBack);
        ssize_t cellsCount = _delegate->numberOfCellsInTableView(this);
        _scrollViewDidScroll(cellsCount);
    }
}
<|endoftext|>