<commit_before>//===-- LiveVariables.cpp - Live Variable Analysis for Machine Code -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the LiveVariable analysis pass.  For each machine
// instruction in the function, this pass calculates the set of registers that
// are immediately dead after the instruction (i.e., the instruction calculates
// the value, but it is never used) and the set of registers that are used by
// the instruction, but are never used after the instruction (i.e., they are
// killed).
//
// This class computes live variables using are sparse implementation based on
// the machine code SSA form.  This class computes live variable information for
// each virtual and _register allocatable_ physical register in a function.  It
// uses the dominance properties of SSA form to efficiently compute live
// variables for virtual registers, and assumes that physical registers are only
// live within a single basic block (allowing it to do a single local analysis
// to resolve physical register lifetimes in each basic block).  If a physical
// register is not register allocatable, it is not tracked.  This is useful for
// things like the stack pointer and condition codes.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/STLExtras.h"
using namespace llvm;

static RegisterAnalysis<LiveVariables> X("livevars", "Live Variable Analysis");

LiveVariables::VarInfo &LiveVariables::getVarInfo(unsigned RegIdx) {
  assert(MRegisterInfo::isVirtualRegister(RegIdx) &&
         "getVarInfo: not a virtual register!");
  RegIdx -= MRegisterInfo::FirstVirtualRegister;
  if (RegIdx >= VirtRegInfo.size()) {
    if (RegIdx >= 2*VirtRegInfo.size())
      VirtRegInfo.resize(RegIdx*2);
    else
      VirtRegInfo.resize(2*VirtRegInfo.size());
  }
  return VirtRegInfo[RegIdx];
}

void LiveVariables::MarkVirtRegAliveInBlock(VarInfo &VRInfo,
                                            MachineBasicBlock *MBB) {
  unsigned BBNum = MBB->getNumber();

  // Check to see if this basic block is one of the killing blocks.  If so,
  // remove it...
  for (unsigned i = 0, e = VRInfo.Kills.size(); i != e; ++i)
    if (VRInfo.Kills[i]->getParent() == MBB) {
      VRInfo.Kills.erase(VRInfo.Kills.begin()+i);  // Erase entry
      break;
    }

  if (MBB == VRInfo.DefInst->getParent()) return;  // Terminate recursion

  if (VRInfo.AliveBlocks.size() <= BBNum)
    VRInfo.AliveBlocks.resize(BBNum+1);  // Make space...

  if (VRInfo.AliveBlocks[BBNum])
    return;  // We already know the block is live

  // Mark the variable known alive in this bb
  VRInfo.AliveBlocks[BBNum] = true;

  for (MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(),
         E = MBB->pred_end(); PI != E; ++PI)
    MarkVirtRegAliveInBlock(VRInfo, *PI);
}

void LiveVariables::HandleVirtRegUse(VarInfo &VRInfo, MachineBasicBlock *MBB,
                                     MachineInstr *MI) {
  assert(VRInfo.DefInst && "Register use before def!");

  // Check to see if this basic block is already a kill block...
  if (!VRInfo.Kills.empty() && VRInfo.Kills.back()->getParent() == MBB) {
    // Yes, this register is killed in this basic block already.  Increase the
    // live range by updating the kill instruction.
    VRInfo.Kills.back() = MI;
    return;
  }

#ifndef NDEBUG
  for (unsigned i = 0, e = VRInfo.Kills.size(); i != e; ++i)
    assert(VRInfo.Kills[i]->getParent() != MBB && "entry should be at end!");
#endif

  assert(MBB != VRInfo.DefInst->getParent() &&
         "Should have kill for defblock!");

  // Add a new kill entry for this basic block.
  VRInfo.Kills.push_back(MI);

  // Update all dominating blocks to mark them known live.
  for (MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(),
         E = MBB->pred_end(); PI != E; ++PI)
    MarkVirtRegAliveInBlock(VRInfo, *PI);
}

void LiveVariables::HandlePhysRegUse(unsigned Reg, MachineInstr *MI) {
  PhysRegInfo[Reg] = MI;
  PhysRegUsed[Reg] = true;

  for (const unsigned *AliasSet = RegInfo->getAliasSet(Reg);
       unsigned Alias = *AliasSet; ++AliasSet) {
    PhysRegInfo[Alias] = MI;
    PhysRegUsed[Alias] = true;
  }
}

void LiveVariables::HandlePhysRegDef(unsigned Reg, MachineInstr *MI) {
  // Does this kill a previous version of this register?
  if (MachineInstr *LastUse = PhysRegInfo[Reg]) {
    if (PhysRegUsed[Reg])
      RegistersKilled.insert(std::make_pair(LastUse, Reg));
    else
      RegistersDead.insert(std::make_pair(LastUse, Reg));
  }
  PhysRegInfo[Reg] = MI;
  PhysRegUsed[Reg] = false;

  for (const unsigned *AliasSet = RegInfo->getAliasSet(Reg);
       unsigned Alias = *AliasSet; ++AliasSet) {
    if (MachineInstr *LastUse = PhysRegInfo[Alias]) {
      if (PhysRegUsed[Alias])
        RegistersKilled.insert(std::make_pair(LastUse, Alias));
      else
        RegistersDead.insert(std::make_pair(LastUse, Alias));
    }
    PhysRegInfo[Alias] = MI;
    PhysRegUsed[Alias] = false;
  }
}

bool LiveVariables::runOnMachineFunction(MachineFunction &MF) {
  const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
  RegInfo = MF.getTarget().getRegisterInfo();
  assert(RegInfo && "Target doesn't have register information?");

  AllocatablePhysicalRegisters = RegInfo->getAllocatableSet(MF);

  // PhysRegInfo - Keep track of which instruction was the last use of a
  // physical register.  This is a purely local property, because all physical
  // register references as presumed dead across basic blocks.
  //
  MachineInstr *PhysRegInfoA[RegInfo->getNumRegs()];
  bool          PhysRegUsedA[RegInfo->getNumRegs()];
  std::fill(PhysRegInfoA, PhysRegInfoA+RegInfo->getNumRegs(), (MachineInstr*)0);
  PhysRegInfo = PhysRegInfoA;
  PhysRegUsed = PhysRegUsedA;

  /// Get some space for a respectable number of registers...
  VirtRegInfo.resize(64);

  // Calculate live variable information in depth first order on the CFG of the
  // function.  This guarantees that we will see the definition of a virtual
  // register before its uses due to dominance properties of SSA (except for PHI
  // nodes, which are treated as a special case).
  //
  MachineBasicBlock *Entry = MF.begin();
  std::set<MachineBasicBlock*> Visited;
  for (df_ext_iterator<MachineBasicBlock*> DFI = df_ext_begin(Entry, Visited),
         E = df_ext_end(Entry, Visited); DFI != E; ++DFI) {
    MachineBasicBlock *MBB = *DFI;
    unsigned BBNum = MBB->getNumber();

    // Loop over all of the instructions, processing them.
    for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end();
         I != E; ++I) {
      MachineInstr *MI = I;
      const TargetInstrDescriptor &MID = TII.get(MI->getOpcode());

      // Process all of the operands of the instruction...
      unsigned NumOperandsToProcess = MI->getNumOperands();

      // Unless it is a PHI node.  In this case, ONLY process the DEF, not any
      // of the uses.  They will be handled in other basic blocks.
      if (MI->getOpcode() == TargetInstrInfo::PHI)
        NumOperandsToProcess = 1;

      // Loop over implicit uses, using them.
      for (const unsigned *ImplicitUses = MID.ImplicitUses;
           *ImplicitUses; ++ImplicitUses)
        HandlePhysRegUse(*ImplicitUses, MI);

      // Process all explicit uses...
      for (unsigned i = 0; i != NumOperandsToProcess; ++i) {
        MachineOperand &MO = MI->getOperand(i);
        if (MO.isUse() && MO.isRegister() && MO.getReg()) {
          if (MRegisterInfo::isVirtualRegister(MO.getReg())){
            HandleVirtRegUse(getVarInfo(MO.getReg()), MBB, MI);
          } else if (MRegisterInfo::isPhysicalRegister(MO.getReg()) &&
                     AllocatablePhysicalRegisters[MO.getReg()]) {
            HandlePhysRegUse(MO.getReg(), MI);
          }
        }
      }

      // Loop over implicit defs, defining them.
      for (const unsigned *ImplicitDefs = MID.ImplicitDefs;
           *ImplicitDefs; ++ImplicitDefs)
        HandlePhysRegDef(*ImplicitDefs, MI);

      // Process all explicit defs...
      for (unsigned i = 0; i != NumOperandsToProcess; ++i) {
        MachineOperand &MO = MI->getOperand(i);
        if (MO.isDef() && MO.isRegister() && MO.getReg()) {
          if (MRegisterInfo::isVirtualRegister(MO.getReg())) {
            VarInfo &VRInfo = getVarInfo(MO.getReg());

            assert(VRInfo.DefInst == 0 && "Variable multiply defined!");
            VRInfo.DefInst = MI;
            // Defaults to dead
            VRInfo.Kills.push_back(MI);
          } else if (MRegisterInfo::isPhysicalRegister(MO.getReg()) &&
                     AllocatablePhysicalRegisters[MO.getReg()]) {
            HandlePhysRegDef(MO.getReg(), MI);
          }
        }
      }
    }

    // Handle any virtual assignments from PHI nodes which might be at the
    // bottom of this basic block.  We check all of our successor blocks to see
    // if they have PHI nodes, and if so, we simulate an assignment at the end
    // of the current block.
    for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(),
           E = MBB->succ_end(); SI != E; ++SI) {
      MachineBasicBlock *Succ = *SI;

      // PHI nodes are guaranteed to be at the top of the block...
      for (MachineBasicBlock::iterator MI = Succ->begin(), ME = Succ->end();
           MI != ME && MI->getOpcode() == TargetInstrInfo::PHI; ++MI) {
        for (unsigned i = 1; ; i += 2) {
          assert(MI->getNumOperands() > i+1 &&
                 "Didn't find an entry for our predecessor??");
          if (MI->getOperand(i+1).getMachineBasicBlock() == MBB) {
            MachineOperand &MO = MI->getOperand(i);
            if (!MO.getVRegValueOrNull()) {
              VarInfo &VRInfo = getVarInfo(MO.getReg());

              // Only mark it alive only in the block we are representing...
              MarkVirtRegAliveInBlock(VRInfo, MBB);
              break;   // Found the PHI entry for this block...
            }
          }
        }
      }
    }

    // Loop over PhysRegInfo, killing any registers that are available at the
    // end of the basic block.  This also resets the PhysRegInfo map.
    for (unsigned i = 0, e = RegInfo->getNumRegs(); i != e; ++i)
      if (PhysRegInfo[i])
        HandlePhysRegDef(i, 0);
  }

  // Convert the information we have gathered into VirtRegInfo and transform it
  // into a form usable by RegistersKilled.
  //
  for (unsigned i = 0, e = VirtRegInfo.size(); i != e; ++i)
    for (unsigned j = 0, e = VirtRegInfo[i].Kills.size(); j != e; ++j) {
      if (VirtRegInfo[i].Kills[j] == VirtRegInfo[i].DefInst)
        RegistersDead.insert(std::make_pair(VirtRegInfo[i].Kills[j],
                             i + MRegisterInfo::FirstVirtualRegister));

      else
        RegistersKilled.insert(std::make_pair(VirtRegInfo[i].Kills[j],
                               i + MRegisterInfo::FirstVirtualRegister));
    }

  // Check to make sure there are no unreachable blocks in the MC CFG for the
  // function.  If so, it is due to a bug in the instruction selector or some
  // other part of the code generator if this happens.
#ifndef NDEBUG
  for(MachineFunction::iterator i = MF.begin(), e = MF.end(); i != e; ++i)
    assert(Visited.count(&*i) != 0 && "unreachable basic block found");
#endif

  return false;
}

/// instructionChanged - When the address of an instruction changes, this
/// method should be called so that live variables can update its internal
/// data structures.  This removes the records for OldMI, transfering them to
/// the records for NewMI.
void LiveVariables::instructionChanged(MachineInstr *OldMI,
                                       MachineInstr *NewMI) {
  // If the instruction defines any virtual registers, update the VarInfo for
  // the instruction.
  for (unsigned i = 0, e = OldMI->getNumOperands(); i != e; ++i) {
    MachineOperand &MO = OldMI->getOperand(i);
    if (MO.isRegister() && MO.isDef() && MO.getReg() &&
        MRegisterInfo::isVirtualRegister(MO.getReg())) {
      unsigned Reg = MO.getReg();
      VarInfo &VI = getVarInfo(Reg);
      if (VI.DefInst == OldMI)
        VI.DefInst = NewMI;
    }
  }

  // Move the killed information over...
  killed_iterator I, E;
  tie(I, E) = killed_range(OldMI);
  std::vector<unsigned> Regs;
  for (killed_iterator A = I; A != E; ++A)
    Regs.push_back(A->second);
  RegistersKilled.erase(I, E);

  for (unsigned i = 0, e = Regs.size(); i != e; ++i)
    RegistersKilled.insert(std::make_pair(NewMI, Regs[i]));
  Regs.clear();

  // Move the dead information over...
  tie(I, E) = dead_range(OldMI);
  for (killed_iterator A = I; A != E; ++A)
    Regs.push_back(A->second);
  RegistersDead.erase(I, E);

  for (unsigned i = 0, e = Regs.size(); i != e; ++i)
    RegistersDead.insert(std::make_pair(NewMI, Regs[i]));
}
<commit_msg>Do not use variable sized arrays in C++, they are non-portable.  Patch contributed by Morten Ofstad<commit_after>//===-- LiveVariables.cpp - Live Variable Analysis for Machine Code -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the LiveVariable analysis pass.  For each machine
// instruction in the function, this pass calculates the set of registers that
// are immediately dead after the instruction (i.e., the instruction calculates
// the value, but it is never used) and the set of registers that are used by
// the instruction, but are never used after the instruction (i.e., they are
// killed).
//
// This class computes live variables using are sparse implementation based on
// the machine code SSA form.  This class computes live variable information for
// each virtual and _register allocatable_ physical register in a function.  It
// uses the dominance properties of SSA form to efficiently compute live
// variables for virtual registers, and assumes that physical registers are only
// live within a single basic block (allowing it to do a single local analysis
// to resolve physical register lifetimes in each basic block).  If a physical
// register is not register allocatable, it is not tracked.  This is useful for
// things like the stack pointer and condition codes.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/alloca.h"
using namespace llvm;

static RegisterAnalysis<LiveVariables> X("livevars", "Live Variable Analysis");

LiveVariables::VarInfo &LiveVariables::getVarInfo(unsigned RegIdx) {
  assert(MRegisterInfo::isVirtualRegister(RegIdx) &&
         "getVarInfo: not a virtual register!");
  RegIdx -= MRegisterInfo::FirstVirtualRegister;
  if (RegIdx >= VirtRegInfo.size()) {
    if (RegIdx >= 2*VirtRegInfo.size())
      VirtRegInfo.resize(RegIdx*2);
    else
      VirtRegInfo.resize(2*VirtRegInfo.size());
  }
  return VirtRegInfo[RegIdx];
}

void LiveVariables::MarkVirtRegAliveInBlock(VarInfo &VRInfo,
                                            MachineBasicBlock *MBB) {
  unsigned BBNum = MBB->getNumber();

  // Check to see if this basic block is one of the killing blocks.  If so,
  // remove it...
  for (unsigned i = 0, e = VRInfo.Kills.size(); i != e; ++i)
    if (VRInfo.Kills[i]->getParent() == MBB) {
      VRInfo.Kills.erase(VRInfo.Kills.begin()+i);  // Erase entry
      break;
    }

  if (MBB == VRInfo.DefInst->getParent()) return;  // Terminate recursion

  if (VRInfo.AliveBlocks.size() <= BBNum)
    VRInfo.AliveBlocks.resize(BBNum+1);  // Make space...

  if (VRInfo.AliveBlocks[BBNum])
    return;  // We already know the block is live

  // Mark the variable known alive in this bb
  VRInfo.AliveBlocks[BBNum] = true;

  for (MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(),
         E = MBB->pred_end(); PI != E; ++PI)
    MarkVirtRegAliveInBlock(VRInfo, *PI);
}

void LiveVariables::HandleVirtRegUse(VarInfo &VRInfo, MachineBasicBlock *MBB,
                                     MachineInstr *MI) {
  assert(VRInfo.DefInst && "Register use before def!");

  // Check to see if this basic block is already a kill block...
  if (!VRInfo.Kills.empty() && VRInfo.Kills.back()->getParent() == MBB) {
    // Yes, this register is killed in this basic block already.  Increase the
    // live range by updating the kill instruction.
    VRInfo.Kills.back() = MI;
    return;
  }

#ifndef NDEBUG
  for (unsigned i = 0, e = VRInfo.Kills.size(); i != e; ++i)
    assert(VRInfo.Kills[i]->getParent() != MBB && "entry should be at end!");
#endif

  assert(MBB != VRInfo.DefInst->getParent() &&
         "Should have kill for defblock!");

  // Add a new kill entry for this basic block.
  VRInfo.Kills.push_back(MI);

  // Update all dominating blocks to mark them known live.
  for (MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(),
         E = MBB->pred_end(); PI != E; ++PI)
    MarkVirtRegAliveInBlock(VRInfo, *PI);
}

void LiveVariables::HandlePhysRegUse(unsigned Reg, MachineInstr *MI) {
  PhysRegInfo[Reg] = MI;
  PhysRegUsed[Reg] = true;

  for (const unsigned *AliasSet = RegInfo->getAliasSet(Reg);
       unsigned Alias = *AliasSet; ++AliasSet) {
    PhysRegInfo[Alias] = MI;
    PhysRegUsed[Alias] = true;
  }
}

void LiveVariables::HandlePhysRegDef(unsigned Reg, MachineInstr *MI) {
  // Does this kill a previous version of this register?
  if (MachineInstr *LastUse = PhysRegInfo[Reg]) {
    if (PhysRegUsed[Reg])
      RegistersKilled.insert(std::make_pair(LastUse, Reg));
    else
      RegistersDead.insert(std::make_pair(LastUse, Reg));
  }
  PhysRegInfo[Reg] = MI;
  PhysRegUsed[Reg] = false;

  for (const unsigned *AliasSet = RegInfo->getAliasSet(Reg);
       unsigned Alias = *AliasSet; ++AliasSet) {
    if (MachineInstr *LastUse = PhysRegInfo[Alias]) {
      if (PhysRegUsed[Alias])
        RegistersKilled.insert(std::make_pair(LastUse, Alias));
      else
        RegistersDead.insert(std::make_pair(LastUse, Alias));
    }
    PhysRegInfo[Alias] = MI;
    PhysRegUsed[Alias] = false;
  }
}

bool LiveVariables::runOnMachineFunction(MachineFunction &MF) {
  const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
  RegInfo = MF.getTarget().getRegisterInfo();
  assert(RegInfo && "Target doesn't have register information?");

  AllocatablePhysicalRegisters = RegInfo->getAllocatableSet(MF);

  // PhysRegInfo - Keep track of which instruction was the last use of a
  // physical register.  This is a purely local property, because all physical
  // register references as presumed dead across basic blocks.
  //
  PhysRegInfo = (MachineInstr**)alloca(sizeof(MachineInstr*) *
                                       RegInfo->getNumRegs());
  PhysRegUsed = (bool*)alloca(sizeof(bool)*RegInfo->getNumRegs());
  std::fill(PhysRegInfo, PhysRegInfo+RegInfo->getNumRegs(), (MachineInstr*)0);

  /// Get some space for a respectable number of registers...
  VirtRegInfo.resize(64);

  // Calculate live variable information in depth first order on the CFG of the
  // function.  This guarantees that we will see the definition of a virtual
  // register before its uses due to dominance properties of SSA (except for PHI
  // nodes, which are treated as a special case).
  //
  MachineBasicBlock *Entry = MF.begin();
  std::set<MachineBasicBlock*> Visited;
  for (df_ext_iterator<MachineBasicBlock*> DFI = df_ext_begin(Entry, Visited),
         E = df_ext_end(Entry, Visited); DFI != E; ++DFI) {
    MachineBasicBlock *MBB = *DFI;
    unsigned BBNum = MBB->getNumber();

    // Loop over all of the instructions, processing them.
    for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end();
         I != E; ++I) {
      MachineInstr *MI = I;
      const TargetInstrDescriptor &MID = TII.get(MI->getOpcode());

      // Process all of the operands of the instruction...
      unsigned NumOperandsToProcess = MI->getNumOperands();

      // Unless it is a PHI node.  In this case, ONLY process the DEF, not any
      // of the uses.  They will be handled in other basic blocks.
      if (MI->getOpcode() == TargetInstrInfo::PHI)
        NumOperandsToProcess = 1;

      // Loop over implicit uses, using them.
      for (const unsigned *ImplicitUses = MID.ImplicitUses;
           *ImplicitUses; ++ImplicitUses)
        HandlePhysRegUse(*ImplicitUses, MI);

      // Process all explicit uses...
      for (unsigned i = 0; i != NumOperandsToProcess; ++i) {
        MachineOperand &MO = MI->getOperand(i);
        if (MO.isUse() && MO.isRegister() && MO.getReg()) {
          if (MRegisterInfo::isVirtualRegister(MO.getReg())){
            HandleVirtRegUse(getVarInfo(MO.getReg()), MBB, MI);
          } else if (MRegisterInfo::isPhysicalRegister(MO.getReg()) &&
                     AllocatablePhysicalRegisters[MO.getReg()]) {
            HandlePhysRegUse(MO.getReg(), MI);
          }
        }
      }

      // Loop over implicit defs, defining them.
      for (const unsigned *ImplicitDefs = MID.ImplicitDefs;
           *ImplicitDefs; ++ImplicitDefs)
        HandlePhysRegDef(*ImplicitDefs, MI);

      // Process all explicit defs...
      for (unsigned i = 0; i != NumOperandsToProcess; ++i) {
        MachineOperand &MO = MI->getOperand(i);
        if (MO.isDef() && MO.isRegister() && MO.getReg()) {
          if (MRegisterInfo::isVirtualRegister(MO.getReg())) {
            VarInfo &VRInfo = getVarInfo(MO.getReg());

            assert(VRInfo.DefInst == 0 && "Variable multiply defined!");
            VRInfo.DefInst = MI;
            // Defaults to dead
            VRInfo.Kills.push_back(MI);
          } else if (MRegisterInfo::isPhysicalRegister(MO.getReg()) &&
                     AllocatablePhysicalRegisters[MO.getReg()]) {
            HandlePhysRegDef(MO.getReg(), MI);
          }
        }
      }
    }

    // Handle any virtual assignments from PHI nodes which might be at the
    // bottom of this basic block.  We check all of our successor blocks to see
    // if they have PHI nodes, and if so, we simulate an assignment at the end
    // of the current block.
    for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(),
           E = MBB->succ_end(); SI != E; ++SI) {
      MachineBasicBlock *Succ = *SI;

      // PHI nodes are guaranteed to be at the top of the block...
      for (MachineBasicBlock::iterator MI = Succ->begin(), ME = Succ->end();
           MI != ME && MI->getOpcode() == TargetInstrInfo::PHI; ++MI) {
        for (unsigned i = 1; ; i += 2) {
          assert(MI->getNumOperands() > i+1 &&
                 "Didn't find an entry for our predecessor??");
          if (MI->getOperand(i+1).getMachineBasicBlock() == MBB) {
            MachineOperand &MO = MI->getOperand(i);
            if (!MO.getVRegValueOrNull()) {
              VarInfo &VRInfo = getVarInfo(MO.getReg());

              // Only mark it alive only in the block we are representing...
              MarkVirtRegAliveInBlock(VRInfo, MBB);
              break;   // Found the PHI entry for this block...
            }
          }
        }
      }
    }

    // Loop over PhysRegInfo, killing any registers that are available at the
    // end of the basic block.  This also resets the PhysRegInfo map.
    for (unsigned i = 0, e = RegInfo->getNumRegs(); i != e; ++i)
      if (PhysRegInfo[i])
        HandlePhysRegDef(i, 0);
  }

  // Convert the information we have gathered into VirtRegInfo and transform it
  // into a form usable by RegistersKilled.
  //
  for (unsigned i = 0, e = VirtRegInfo.size(); i != e; ++i)
    for (unsigned j = 0, e = VirtRegInfo[i].Kills.size(); j != e; ++j) {
      if (VirtRegInfo[i].Kills[j] == VirtRegInfo[i].DefInst)
        RegistersDead.insert(std::make_pair(VirtRegInfo[i].Kills[j],
                             i + MRegisterInfo::FirstVirtualRegister));

      else
        RegistersKilled.insert(std::make_pair(VirtRegInfo[i].Kills[j],
                               i + MRegisterInfo::FirstVirtualRegister));
    }

  // Check to make sure there are no unreachable blocks in the MC CFG for the
  // function.  If so, it is due to a bug in the instruction selector or some
  // other part of the code generator if this happens.
#ifndef NDEBUG
  for(MachineFunction::iterator i = MF.begin(), e = MF.end(); i != e; ++i)
    assert(Visited.count(&*i) != 0 && "unreachable basic block found");
#endif

  return false;
}

/// instructionChanged - When the address of an instruction changes, this
/// method should be called so that live variables can update its internal
/// data structures.  This removes the records for OldMI, transfering them to
/// the records for NewMI.
void LiveVariables::instructionChanged(MachineInstr *OldMI,
                                       MachineInstr *NewMI) {
  // If the instruction defines any virtual registers, update the VarInfo for
  // the instruction.
  for (unsigned i = 0, e = OldMI->getNumOperands(); i != e; ++i) {
    MachineOperand &MO = OldMI->getOperand(i);
    if (MO.isRegister() && MO.isDef() && MO.getReg() &&
        MRegisterInfo::isVirtualRegister(MO.getReg())) {
      unsigned Reg = MO.getReg();
      VarInfo &VI = getVarInfo(Reg);
      if (VI.DefInst == OldMI)
        VI.DefInst = NewMI;
    }
  }

  // Move the killed information over...
  killed_iterator I, E;
  tie(I, E) = killed_range(OldMI);
  std::vector<unsigned> Regs;
  for (killed_iterator A = I; A != E; ++A)
    Regs.push_back(A->second);
  RegistersKilled.erase(I, E);

  for (unsigned i = 0, e = Regs.size(); i != e; ++i)
    RegistersKilled.insert(std::make_pair(NewMI, Regs[i]));
  Regs.clear();

  // Move the dead information over...
  tie(I, E) = dead_range(OldMI);
  for (killed_iterator A = I; A != E; ++A)
    Regs.push_back(A->second);
  RegistersDead.erase(I, E);

  for (unsigned i = 0, e = Regs.size(); i != e; ++i)
    RegistersDead.insert(std::make_pair(NewMI, Regs[i]));
}
<|endoftext|>


<commit_before>/*
  Copyright (C) 2014-2017 Sven Willner <sven.willner@pik-potsdam.de>
                          Christian Otto <christian.otto@pik-potsdam.de>

  This file is part of Acclimate.

  Acclimate is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as
  published by the Free Software Foundation, either version 3 of
  the License, or (at your option) any later version.

  Acclimate is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with Acclimate.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <cstring>
#include "acclimate.h"
#include "model/Model.h"
#include "output/ArrayOutput.h"
#include "settings.h"
#include "variants/VariantPrices.h"
#include "version.h"

namespace acclimate {

template<class ModelVariant>
static void acclimate_get_variable(const char* name, const FloatType** data, std::size_t* size, const std::size_t** shape, std::size_t* dimension) {
    const typename ArrayOutput<ModelVariant>::Variable& var =
        static_cast<const ArrayOutput<ModelVariant>*>(Acclimate::Run<ModelVariant>::instance()->output(0))->get_variable(name);
    *data = &var.data[0];
    *size = var.data.size();
    *shape = &var.shape[0];
    *dimension = var.shape.size();
}

template<class ModelVariant>
static void acclimate_get_event(const std::size_t index, std::size_t* timestep, char* event, FloatType* value) {
    const ArrayOutput<ModelVariant>* output = static_cast<const ArrayOutput<ModelVariant>*>(Acclimate::Run<ModelVariant>::instance()->output(0));
    if (index >= output->get_events().size()) {
        *timestep = 0;
        event[0] = '\0';
        *value = std::numeric_limits<FloatType>::quiet_NaN();
    } else {
        const typename ArrayOutput<ModelVariant>::Event& e = output->get_events()[index];
        *timestep = e.time;
        std::string desc = std::string(Acclimate::event_names[e.type]) + " " + (e.sector_from < 0 ? "" : std::string(*output->model->sectors_C[e.sector_from]))
                           + (e.sector_from >= 0 && e.region_from >= 0 ? ":" : "")
                           + (e.region_from < 0 ? "" : std::string(*output->model->regions_R[e.region_from]))
                           + (e.sector_to < 0 ? "" : std::string(*output->model->sectors_C[e.sector_to])) + (e.sector_to >= 0 && e.region_to >= 0 ? ":" : "")
                           + (e.region_to < 0 ? "" : std::string(*output->model->regions_R[e.region_to]));
        std::memcpy(event, desc.c_str(), desc.length() + 1);
        *value = std::numeric_limits<FloatType>::quiet_NaN();
    }
}

extern "C" {

extern const char* git_diff;
static std::string last_error;

const char* acclimate_get_last_error() { return last_error.c_str(); }
const char* acclimate_get_version() { return ACCLIMATE_VERSION; }
bool acclimate_get_openmp() {
#ifdef _OPENMP
    return true;
#else
    return false;
#endif
}
const char* acclimate_get_options_string() { return ACCLIMATE_OPTIONS; }

int acclimate_initialize(const char* settings) {
    try {
        std::istringstream ss(settings);
        Acclimate::initialize(settings::SettingsNode(ss));
        return 0;
    } catch (const std::exception& ex) {
        last_error = ex.what();
        return -1;
    }
}

int acclimate_run() {
    try {
        Acclimate::instance()->run();
        return 0;
    } catch (const std::exception& ex) {
        last_error = ex.what();
        return -1;
    }
}

int acclimate_get_variable_prices(const char* name, const FloatType** data, std::size_t* size, const std::size_t** shape, std::size_t* dimension) {
    try {
        acclimate_get_variable<VariantPrices>(name, data, size, shape, dimension);
        return 0;
    } catch (const std::exception& ex) {
        last_error = ex.what();
        return -1;
    }
}

int acclimate_get_event_prices(const std::size_t index, std::size_t* timestep, char* event, FloatType* value) {
    try {
        acclimate_get_event<VariantPrices>(index, timestep, event, value);
        return 0;
    } catch (const std::exception& ex) {
        last_error = ex.what();
        return -1;
    }
}

int acclimate_cleanup() {
    try {
        Acclimate::instance()->cleanup();
        return 0;
    } catch (const std::exception& ex) {
        last_error = ex.what();
        return -1;
    }
}
}
}  // namespace acclimate
<commit_msg>Include fix<commit_after>/*
  Copyright (C) 2014-2017 Sven Willner <sven.willner@pik-potsdam.de>
                          Christian Otto <christian.otto@pik-potsdam.de>

  This file is part of Acclimate.

  Acclimate is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as
  published by the Free Software Foundation, either version 3 of
  the License, or (at your option) any later version.

  Acclimate is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with Acclimate.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <cstring>
#include "acclimate.h"
#include "model/Model.h"
#include "output/ArrayOutput.h"
#include "variants/VariantPrices.h"
#include "version.h"

namespace acclimate {

template<class ModelVariant>
static void acclimate_get_variable(const char* name, const FloatType** data, std::size_t* size, const std::size_t** shape, std::size_t* dimension) {
    const typename ArrayOutput<ModelVariant>::Variable& var =
        static_cast<const ArrayOutput<ModelVariant>*>(Acclimate::Run<ModelVariant>::instance()->output(0))->get_variable(name);
    *data = &var.data[0];
    *size = var.data.size();
    *shape = &var.shape[0];
    *dimension = var.shape.size();
}

template<class ModelVariant>
static void acclimate_get_event(const std::size_t index, std::size_t* timestep, char* event, FloatType* value) {
    const ArrayOutput<ModelVariant>* output = static_cast<const ArrayOutput<ModelVariant>*>(Acclimate::Run<ModelVariant>::instance()->output(0));
    if (index >= output->get_events().size()) {
        *timestep = 0;
        event[0] = '\0';
        *value = std::numeric_limits<FloatType>::quiet_NaN();
    } else {
        const typename ArrayOutput<ModelVariant>::Event& e = output->get_events()[index];
        *timestep = e.time;
        std::string desc = std::string(Acclimate::event_names[e.type]) + " " + (e.sector_from < 0 ? "" : std::string(*output->model->sectors_C[e.sector_from]))
                           + (e.sector_from >= 0 && e.region_from >= 0 ? ":" : "")
                           + (e.region_from < 0 ? "" : std::string(*output->model->regions_R[e.region_from]))
                           + (e.sector_to < 0 ? "" : std::string(*output->model->sectors_C[e.sector_to])) + (e.sector_to >= 0 && e.region_to >= 0 ? ":" : "")
                           + (e.region_to < 0 ? "" : std::string(*output->model->regions_R[e.region_to]));
        std::memcpy(event, desc.c_str(), desc.length() + 1);
        *value = std::numeric_limits<FloatType>::quiet_NaN();
    }
}

extern "C" {

extern const char* git_diff;
static std::string last_error;

const char* acclimate_get_last_error() { return last_error.c_str(); }
const char* acclimate_get_version() { return ACCLIMATE_VERSION; }
bool acclimate_get_openmp() {
#ifdef _OPENMP
    return true;
#else
    return false;
#endif
}
const char* acclimate_get_options_string() { return ACCLIMATE_OPTIONS; }

int acclimate_initialize(const char* settings) {
    try {
        std::istringstream ss(settings);
        Acclimate::initialize(settings::SettingsNode(ss));
        return 0;
    } catch (const std::exception& ex) {
        last_error = ex.what();
        return -1;
    }
}

int acclimate_run() {
    try {
        Acclimate::instance()->run();
        return 0;
    } catch (const std::exception& ex) {
        last_error = ex.what();
        return -1;
    }
}

int acclimate_get_variable_prices(const char* name, const FloatType** data, std::size_t* size, const std::size_t** shape, std::size_t* dimension) {
    try {
        acclimate_get_variable<VariantPrices>(name, data, size, shape, dimension);
        return 0;
    } catch (const std::exception& ex) {
        last_error = ex.what();
        return -1;
    }
}

int acclimate_get_event_prices(const std::size_t index, std::size_t* timestep, char* event, FloatType* value) {
    try {
        acclimate_get_event<VariantPrices>(index, timestep, event, value);
        return 0;
    } catch (const std::exception& ex) {
        last_error = ex.what();
        return -1;
    }
}

int acclimate_cleanup() {
    try {
        Acclimate::instance()->cleanup();
        return 0;
    } catch (const std::exception& ex) {
        last_error = ex.what();
        return -1;
    }
}
}
}  // namespace acclimate
<|endoftext|>


<commit_before>#ifndef TZ_CORE_TZ_HPP
#define TZ_CORE_TZ_HPP
#include "core/game_info.hpp"
#include "core/window.hpp"

namespace tz
{
	namespace literals
	{
		inline constexpr unsigned char operator "" _uc(unsigned long long arg) noexcept
		{
		    return static_cast<unsigned char>(arg);
		}
	}

	/**
	 * \addtogroup tz_core Topaz Core Library (tz)
	 * A collection of platform-agnostic core interfaces.
	 *
	 * This is the only module containing members of the Initial Group. The Initial Group is a group of functions and structures which can be invoked before @ref tz::initialise().
	 * @{
	 */
	/**
	 * Describes a given application.
	 */
	enum class ApplicationType
	{
		WindowApplication,
		HiddenWindowApplication,
		Headless
	};

	struct InitialiseInfo
	{
		const char* name = "Untitled";
		tz::Version version = {1, 0, 0};
		ApplicationType app_type = ApplicationType::WindowApplication;
		WindowInitArgs window = {};
	};

	/**
	 * @brief Initialise Topaz.
	 * @pre If any other Topaz code not within the "Initial Group" has been invoked before this, then the behaviour of the program is undefined. To know if something is within the Initial Group, check their doucmentation notes.
	 * @post If `tz::terminate()` is not called before the end of program runtime, then the behaviour of the program is undefined.
	 * @details This initialises the render-api backend. Also creates a window unless `ApplicationType::Headless` is specified. Note that for `ApplicationType::HiddenWindowApplication`, a window is created but it is invisible.
	 *
	 * @param game_info Information about the application
	 * @param app_type Describes the anatomy of the application.
	 */
	void initialise(GameInfo game_info, ApplicationType app_type = ApplicationType::WindowApplication, WindowInitArgs wargs = {});
	void initialise(InitialiseInfo init = {});
	/**
	 * @brief Terminate Topaz.
	 * @pre If `tz::initialise` has not been invoked before this, then the behaviour of the program is undefined.
	 * @post If anything in `tz` is invoked after this, then the behaviour of the program is undefined.
	 * @details This destroys the render-api backend. If a window was created previously by `tz::initialise`, then it will be destroyed here.
	 */
	void terminate();
	/**
	 * @brief Retrieve the application window.
	 * @pre @ref tz::initialise() has been invoked but not with `ApplicationType::Headless`.
	 * @post @ref tz::terminate() has not yet been invoked.
	 * @return Window& Reference to the application window.
	 */
	Window& window();
	/**
	 * @brief Query as to whether Topaz is initialised.
	 * @note This function is within the Initial Group.
	 * @return true If `tz::initialise` has been invoked and `tz::terminate()` has not yet been invoked. Otherwise, returns false.
	 */
	bool is_initialised();

	/**
	 * @}
	 */
}
#include "core/tz.inl"

/*! \mainpage Topaz v3.1.0-indev
 * \section intro_sec Introduction
 *
 * Welcome to the Topaz documentation. This was generated automatically via https://github.com/Harrand/Topaz/actions.
 *
 * If you're here to learn how to use Topaz, it is also recommended to visit the wiki which contains examples and explanations of various engine features. You can find it at: https://github.com/Harrand/Topaz/wiki.
 *
 * \section modules_sec Topaz Modules
 * The Topaz engine is comprised of several large modules. Each have their own responsibility, namespace and location with the source code. For more detailed information about the modules, visit the 'Modules' tab above. A summary of the modules has been provided for you below.
 *

 * \subsection tzcore Topaz Core
 *
 * The core module of Topaz.
 *
 * Source location: Topaz/src/core

 * Namespace: `tz`
 *

 * \subsection tzgl Topaz Graphics Library
 * Low-level 3D graphics functionality. Interacts with a Vulkan or OpenGL frontend, depending on configuration.
 *
 * Source location: Topaz/src/gl

 * Namespace: `tz::gl`
 *

 */

#endif // TZ_CORE_TZ_HPP
<commit_msg>+ Added a static_assert to make sure we're building against either Vulkan or OGL. Error message should be very clear if setup is incorrect<commit_after>#ifndef TZ_CORE_TZ_HPP
#define TZ_CORE_TZ_HPP
#include "core/game_info.hpp"
#include "core/window.hpp"

static_assert(TZ_VULKAN || TZ_OGL, "No graphics API detected. You have not configured CMake correctly.");

namespace tz
{
	namespace literals
	{
		inline constexpr unsigned char operator "" _uc(unsigned long long arg) noexcept
		{
		    return static_cast<unsigned char>(arg);
		}
	}

	/**
	 * \addtogroup tz_core Topaz Core Library (tz)
	 * A collection of platform-agnostic core interfaces.
	 *
	 * This is the only module containing members of the Initial Group. The Initial Group is a group of functions and structures which can be invoked before @ref tz::initialise().
	 * @{
	 */
	/**
	 * Describes a given application.
	 */
	enum class ApplicationType
	{
		WindowApplication,
		HiddenWindowApplication,
		Headless
	};

	struct InitialiseInfo
	{
		const char* name = "Untitled";
		tz::Version version = {1, 0, 0};
		ApplicationType app_type = ApplicationType::WindowApplication;
		WindowInitArgs window = {};
	};

	/**
	 * @brief Initialise Topaz.
	 * @pre If any other Topaz code not within the "Initial Group" has been invoked before this, then the behaviour of the program is undefined. To know if something is within the Initial Group, check their doucmentation notes.
	 * @post If `tz::terminate()` is not called before the end of program runtime, then the behaviour of the program is undefined.
	 * @details This initialises the render-api backend. Also creates a window unless `ApplicationType::Headless` is specified. Note that for `ApplicationType::HiddenWindowApplication`, a window is created but it is invisible.
	 *
	 * @param game_info Information about the application
	 * @param app_type Describes the anatomy of the application.
	 */
	void initialise(GameInfo game_info, ApplicationType app_type = ApplicationType::WindowApplication, WindowInitArgs wargs = {});
	void initialise(InitialiseInfo init = {});
	/**
	 * @brief Terminate Topaz.
	 * @pre If `tz::initialise` has not been invoked before this, then the behaviour of the program is undefined.
	 * @post If anything in `tz` is invoked after this, then the behaviour of the program is undefined.
	 * @details This destroys the render-api backend. If a window was created previously by `tz::initialise`, then it will be destroyed here.
	 */
	void terminate();
	/**
	 * @brief Retrieve the application window.
	 * @pre @ref tz::initialise() has been invoked but not with `ApplicationType::Headless`.
	 * @post @ref tz::terminate() has not yet been invoked.
	 * @return Window& Reference to the application window.
	 */
	Window& window();
	/**
	 * @brief Query as to whether Topaz is initialised.
	 * @note This function is within the Initial Group.
	 * @return true If `tz::initialise` has been invoked and `tz::terminate()` has not yet been invoked. Otherwise, returns false.
	 */
	bool is_initialised();

	/**
	 * @}
	 */
}
#include "core/tz.inl"

/*! \mainpage Topaz v3.1.0-indev
 * \section intro_sec Introduction
 *
 * Welcome to the Topaz documentation. This was generated automatically via https://github.com/Harrand/Topaz/actions.
 *
 * If you're here to learn how to use Topaz, it is also recommended to visit the wiki which contains examples and explanations of various engine features. You can find it at: https://github.com/Harrand/Topaz/wiki.
 *
 * \section modules_sec Topaz Modules
 * The Topaz engine is comprised of several large modules. Each have their own responsibility, namespace and location with the source code. For more detailed information about the modules, visit the 'Modules' tab above. A summary of the modules has been provided for you below.
 *

 * \subsection tzcore Topaz Core
 *
 * The core module of Topaz.
 *
 * Source location: Topaz/src/core

 * Namespace: `tz`
 *

 * \subsection tzgl Topaz Graphics Library
 * Low-level 3D graphics functionality. Interacts with a Vulkan or OpenGL frontend, depending on configuration.
 *
 * Source location: Topaz/src/gl

 * Namespace: `tz::gl`
 *

 */

#endif // TZ_CORE_TZ_HPP
<|endoftext|>


<commit_before>///
/// @file   count_primes3.cpp
/// @brief  Count the primes within [10^13, 10^13 + 5*10^9] randomly
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/ParallelPrimeSieve.hpp>

#include <stdint.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <random>

using namespace std;
using namespace primesieve;

void check(bool OK)
{
  cout << "   " << (OK ? "OK" : "ERROR") << "\n";
  if (!OK)
    exit(1);
}

int main()
{
  cout << "Sieving the primes within [10^13, 10^13 + 5*10^9] randomly" << endl;

  uint64_t maxDist = (uint64_t) 2e7;
  uint64_t lowerBound = (uint64_t) 1e13;
  uint64_t upperBound = lowerBound + (uint64_t) 5e9;
  uint64_t count = 0;

  ParallelPrimeSieve p;
  p.setStart(lowerBound - 1);
  p.setStop(lowerBound - 1);

  random_device rd;
  mt19937 gen(rd());
  uniform_int_distribution<uint64_t> dist(0, maxDist);

  while (p.getStop() < upperBound)
  {
    p.setStart(p.getStop() + 1);
    p.setStop(min(p.getStart() + dist(gen), upperBound));
    p.setSieveSize(1 << (dist(gen) % 12));
    p.sieve();
    count += p.getPrimeCount();

    cout << "\rRemaining chunk:             "
         << "\rRemaining chunk: "
         << upperBound - p.getStop() << flush;
  }

  cout << endl << "Prime count: " << count;
  check(count == 167038410);

  cout << endl;
  cout << "Test passed successfully!" << endl;

  return 0;
}
<commit_msg>Max sieve size = 4096 kilobytes<commit_after>///
/// @file   count_primes3.cpp
/// @brief  Count the primes within [10^13, 10^13 + 5*10^9] randomly
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/ParallelPrimeSieve.hpp>

#include <stdint.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <random>

using namespace std;
using namespace primesieve;

void check(bool OK)
{
  cout << "   " << (OK ? "OK" : "ERROR") << "\n";
  if (!OK)
    exit(1);
}

int main()
{
  cout << "Sieving the primes within [10^13, 10^13 + 5*10^9] randomly" << endl;

  uint64_t maxDist = (uint64_t) 2e7;
  uint64_t lowerBound = (uint64_t) 1e13;
  uint64_t upperBound = lowerBound + (uint64_t) 5e9;
  uint64_t count = 0;

  ParallelPrimeSieve p;
  p.setStart(lowerBound - 1);
  p.setStop(lowerBound - 1);

  random_device rd;
  mt19937 gen(rd());
  uniform_int_distribution<uint64_t> dist(0, maxDist);

  while (p.getStop() < upperBound)
  {
    p.setStart(p.getStop() + 1);
    p.setStop(min(p.getStart() + dist(gen), upperBound));
    p.setSieveSize(1 << (dist(gen) % 13));
    p.sieve();
    count += p.getPrimeCount();

    cout << "\rRemaining chunk:             "
         << "\rRemaining chunk: "
         << upperBound - p.getStop() << flush;
  }

  cout << endl << "Prime count: " << count;
  check(count == 167038410);

  cout << endl;
  cout << "Test passed successfully!" << endl;

  return 0;
}
<|endoftext|>


<commit_before>// Generates Documentation

gb_global int print_entity_kind_ordering[Entity_Count] = {
	/*Invalid*/     -1,
	/*Constant*/    0,
	/*Variable*/    1,
	/*TypeName*/    4,
	/*Procedure*/   2,
	/*ProcGroup*/   3,
	/*Builtin*/     -1,
	/*ImportName*/  -1,
	/*LibraryName*/ -1,
	/*Nil*/         -1,
	/*Label*/       -1,
};
gb_global char const *print_entity_names[Entity_Count] = {
	/*Invalid*/     "",
	/*Constant*/    "constants",
	/*Variable*/    "variables",
	/*TypeName*/    "types",
	/*Procedure*/   "procedures",
	/*ProcGroup*/   "proc_group",
	/*Builtin*/     "",
	/*ImportName*/  "import names",
	/*LibraryName*/ "library names",
	/*Nil*/         "",
	/*Label*/       "",
};

GB_COMPARE_PROC(cmp_entities_for_printing) {
	GB_ASSERT(a != nullptr);
	GB_ASSERT(b != nullptr);
	Entity *x = *cast(Entity **)a;
	Entity *y = *cast(Entity **)b;
	int res = 0;
	res = string_compare(x->pkg->name, y->pkg->name);
	if (res != 0) {
		return res;
	}
	int ox = print_entity_kind_ordering[x->kind];
	int oy = print_entity_kind_ordering[y->kind];
	if (ox < oy) {
		return -1;
	} else if (ox > oy) {
		return +1;
	}
	res = string_compare(x->token.string, y->token.string);
	return res;
}

GB_COMPARE_PROC(cmp_ast_package_by_name) {
	GB_ASSERT(a != nullptr);
	GB_ASSERT(b != nullptr);
	AstPackage *x = *cast(AstPackage **)a;
	AstPackage *y = *cast(AstPackage **)b;
	return string_compare(x->name, y->name);
}

String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
	isize len = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		len += comment.len;
		len += 1; // for \n
	}
	if (len == 0) {
		return make_string(nullptr, 0);
	}

	u8 *text = gb_alloc_array(a, u8, len+1);
	len = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		if (comment[1] == '/') {
			comment.text += 2;
			comment.len  -= 2;
		} else if (comment[1] == '*') {
			comment.text += 2;
			comment.len  -= 4;
		}
		comment = string_trim_whitespace(comment);
		gb_memmove(text+len, comment.text, comment.len);
		len += comment.len;
		text[len++] = '\n';
	}
	return make_string(text, len);
}

void print_doc_line(i32 indent, char const *fmt, ...) {
	while (indent --> 0) {
		gb_printf("\t");
	}
	va_list va;
	va_start(va, fmt);
	gb_printf_va(fmt, va);
	va_end(va);
	gb_printf("\n");
}
void print_doc_line_no_newline(i32 indent, char const *fmt, ...) {
	while (indent --> 0) {
		gb_printf("\t");
	}
	va_list va;
	va_start(va, fmt);
	gb_printf_va(fmt, va);
	va_end(va);
}

bool print_doc_comment_group_string(i32 indent, CommentGroup const &g) {
	isize len = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		len += comment.len;
		len += 1; // for \n
	}
	if (len == 0) {
		return false;
	}

	isize count = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		if (comment[1] == '/') {
			comment.text += 2;
			comment.len  -= 2;
		} else if (comment[1] == '*') {
			comment.text += 2;
			comment.len  -= 4;
		}
		comment = string_trim_whitespace(comment);
		if (string_starts_with(comment, str_lit("@("))) {
			continue;
		}

		print_doc_line(indent, "%.*s", LIT(comment));
		count += 1;
	}
	return count > 0;
}

void print_doc_expr(Ast *expr) {
	gbString s = nullptr;
	if (build_context.cmd_doc_flags & CmdDocFlag_All) {
		s = expr_to_string(expr);
	} else {
		s = expr_to_string_shorthand(expr);
	}
	gb_file_write(gb_file_get_standard(gbFileStandard_Output), s, gb_string_length(s));
	gb_string_free(s);
}

void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
	if (pkg == nullptr) {
		return;
	}

	print_doc_line(0, "package %.*s", LIT(pkg->name));

	if (pkg->scope != nullptr) {
		auto entities = array_make<Entity *>(heap_allocator(), 0, pkg->scope->elements.entries.count);
		defer (array_free(&entities));
		for_array(i, pkg->scope->elements.entries) {
			Entity *e = pkg->scope->elements.entries[i].value;
			switch (e->kind) {
			case Entity_Invalid:
			case Entity_Builtin:
			case Entity_Nil:
			case Entity_Label:
				continue;
			case Entity_Constant:
			case Entity_Variable:
			case Entity_TypeName:
			case Entity_Procedure:
			case Entity_ProcGroup:
			case Entity_ImportName:
			case Entity_LibraryName:
				// Fine
				break;
			}
			array_add(&entities, e);
		}
		gb_sort_array(entities.data, entities.count, cmp_entities_for_printing);

		AstPackage *curr_pkg = nullptr;
		EntityKind curr_entity_kind = Entity_Invalid;
		for_array(i, entities) {
			Entity *e = entities[i];
			if (e->pkg != pkg) {
				continue;
			}
			if (!is_entity_exported(e)) {
				continue;
			}

			if (curr_entity_kind != e->kind) {
				curr_entity_kind = e->kind;
				print_doc_line(0, "");
				print_doc_line(1, "%s", print_entity_names[e->kind]);
			}

			Ast *type_expr = nullptr;
			Ast *init_expr = nullptr;
			Ast *decl_node = nullptr;
			CommentGroup *comment = nullptr;
			CommentGroup *docs = nullptr;
			if (e->decl_info != nullptr) {
				type_expr = e->decl_info->type_expr;
				init_expr = e->decl_info->init_expr;
				decl_node = e->decl_info->decl_node;
			}
			GB_ASSERT(type_expr != nullptr || init_expr != nullptr);
			print_doc_line_no_newline(2, "%.*s", LIT(e->token.string));
			if (type_expr != nullptr) {
				gbString t = expr_to_string(type_expr);
				gb_printf(": %s ", t);
				gb_string_free(t);
			} else {
				gb_printf(" :");
			}
			if (e->kind == Entity_Variable) {
				if (init_expr != nullptr) {
					gb_printf("= ");
					print_doc_expr(init_expr);
				}
			} else {
				gb_printf(": ");
				print_doc_expr(init_expr);
			}

			gb_printf(";\n");

			if (build_context.cmd_doc_flags & CmdDocFlag_All) {
				if (comment) {
					// gb_printf(" <comment>");
				}
				if (docs) {
					if (print_doc_comment_group_string(3, *docs)) {
						gb_printf("\n");
					}
				}
			}
		}
		print_doc_line(0, "");
	}

	if (pkg->fullpath.len != 0) {
		print_doc_line(0, "");
		print_doc_line(1, "fullpath: %.*s", LIT(pkg->fullpath));
		print_doc_line(1, "files:");
		for_array(i, pkg->files) {
			AstFile *f = pkg->files[i];
			String filename = remove_directory_from_path(f->fullpath);
			print_doc_line(2, "%.*s", LIT(filename));
		}
	}

}

void generate_documentation(Checker *c) {
	CheckerInfo *info = &c->info;

	if (build_context.doc_packages.count != 0) {
		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
		bool was_error = false;
		for_array(j, build_context.doc_packages) {
			bool found = false;
			String name = build_context.doc_packages[j];
			for_array(i, info->packages.entries) {
				AstPackage *pkg = info->packages.entries[i].value;
				if (name == pkg->name) {
					found = true;
					array_add(&pkgs, pkg);
					break;
				}
			}
			if (!found) {
				gb_printf_err("Unknown package %.*s\n", LIT(name));
				was_error = true;
			}
		}
		if (was_error) {
			gb_exit(1);
			return;
		}

		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);

		for_array(i, pkgs) {
			print_doc_package(info, pkgs[i]);
		}
	} else if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
		for_array(i, info->packages.entries) {
			AstPackage *pkg = info->packages.entries[i].value;
			array_add(&pkgs, pkg);
		}

		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);

		for_array(i, pkgs) {
			print_doc_package(info, pkgs[i]);
		}
	} else {
		GB_ASSERT(info->init_scope->flags & ScopeFlag_Pkg);
		AstPackage *pkg = info->init_scope->pkg;
		print_doc_package(info, pkg);

	}
}
<commit_msg>Fix typo<commit_after>// Generates Documentation

gb_global int print_entity_kind_ordering[Entity_Count] = {
	/*Invalid*/     -1,
	/*Constant*/    0,
	/*Variable*/    1,
	/*TypeName*/    4,
	/*Procedure*/   2,
	/*ProcGroup*/   3,
	/*Builtin*/     -1,
	/*ImportName*/  -1,
	/*LibraryName*/ -1,
	/*Nil*/         -1,
	/*Label*/       -1,
};
gb_global char const *print_entity_names[Entity_Count] = {
	/*Invalid*/     "",
	/*Constant*/    "constants",
	/*Variable*/    "variables",
	/*TypeName*/    "types",
	/*Procedure*/   "procedures",
	/*ProcGroup*/   "proc_group",
	/*Builtin*/     "",
	/*ImportName*/  "import names",
	/*LibraryName*/ "library names",
	/*Nil*/         "",
	/*Label*/       "",
};

GB_COMPARE_PROC(cmp_entities_for_printing) {
	GB_ASSERT(a != nullptr);
	GB_ASSERT(b != nullptr);
	Entity *x = *cast(Entity **)a;
	Entity *y = *cast(Entity **)b;
	int res = 0;
	res = string_compare(x->pkg->name, y->pkg->name);
	if (res != 0) {
		return res;
	}
	int ox = print_entity_kind_ordering[x->kind];
	int oy = print_entity_kind_ordering[y->kind];
	if (ox < oy) {
		return -1;
	} else if (ox > oy) {
		return +1;
	}
	res = string_compare(x->token.string, y->token.string);
	return res;
}

GB_COMPARE_PROC(cmp_ast_package_by_name) {
	GB_ASSERT(a != nullptr);
	GB_ASSERT(b != nullptr);
	AstPackage *x = *cast(AstPackage **)a;
	AstPackage *y = *cast(AstPackage **)b;
	return string_compare(x->name, y->name);
}

String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
	isize len = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		len += comment.len;
		len += 1; // for \n
	}
	if (len == 0) {
		return make_string(nullptr, 0);
	}

	u8 *text = gb_alloc_array(a, u8, len+1);
	len = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		if (comment[1] == '/') {
			comment.text += 2;
			comment.len  -= 2;
		} else if (comment[1] == '*') {
			comment.text += 2;
			comment.len  -= 4;
		}
		comment = string_trim_whitespace(comment);
		gb_memmove(text+len, comment.text, comment.len);
		len += comment.len;
		text[len++] = '\n';
	}
	return make_string(text, len);
}

void print_doc_line(i32 indent, char const *fmt, ...) {
	while (indent --> 0) {
		gb_printf("\t");
	}
	va_list va;
	va_start(va, fmt);
	gb_printf_va(fmt, va);
	va_end(va);
	gb_printf("\n");
}
void print_doc_line_no_newline(i32 indent, char const *fmt, ...) {
	while (indent --> 0) {
		gb_printf("\t");
	}
	va_list va;
	va_start(va, fmt);
	gb_printf_va(fmt, va);
	va_end(va);
}

bool print_doc_comment_group_string(i32 indent, CommentGroup const &g) {
	isize len = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		len += comment.len;
		len += 1; // for \n
	}
	if (len == 0) {
		return false;
	}

	isize count = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		if (comment[1] == '/') {
			comment.text += 2;
			comment.len  -= 2;
		} else if (comment[1] == '*') {
			comment.text += 2;
			comment.len  -= 4;
		}
		comment = string_trim_whitespace(comment);
		if (string_starts_with(comment, str_lit("@("))) {
			continue;
		}

		print_doc_line(indent, "%.*s", LIT(comment));
		count += 1;
	}
	return count > 0;
}

void print_doc_expr(Ast *expr) {
	gbString s = nullptr;
	if (build_context.cmd_doc_flags & CmdDocFlag_All) {
		s = expr_to_string(expr);
	} else {
		s = expr_to_string_shorthand(expr);
	}
	gb_file_write(gb_file_get_standard(gbFileStandard_Output), s, gb_string_length(s));
	gb_string_free(s);
}

void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
	if (pkg == nullptr) {
		return;
	}

	print_doc_line(0, "package %.*s", LIT(pkg->name));

	if (pkg->scope != nullptr) {
		auto entities = array_make<Entity *>(heap_allocator(), 0, pkg->scope->elements.entries.count);
		defer (array_free(&entities));
		for_array(i, pkg->scope->elements.entries) {
			Entity *e = pkg->scope->elements.entries[i].value;
			switch (e->kind) {
			case Entity_Invalid:
			case Entity_Builtin:
			case Entity_Nil:
			case Entity_Label:
				continue;
			case Entity_Constant:
			case Entity_Variable:
			case Entity_TypeName:
			case Entity_Procedure:
			case Entity_ProcGroup:
			case Entity_ImportName:
			case Entity_LibraryName:
				// Fine
				break;
			}
			array_add(&entities, e);
		}
		gb_sort_array(entities.data, entities.count, cmp_entities_for_printing);

		AstPackage *curr_pkg = nullptr;
		EntityKind curr_entity_kind = Entity_Invalid;
		for_array(i, entities) {
			Entity *e = entities[i];
			if (e->pkg != pkg) {
				continue;
			}
			if (!is_entity_exported(e)) {
				continue;
			}

			if (curr_entity_kind != e->kind) {
				curr_entity_kind = e->kind;
				print_doc_line(0, "");
				print_doc_line(1, "%s", print_entity_names[e->kind]);
			}

			Ast *type_expr = nullptr;
			Ast *init_expr = nullptr;
			Ast *decl_node = nullptr;
			CommentGroup *comment = nullptr;
			CommentGroup *docs = nullptr;
			if (e->decl_info != nullptr) {
				type_expr = e->decl_info->type_expr;
				init_expr = e->decl_info->init_expr;
				decl_node = e->decl_info->decl_node;
				comment = e->decl_info->comment;
				docs = e->decl_info->docs;
			}
			GB_ASSERT(type_expr != nullptr || init_expr != nullptr);
			print_doc_line_no_newline(2, "%.*s", LIT(e->token.string));
			if (type_expr != nullptr) {
				gbString t = expr_to_string(type_expr);
				gb_printf(": %s ", t);
				gb_string_free(t);
			} else {
				gb_printf(" :");
			}
			if (e->kind == Entity_Variable) {
				if (init_expr != nullptr) {
					gb_printf("= ");
					print_doc_expr(init_expr);
				}
			} else {
				gb_printf(": ");
				print_doc_expr(init_expr);
			}

			gb_printf(";\n");

			if (build_context.cmd_doc_flags & CmdDocFlag_All) {
				if (comment) {
					// gb_printf(" <comment>");
				}
				if (docs) {
					if (print_doc_comment_group_string(3, *docs)) {
						gb_printf("\n");
					}
				}
			}
		}
		print_doc_line(0, "");
	}

	if (pkg->fullpath.len != 0) {
		print_doc_line(0, "");
		print_doc_line(1, "fullpath: %.*s", LIT(pkg->fullpath));
		print_doc_line(1, "files:");
		for_array(i, pkg->files) {
			AstFile *f = pkg->files[i];
			String filename = remove_directory_from_path(f->fullpath);
			print_doc_line(2, "%.*s", LIT(filename));
		}
	}

}

void generate_documentation(Checker *c) {
	CheckerInfo *info = &c->info;

	if (build_context.doc_packages.count != 0) {
		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
		bool was_error = false;
		for_array(j, build_context.doc_packages) {
			bool found = false;
			String name = build_context.doc_packages[j];
			for_array(i, info->packages.entries) {
				AstPackage *pkg = info->packages.entries[i].value;
				if (name == pkg->name) {
					found = true;
					array_add(&pkgs, pkg);
					break;
				}
			}
			if (!found) {
				gb_printf_err("Unknown package %.*s\n", LIT(name));
				was_error = true;
			}
		}
		if (was_error) {
			gb_exit(1);
			return;
		}

		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);

		for_array(i, pkgs) {
			print_doc_package(info, pkgs[i]);
		}
	} else if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
		for_array(i, info->packages.entries) {
			AstPackage *pkg = info->packages.entries[i].value;
			array_add(&pkgs, pkg);
		}

		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);

		for_array(i, pkgs) {
			print_doc_package(info, pkgs[i]);
		}
	} else {
		GB_ASSERT(info->init_scope->flags & ScopeFlag_Pkg);
		AstPackage *pkg = info->init_scope->pkg;
		print_doc_package(info, pkg);

	}
}
<|endoftext|>


<commit_before>#include"block.h"
#include<tgmath.h>
#include"validator.h"
#include<iostream>
#include"keccak.h"
#include"rlp.h"

using namespace std;

void validateAll(const Block& parent, const Block& child) {
    unsigned short int error_found = 0; //signals if some validation faile 0 means nothing failed;
    if (validateParentHash(parent, child) != 0) {
            error_found = 1;
            cout << "Parent hash is invalid." << endl;
    }
    if (validateBlockNumber(parent, child) != 0) {
            error_found = 1;
            cout << "Block number is invalid." << endl;
    }
    if (validateDifficulty(parent, child) != 0) {
            error_found = 1;
            cout << "Block difficulty is invalid." << endl;
    }
    if (validateGasLimit(parent, child) != 0) {
            error_found = 1;
            cout << "Gas limit is invalid." << endl;
    }
    if (validateTimeStamp(parent, child) != 0) {
            error_found = 1;
            cout << "Timestamp is invalid." << endl;
    }
    if (validateTransactionsRoot(parent, child) != 0) {
            error_found = 1;
            cout << "Hash of root of transactions tree is invalid." << endl;
    }
    if (validateNonce(parent, child) != 0) {
            error_found = 1;
            cout << "Nonce is invalid." << endl;
    }
    if (validateMixHash(parent, child) != 0) {
            error_found = 1;
            cout << "Mixh hash is invalid." << endl;
    }
    if (validateReceipts(parent, child) != 0) {
            error_found = 1;
            cout << "Hash of root of transaction receipts tree is not valid." << endl;
    }
    if (validateLogsBloom(parent, child) != 0) {
            error_found = 1;
            cout << "Logs Bloom filters are invalid." << endl;
    }
    if (error_found == 0) {
            cout << "Block is valid." << endl;
    }
}

/* validates The Keccak 256-bit hash of the parent block's header, in its entirety
 * * @param Block
 * @ param Block
 * @return int
*/
int validateParentHash(const Block& parent, const Block& child) {
    /*now getting parts of Block header, creating a vector of RLPfield
     * then serializing them through RLP.serialize and calculating their hash
    */
    Header header = parent.header();
    RLPField parenthash = {header.parentHash(), false};
    RLPField ommershash = {header.ommersHash(), false};
    RLPField beneficiary = {header.beneficiary(), false};
    RLPField stateroot = {header.stateRoot(), false};
    RLPField transactionsroot = {header.transactionsRoot(), false};
    RLPField receiptsroot = {header.receiptsRoot(), false};
    RLPField logsbloom = {header.logsBloom(), false};
    RLPField difficulty = {numberToVector(header.difficulty()), false};
    RLPField number = {numberToVector(header.number()), false};
    RLPField gaslimit = {numberToVector(header.gasLimit()), false};
    RLPField gasused = {numberToVector(header.gasUsed()), false};
    RLPField timestamp = {numberToVector(header.timestamp()), false};
    RLPField extradata = {header.extraData(), false};
    RLPField mixhash = {header.mixHash(), false};
    RLPField nonce = {header.nonce(), false};
    vector<RLPField> fields = {parenthash, ommershash, beneficiary, stateroot, transactionsroot, receiptsroot, logsbloom, difficulty, number, gaslimit, gasused, timestamp, extradata, mixhash, nonce};
    vector<uint8_t> headerbytes = RLP::serialize(fields);
    vector<uint8_t> parentheaderhash = keccak(headerbytes);
    vector<uint8_t> childhash = child.header().parentHash();
    if (parentheaderhash == childhash) {
            return 0;
    }
    else {
            return 1;
    }
}

int validateBlockNumber(const Block& parent, const Block& child) {
    if (parent.header().number() == (child.header().number() - 1)) {
            return 0;
    }
    else {
            return 1;
    }
}

//difficulty formula taken from https://ethereum.stackexchange.com/questions/1880/how-is-the-mining-difficulty-calculated-on-ethereum
//doplnit že se bere maximum ze vzorce a 131072
int validateDifficulty(const Block& parent, const Block& child) {
    size_t block_diff = fmax(parent.header().difficulty() + parent.header().difficulty() / 2048 * fmax(1 - (child.header().timestamp() - parent.header().timestamp()) / 10, -99) + pow(2, ((child.header().number() / 100000) - 2)), 131072);
    if (block_diff == child.header().difficulty()) {
            return 0;
    }
    else {
            return 1;
    }
}

int validateGasLimit(const Block& parent, const Block& child) {
    if ((child.header().gasLimit() < parent.header().gasLimit() + (parent.header().gasLimit() / 1024)) && (child.header().gasLimit() > parent.header().gasLimit() - (parent.header().gasLimit() / 1024))) {
            return 0;
    }
    else {
            return 1;
    }
}

int validateTimeStamp(const Block& parent, const Block& child) {
    if (child.header().timestamp() > parent.header().timestamp()) {
            return 0;
    }
    else {
            return 1;
    }
}

//nothing for now, waiting for merkle trees
int validateTransactionsRoot(const Block& parent, const Block& child) {
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateNonce(const Block& parent, const Block& child) {
    /*This method is not implemented because proper verification of nonce requires download whole state database. We think that downloading of whole state database and parsing it is a bit over the main goal of this project.*/
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateMixHash(const Block& parent, const Block& child) {
    /*This method is not implemented because proper verification of mixHash requires download whole state database. We think that downloading of whole state database and parsing it is a bit over the main goal of this project.*/
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateReceipts(const Block& parent, const Block& child) {
    /*This method is not implemented because proper verification of receipts trie requires download whole state database. We think that downloading of whole state database and parsing it is a bit over the main goal of this project.*/
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateLogsBloom(const Block& parent, const Block& child) {
    /*This method is not implemented because we would need to implement or use EVM (Ethereum virtual machine). We think that this is strongly out of scope of this project. */
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

<commit_msg>No need to serialize header manually now<commit_after>#include"block.h"
#include<tgmath.h>
#include"validator.h"
#include<iostream>
#include"keccak.h"
#include"rlp.h"

using namespace std;

void validateAll(const Block& parent, const Block& child) {
    unsigned short int error_found = 0; //signals if some validation faile 0 means nothing failed;
    if (validateParentHash(parent, child) != 0) {
            error_found = 1;
            cout << "Parent hash is invalid." << endl;
    }
    if (validateBlockNumber(parent, child) != 0) {
            error_found = 1;
            cout << "Block number is invalid." << endl;
    }
    if (validateDifficulty(parent, child) != 0) {
            error_found = 1;
            cout << "Block difficulty is invalid." << endl;
    }
    if (validateGasLimit(parent, child) != 0) {
            error_found = 1;
            cout << "Gas limit is invalid." << endl;
    }
    if (validateTimeStamp(parent, child) != 0) {
            error_found = 1;
            cout << "Timestamp is invalid." << endl;
    }
    if (validateTransactionsRoot(parent, child) != 0) {
            error_found = 1;
            cout << "Hash of root of transactions tree is invalid." << endl;
    }
    if (validateNonce(parent, child) != 0) {
            error_found = 1;
            cout << "Nonce is invalid." << endl;
    }
    if (validateMixHash(parent, child) != 0) {
            error_found = 1;
            cout << "Mixh hash is invalid." << endl;
    }
    if (validateReceipts(parent, child) != 0) {
            error_found = 1;
            cout << "Hash of root of transaction receipts tree is not valid." << endl;
    }
    if (validateLogsBloom(parent, child) != 0) {
            error_found = 1;
            cout << "Logs Bloom filters are invalid." << endl;
    }
    if (error_found == 0) {
            cout << "Block is valid." << endl;
    }
}

/* validates The Keccak 256-bit hash of the parent block's header, in its entirety
 * * @param Block
 * @ param Block
 * @return int
*/
int validateParentHash(const Block& parent, const Block& child) {
    /*now getting parts of Block header, creating a vector of RLPfield
     * then serializing them through RLP.serialize and calculating their hash
    */
    Header header = parent.header();
    vector<uint8_t> headerbytes = header.toRLP();
    vector<uint8_t> parentheaderhash = keccak(headerbytes);
    vector<uint8_t> childhash = child.header().parentHash();
    if (parentheaderhash == childhash) {
            return 0;
    }
    else {
            return 1;
    }
}

int validateBlockNumber(const Block& parent, const Block& child) {
    if (parent.header().number() == (child.header().number() - 1)) {
            return 0;
    }
    else {
            return 1;
    }
}

//difficulty formula taken from https://ethereum.stackexchange.com/questions/1880/how-is-the-mining-difficulty-calculated-on-ethereum
int validateDifficulty(const Block& parent, const Block& child) {
    size_t block_diff = fmax(parent.header().difficulty() + parent.header().difficulty() / 2048 * fmax(1 - (child.header().timestamp() - parent.header().timestamp()) / 10, -99) + pow(2, ((child.header().number() / 100000) - 2)), 131072);
    if (block_diff == child.header().difficulty()) {
            return 0;
    }
    else {
            return 1;
    }
}

int validateGasLimit(const Block& parent, const Block& child) {
    if ((child.header().gasLimit() < parent.header().gasLimit() + (parent.header().gasLimit() / 1024)) && (child.header().gasLimit() > parent.header().gasLimit() - (parent.header().gasLimit() / 1024))) {
            return 0;
    }
    else {
            return 1;
    }
}

int validateTimeStamp(const Block& parent, const Block& child) {
    if (child.header().timestamp() > parent.header().timestamp()) {
            return 0;
    }
    else {
            return 1;
    }
}

//nothing for now, waiting for merkle trees
int validateTransactionsRoot(const Block& parent, const Block& child) {
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateNonce(const Block& parent, const Block& child) {
    /*This method is not implemented because proper verification of nonce requires download whole state database. We think that downloading of whole state database and parsing it is a bit over the main goal of this project.*/
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateMixHash(const Block& parent, const Block& child) {
    /*This method is not implemented because proper verification of mixHash requires download whole state database. We think that downloading of whole state database and parsing it is a bit over the main goal of this project.*/
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateReceipts(const Block& parent, const Block& child) {
    /*This method is not implemented because proper verification of receipts trie requires download whole state database. We think that downloading of whole state database and parsing it is a bit over the main goal of this project.*/
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

int validateLogsBloom(const Block& parent, const Block& child) {
    /*This method is not implemented because we would need to implement or use EVM (Ethereum virtual machine). We think that this is strongly out of scope of this project. */
    Block tmp1 = parent;
    Block tmp2 = child;
    return 0;
}

<|endoftext|>


<commit_before>#ifndef VPP_FILL_HH__
# define VPP_FILL_HH__

# include <vpp/core/boxNd.hh>
# include <vpp/core/vector.hh>
# include <vpp/core/pixel_wise.hh>

namespace vpp
{

  template <typename V, typename U, unsigned N>
  void fill(imageNd<V, N>& img, U&& value)
  {
    pixel_wise(img) | [=] (auto& pix) { pix = value; };
  }

  template <typename V, unsigned N>
  void fill(imageNd<V, N>& img, V value, const boxNd<N>& box)
  {
    pixel_wise(box, img) | [=] (auto&, auto& pix) { pix = value; };
  }

  template <typename V, typename U, unsigned N>
  void fill_with_border(imageNd<V, N>& img, U&& value)
  {
    auto box = img.domain_with_border();
    pixel_wise(box, img) | [=] (auto&, auto& pix) { pix = value; };
  }

  template <typename V, typename U>
  void fill_border(image2d<V>& img, U&& value)
  {
    int border = img.border();
    int nc = img.ncols();
    int nr = img.nrows();

    auto top = box2d({-border, -border}, {-1, nc + border - 1});
    auto bottom = box2d({nr, -border}, {nr + border - 1, nc + border - 1});
    auto left = box2d({0, -border}, {nr - 1, -1});
    auto right = box2d({0, nc}, {nr - 1, nc + border - 1});

    for (auto b : {top, bottom, left, right})
      pixel_wise(b, img) | [=] (auto&, auto& pix) { pix = value; };
  }

  template <typename V>
  void fill_border_mirror(image2d<V>& img)
  {
    int border = img.border();
    int nc = img.ncols();
    int nr = img.nrows();

    // 1  2  3
    // 4     5
    // 6  7  8

    // Corners.
    pixel_wise(box2d({-border, -border}, {-1, -1}), img) | // 1
      [&] (auto& p, auto& pix) { pix = img(-p[0] - 1, -p[1] - 1); };

    pixel_wise(box2d({-border, nc}, {-1, nc + border - 1}), img) | // 3
      [&] (auto& p, auto& pix) { pix = img(-p[0] - 1, 2 * nc - p[1] - 1); };

    pixel_wise(box2d({nr, -border}, {nr + border -1, -1}), img) | // 6
      [&] (auto& p, auto& pix) { pix = img(2 * nr - p[0] - 1, -p[1] - 1); };

    pixel_wise(box2d({nr, nc}, {nr + border - 1, nc + border - 1}), img) | // 8
      [&] (auto& p, auto& pix) { pix = img(2 * nr - p[0] - 1, 2 * nc - p[1] - 1); };

    // Edges.
    pixel_wise(box2d({-border, 0}, { - 1, nc - 1}), img) | // 2
      [&] (auto& p, auto& pix) { pix = img(-p[0] - 1, p[1]); };

    pixel_wise(box2d({nr, 0}, {nr + border - 1, nc - 1}), img) | // 7
      [&] (auto& p, auto& pix) { pix = img(2 * nr -p[0] - 1, p[1]); };

    pixel_wise(box2d({0, -border}, {nr - 1, -1}), img) | // 4
      [&] (auto& p, auto& pix) { pix = img(p[0], - p[1] - 1); };

    pixel_wise(box2d({0, nc}, {nr - 1, nc + border - 1}), img) | // 5
      [&] (auto& p, auto& pix) { pix = img(p[0],  2 * nc - p[1] - 1); };
  }

  template <typename V>
  void fill_border_closest(image2d<V>& img)
  {
    int border = img.border();
    int nc = img.ncols();
    int nr = img.nrows();

    // Corners.
    pixel_wise(box2d({-border, -border}, {-1, -1}), img) |
      [&] (auto& p, auto& pix) { pix = img(0, 0); };

    pixel_wise(box2d({-border, nc}, {-1, nc + border - 1}), img) |
      [&] (auto& p, auto& pix) { pix = img(0, nc - 1); };

    pixel_wise(box2d({nr, -border}, {nr + border -1, -1}), img) |
      [&] (auto& p, auto& pix) { pix = img(nr - 1, 0); };

    pixel_wise(box2d({nr, nc}, {nr + border - 1, nc + border - 1}), img) |
      [&] (auto& p, auto& pix) { pix = img(nr - 1, nc - 1); };

    // Edges.
    pixel_wise(box2d({-border, 0}, { - 1, nc - 1}), img) |
      [&] (auto& p, auto& pix) { pix = img(0, p[1]); };

    pixel_wise(box2d({nr, 0}, {nr + border - 1, nc - 1}), img) |
      [&] (auto& p, auto& pix) { pix = img(nr - 1, p[1]); };

    pixel_wise(box2d({0, -border}, {nr - 1, -1}), img) |
      [&] (auto& p, auto& pix) { pix = img(p[0], 0); };

    pixel_wise(box2d({0, nc}, {nr - 1, nc + border - 1}), img) |
      [&] (auto& p, auto& pix) { pix = img(p[0], nc - 1); };
  }

};

#endif
<commit_msg>Fix clone to properly clone the border and all the other attributes. Add fill_border_with_value, _mirror and _closest.<commit_after>#ifndef VPP_FILL_HH__
# define VPP_FILL_HH__

# include <vpp/core/boxNd.hh>
# include <vpp/core/vector.hh>
# include <vpp/core/pixel_wise.hh>

namespace vpp
{

  template <typename V, typename U, unsigned N>
  void fill(imageNd<V, N>& img, U&& value)
  {
    pixel_wise(img) | [=] (auto& pix) { pix = value; };
  }

  template <typename V, unsigned N>
  void fill(imageNd<V, N>& img, V value, const boxNd<N>& box)
  {
    pixel_wise(box, img) | [=] (auto&, auto& pix) { pix = value; };
  }

  template <typename V, typename U, unsigned N>
  void fill_with_border(imageNd<V, N>& img, U&& value)
  {
    auto box = img.domain_with_border();
    pixel_wise(box, img) | [=] (auto&, auto& pix) { pix = value; };
  }

  template <typename V, typename U>
  void fill_border_with_value(image2d<V>& img, U&& value)
  {
    int border = img.border();
    int nc = img.ncols();
    int nr = img.nrows();

    auto top = box2d({-border, -border}, {-1, nc + border - 1});
    auto bottom = box2d({nr, -border}, {nr + border - 1, nc + border - 1});
    auto left = box2d({0, -border}, {nr - 1, -1});
    auto right = box2d({0, nc}, {nr - 1, nc + border - 1});

    for (auto b : {top, bottom, left, right})
      pixel_wise(b, img) | [=] (auto&, auto& pix) { pix = value; };
  }

  template <typename V>
  void fill_border_mirror(image2d<V>& img)
  {
    int border = img.border();
    int nc = img.ncols();
    int nr = img.nrows();

    // 1  2  3
    // 4     5
    // 6  7  8

    // Corners.
    pixel_wise(box2d({-border, -border}, {-1, -1}), img) | // 1
      [&] (auto& p, auto& pix) { pix = img(-p[0] - 1, -p[1] - 1); };

    pixel_wise(box2d({-border, nc}, {-1, nc + border - 1}), img) | // 3
      [&] (auto& p, auto& pix) { pix = img(-p[0] - 1, 2 * nc - p[1] - 1); };

    pixel_wise(box2d({nr, -border}, {nr + border -1, -1}), img) | // 6
      [&] (auto& p, auto& pix) { pix = img(2 * nr - p[0] - 1, -p[1] - 1); };

    pixel_wise(box2d({nr, nc}, {nr + border - 1, nc + border - 1}), img) | // 8
      [&] (auto& p, auto& pix) { pix = img(2 * nr - p[0] - 1, 2 * nc - p[1] - 1); };

    // Edges.
    pixel_wise(box2d({-border, 0}, { - 1, nc - 1}), img) | // 2
      [&] (auto& p, auto& pix) { pix = img(-p[0] - 1, p[1]); };

    pixel_wise(box2d({nr, 0}, {nr + border - 1, nc - 1}), img) | // 7
      [&] (auto& p, auto& pix) { pix = img(2 * nr -p[0] - 1, p[1]); };

    pixel_wise(box2d({0, -border}, {nr - 1, -1}), img) | // 4
      [&] (auto& p, auto& pix) { pix = img(p[0], - p[1] - 1); };

    pixel_wise(box2d({0, nc}, {nr - 1, nc + border - 1}), img) | // 5
      [&] (auto& p, auto& pix) { pix = img(p[0],  2 * nc - p[1] - 1); };
  }

  template <typename V>
  void fill_border_closest(image2d<V>& img)
  {
    int border = img.border();
    int nc = img.ncols();
    int nr = img.nrows();

    // Corners.
    pixel_wise(box2d({-border, -border}, {-1, -1}), img) |
      [&] (auto& p, auto& pix) { pix = img(0, 0); };

    pixel_wise(box2d({-border, nc}, {-1, nc + border - 1}), img) |
      [&] (auto& p, auto& pix) { pix = img(0, nc - 1); };

    pixel_wise(box2d({nr, -border}, {nr + border -1, -1}), img) |
      [&] (auto& p, auto& pix) { pix = img(nr - 1, 0); };

    pixel_wise(box2d({nr, nc}, {nr + border - 1, nc + border - 1}), img) |
      [&] (auto& p, auto& pix) { pix = img(nr - 1, nc - 1); };

    // Edges.
    pixel_wise(box2d({-border, 0}, { - 1, nc - 1}), img) |
      [&] (auto& p, auto& pix) { pix = img(0, p[1]); };

    pixel_wise(box2d({nr, 0}, {nr + border - 1, nc - 1}), img) |
      [&] (auto& p, auto& pix) { pix = img(nr - 1, p[1]); };

    pixel_wise(box2d({0, -border}, {nr - 1, -1}), img) |
      [&] (auto& p, auto& pix) { pix = img(p[0], 0); };

    pixel_wise(box2d({0, nc}, {nr - 1, nc + border - 1}), img) |
      [&] (auto& p, auto& pix) { pix = img(p[0], nc - 1); };
  }

};

#endif
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Magnus Jonsson & Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/file.hpp"
#include "libtorrent/utf8.hpp"

#include <sstream>
#include <windows.h>

namespace
{
	// must be used to not leak memory in case something would throw
	class auto_localfree
	{
	public:
		auto_localfree(HLOCAL memory)
			: m_memory(memory)
		{
		}
		~auto_localfree()
		{
			if (m_memory)
				LocalFree(m_memory);
		}
	private:
		HLOCAL m_memory;
	};

	std::string utf8_native(std::string const& s)
	{
		std::wstring ws;
		libtorrent::utf8_wchar(s, ws);
		std::size_t size = wcstombs(0, ws.c_str(), 0);
		if (size == std::size_t(-1)) return s;
		std::string ret(size + 1);
		size = wcstombs(&ret[0], ws.c_str(), size + 1);
		ret.resize(size - 1);
		return ret;
	}

	void throw_exception(const char* thrower)
	{
		DWORD err = GetLastError();

#ifdef UNICODE
		wchar_t *wbuffer = 0;
		FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM
			|FORMAT_MESSAGE_ALLOCATE_BUFFER
			, 0, err, 0, (LPWSTR)&wbuffer, 0, 0);
		auto_localfree auto_free(wbuffer);
		std::string tmp_utf8;
		libtorrent::wchar_utf8(wbuffer, tmp_utf8);
		char const* buffer = tmp_utf8.c_str();
#else
		char* buffer = 0;
		FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM
			|FORMAT_MESSAGE_ALLOCATE_BUFFER
			, 0, err, 0, (LPSTR)&buffer, 0, 0);
		auto_localfree auto_free(buffer);
#endif

		std::stringstream s;
		s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");

		throw libtorrent::file_error(s.str());
	}
}

namespace libtorrent
{

	struct file::impl : boost::noncopyable
	{
		enum open_flags
		{
			read_flag = 1,
			write_flag = 2
		};

		enum seek_mode
		{
			seek_begin = FILE_BEGIN,
			seek_from_here = FILE_CURRENT,
			seek_end = FILE_END
		};

		impl()
		{
			m_file_handle = INVALID_HANDLE_VALUE;
		}

		void open(const char *file_name, open_flags flags)
		{
			assert(file_name);
			assert(flags & (read_flag | write_flag));

			DWORD access_mask = 0;
			if (flags & read_flag)
				access_mask |= GENERIC_READ;
			if (flags & write_flag)
				access_mask |= GENERIC_WRITE;

			assert(access_mask & (GENERIC_READ | GENERIC_WRITE));

		#ifdef UNICODE
			std::wstring wfile_name(utf8_wchar(file_name));
			HANDLE new_handle = CreateFile(
				(LPCWSTR)wfile_name.c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#else
			HANDLE new_handle = CreateFile(
				utf8_native(file_name).c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#endif

			if (new_handle == INVALID_HANDLE_VALUE)
			{
				std::stringstream s;
				throw_exception(file_name);
			}
			// will only close old file if the open succeeded
			close();
			m_file_handle = new_handle;
		}

		void close()
		{
			if (m_file_handle != INVALID_HANDLE_VALUE)
			{
				CloseHandle(m_file_handle);
				m_file_handle = INVALID_HANDLE_VALUE;
			}
		}

		~impl()
		{
			close();
		}

		size_type write(const char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);
			DWORD bytes_written = 0;
			if (num_bytes != 0)
			{
				if (FALSE == WriteFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_written
					, 0))
				{
					throw_exception("file::write");
				}
			}
			return bytes_written;
		}

		size_type read(char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);

			DWORD bytes_read = 0;
			if (num_bytes != 0)
			{
				if (FALSE == ReadFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_read
					, 0))
				{
					throw_exception("file::read");
				}
			}
			return bytes_read;
		}

		void seek(size_type pos, seek_mode from_where)
		{
			assert(pos >= 0 || from_where != seek_begin);
			assert(pos <= 0 || from_where != seek_end);
			LARGE_INTEGER offs;
			offs.QuadPart = pos;
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, from_where))
			{
				throw_exception("file::seek");
			}
		}

		size_type tell()
		{
			LARGE_INTEGER offs;
			offs.QuadPart = 0;

			// is there any other way to get offset?
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, FILE_CURRENT))
			{
				throw_exception("file::tell");
			}

			size_type pos=offs.QuadPart;
			assert(pos>=0);
			return pos;
		}
/*
		size_type size()
		{
			LARGE_INTEGER s;
			if (FALSE == GetFileSizeEx(m_file_handle, &s))
			{
				throw_exception("file::size");
			}

			size_type size = s.QuadPart;
			assert(size >= 0);
			return size;
		}
*/
	private:

		HANDLE m_file_handle;

	};
}

namespace libtorrent
{

	const file::seek_mode file::begin(file::impl::seek_begin);
	const file::seek_mode file::end(file::impl::seek_end);

	const file::open_mode file::in(file::impl::read_flag);
	const file::open_mode file::out(file::impl::write_flag);

	file::file()
		: m_impl(new libtorrent::file::impl())
	{
	}
	file::file(boost::filesystem::path const& p, open_mode m)
		: m_impl(new libtorrent::file::impl())
	{
		open(p,m);
	}

	file::~file()
	{
	}

	void file::open(boost::filesystem::path const& p, open_mode m)
	{
		assert(p.is_complete());
		m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buffer, size_type num_bytes)
	{
		return m_impl->write(buffer, num_bytes);
	}

	size_type file::read(char* buffer, size_type num_bytes)
	{
		return m_impl->read(buffer, num_bytes);
	}

	void file::seek(size_type pos, seek_mode m)
	{
		m_impl->seek(pos,impl::seek_mode(m.m_val));
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}
}
<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, Magnus Jonsson & Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/file.hpp"
#include "libtorrent/utf8.hpp"

#include <sstream>
#include <windows.h>

namespace
{
	// must be used to not leak memory in case something would throw
	class auto_localfree
	{
	public:
		auto_localfree(HLOCAL memory)
			: m_memory(memory)
		{
		}
		~auto_localfree()
		{
			if (m_memory)
				LocalFree(m_memory);
		}
	private:
		HLOCAL m_memory;
	};

	std::string utf8_native(std::string const& s)
	{
		std::wstring ws;
		libtorrent::utf8_wchar(s, ws);
		std::size_t size = wcstombs(0, ws.c_str(), 0);
		if (size == std::size_t(-1)) return s;
		std::string ret;
		ret.resize(size);
		size = wcstombs(&ret[0], ws.c_str(), size + 1);
		ret.resize(size);
		return ret;
	}

	void throw_exception(const char* thrower)
	{
		DWORD err = GetLastError();

#ifdef UNICODE
		wchar_t *wbuffer = 0;
		FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM
			|FORMAT_MESSAGE_ALLOCATE_BUFFER
			, 0, err, 0, (LPWSTR)&wbuffer, 0, 0);
		auto_localfree auto_free(wbuffer);
		std::string tmp_utf8;
		libtorrent::wchar_utf8(wbuffer, tmp_utf8);
		char const* buffer = tmp_utf8.c_str();
#else
		char* buffer = 0;
		FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM
			|FORMAT_MESSAGE_ALLOCATE_BUFFER
			, 0, err, 0, (LPSTR)&buffer, 0, 0);
		auto_localfree auto_free(buffer);
#endif

		std::stringstream s;
		s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");

		throw libtorrent::file_error(s.str());
	}
}

namespace libtorrent
{

	struct file::impl : boost::noncopyable
	{
		enum open_flags
		{
			read_flag = 1,
			write_flag = 2
		};

		enum seek_mode
		{
			seek_begin = FILE_BEGIN,
			seek_from_here = FILE_CURRENT,
			seek_end = FILE_END
		};

		impl()
		{
			m_file_handle = INVALID_HANDLE_VALUE;
		}

		void open(const char *file_name, open_flags flags)
		{
			assert(file_name);
			assert(flags & (read_flag | write_flag));

			DWORD access_mask = 0;
			if (flags & read_flag)
				access_mask |= GENERIC_READ;
			if (flags & write_flag)
				access_mask |= GENERIC_WRITE;

			assert(access_mask & (GENERIC_READ | GENERIC_WRITE));

		#ifdef UNICODE
			std::wstring wfile_name(utf8_wchar(file_name));
			HANDLE new_handle = CreateFile(
				(LPCWSTR)wfile_name.c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#else
			HANDLE new_handle = CreateFile(
				utf8_native(file_name).c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#endif

			if (new_handle == INVALID_HANDLE_VALUE)
			{
				std::stringstream s;
				throw_exception(file_name);
			}
			// will only close old file if the open succeeded
			close();
			m_file_handle = new_handle;
		}

		void close()
		{
			if (m_file_handle != INVALID_HANDLE_VALUE)
			{
				CloseHandle(m_file_handle);
				m_file_handle = INVALID_HANDLE_VALUE;
			}
		}

		~impl()
		{
			close();
		}

		size_type write(const char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);
			DWORD bytes_written = 0;
			if (num_bytes != 0)
			{
				if (FALSE == WriteFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_written
					, 0))
				{
					throw_exception("file::write");
				}
			}
			return bytes_written;
		}

		size_type read(char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);

			DWORD bytes_read = 0;
			if (num_bytes != 0)
			{
				if (FALSE == ReadFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_read
					, 0))
				{
					throw_exception("file::read");
				}
			}
			return bytes_read;
		}

		void seek(size_type pos, seek_mode from_where)
		{
			assert(pos >= 0 || from_where != seek_begin);
			assert(pos <= 0 || from_where != seek_end);
			LARGE_INTEGER offs;
			offs.QuadPart = pos;
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, from_where))
			{
				throw_exception("file::seek");
			}
		}

		size_type tell()
		{
			LARGE_INTEGER offs;
			offs.QuadPart = 0;

			// is there any other way to get offset?
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, FILE_CURRENT))
			{
				throw_exception("file::tell");
			}

			size_type pos=offs.QuadPart;
			assert(pos>=0);
			return pos;
		}
/*
		size_type size()
		{
			LARGE_INTEGER s;
			if (FALSE == GetFileSizeEx(m_file_handle, &s))
			{
				throw_exception("file::size");
			}

			size_type size = s.QuadPart;
			assert(size >= 0);
			return size;
		}
*/
	private:

		HANDLE m_file_handle;

	};
}

namespace libtorrent
{

	const file::seek_mode file::begin(file::impl::seek_begin);
	const file::seek_mode file::end(file::impl::seek_end);

	const file::open_mode file::in(file::impl::read_flag);
	const file::open_mode file::out(file::impl::write_flag);

	file::file()
		: m_impl(new libtorrent::file::impl())
	{
	}
	file::file(boost::filesystem::path const& p, open_mode m)
		: m_impl(new libtorrent::file::impl())
	{
		open(p,m);
	}

	file::~file()
	{
	}

	void file::open(boost::filesystem::path const& p, open_mode m)
	{
		assert(p.is_complete());
		m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buffer, size_type num_bytes)
	{
		return m_impl->write(buffer, num_bytes);
	}

	size_type file::read(char* buffer, size_type num_bytes)
	{
		return m_impl->read(buffer, num_bytes);
	}

	void file::seek(size_type pos, seek_mode m)
	{
		m_impl->seek(pos,impl::seek_mode(m.m_val));
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}
}
<|endoftext|>