<commit_before>// $Id$
//***************************************************************************
// File:
//	MachineInstr.cpp
//
// Purpose:
//
//
// Strategy:
//
// History:
//	7/2/01	 -  Vikram Adve  -  Created
//**************************************************************************/

#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/MachineRegInfo.h"
#include "llvm/Method.h"
#include "llvm/ConstPoolVals.h"
#include "llvm/Instruction.h"

//************************ Class Implementations **************************/

// Constructor for instructions with fixed #operands (nearly all)
MachineInstr::MachineInstr(MachineOpCode _opCode,
			   OpCodeMask    _opCodeMask)
  : opCode(_opCode),
    opCodeMask(_opCodeMask),
    operands(TargetInstrDescriptors[_opCode].numOperands)
{
  assert(TargetInstrDescriptors[_opCode].numOperands >= 0);
}

// Constructor for instructions with variable #operands
MachineInstr::MachineInstr(MachineOpCode _opCode,
			   unsigned	 numOperands,
			   OpCodeMask    _opCodeMask)
  : opCode(_opCode),
    opCodeMask(_opCodeMask),
    operands(numOperands)
{
}

void
MachineInstr::SetMachineOperand(unsigned int i,
				MachineOperand::MachineOperandType operandType,
				Value* _val, bool isdef=false)
{
  assert(i < operands.size());
  operands[i].Initialize(operandType, _val);
  operands[i].isDef = isdef ||
    TargetInstrDescriptors[opCode].resultPos == (int) i;
}

void
MachineInstr::SetMachineOperand(unsigned int i,
				MachineOperand::MachineOperandType operandType,
				int64_t intValue, bool isdef=false)
{
  assert(i < operands.size());
  operands[i].InitializeConst(operandType, intValue);
  operands[i].isDef = isdef ||
    TargetInstrDescriptors[opCode].resultPos == (int) i;
}

void
MachineInstr::SetMachineOperand(unsigned int i,
				unsigned int regNum, bool isdef=false)
{
  assert(i < operands.size());
  operands[i].InitializeReg(regNum);
  operands[i].isDef = isdef ||
    TargetInstrDescriptors[opCode].resultPos == (int) i;
}

void
MachineInstr::dump(unsigned int indent) const
{
  for (unsigned i=0; i < indent; i++)
    cout << "    ";

  cout << *this;
}

ostream&
operator<< (ostream& os, const MachineInstr& minstr)
{
  os << TargetInstrDescriptors[minstr.opCode].opCodeString;

  for (unsigned i=0, N=minstr.getNumOperands(); i < N; i++)
    os << "\t" << minstr.getOperand(i);

#undef DEBUG_VAL_OP_ITERATOR
#ifdef DEBUG_VAL_OP_ITERATOR
  os << endl << "\tValue operands are: ";
  for (MachineInstr::val_op_const_iterator vo(&minstr); ! vo.done(); ++vo)
    {
      const Value* val = *vo;
      os << val << (vo.isDef()? "(def), " : ", ");
    }
  os << endl;
#endif

  return os;
}

static inline ostream&
OutputOperand(ostream &os, const MachineOperand &mop)
{
  switch (mop.getOperandType())
    {
    case MachineOperand::MO_CCRegister:
    case MachineOperand::MO_VirtualRegister:
      return os << "(val " << mop.getVRegValue() << ")";
    case MachineOperand::MO_MachineRegister:
      return os << "("     << mop.getMachineRegNum() << ")";
    default:
      assert(0 && "Unknown operand type");
      return os;
    }
}

ostream&
operator<<(ostream &os, const MachineOperand &mop)
{
  switch(mop.opType)
    {
    case MachineOperand::MO_VirtualRegister:
    case MachineOperand::MO_MachineRegister:
      os << "%reg";
      return OutputOperand(os, mop);
    case MachineOperand::MO_CCRegister:
      os << "%ccreg";
      return OutputOperand(os, mop);
    case MachineOperand::MO_SignExtendedImmed:
      return os << mop.immedVal;
    case MachineOperand::MO_UnextendedImmed:
      return os << mop.immedVal;
    case MachineOperand::MO_PCRelativeDisp:
      return os << "%disp(label " << mop.getVRegValue() << ")";
    default:
      assert(0 && "Unrecognized operand type");
      break;
    }

  return os;
}

//---------------------------------------------------------------------------
// Target-independent utility routines for creating machine instructions
//---------------------------------------------------------------------------

//------------------------------------------------------------------------
// Function Set2OperandsFromInstr
// Function Set3OperandsFromInstr
//
// For the common case of 2- and 3-operand arithmetic/logical instructions,
// set the m/c instr. operands directly from the VM instruction's operands.
// Check whether the first or second operand is 0 and can use a dedicated "0"
// register.
// Check whether the second operand should use an immediate field or register.
// (First and third operands are never immediates for such instructions.)
//
// Arguments:
// canDiscardResult: Specifies that the result operand can be discarded
//		     by using the dedicated "0"
//
// op1position, op2position and resultPosition: Specify in which position
//		     in the machine instruction the 3 operands (arg1, arg2
//		     and result) should go.
//
// RETURN VALUE: unsigned int flags, where
//	flags & 0x01	=> operand 1 is constant and needs a register
//	flags & 0x02	=> operand 2 is constant and needs a register
//------------------------------------------------------------------------

void
Set2OperandsFromInstr(MachineInstr* minstr,
		      InstructionNode* vmInstrNode,
		      const TargetMachine& target,
		      bool canDiscardResult,
		      int op1Position,
		      int resultPosition)
{
  Set3OperandsFromInstr(minstr, vmInstrNode, target,
			canDiscardResult, op1Position,
			/*op2Position*/ -1, resultPosition);
}

#undef REVERT_TO_EXPLICIT_CONSTANT_CHECKS
#ifdef REVERT_TO_EXPLICIT_CONSTANT_CHECKS
unsigned
Set3OperandsFromInstrJUNK(MachineInstr* minstr,
			  InstructionNode* vmInstrNode,
			  const TargetMachine& target,
			  bool canDiscardResult,
			  int op1Position,
			  int op2Position,
			  int resultPosition)
{
  assert(op1Position >= 0);
  assert(resultPosition >= 0);

  unsigned returnFlags = 0x0;

  // Check if operand 1 is 0.  If so, try to use a hardwired 0 register.
  Value* op1Value = vmInstrNode->leftChild()->getValue();
  bool isValidConstant;
  int64_t intValue = GetConstantValueAsSignedInt(op1Value, isValidConstant);
  if (isValidConstant && intValue == 0 && target.zeroRegNum >= 0)
    minstr->SetMachineOperand(op1Position, /*regNum*/ target.zeroRegNum);
  else
    {
      if (op1Value->isConstant())
	{
	  // value is constant and must be loaded from constant pool
	  returnFlags = returnFlags | (1 << op1Position);
	}
      minstr->SetMachineOperand(op1Position, MachineOperand::MO_VirtualRegister,
				op1Value);
    }

  // Check if operand 2 (if any) fits in the immed. field of the instruction,
  // or if it is 0 and can use a dedicated machine register
  if (op2Position >= 0)
    {
      Value* op2Value = vmInstrNode->rightChild()->getValue();
      int64_t immedValue;
      unsigned int machineRegNum;

      MachineOperand::MachineOperandType
	op2type = ChooseRegOrImmed(op2Value, minstr->getOpCode(), target,
				   /*canUseImmed*/ true,
				   machineRegNum, immedValue);

      if (op2type == MachineOperand::MO_MachineRegister)
	minstr->SetMachineOperand(op2Position, machineRegNum);
      else if (op2type == MachineOperand::MO_VirtualRegister)
	{
	  if (op2Value->isConstant())
	    {
	      // value is constant and must be loaded from constant pool
	      returnFlags = returnFlags | (1 << op2Position);
	    }
	  minstr->SetMachineOperand(op2Position, op2type, op2Value);
	}
      else
	{
	  assert(op2type != MO_CCRegister);
	  minstr->SetMachineOperand(op2Position, op2type, immedValue);
	}
    }

  // If operand 3 (result) can be discarded, use a dead register if one exists
  if (canDiscardResult && target.zeroRegNum >= 0)
    minstr->SetMachineOperand(resultPosition, target.zeroRegNum);
  else
    minstr->SetMachineOperand(resultPosition, MachineOperand::MO_VirtualRegister, vmInstrNode->getValue());

  return returnFlags;
}
#endif

void
Set3OperandsFromInstr(MachineInstr* minstr,
		      InstructionNode* vmInstrNode,
		      const TargetMachine& target,
		      bool canDiscardResult,
		      int op1Position,
		      int op2Position,
		      int resultPosition)
{
  assert(op1Position >= 0);
  assert(resultPosition >= 0);

  // operand 1
  minstr->SetMachineOperand(op1Position, MachineOperand::MO_VirtualRegister,
			    vmInstrNode->leftChild()->getValue());

  // operand 2 (if any)
  if (op2Position >= 0)
    minstr->SetMachineOperand(op2Position, MachineOperand::MO_VirtualRegister,
			      vmInstrNode->rightChild()->getValue());

  // result operand: if it can be discarded, use a dead register if one exists
  if (canDiscardResult && target.getRegInfo().getZeroRegNum() >= 0)
    minstr->SetMachineOperand(resultPosition,
			      target.getRegInfo().getZeroRegNum());
  else
    minstr->SetMachineOperand(resultPosition,
			      MachineOperand::MO_VirtualRegister, vmInstrNode->getValue());
}

MachineOperand::MachineOperandType
ChooseRegOrImmed(Value* val,
		 MachineOpCode opCode,
		 const TargetMachine& target,
		 bool canUseImmed,
		 unsigned int& getMachineRegNum,
		 int64_t& getImmedValue)
{
  MachineOperand::MachineOperandType opType =
    MachineOperand::MO_VirtualRegister;
  getMachineRegNum = 0;
  getImmedValue = 0;

  // Check for the common case first: argument is not constant
  //
  ConstPoolVal *CPV = val->castConstant();
  if (!CPV) return opType;

  if (CPV->getType() == Type::BoolTy)
    {
      ConstPoolBool *CPB = (ConstPoolBool*)CPV;
      if (!CPB->getValue() && target.getRegInfo().getZeroRegNum() >= 0)
	{
	  getMachineRegNum = target.getRegInfo().getZeroRegNum();
	  return MachineOperand::MO_MachineRegister;
	}

      getImmedValue = 1;
      return MachineOperand::MO_SignExtendedImmed;
    }

  if (!CPV->getType()->isIntegral()) return opType;

  // Now get the constant value and check if it fits in the IMMED field.
  // Take advantage of the fact that the max unsigned value will rarely
  // fit into any IMMED field and ignore that case (i.e., cast smaller
  // unsigned constants to signed).
  //
  int64_t intValue;
  if (CPV->getType()->isSigned())
    {
      intValue = ((ConstPoolSInt*)CPV)->getValue();
    }
  else
    {
      uint64_t V = ((ConstPoolUInt*)CPV)->getValue();
      if (V >= INT64_MAX) return opType;
      intValue = (int64_t)V;
    }

  if (intValue == 0 && target.getRegInfo().getZeroRegNum() >= 0)
    {
      opType = MachineOperand::MO_MachineRegister;
      getMachineRegNum = target.getRegInfo().getZeroRegNum();
    }
  else if (canUseImmed &&
	   target.getInstrInfo().constantFitsInImmedField(opCode, intValue))
    {
      opType = MachineOperand::MO_SignExtendedImmed;
      getImmedValue = intValue;
    }

  return opType;
}

void
PrintMachineInstructions(const Method *const method)
{
  cout << "\n" << method->getReturnType()
       << " \"" << method->getName() << "\"" << endl;

  for (Method::const_iterator BI = method->begin(); BI != method->end(); ++BI)
    {
      BasicBlock* bb = *BI;
      cout << "\n"
	   << (bb->hasName()? bb->getName() : "Label")
	   << " (" << bb << ")" << ":"
	   << endl;

      MachineCodeForBasicBlock& mvec = bb->getMachineInstrVec();
      for (unsigned i=0; i < mvec.size(); i++)
	cout << "\t" << *mvec[i] << endl;
    }
  cout << endl << "End method \"" << method->getName() << "\""
       << endl << endl;
}
<commit_msg>Improved dump for disp type operand.<commit_after>// $Id$
//***************************************************************************
// File:
//	MachineInstr.cpp
//
// Purpose:
//
//
// Strategy:
//
// History:
//	7/2/01	 -  Vikram Adve  -  Created
//**************************************************************************/

#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/MachineRegInfo.h"
#include "llvm/Method.h"
#include "llvm/ConstPoolVals.h"
#include "llvm/Instruction.h"

//************************ Class Implementations **************************/

// Constructor for instructions with fixed #operands (nearly all)
MachineInstr::MachineInstr(MachineOpCode _opCode,
			   OpCodeMask    _opCodeMask)
  : opCode(_opCode),
    opCodeMask(_opCodeMask),
    operands(TargetInstrDescriptors[_opCode].numOperands)
{
  assert(TargetInstrDescriptors[_opCode].numOperands >= 0);
}

// Constructor for instructions with variable #operands
MachineInstr::MachineInstr(MachineOpCode _opCode,
			   unsigned	 numOperands,
			   OpCodeMask    _opCodeMask)
  : opCode(_opCode),
    opCodeMask(_opCodeMask),
    operands(numOperands)
{
}

void
MachineInstr::SetMachineOperand(unsigned int i,
				MachineOperand::MachineOperandType operandType,
				Value* _val, bool isdef=false)
{
  assert(i < operands.size());
  operands[i].Initialize(operandType, _val);
  operands[i].isDef = isdef ||
    TargetInstrDescriptors[opCode].resultPos == (int) i;
}

void
MachineInstr::SetMachineOperand(unsigned int i,
				MachineOperand::MachineOperandType operandType,
				int64_t intValue, bool isdef=false)
{
  assert(i < operands.size());
  operands[i].InitializeConst(operandType, intValue);
  operands[i].isDef = isdef ||
    TargetInstrDescriptors[opCode].resultPos == (int) i;
}

void
MachineInstr::SetMachineOperand(unsigned int i,
				unsigned int regNum, bool isdef=false)
{
  assert(i < operands.size());
  operands[i].InitializeReg(regNum);
  operands[i].isDef = isdef ||
    TargetInstrDescriptors[opCode].resultPos == (int) i;
}

void
MachineInstr::dump(unsigned int indent) const
{
  for (unsigned i=0; i < indent; i++)
    cout << "    ";

  cout << *this;
}

ostream&
operator<< (ostream& os, const MachineInstr& minstr)
{
  os << TargetInstrDescriptors[minstr.opCode].opCodeString;

  for (unsigned i=0, N=minstr.getNumOperands(); i < N; i++)
    os << "\t" << minstr.getOperand(i);

#undef DEBUG_VAL_OP_ITERATOR
#ifdef DEBUG_VAL_OP_ITERATOR
  os << endl << "\tValue operands are: ";
  for (MachineInstr::val_op_const_iterator vo(&minstr); ! vo.done(); ++vo)
    {
      const Value* val = *vo;
      os << val << (vo.isDef()? "(def), " : ", ");
    }
  os << endl;
#endif

  return os;
}

static inline ostream&
OutputOperand(ostream &os, const MachineOperand &mop)
{
  switch (mop.getOperandType())
    {
    case MachineOperand::MO_CCRegister:
    case MachineOperand::MO_VirtualRegister:
      return os << "(val " << mop.getVRegValue() << ")";
    case MachineOperand::MO_MachineRegister:
      return os << "("     << mop.getMachineRegNum() << ")";
    default:
      assert(0 && "Unknown operand type");
      return os;
    }
}

ostream&
operator<<(ostream &os, const MachineOperand &mop)
{
  switch(mop.opType)
    {
    case MachineOperand::MO_VirtualRegister:
    case MachineOperand::MO_MachineRegister:
      os << "%reg";
      return OutputOperand(os, mop);
    case MachineOperand::MO_CCRegister:
      os << "%ccreg";
      return OutputOperand(os, mop);
    case MachineOperand::MO_SignExtendedImmed:
      return os << mop.immedVal;
    case MachineOperand::MO_UnextendedImmed:
      return os << mop.immedVal;
    case MachineOperand::MO_PCRelativeDisp:
      {
        const Value* opVal = mop.getVRegValue();
        bool isLabel = opVal->isMethod() || opVal->isBasicBlock();
        return os << "%disp("
                  << (isLabel? "label " : "addr-of-val ")
                  << opVal << ")";
      }
    default:
      assert(0 && "Unrecognized operand type");
      break;
    }

  return os;
}

//---------------------------------------------------------------------------
// Target-independent utility routines for creating machine instructions
//---------------------------------------------------------------------------

//------------------------------------------------------------------------
// Function Set2OperandsFromInstr
// Function Set3OperandsFromInstr
//
// For the common case of 2- and 3-operand arithmetic/logical instructions,
// set the m/c instr. operands directly from the VM instruction's operands.
// Check whether the first or second operand is 0 and can use a dedicated "0"
// register.
// Check whether the second operand should use an immediate field or register.
// (First and third operands are never immediates for such instructions.)
//
// Arguments:
// canDiscardResult: Specifies that the result operand can be discarded
//		     by using the dedicated "0"
//
// op1position, op2position and resultPosition: Specify in which position
//		     in the machine instruction the 3 operands (arg1, arg2
//		     and result) should go.
//
// RETURN VALUE: unsigned int flags, where
//	flags & 0x01	=> operand 1 is constant and needs a register
//	flags & 0x02	=> operand 2 is constant and needs a register
//------------------------------------------------------------------------

void
Set2OperandsFromInstr(MachineInstr* minstr,
		      InstructionNode* vmInstrNode,
		      const TargetMachine& target,
		      bool canDiscardResult,
		      int op1Position,
		      int resultPosition)
{
  Set3OperandsFromInstr(minstr, vmInstrNode, target,
			canDiscardResult, op1Position,
			/*op2Position*/ -1, resultPosition);
}

#undef REVERT_TO_EXPLICIT_CONSTANT_CHECKS
#ifdef REVERT_TO_EXPLICIT_CONSTANT_CHECKS
unsigned
Set3OperandsFromInstrJUNK(MachineInstr* minstr,
			  InstructionNode* vmInstrNode,
			  const TargetMachine& target,
			  bool canDiscardResult,
			  int op1Position,
			  int op2Position,
			  int resultPosition)
{
  assert(op1Position >= 0);
  assert(resultPosition >= 0);

  unsigned returnFlags = 0x0;

  // Check if operand 1 is 0.  If so, try to use a hardwired 0 register.
  Value* op1Value = vmInstrNode->leftChild()->getValue();
  bool isValidConstant;
  int64_t intValue = GetConstantValueAsSignedInt(op1Value, isValidConstant);
  if (isValidConstant && intValue == 0 && target.zeroRegNum >= 0)
    minstr->SetMachineOperand(op1Position, /*regNum*/ target.zeroRegNum);
  else
    {
      if (op1Value->isConstant())
	{
	  // value is constant and must be loaded from constant pool
	  returnFlags = returnFlags | (1 << op1Position);
	}
      minstr->SetMachineOperand(op1Position, MachineOperand::MO_VirtualRegister,
				op1Value);
    }

  // Check if operand 2 (if any) fits in the immed. field of the instruction,
  // or if it is 0 and can use a dedicated machine register
  if (op2Position >= 0)
    {
      Value* op2Value = vmInstrNode->rightChild()->getValue();
      int64_t immedValue;
      unsigned int machineRegNum;

      MachineOperand::MachineOperandType
	op2type = ChooseRegOrImmed(op2Value, minstr->getOpCode(), target,
				   /*canUseImmed*/ true,
				   machineRegNum, immedValue);

      if (op2type == MachineOperand::MO_MachineRegister)
	minstr->SetMachineOperand(op2Position, machineRegNum);
      else if (op2type == MachineOperand::MO_VirtualRegister)
	{
	  if (op2Value->isConstant())
	    {
	      // value is constant and must be loaded from constant pool
	      returnFlags = returnFlags | (1 << op2Position);
	    }
	  minstr->SetMachineOperand(op2Position, op2type, op2Value);
	}
      else
	{
	  assert(op2type != MO_CCRegister);
	  minstr->SetMachineOperand(op2Position, op2type, immedValue);
	}
    }

  // If operand 3 (result) can be discarded, use a dead register if one exists
  if (canDiscardResult && target.zeroRegNum >= 0)
    minstr->SetMachineOperand(resultPosition, target.zeroRegNum);
  else
    minstr->SetMachineOperand(resultPosition, MachineOperand::MO_VirtualRegister, vmInstrNode->getValue());

  return returnFlags;
}
#endif

void
Set3OperandsFromInstr(MachineInstr* minstr,
		      InstructionNode* vmInstrNode,
		      const TargetMachine& target,
		      bool canDiscardResult,
		      int op1Position,
		      int op2Position,
		      int resultPosition)
{
  assert(op1Position >= 0);
  assert(resultPosition >= 0);

  // operand 1
  minstr->SetMachineOperand(op1Position, MachineOperand::MO_VirtualRegister,
			    vmInstrNode->leftChild()->getValue());

  // operand 2 (if any)
  if (op2Position >= 0)
    minstr->SetMachineOperand(op2Position, MachineOperand::MO_VirtualRegister,
			      vmInstrNode->rightChild()->getValue());

  // result operand: if it can be discarded, use a dead register if one exists
  if (canDiscardResult && target.getRegInfo().getZeroRegNum() >= 0)
    minstr->SetMachineOperand(resultPosition,
			      target.getRegInfo().getZeroRegNum());
  else
    minstr->SetMachineOperand(resultPosition,
			      MachineOperand::MO_VirtualRegister, vmInstrNode->getValue());
}

MachineOperand::MachineOperandType
ChooseRegOrImmed(Value* val,
		 MachineOpCode opCode,
		 const TargetMachine& target,
		 bool canUseImmed,
		 unsigned int& getMachineRegNum,
		 int64_t& getImmedValue)
{
  MachineOperand::MachineOperandType opType =
    MachineOperand::MO_VirtualRegister;
  getMachineRegNum = 0;
  getImmedValue = 0;

  // Check for the common case first: argument is not constant
  //
  ConstPoolVal *CPV = val->castConstant();
  if (!CPV) return opType;

  if (CPV->getType() == Type::BoolTy)
    {
      ConstPoolBool *CPB = (ConstPoolBool*)CPV;
      if (!CPB->getValue() && target.getRegInfo().getZeroRegNum() >= 0)
	{
	  getMachineRegNum = target.getRegInfo().getZeroRegNum();
	  return MachineOperand::MO_MachineRegister;
	}

      getImmedValue = 1;
      return MachineOperand::MO_SignExtendedImmed;
    }

  if (!CPV->getType()->isIntegral()) return opType;

  // Now get the constant value and check if it fits in the IMMED field.
  // Take advantage of the fact that the max unsigned value will rarely
  // fit into any IMMED field and ignore that case (i.e., cast smaller
  // unsigned constants to signed).
  //
  int64_t intValue;
  if (CPV->getType()->isSigned())
    {
      intValue = ((ConstPoolSInt*)CPV)->getValue();
    }
  else
    {
      uint64_t V = ((ConstPoolUInt*)CPV)->getValue();
      if (V >= INT64_MAX) return opType;
      intValue = (int64_t)V;
    }

  if (intValue == 0 && target.getRegInfo().getZeroRegNum() >= 0)
    {
      opType = MachineOperand::MO_MachineRegister;
      getMachineRegNum = target.getRegInfo().getZeroRegNum();
    }
  else if (canUseImmed &&
	   target.getInstrInfo().constantFitsInImmedField(opCode, intValue))
    {
      opType = MachineOperand::MO_SignExtendedImmed;
      getImmedValue = intValue;
    }

  return opType;
}

void
PrintMachineInstructions(const Method *const method)
{
  cout << "\n" << method->getReturnType()
       << " \"" << method->getName() << "\"" << endl;

  for (Method::const_iterator BI = method->begin(); BI != method->end(); ++BI)
    {
      BasicBlock* bb = *BI;
      cout << "\n"
	   << (bb->hasName()? bb->getName() : "Label")
	   << " (" << bb << ")" << ":"
	   << endl;

      MachineCodeForBasicBlock& mvec = bb->getMachineInstrVec();
      for (unsigned i=0; i < mvec.size(); i++)
	cout << "\t" << *mvec[i] << endl;
    }
  cout << endl << "End method \"" << method->getName() << "\""
       << endl << endl;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <exception>

#include <folly/FileUtil.h>
#include <folly/portability/Unistd.h>
#include <folly/json.h>
#include <wangle/client/persistence/FilePersistenceLayer.h>

namespace wangle {

bool FilePersistenceLayer::persist(
  const folly::dynamic& dynObj) noexcept {
  std::string serializedCache;
  try {
    folly::json::serialization_opts opts;
    opts.allow_non_string_keys = true;
    serializedCache = folly::json::serialize(dynObj, opts);
  } catch (const std::exception& err) {
    LOG(ERROR) << "Serializing to JSON failed with error: " << err.what();
    return false;
  }
  bool persisted = false;
  const auto fd = folly::openNoInt(
    file_.c_str(),
    O_WRONLY | O_CREAT | O_TRUNC,
    0600
  );
  if (fd == -1) {
    return false;
  }
  const auto nWritten = folly::writeFull(
    fd,
    serializedCache.data(),
    serializedCache.size()
  );
  persisted = nWritten >= 0 &&
    (static_cast<size_t>(nWritten) == serializedCache.size());
  if (!persisted) {
    LOG(ERROR) << "Failed to write to " << file_ << ":";
    if (nWritten == -1) {
      LOG(ERROR) << "write failed with errno " << errno;
    }
  }
  if (folly::fdatasyncNoInt(fd) != 0) {
    LOG(ERROR) << "Failed to sync " << file_ << ": errno " << errno;
    persisted = false;
  }
  if (folly::closeNoInt(fd) != 0) {
    LOG(ERROR) << "Failed to close " << file_ << ": errno " << errno;
    persisted = false;
  }
  return persisted;
}

folly::Optional<folly::dynamic> FilePersistenceLayer::load() noexcept {
  std::string serializedCache;
  // not being able to read the backing storage means we just
  // start with an empty cache. Failing to deserialize, or write,
  // is a real error so we report errors there.
  std::string exceptionWhat;
  try {
    if (!folly::readFile(file_.c_str(), serializedCache)) {
      return folly::none;
    }

    folly::json::serialization_opts opts;
    opts.allow_non_string_keys = true;
    return folly::parseJson(serializedCache, opts);
  } catch (const std::exception& err) {
    exceptionWhat = err.what();
  } catch (...) {
    exceptionWhat = "Non-standard excpetion";
  }
  LOG(ERROR) << "Deserialization of cache file " << file_
             << " failed with error: " << exceptionWhat;
  return folly::none;
}

void FilePersistenceLayer::clear() {
  // This may fail but it's ok
  ::unlink(file_.c_str());
}

} // namespace wangle
<commit_msg>fixup catch in FilePersistenceLayer<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <wangle/client/persistence/FilePersistenceLayer.h>

#include <exception>

#include <folly/FileUtil.h>
#include <folly/portability/Unistd.h>
#include <folly/json.h>

namespace wangle {

bool FilePersistenceLayer::persist(
  const folly::dynamic& dynObj) noexcept {
  std::string serializedCache;
  try {
    folly::json::serialization_opts opts;
    opts.allow_non_string_keys = true;
    serializedCache = folly::json::serialize(dynObj, opts);
  } catch (...) {
    LOG(ERROR) << "Serializing to JSON failed with error: "
               << folly::exceptionStr(std::current_exception());
    return false;
  }
  bool persisted = false;
  const auto fd = folly::openNoInt(
    file_.c_str(),
    O_WRONLY | O_CREAT | O_TRUNC,
    0600
  );
  if (fd == -1) {
    return false;
  }
  const auto nWritten = folly::writeFull(
    fd,
    serializedCache.data(),
    serializedCache.size()
  );
  persisted = nWritten >= 0 &&
    (static_cast<size_t>(nWritten) == serializedCache.size());
  if (!persisted) {
    LOG(ERROR) << "Failed to write to " << file_ << ":";
    if (nWritten == -1) {
      LOG(ERROR) << "write failed with errno " << errno;
    }
  }
  if (folly::fdatasyncNoInt(fd) != 0) {
    LOG(ERROR) << "Failed to sync " << file_ << ": errno " << errno;
    persisted = false;
  }
  if (folly::closeNoInt(fd) != 0) {
    LOG(ERROR) << "Failed to close " << file_ << ": errno " << errno;
    persisted = false;
  }
  return persisted;
}

folly::Optional<folly::dynamic> FilePersistenceLayer::load() noexcept {
  std::string serializedCache;
  // not being able to read the backing storage means we just
  // start with an empty cache. Failing to deserialize, or write,
  // is a real error so we report errors there.
  try {
    if (!folly::readFile(file_.c_str(), serializedCache)) {
      return folly::none;
    }

    folly::json::serialization_opts opts;
    opts.allow_non_string_keys = true;
    return folly::parseJson(serializedCache, opts);
  } catch (...) {
    LOG(ERROR) << "Deserialization of cache file " << file_ << "failed: "
               << folly::exceptionStr(std::current_exception());
    return folly::none;
  }
}

void FilePersistenceLayer::clear() {
  // This may fail but it's ok
  ::unlink(file_.c_str());
}

} // namespace wangle
<|endoftext|>


<commit_before>// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "build/build_config.h"
#include "base/debug_util.h"

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <unistd.h>

#include "base/basictypes.h"
#include "base/compat_execinfo.h"
#include "base/eintr_wrapper.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/string_piece.h"

// static
bool DebugUtil::SpawnDebuggerOnProcess(unsigned /* process_id */) {
  NOTIMPLEMENTED();
  return false;
}

#if defined(OS_MACOSX)

// Based on Apple's recommended method as described in
// http://developer.apple.com/qa/qa2004/qa1361.html
// static
bool DebugUtil::BeingDebugged() {
  // If the process is sandboxed then we can't use the sysctl, so cache the
  // value.
  static bool is_set = false;
  static bool being_debugged = false;

  if (is_set) {
    return being_debugged;
  }

  // Initialize mib, which tells sysctl what info we want.  In this case,
  // we're looking for information about a specific process ID.
  int mib[] = {
    CTL_KERN,
    KERN_PROC,
    KERN_PROC_PID,
    getpid()
  };

  // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE.  The source and
  // binary interfaces may change.
  struct kinfo_proc info;
  size_t info_size = sizeof(info);

  int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0);
  DCHECK(sysctl_result == 0);
  if (sysctl_result != 0) {
    is_set = true;
    being_debugged = false;
    return being_debugged;
  }

  // This process is being debugged if the P_TRACED flag is set.
  is_set = true;
  being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
  return being_debugged;
}

#elif defined(OS_LINUX)

// We can look in /proc/self/status for TracerPid.  We are likely used in crash
// handling, so we are careful not to use the heap or have side effects.
// Another option that is common is to try to ptrace yourself, but then we
// can't detach without forking(), and that's not so great.
// static
bool DebugUtil::BeingDebugged() {
  int status_fd = open("/proc/self/status", O_RDONLY);
  if (status_fd == -1)
    return false;

  // We assume our line will be in the first 1024 characters and that we can
  // read this much all at once.  In practice this will generally be true.
  // This simplifies and speeds up things considerably.
  char buf[1024];

  ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf)));
  HANDLE_EINTR(close(status_fd));

  if (num_read <= 0)
    return false;

  base::StringPiece status(buf, num_read);
  base::StringPiece tracer("TracerPid:\t");

  base::StringPiece::size_type pid_index = status.find(tracer);
  if (pid_index == base::StringPiece::npos)
    return false;

  // Our pid is 0 without a debugger, assume this for any pid starting with 0.
  pid_index += tracer.size();
  return pid_index < status.size() && status[pid_index] != '0';
}

#endif  // OS_LINUX

// static
void DebugUtil::BreakDebugger() {
#if defined(ARCH_CPU_ARM_FAMILY)
  asm("bkpt 0");
#else
  asm("int3");
#endif
}

StackTrace::StackTrace() {
  if (backtrace == NULL) {
    count_ = 0;
  } else {
    // Though the backtrace API man page does not list any possible negative
    // return values, we take no chance.
    count_ = std::max(backtrace(trace_, arraysize(trace_)), 0);
  }
}

void StackTrace::PrintBacktrace() {
  if (backtrace_symbols_fd != NULL) {
    fflush(stderr);
    backtrace_symbols_fd(trace_, count_, STDERR_FILENO);
  }
}

void StackTrace::OutputToStream(std::ostream* os) {
  if (backtrace_symbols != NULL) {
    scoped_ptr_malloc<char*> trace_symbols(backtrace_symbols(trace_, count_));

    // If we can't retrieve the symbols, print an error and just dump the raw
    // addresses.
    if (trace_symbols.get() == NULL) {
      (*os) << "Unable get symbols for backtrace (" << strerror(errno)
            << "). Dumping raw addresses in trace:\n";
      for (int i = 0; i < count_; ++i) {
        (*os) << "\t" << trace_[i] << "\n";
      }
    } else {
      (*os) << "Backtrace:\n";
      for (int i = 0; i < count_; ++i) {
        (*os) << "\t" << trace_symbols.get()[i] << "\n";
      }
    }
  }
}
<commit_msg>A build fix for gcc 4.3 (and later). Comparing a function with NULL has been prohibited since gcc 4.3 and produces a compilation error. This change encloses your code which compares a function with NULL with "#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5" and "#endif".<commit_after>// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "build/build_config.h"
#include "base/debug_util.h"

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <unistd.h>

#if defined(OS_MACOSX)
#include <AvailabilityMacros.h>
#endif

#include "base/basictypes.h"
#include "base/compat_execinfo.h"
#include "base/eintr_wrapper.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/string_piece.h"

// static
bool DebugUtil::SpawnDebuggerOnProcess(unsigned /* process_id */) {
  NOTIMPLEMENTED();
  return false;
}

#if defined(OS_MACOSX)

// Based on Apple's recommended method as described in
// http://developer.apple.com/qa/qa2004/qa1361.html
// static
bool DebugUtil::BeingDebugged() {
  // If the process is sandboxed then we can't use the sysctl, so cache the
  // value.
  static bool is_set = false;
  static bool being_debugged = false;

  if (is_set) {
    return being_debugged;
  }

  // Initialize mib, which tells sysctl what info we want.  In this case,
  // we're looking for information about a specific process ID.
  int mib[] = {
    CTL_KERN,
    KERN_PROC,
    KERN_PROC_PID,
    getpid()
  };

  // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE.  The source and
  // binary interfaces may change.
  struct kinfo_proc info;
  size_t info_size = sizeof(info);

  int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0);
  DCHECK(sysctl_result == 0);
  if (sysctl_result != 0) {
    is_set = true;
    being_debugged = false;
    return being_debugged;
  }

  // This process is being debugged if the P_TRACED flag is set.
  is_set = true;
  being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
  return being_debugged;
}

#elif defined(OS_LINUX)

// We can look in /proc/self/status for TracerPid.  We are likely used in crash
// handling, so we are careful not to use the heap or have side effects.
// Another option that is common is to try to ptrace yourself, but then we
// can't detach without forking(), and that's not so great.
// static
bool DebugUtil::BeingDebugged() {
  int status_fd = open("/proc/self/status", O_RDONLY);
  if (status_fd == -1)
    return false;

  // We assume our line will be in the first 1024 characters and that we can
  // read this much all at once.  In practice this will generally be true.
  // This simplifies and speeds up things considerably.
  char buf[1024];

  ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf)));
  HANDLE_EINTR(close(status_fd));

  if (num_read <= 0)
    return false;

  base::StringPiece status(buf, num_read);
  base::StringPiece tracer("TracerPid:\t");

  base::StringPiece::size_type pid_index = status.find(tracer);
  if (pid_index == base::StringPiece::npos)
    return false;

  // Our pid is 0 without a debugger, assume this for any pid starting with 0.
  pid_index += tracer.size();
  return pid_index < status.size() && status[pid_index] != '0';
}

#endif  // OS_LINUX

// static
void DebugUtil::BreakDebugger() {
#if defined(ARCH_CPU_ARM_FAMILY)
  asm("bkpt 0");
#else
  asm("int3");
#endif
}

StackTrace::StackTrace() {
#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  if (!backtrace) {
    count_ = 0;
    return;
  }
#endif
  // Though the backtrace API man page does not list any possible negative
  // return values, we take no chance.
  count_ = std::max(backtrace(trace_, arraysize(trace_)), 0);
}

void StackTrace::PrintBacktrace() {
#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  if (!backtrace_symbols_fd)
    return;
#endif
  fflush(stderr);
  backtrace_symbols_fd(trace_, count_, STDERR_FILENO);
}

void StackTrace::OutputToStream(std::ostream* os) {
#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  if (!backtrace_symbols)
    return;
#endif
  scoped_ptr_malloc<char*> trace_symbols(backtrace_symbols(trace_, count_));

  // If we can't retrieve the symbols, print an error and just dump the raw
  // addresses.
  if (trace_symbols.get() == NULL) {
    (*os) << "Unable get symbols for backtrace (" << strerror(errno)
          << "). Dumping raw addresses in trace:\n";
    for (int i = 0; i < count_; ++i) {
      (*os) << "\t" << trace_[i] << "\n";
    }
  } else {
    (*os) << "Backtrace:\n";
    for (int i = 0; i < count_; ++i) {
      (*os) << "\t" << trace_symbols.get()[i] << "\n";
    }
  }
}
<|endoftext|>


<commit_before>/*
 * This file is part of xyzcrush. Copyright (c) 2017 xyzcrush authors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <zlib.h>
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#ifdef _WIN32
# include <algorithm>
#endif
#include "zopfli/zlib_container.h"

# ifdef __MINGW64_VERSION_MAJOR
int _dowildcard = -1; /* enable wildcard expansion for mingw-w64 */
# endif

/** Returns the filename (without extension). */
std::string GetFilename(const std::string& str);

/** Returns that path (everything left to the last /) */
std::string GetPath(const std::string& str);

std::string GetFilename(const std::string& str) {
	std::string s = str;
#ifdef _WIN32
	std::replace(s.begin(), s.end(), '\\', '/');
#endif

	// Extension
	size_t found = s.find_last_of(".");
	if(found != std::string::npos) {
		s = s.substr(0, found);
	}

	// Filename
	found = s.find_last_of("/");
	if(found == std::string::npos) {
		return s;
	}

	s = s.substr(found + 1);
	return s;
}

std::string GetPath(const std::string& str) {
	std::string s = str;
#ifdef _WIN32
	std::replace(s.begin(), s.end(), '\\', '/');
#endif
	// Path
	size_t found = s.find_last_of("/");
	if(found == std::string::npos) {
		return ".";
	}

	s = s.substr(0, found);
	return s;
}

int main(int argc, char* argv[]) {
	ZopfliOptions zopfli_options;
	ZopfliInitOptions(&zopfli_options);
	zopfli_options.verbose = 0;
	zopfli_options.verbose_more = 0;
	zopfli_options.numiterations = 15;
	zopfli_options.blocksplitting = 1;
	zopfli_options.blocksplittinglast = 0;
	zopfli_options.blocksplittingmax = 15;

	if (argc < 2) {
		std::cout << "Usage: " << argv[0]
			<< " filename" << std::endl;
		return 1;
	}

	unsigned int errors;
	char header[5];

	for (int arg = 1; arg < argc; arg++) {
		std::ifstream file(argv[arg],
			std::ios::binary | std::ios::ate);
		if (!file) {
			std::cerr << "Error reading file " << argv[arg] << "."
				<< std::endl;
			errors++;
			continue;
		}

		long size = file.tellg();
		header[4] = '\0';

		file.seekg(0, std::ios::beg);
		file.read(header, 4);

		if (memcmp(header, "XYZ1", 4) != 0) {
			std::cerr << "Input file " << argv[arg]
				<< " is not an XYZ file: '" << header << "'." << std::endl;
			errors++;
			continue;
		}

		unsigned short width;
		unsigned short height;
		file.read((char*) &width, 2);
		file.read((char*) &height, 2);

		int compressed_xyz_size = size - 8;
		Bytef* compressed_xyz_data = new Bytef[compressed_xyz_size];

		file.read((char*) compressed_xyz_data, compressed_xyz_size);

		uLongf xyz_size = 768 + (width * height);
		Bytef* xyz_data = new Bytef[xyz_size];

		int status = uncompress(xyz_data, &xyz_size, compressed_xyz_data,
			compressed_xyz_size);

		if (status != Z_OK) {
			std::cerr << "XYZ error in file " << argv[arg] << "." << std::endl;
			errors++;
			continue;
		}
		delete[] compressed_xyz_data;

		// Compress XYZ data
		size_t comp_size = 0;
		unsigned char* comp_data = 0;

		ZopfliZlibCompress(&zopfli_options, xyz_data, xyz_size, &comp_data,
			&comp_size);

		delete[] xyz_data;

		std::stringstream ss;
		ss << GetFilename(argv[arg]) + std::string(".xyz");
		std::string xyz_filename = ss.str();
		std::ofstream xyz_file(xyz_filename.c_str(), std::ofstream::binary);
		xyz_file.write("XYZ1", 4);
		xyz_file.write(reinterpret_cast<char*>(&width), 2);
		xyz_file.write(reinterpret_cast<char*>(&height), 2);
		xyz_file.write(reinterpret_cast<char*>(comp_data), comp_size);
		xyz_file.close();
		delete[] comp_data;

		std::cout << "Input file " << argv[arg] << ": " << size << "->"
			<< comp_size + 8 << " (" << (comp_size + 8) * 100 / size << "%)"
			<< std::endl;
	}

	if (errors > 0) {
		return 1;
	}
	return 0;
}
<commit_msg>Fix an oversight in xyzcrush<commit_after>/*
 * This file is part of xyzcrush. Copyright (c) 2017 xyzcrush authors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <zlib.h>
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#ifdef _WIN32
# include <algorithm>
#endif
#include "zopfli/zlib_container.h"

# ifdef __MINGW64_VERSION_MAJOR
int _dowildcard = -1; /* enable wildcard expansion for mingw-w64 */
# endif

/** Returns the filename (without extension). */
std::string GetFilename(const std::string& str);

/** Returns that path (everything left to the last /) */
std::string GetPath(const std::string& str);

std::string GetFilename(const std::string& str) {
	std::string s = str;
#ifdef _WIN32
	std::replace(s.begin(), s.end(), '\\', '/');
#endif

	// Extension
	size_t found = s.find_last_of(".");
	if(found != std::string::npos) {
		s = s.substr(0, found);
	}

	// Filename
	found = s.find_last_of("/");
	if(found == std::string::npos) {
		return s;
	}

	s = s.substr(found + 1);
	return s;
}

std::string GetPath(const std::string& str) {
	std::string s = str;
#ifdef _WIN32
	std::replace(s.begin(), s.end(), '\\', '/');
#endif
	// Path
	size_t found = s.find_last_of("/");
	if(found == std::string::npos) {
		return ".";
	}

	s = s.substr(0, found);
	return s;
}

int main(int argc, char* argv[]) {
	ZopfliOptions zopfli_options;
	ZopfliInitOptions(&zopfli_options);
	zopfli_options.verbose = 0;
	zopfli_options.verbose_more = 0;
	zopfli_options.numiterations = 15;
	zopfli_options.blocksplitting = 1;
	zopfli_options.blocksplittinglast = 0;
	zopfli_options.blocksplittingmax = 15;

	if (argc < 2) {
		std::cout << "Usage: " << argv[0]
			<< " filename" << std::endl;
		return 1;
	}

	unsigned int errors = 0;
	char header[5];

	for (int arg = 1; arg < argc; arg++) {
		std::ifstream file(argv[arg],
			std::ios::binary | std::ios::ate);
		if (!file) {
			std::cerr << "Error reading file " << argv[arg] << "."
				<< std::endl;
			errors++;
			continue;
		}

		long size = file.tellg();
		header[4] = '\0';

		file.seekg(0, std::ios::beg);
		file.read(header, 4);

		if (memcmp(header, "XYZ1", 4) != 0) {
			std::cerr << "Input file " << argv[arg]
				<< " is not an XYZ file: '" << header << "'." << std::endl;
			errors++;
			continue;
		}

		unsigned short width;
		unsigned short height;
		file.read((char*) &width, 2);
		file.read((char*) &height, 2);

		int compressed_xyz_size = size - 8;
		Bytef* compressed_xyz_data = new Bytef[compressed_xyz_size];

		file.read((char*) compressed_xyz_data, compressed_xyz_size);

		uLongf xyz_size = 768 + (width * height);
		Bytef* xyz_data = new Bytef[xyz_size];

		int status = uncompress(xyz_data, &xyz_size, compressed_xyz_data,
			compressed_xyz_size);

		if (status != Z_OK) {
			std::cerr << "XYZ error in file " << argv[arg] << "." << std::endl;
			errors++;
			continue;
		}
		delete[] compressed_xyz_data;

		// Compress XYZ data
		size_t comp_size = 0;
		unsigned char* comp_data = 0;

		ZopfliZlibCompress(&zopfli_options, xyz_data, xyz_size, &comp_data,
			&comp_size);

		delete[] xyz_data;

		std::stringstream ss;
		ss << GetFilename(argv[arg]) + std::string(".xyz");
		std::string xyz_filename = ss.str();
		std::ofstream xyz_file(xyz_filename.c_str(), std::ofstream::binary);
		xyz_file.write("XYZ1", 4);
		xyz_file.write(reinterpret_cast<char*>(&width), 2);
		xyz_file.write(reinterpret_cast<char*>(&height), 2);
		xyz_file.write(reinterpret_cast<char*>(comp_data), comp_size);
		xyz_file.close();
		delete[] comp_data;

		std::cout << "Input file " << argv[arg] << ": " << size << "->"
			<< comp_size + 8 << " (" << (comp_size + 8) * 100 / size << "%)"
			<< std::endl;
	}

	if (errors > 0) {
		return 1;
	}
	return 0;
}
<|endoftext|>


<commit_before><commit_msg>adding tone function to spark<commit_after><|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Morwenn
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <algorithm>
#include <array>
#include <cassert>
#include <chrono>
#include <cstddef>
#include <fstream>
#include <iterator>
#include <type_traits>
#include <utility>
#include <vector>
#include <cpp-sort/adapters.h>
#include <cpp-sort/fixed_sorters.h>
#include <cpp-sort/sort.h>
#include <cpp-sort/sorters.h>
#include "distributions.h"

////////////////////////////////////////////////////////////
// Timing functions

template<
    typename T,
    std::size_t N,
    typename Sorter,
    typename DistributionFunction
>
auto time_it(Sorter sorter, DistributionFunction dist, std::size_t times)
    -> std::chrono::milliseconds
{
    // Choose the best clock type (always steady)
    using clock_type = std::conditional_t<
        std::chrono::high_resolution_clock::is_steady,
        std::chrono::high_resolution_clock,
        std::chrono::steady_clock
    >;

    // Generate times arrays of size N thanks to dist
    std::vector<std::array<T, N>> arrays(times);
    for (auto&& array: arrays)
    {
        dist(std::begin(array), std::end(array));
    }

    // Time while sorting the arrays
    auto start = clock_type::now();
    for (auto&& array: arrays)
    {
        cppsort::sort(array, sorter);
    }
    auto end = clock_type::now();

    // Double benchmark as unit test
    for (auto&& array: arrays)
    {
        assert(std::is_sorted(std::begin(array), std::end(array)));
    }

    // Return the time it took to sort the arrays
    return std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
}

template<
    typename T,
    typename Distribution,
    std::size_t... Ind
>
auto time_distribution(std::size_t times, std::index_sequence<Ind...>)
    -> void
{
    using sorting_network_sorter = cppsort::small_array_adapter<
        cppsort::sorting_network_sorter
    >;

    using low_comparisons_sorter = cppsort::small_array_adapter<
        cppsort::low_comparisons_sorter
    >;

    using low_moves_sorter = cppsort::small_array_adapter<
        cppsort::low_moves_sorter
    >;

    // Compute results for the different sorting algorithms
    std::pair<const char*, std::array<std::chrono::milliseconds, sizeof...(Ind)>> results[] = {
        { "insertion_sorter",       { time_it<T, Ind>(cppsort::insertion_sorter{},  Distribution{}, times)... } },
        { "selection_sorter",       { time_it<T, Ind>(cppsort::selection_sorter{},  Distribution{}, times)... } },
        { "low_moves_sorter",       { time_it<T, Ind>(low_moves_sorter{},           Distribution{}, times)... } },
        { "low_comparisons_sorter", { time_it<T, Ind>(low_comparisons_sorter{},     Distribution{}, times)... } },
        { "sorting_network_sorter", { time_it<T, Ind>(sorting_network_sorter{},     Distribution{}, times)... } },
    };

    // Output the results to their respective files
    std::ofstream output(Distribution::output);
    for (auto&& sort_result: results)
    {
        output << std::get<0>(sort_result) << ' ';
        for (auto&& time: std::get<1>(sort_result))
        {
            output << time.count() << ' ';
        }
        output << '\n';
    }
}

template<
    typename T,
    std::size_t N,
    typename... Distributions
>
auto time_distributions(std::size_t times)
    -> void
{
    using indices = std::make_index_sequence<N>;

    // Variadic dispatch only works with expressions
    int dummy[] = {
        (time_distribution<T, Distributions>(times, indices{}), 0)...
    };
    (void) dummy;
}

int main()
{
    time_distributions<int, 14u,
        shuffled/*,
        all_equal,
        ascending,
        descending,
        pipe_organ,
        push_front,
        push_middle*/
    >(1'000'000u);
}
<commit_msg>Rollback unwilling commit of benchmark.<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Morwenn
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <algorithm>
#include <array>
#include <cassert>
#include <chrono>
#include <cstddef>
#include <fstream>
#include <iterator>
#include <type_traits>
#include <utility>
#include <vector>
#include <cpp-sort/adapters.h>
#include <cpp-sort/fixed_sorters.h>
#include <cpp-sort/sort.h>
#include <cpp-sort/sorters.h>
#include "distributions.h"

////////////////////////////////////////////////////////////
// Timing functions

template<
    typename T,
    std::size_t N,
    typename Sorter,
    typename DistributionFunction
>
auto time_it(Sorter sorter, DistributionFunction dist, std::size_t times)
    -> std::chrono::milliseconds
{
    // Choose the best clock type (always steady)
    using clock_type = std::conditional_t<
        std::chrono::high_resolution_clock::is_steady,
        std::chrono::high_resolution_clock,
        std::chrono::steady_clock
    >;

    // Generate times arrays of size N thanks to dist
    std::vector<std::array<T, N>> arrays(times);
    for (auto&& array: arrays)
    {
        dist(std::begin(array), std::end(array));
    }

    // Time while sorting the arrays
    auto start = clock_type::now();
    for (auto&& array: arrays)
    {
        cppsort::sort(array, sorter);
    }
    auto end = clock_type::now();

    // Double benchmark as unit test
    for (auto&& array: arrays)
    {
        assert(std::is_sorted(std::begin(array), std::end(array)));
    }

    // Return the time it took to sort the arrays
    return std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
}

template<
    typename T,
    typename Distribution,
    std::size_t... Ind
>
auto time_distribution(std::size_t times, std::index_sequence<Ind...>)
    -> void
{
    using sorting_network_sorter = cppsort::small_array_adapter<
        cppsort::sorting_network_sorter
    >;

    using low_comparisons_sorter = cppsort::small_array_adapter<
        cppsort::low_comparisons_sorter
    >;

    using low_moves_sorter = cppsort::small_array_adapter<
        cppsort::low_moves_sorter
    >;

    // Compute results for the different sorting algorithms
    std::pair<const char*, std::array<std::chrono::milliseconds, sizeof...(Ind)>> results[] = {
        { "insertion_sorter",       { time_it<T, Ind>(cppsort::insertion_sorter{},  Distribution{}, times)... } },
        { "selection_sorter",       { time_it<T, Ind>(cppsort::selection_sorter{},  Distribution{}, times)... } },
        { "low_moves_sorter",       { time_it<T, Ind>(low_moves_sorter{},           Distribution{}, times)... } },
        { "low_comparisons_sorter", { time_it<T, Ind>(low_comparisons_sorter{},     Distribution{}, times)... } },
        { "sorting_network_sorter", { time_it<T, Ind>(sorting_network_sorter{},     Distribution{}, times)... } },
    };

    // Output the results to their respective files
    std::ofstream output(Distribution::output);
    for (auto&& sort_result: results)
    {
        output << std::get<0>(sort_result) << ' ';
        for (auto&& time: std::get<1>(sort_result))
        {
            output << time.count() << ' ';
        }
        output << '\n';
    }
}

template<
    typename T,
    std::size_t N,
    typename... Distributions
>
auto time_distributions(std::size_t times)
    -> void
{
    using indices = std::make_index_sequence<N>;

    // Variadic dispatch only works with expressions
    int dummy[] = {
        (time_distribution<T, Distributions>(times, indices{}), 0)...
    };
    (void) dummy;
}

int main()
{
    time_distributions<int, 14u,
        shuffled,
        all_equal,
        ascending,
        descending,
        pipe_organ,
        push_front,
        push_middle
    >(1'000'000u);
}
<|endoftext|>


<commit_before><commit_msg>fix wrong version numbers for options<commit_after><|endoftext|>


<commit_before>#include "bigreader.hpp"
#include "log.hpp"
#include <algorithm>
#include <cstdio>
#include <cctype>

#include FILESYSTEM_HEADER
namespace fs = FILESYSTEM_NAMESPACE;

namespace OpenBFME {

uint32_t readUInt32(FILE* file){
    uint8_t val[4];
    fread(val, 1, 4, file);
    return val[0] << 24 | val[1] << 16 | val[2] << 8 | val[3];
}

string readString(FILE* file, uint32_t limit, char terminator = '\0'){
    string data;
    while(uint32_t(ftell(file)) < limit){
        character c = fgetc(file);
        if(c == '\0' || c == terminator || ferror(file) || feof(file)){
            break;
        }
        data += c;
    }
    return data;
}

BigArchive::BigArchive(const string &filename, BigFilesystem &fs) : archiveFilename(filename), file(nullptr), filesystem(fs) {
    std::replace(archiveFilename.begin(), archiveFilename.end(), '\\', '/');
}

BigArchive::~BigArchive(){
    close();
}

bool BigArchive::readHeader(){
    if (fs::is_directory(fs::path(archiveFilename))) {
        backend = Folder;

        for (fs::recursive_directory_iterator dir(archiveFilename), end; dir != end; ++dir) {
            const fs::path& currentPath = dir->path();
            if (fs::is_regular_file(currentPath)) {
                auto entry = entries.emplace(*this, 0, uint32_t(fs::file_size(currentPath)),
                                             currentPath.string().substr(currentPath.string().find_first_of('/') + 1));
                Log::debug("File path: \"%s\" length: %#08x", entry.first->filename, entry.first->end);
            }
        }

        return true;
    }

    backend = BigFile;

    if(!open()){
        return false;
    }

    character id[4] = {0};
    fread(id, 1, 4, file);

    if (id[0] != 'B' || id[1] != 'I' || id[2] != 'G' || (id[3] != '4' && id[3] != 'F')){
        close();
        return false;
    }

    fseek(file, 8, SEEK_SET);

    uint32_t fileCount = readUInt32(file);
    uint32_t headerEnd = readUInt32(file);

    Log::info("File Count: %u Header End: %#08x", fileCount, headerEnd);

    for(uint32_t f = 0; f < fileCount; ++f){
        uint32_t start = readUInt32(file);
        uint32_t end   = start + readUInt32(file);
        string path = readString(file, headerEnd);
        std::replace(path.begin(), path.end(), '\\', '/');

        entries.emplace(*this, start, end, path);

        Log::debug("File #%04d start: %#08x end: %#08x path: \"%s\"", f + 1, start, end, path);
    }

    if(uint32_t(ftell(file)) > headerEnd){
        Log::warning("Reading of file info passed through end of header.");
    }

    return true;
}

bool BigArchive::open(){
    if(file != nullptr){
        return true;
    }

    if(backend == BigFile){
        file = fopen(archiveFilename.c_str(), "rb");
    }

    return file != nullptr;
}

void BigArchive::close(){
    if(file != nullptr){
        fclose(file);
        file = nullptr;
    }
    currentEntry = nullptr;
}

bool BigArchive::openEntry(const BigEntry& entry) {
    entry.line = 0;
    /* Comments mode must be reenabled after opening a new file. */
    comments = false;

    switch (backend) {
    case BigFile:
        if (open()) {
            fseek(file, entry.start, SEEK_SET);
            currentEntry = &entry;
            return true;
        }
        break;
    case Folder:
        close();
        file = fopen((archiveFilename + '/' + entry.filename).c_str(), "rb");
        if (file != nullptr) {
            currentEntry = &entry;
            return true;
        }
        break;
    }
    return false;
}

const BigEntry* BigArchive::openFile(const string &filename){
    auto entry = entries.find(BigEntry(*this, 0, 0, filename));
    if(entry != entries.end() && openEntry(*entry)){
        return &(*entry);
    }

    return nullptr;
}

string BigArchive::getLine(const BigEntry &entry){
    if(!open() || eof(entry)){
        return "";
    }
    string str = readString(file, entry.end, '\n');

    if(str.back() == '\r'){
        str.pop_back();
    }

    string::size_type comment = std::min(str.find(';'), str.find("//"));
    if(comment != string::npos)
        str.erase(comment);

    entry.line++;

    return str;
}

string BigArchive::getWord(const BigEntry &entry){
    if(!open() || eof(entry)){
        return "";
    }

    bool isWrd = false;
    bool isStr = false;
    bool isNmb = false;
    bool isSym = false;

    string data;
    while(!eof(entry)){
        character c = fgetc(file);

        if(ferror(file) || feof(file)){
            break;
        }

        if(data.empty()){
            if(c == '\n'){
                /* return a newline character if it's the first non-space we run into. */
                entry.line++;
                return "\n";
            }
            if(std::isspace(c)){
                /* Ignore a space. */
                continue;
            }
            if(std::isalpha(c)){
                /* we have a word! */
                isWrd = true;
            }else if(std::isdigit(c)){
                /* we have a number! */
                isNmb = true;
            }else if(c == '"'){
                /* we have a string! */
                isStr = true;
            }else{
                isSym = true;
            }
        }else{
            if(!isStr && (std::isspace(c) ||
                    (isWrd && !std::isalnum(c) && c != '_') ||
                    (isNmb && !std::isdigit(c) && c != '.') ||
                    (isSym && std::isalnum(c)))){
                ungetc(c, file);
                break;
            }
            if(isStr && c == '"'){
                data += c;
                break;
            }
        }
        data += c;
    }

    string::size_type comment = std::min(data.find(';'), data.find("//"));
    if(isSym && comment != string::npos){
        getLine(entry);

        /* If the comment is at the very start of the line we return a newline character. */
        if(comment == 0)
            return "\n";

        data.erase(comment);
    }

    return data;
}

bool BigArchive::seek(const BigEntry &entry, uint32_t pos){
    if(&entry != currentEntry){
        openEntry(entry);
    }

    pos += entry.start;
    if(pos < entry.end){
        fseek(file, pos, SEEK_SET);
        return true;
    }
    return false;
}

uint32_t BigArchive::tell(const BigEntry &entry){
    if(&entry != currentEntry){
        openEntry(entry);
    }

    uint32_t pos = ftell(file);
    if(pos < entry.start){
        return 0;
    }
    if(pos > entry.end){
        return entry.end - entry.start;
    }
    return pos - entry.start;
}

bool BigArchive::eof(const BigEntry &entry){
    uint32_t cpos = ftell(file);
    return cpos < entry.start || cpos >= entry.end;
}

bool BigArchive::extract(const string &filename, const string &directory, bool fullPath){
    const BigEntry* entry = openFile(filename);

    if(entry == nullptr){
        return false;
    }

    string outfilename = filename;

    if(!fullPath){
        outfilename.erase(0, outfilename.find_last_of('/') + 1);
    }
    outfilename.insert(0, directory);
    fs::create_directories(fs::path(outfilename.substr(0, outfilename.find_last_of('/'))));

    Log::info("Extracting to \"%s\"...", outfilename);

    FILE* out = fopen(outfilename.c_str(), "wb");

    if(out == nullptr){
        Log::error("Unable to create file \"%s\"!", outfilename);
        return false;
    }
    uint32_t length = entry->end - entry->start;
    uint8_t *buffer = new uint8_t[length];

    fread(buffer, 1, length, file);
    fwrite(buffer, 1, length, out);

    fclose(out);
    delete[] buffer;

    Log::info("File successfully extracted.");

    return true;
}

bool BigArchive::extractAll(const string &directory){
    fs::create_directories(fs::path(directory));
    for(auto &entry : entries){
        if(!extract(entry.filename, directory, true)){
            return false;
        }
    }
    return true;
}

}
<commit_msg>Restructured getWord() a bit.<commit_after>#include "bigreader.hpp"
#include "log.hpp"
#include <algorithm>
#include <cstdio>
#include <cctype>

#include FILESYSTEM_HEADER
namespace fs = FILESYSTEM_NAMESPACE;

namespace OpenBFME {

uint32_t readUInt32(FILE* file){
    uint8_t val[4];
    fread(val, 1, 4, file);
    return val[0] << 24 | val[1] << 16 | val[2] << 8 | val[3];
}

string readString(FILE* file, uint32_t limit, char terminator = '\0'){
    string data;
    while(uint32_t(ftell(file)) < limit){
        character c = fgetc(file);
        if(c == '\0' || c == terminator || ferror(file) || feof(file)){
            break;
        }
        data += c;
    }
    return data;
}

BigArchive::BigArchive(const string &filename, BigFilesystem &fs) : archiveFilename(filename), file(nullptr), filesystem(fs) {
    std::replace(archiveFilename.begin(), archiveFilename.end(), '\\', '/');
}

BigArchive::~BigArchive(){
    close();
}

bool BigArchive::readHeader(){
    if (fs::is_directory(fs::path(archiveFilename))) {
        backend = Folder;

        for (fs::recursive_directory_iterator dir(archiveFilename), end; dir != end; ++dir) {
            const fs::path& currentPath = dir->path();
            if (fs::is_regular_file(currentPath)) {
                auto entry = entries.emplace(*this, 0, uint32_t(fs::file_size(currentPath)),
                                             currentPath.string().substr(currentPath.string().find_first_of('/') + 1));
                Log::debug("File path: \"%s\" length: %#08x", entry.first->filename, entry.first->end);
            }
        }

        return true;
    }

    backend = BigFile;

    if(!open()){
        return false;
    }

    character id[4] = {0};
    fread(id, 1, 4, file);

    if (id[0] != 'B' || id[1] != 'I' || id[2] != 'G' || (id[3] != '4' && id[3] != 'F')){
        close();
        return false;
    }

    fseek(file, 8, SEEK_SET);

    uint32_t fileCount = readUInt32(file);
    uint32_t headerEnd = readUInt32(file);

    Log::info("File Count: %u Header End: %#08x", fileCount, headerEnd);

    for(uint32_t f = 0; f < fileCount; ++f){
        uint32_t start = readUInt32(file);
        uint32_t end   = start + readUInt32(file);
        string path = readString(file, headerEnd);
        std::replace(path.begin(), path.end(), '\\', '/');

        entries.emplace(*this, start, end, path);

        Log::debug("File #%04d start: %#08x end: %#08x path: \"%s\"", f + 1, start, end, path);
    }

    if(uint32_t(ftell(file)) > headerEnd){
        Log::warning("Reading of file info passed through end of header.");
    }

    return true;
}

bool BigArchive::open(){
    if(file != nullptr){
        return true;
    }

    if(backend == BigFile){
        file = fopen(archiveFilename.c_str(), "rb");
    }

    return file != nullptr;
}

void BigArchive::close(){
    if(file != nullptr){
        fclose(file);
        file = nullptr;
    }
    currentEntry = nullptr;
}

bool BigArchive::openEntry(const BigEntry& entry) {
    entry.line = 0;
    /* Comments mode must be reenabled after opening a new file. */
    comments = false;

    switch (backend) {
    case BigFile:
        if (open()) {
            fseek(file, entry.start, SEEK_SET);
            currentEntry = &entry;
            return true;
        }
        break;
    case Folder:
        close();
        file = fopen((archiveFilename + '/' + entry.filename).c_str(), "rb");
        if (file != nullptr) {
            currentEntry = &entry;
            return true;
        }
        break;
    }
    return false;
}

const BigEntry* BigArchive::openFile(const string &filename){
    auto entry = entries.find(BigEntry(*this, 0, 0, filename));
    if(entry != entries.end() && openEntry(*entry)){
        return &(*entry);
    }

    return nullptr;
}

string BigArchive::getLine(const BigEntry &entry){
    if(!open() || eof(entry)){
        return "";
    }
    string str = readString(file, entry.end, '\n');

    if(str.back() == '\r'){
        str.pop_back();
    }

    string::size_type comment = std::min(str.find(';'), str.find("//"));
    if(comment != string::npos)
        str.erase(comment);

    entry.line++;

    return str;
}

string BigArchive::getWord(const BigEntry &entry){
    if(!open() || eof(entry)){
        return "";
    }

    bool isWrd = false;
    bool isStr = false;
    bool isNmb = false;
    bool isSym = false;

    string data;
    while(!eof(entry)){
        character c = fgetc(file);

        if(ferror(file) || feof(file)){
            break;
        }

        if(data.empty()){
            if(c == '\n'){
                /* return a newline character if it's the first non-space we run into. */
                entry.line++;
                return "\n";
            }
            if(std::isspace(c)){
                /* Ignore a space. */
                continue;
            }
            if(std::isalpha(c)){
                /* we have a word! */
                isWrd = true;
            }else if(std::isdigit(c)){
                /* we have a number! */
                isNmb = true;
            }else if(c == '"'){
                /* we have a string! */
                isStr = true;
            }else if(c == ';'){
                /* We have a comment! */
                getLine(entry);
                return "\n";
            }else{
                isSym = true;
            }
        }else{
            if(!isStr){
                if(c == ';'){
                    /* We have a comment! */
                    getLine(entry);
                    break;
                }else if(c == '/' && data.back() == '/'){
                    /* We have a comment! */
                    getLine(entry);

                    /* Is the comment all that was in the string? */
                    if(data.size() == 1)
                        return "\n";

                    /* Remove the other '/' character. */
                    data.pop_back();
                    break;
                }else if((std::isspace(c) || /* A space ends anything. */
                        /* Words break on non alpha-numeric characters other than underscores. */
                        (isWrd && !std::isalnum(c) && c != '_') ||
                        /* Numbers break on anything that isn't a digit or a period. */
                        (isNmb && !std::isdigit(c) && c != '.') ||
                        /* Symbols break on anything alpha-numeric. */
                        (isSym && std::isalnum(c)))){
                    ungetc(c, file);
                    break;
                }
            }else if(c == '"'){
                data += c;
                break;
            }
        }
        data += c;
    }

    return data;
}

bool BigArchive::seek(const BigEntry &entry, uint32_t pos){
    if(&entry != currentEntry){
        openEntry(entry);
    }

    pos += entry.start;
    if(pos < entry.end){
        fseek(file, pos, SEEK_SET);
        return true;
    }
    return false;
}

uint32_t BigArchive::tell(const BigEntry &entry){
    if(&entry != currentEntry){
        openEntry(entry);
    }

    uint32_t pos = ftell(file);
    if(pos < entry.start){
        return 0;
    }
    if(pos > entry.end){
        return entry.end - entry.start;
    }
    return pos - entry.start;
}

bool BigArchive::eof(const BigEntry &entry){
    uint32_t cpos = ftell(file);
    return cpos < entry.start || cpos >= entry.end;
}

bool BigArchive::extract(const string &filename, const string &directory, bool fullPath){
    const BigEntry* entry = openFile(filename);

    if(entry == nullptr){
        return false;
    }

    string outfilename = filename;

    if(!fullPath){
        outfilename.erase(0, outfilename.find_last_of('/') + 1);
    }
    outfilename.insert(0, directory);
    fs::create_directories(fs::path(outfilename.substr(0, outfilename.find_last_of('/'))));

    Log::info("Extracting to \"%s\"...", outfilename);

    FILE* out = fopen(outfilename.c_str(), "wb");

    if(out == nullptr){
        Log::error("Unable to create file \"%s\"!", outfilename);
        return false;
    }
    uint32_t length = entry->end - entry->start;
    uint8_t *buffer = new uint8_t[length];

    fread(buffer, 1, length, file);
    fwrite(buffer, 1, length, out);

    fclose(out);
    delete[] buffer;

    Log::info("File successfully extracted.");

    return true;
}

bool BigArchive::extractAll(const string &directory){
    fs::create_directories(fs::path(directory));
    for(auto &entry : entries){
        if(!extract(entry.filename, directory, true)){
            return false;
        }
    }
    return true;
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2021 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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 "lexer.hh"

namespace tadpole {

Token Lexer::next_token() {
  skip_whitespace();

  begpos_ = curpos_;
  if (is_tail())
    return make_token(TokenKind::TK_EOF);

  char c = advance();
  if (is_alpha(c))
    return make_identifier();
  if (is_digit(c))
    return make_numeric();

  // TODO:
  return make_error(from_fmt("unexpected character `%c`", c));
}

void Lexer::skip_whitespace() {
  // TODO:
}

Token Lexer::make_token(TokenKind kind) {
  return Token(kind, gen_literal(begpos_, curpos_), lineno_);
}

Token Lexer::make_token(TokenKind kind, const str_t& literal) {
  return Token(kind, literal, lineno_);
}

Token Lexer::make_error(const str_t& message) {
  return Token(TokenKind::TK_ERR, message, lineno_);
}

Token Lexer::make_identifier() {
  while (is_alnum(peek()))
    advance();

  str_t literal = gen_literal(begpos_, curpos_);
  return make_token(get_keyword_kind(literal), literal);
}

Token Lexer::make_numeric() {
  // TODO:
  return make_token(TokenKind::TK_NUMERIC);
}

Token Lexer::make_string() {
#define _MAKE_CHAR(x, y) case x: c = y; advance(); break

  str_t literal;
  while (!is_tail() && peek() != '"') {
    char c = peek();
    switch (c) {
    case '\n': ++lineno_; break;
    case '\\':
      switch (peek()) {
      _MAKE_CHAR('"', '"');
      _MAKE_CHAR('\\', '\\');
      _MAKE_CHAR('%', '%');
      _MAKE_CHAR('0', '\0');
      _MAKE_CHAR('a', '\a');
      _MAKE_CHAR('b', '\b');
      _MAKE_CHAR('f', '\f');
      _MAKE_CHAR('n', '\n');
      _MAKE_CHAR('r', '\r');
      _MAKE_CHAR('t', '\t');
      _MAKE_CHAR('v', '\v');
      }
      break;
    }
    literal.push_back(c);
    advance();
  }
#undef _MAKE_CHAR

  if (is_tail())
    return make_error("unterminated string");

  advance();
  return make_token(TokenKind::TK_STRING, literal);
}

}
<commit_msg>:construction: chore(numeric): add implementation of making numeric<commit_after>// Copyright (c) 2021 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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 "lexer.hh"

namespace tadpole {

Token Lexer::next_token() {
  skip_whitespace();

  begpos_ = curpos_;
  if (is_tail())
    return make_token(TokenKind::TK_EOF);

  char c = advance();
  if (is_alpha(c))
    return make_identifier();
  if (is_digit(c))
    return make_numeric();

  // TODO:
  return make_error(from_fmt("unexpected character `%c`", c));
}

void Lexer::skip_whitespace() {
  // TODO:
}

Token Lexer::make_token(TokenKind kind) {
  return Token(kind, gen_literal(begpos_, curpos_), lineno_);
}

Token Lexer::make_token(TokenKind kind, const str_t& literal) {
  return Token(kind, literal, lineno_);
}

Token Lexer::make_error(const str_t& message) {
  return Token(TokenKind::TK_ERR, message, lineno_);
}

Token Lexer::make_identifier() {
  while (is_alnum(peek()))
    advance();

  str_t literal = gen_literal(begpos_, curpos_);
  return make_token(get_keyword_kind(literal), literal);
}

Token Lexer::make_numeric() {
  while (is_digit(peek()))
    advance();
  if (peek() == '.' && is_digit(peek(1))) {
    advance();
    while (is_digit(peek()))
      advance();
  }
  return make_token(TokenKind::TK_NUMERIC);
}

Token Lexer::make_string() {
#define _MAKE_CHAR(x, y) case x: c = y; advance(); break

  str_t literal;
  while (!is_tail() && peek() != '"') {
    char c = peek();
    switch (c) {
    case '\n': ++lineno_; break;
    case '\\':
      switch (peek()) {
      _MAKE_CHAR('"', '"');
      _MAKE_CHAR('\\', '\\');
      _MAKE_CHAR('%', '%');
      _MAKE_CHAR('0', '\0');
      _MAKE_CHAR('a', '\a');
      _MAKE_CHAR('b', '\b');
      _MAKE_CHAR('f', '\f');
      _MAKE_CHAR('n', '\n');
      _MAKE_CHAR('r', '\r');
      _MAKE_CHAR('t', '\t');
      _MAKE_CHAR('v', '\v');
      }
      break;
    }
    literal.push_back(c);
    advance();
  }
#undef _MAKE_CHAR

  if (is_tail())
    return make_error("unterminated string");

  advance();
  return make_token(TokenKind::TK_STRING, literal);
}

}
<|endoftext|>


<commit_before>#include "ssh.hh"

namespace nix {

SSHMaster::SSHMaster(const std::string & host, const std::string & keyFile, bool useMaster, bool compress, int logFD)
    : host(host)
    , fakeSSH(host == "localhost")
    , keyFile(keyFile)
    , useMaster(useMaster && !fakeSSH)
    , compress(compress)
    , logFD(logFD)
{
    if (host == "" || hasPrefix(host, "-"))
        throw Error("invalid SSH host name '%s'", host);
}

void SSHMaster::addCommonSSHOpts(Strings & args)
{
    for (auto & i : tokenizeString<Strings>(getEnv("NIX_SSHOPTS").value_or("")))
        args.push_back(i);
    if (!keyFile.empty())
        args.insert(args.end(), {"-i", keyFile});
    if (compress)
        args.push_back("-C");
}

std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string & command)
{
    Path socketPath = startMaster();

    Pipe in, out;
    in.create();
    out.create();

    auto conn = std::make_unique<Connection>();
    conn->sshPid = startProcess([&]() {
        restoreSignals();

        close(in.writeSide.get());
        close(out.readSide.get());

        if (dup2(in.readSide.get(), STDIN_FILENO) == -1)
            throw SysError("duping over stdin");
        if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1)
            throw SysError("duping over stdout");
        if (logFD != -1 && dup2(logFD, STDERR_FILENO) == -1)
            throw SysError("duping over stderr");

        Strings args;

        if (fakeSSH) {
            args = { "bash", "-c" };
        } else {
            args = { "ssh", host.c_str(), "-x", "-a" };
            addCommonSSHOpts(args);
            if (socketPath != "")
                args.insert(args.end(), {"-S", socketPath});
            if (verbosity >= lvlChatty)
                args.push_back("-v");
        }

        args.push_back(command);
        execvp(args.begin()->c_str(), stringsToCharPtrs(args).data());

        // could not exec ssh/bash
        throw SysError("unable to execute '%s'", args.front());
    });

    in.readSide = -1;
    out.writeSide = -1;

    conn->out = std::move(out.readSide);
    conn->in = std::move(in.writeSide);

    return conn;
}

Path SSHMaster::startMaster()
{
    if (!useMaster) return "";

    auto state(state_.lock());

    if (state->sshMaster != -1) return state->socketPath;

    state->tmpDir = std::make_unique<AutoDelete>(createTempDir("", "nix", true, true, 0700));

    state->socketPath = (Path) *state->tmpDir + "/ssh.sock";

    Pipe out;
    out.create();

    state->sshMaster = startProcess([&]() {
        restoreSignals();

        close(out.readSide.get());

        if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1)
            throw SysError("duping over stdout");

        Strings args =
            { "ssh", host.c_str(), "-M", "-N", "-S", state->socketPath
            , "-o", "LocalCommand=echo started"
            , "-o", "PermitLocalCommand=yes"
            };
        if (verbosity >= lvlChatty)
            args.push_back("-v");
        addCommonSSHOpts(args);
        execvp(args.begin()->c_str(), stringsToCharPtrs(args).data());

        throw SysError("unable to execute '%s'", args.front());
    });

    out.writeSide = -1;

    std::string reply;
    try {
        reply = readLine(out.readSide.get());
    } catch (EndOfFile & e) { }

    if (reply != "started")
        throw Error("failed to start SSH master connection to '%s'", host);

    return state->socketPath;
}

}
<commit_msg>Fix PR_SET_PDEATHSIG results in Broken pipe (#2395)<commit_after>#include "ssh.hh"

namespace nix {

SSHMaster::SSHMaster(const std::string & host, const std::string & keyFile, bool useMaster, bool compress, int logFD)
    : host(host)
    , fakeSSH(host == "localhost")
    , keyFile(keyFile)
    , useMaster(useMaster && !fakeSSH)
    , compress(compress)
    , logFD(logFD)
{
    if (host == "" || hasPrefix(host, "-"))
        throw Error("invalid SSH host name '%s'", host);
}

void SSHMaster::addCommonSSHOpts(Strings & args)
{
    for (auto & i : tokenizeString<Strings>(getEnv("NIX_SSHOPTS").value_or("")))
        args.push_back(i);
    if (!keyFile.empty())
        args.insert(args.end(), {"-i", keyFile});
    if (compress)
        args.push_back("-C");
}

std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string & command)
{
    Path socketPath = startMaster();

    Pipe in, out;
    in.create();
    out.create();

    auto conn = std::make_unique<Connection>();
    ProcessOptions options;
    options.dieWithParent = false;

    conn->sshPid = startProcess([&]() {
        restoreSignals();

        close(in.writeSide.get());
        close(out.readSide.get());

        if (dup2(in.readSide.get(), STDIN_FILENO) == -1)
            throw SysError("duping over stdin");
        if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1)
            throw SysError("duping over stdout");
        if (logFD != -1 && dup2(logFD, STDERR_FILENO) == -1)
            throw SysError("duping over stderr");

        Strings args;

        if (fakeSSH) {
            args = { "bash", "-c" };
        } else {
            args = { "ssh", host.c_str(), "-x", "-a" };
            addCommonSSHOpts(args);
            if (socketPath != "")
                args.insert(args.end(), {"-S", socketPath});
            if (verbosity >= lvlChatty)
                args.push_back("-v");
        }

        args.push_back(command);
        execvp(args.begin()->c_str(), stringsToCharPtrs(args).data());

        // could not exec ssh/bash
        throw SysError("unable to execute '%s'", args.front());
    }, options);

    in.readSide = -1;
    out.writeSide = -1;

    conn->out = std::move(out.readSide);
    conn->in = std::move(in.writeSide);

    return conn;
}

Path SSHMaster::startMaster()
{
    if (!useMaster) return "";

    auto state(state_.lock());

    if (state->sshMaster != -1) return state->socketPath;

    state->tmpDir = std::make_unique<AutoDelete>(createTempDir("", "nix", true, true, 0700));

    state->socketPath = (Path) *state->tmpDir + "/ssh.sock";

    Pipe out;
    out.create();

    ProcessOptions options;
    options.dieWithParent = false;

    state->sshMaster = startProcess([&]() {
        restoreSignals();

        close(out.readSide.get());

        if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1)
            throw SysError("duping over stdout");

        Strings args =
            { "ssh", host.c_str(), "-M", "-N", "-S", state->socketPath
            , "-o", "LocalCommand=echo started"
            , "-o", "PermitLocalCommand=yes"
            };
        if (verbosity >= lvlChatty)
            args.push_back("-v");
        addCommonSSHOpts(args);
        execvp(args.begin()->c_str(), stringsToCharPtrs(args).data());

        throw SysError("unable to execute '%s'", args.front());
    }, options);

    out.writeSide = -1;

    std::string reply;
    try {
        reply = readLine(out.readSide.get());
    } catch (EndOfFile & e) { }

    if (reply != "started")
        throw Error("failed to start SSH master connection to '%s'", host);

    return state->socketPath;
}

}
<|endoftext|>


<commit_before>// Copyright (C) 2011, 2012  Strahinja Val Markovic  <val@markovic.io>
//
// This file is part of YouCompleteMe.
//
// YouCompleteMe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// YouCompleteMe 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with YouCompleteMe.  If not, see <http://www.gnu.org/licenses/>.

#include "CandidateRepository.h"
#include "Candidate.h"
#include "standard.h"
#include "Utils.h"

#include <boost/thread/locks.hpp>

#ifdef USE_CLANG_COMPLETER
#  include "CompletionData.h"
#endif // USE_CLANG_COMPLETER

namespace YouCompleteMe {

boost::mutex CandidateRepository::singleton_mutex_;
CandidateRepository *CandidateRepository::instance_ = NULL;

CandidateRepository &CandidateRepository::Instance() {
  boost::lock_guard< boost::mutex > locker( singleton_mutex_ );

  if ( !instance_ ) {
    static CandidateRepository repo;
    instance_ = &repo;
  }

  return *instance_;
}

int CandidateRepository::NumStoredCandidates() {
  boost::lock_guard< boost::mutex > locker( holder_mutex_ );
  return candidate_holder_.size();
}

std::vector< const Candidate * > CandidateRepository::GetCandidatesForStrings(
  const std::vector< std::string > &strings ) {
  std::vector< const Candidate * > candidates;
  candidates.reserve( strings.size() );

  {
    boost::lock_guard< boost::mutex > locker( holder_mutex_ );

    foreach ( const std::string & candidate_text, strings ) {
      const Candidate *&candidate = GetValueElseInsert( candidate_holder_,
                                                        candidate_text,
                                                        NULL );

      if ( !candidate )
        candidate = new Candidate( candidate_text );

      candidates.push_back( candidate );
    }
  }

  return candidates;
}

#ifdef USE_CLANG_COMPLETER

std::vector< const Candidate * > CandidateRepository::GetCandidatesForStrings(
  const std::vector< CompletionData > &datas ) {
  std::vector< const Candidate * > candidates;
  candidates.reserve( datas.size() );

  {
    boost::lock_guard< boost::mutex > locker( holder_mutex_ );

    foreach ( const CompletionData & data, datas ) {
      const Candidate *&candidate = GetValueElseInsert( candidate_holder_,
                                                        data.original_string_,
                                                        NULL );

      if ( !candidate )
        candidate = new Candidate( data.original_string_ );

      candidates.push_back( candidate );
    }
  }

  return candidates;
}

#endif // USE_CLANG_COMPLETER

CandidateRepository::~CandidateRepository() {
  foreach ( const CandidateHolder::value_type & pair,
            candidate_holder_ ) {
    delete pair.second;
  }
}

} // namespace YouCompleteMe
<commit_msg>Changing an include path for readability<commit_after>// Copyright (C) 2011, 2012  Strahinja Val Markovic  <val@markovic.io>
//
// This file is part of YouCompleteMe.
//
// YouCompleteMe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// YouCompleteMe 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with YouCompleteMe.  If not, see <http://www.gnu.org/licenses/>.

#include "CandidateRepository.h"
#include "Candidate.h"
#include "standard.h"
#include "Utils.h"

#include <boost/thread/locks.hpp>

#ifdef USE_CLANG_COMPLETER
#  include "ClangCompleter/CompletionData.h"
#endif // USE_CLANG_COMPLETER

namespace YouCompleteMe {

boost::mutex CandidateRepository::singleton_mutex_;
CandidateRepository *CandidateRepository::instance_ = NULL;

CandidateRepository &CandidateRepository::Instance() {
  boost::lock_guard< boost::mutex > locker( singleton_mutex_ );

  if ( !instance_ ) {
    static CandidateRepository repo;
    instance_ = &repo;
  }

  return *instance_;
}

int CandidateRepository::NumStoredCandidates() {
  boost::lock_guard< boost::mutex > locker( holder_mutex_ );
  return candidate_holder_.size();
}

std::vector< const Candidate * > CandidateRepository::GetCandidatesForStrings(
  const std::vector< std::string > &strings ) {
  std::vector< const Candidate * > candidates;
  candidates.reserve( strings.size() );

  {
    boost::lock_guard< boost::mutex > locker( holder_mutex_ );

    foreach ( const std::string & candidate_text, strings ) {
      const Candidate *&candidate = GetValueElseInsert( candidate_holder_,
                                                        candidate_text,
                                                        NULL );

      if ( !candidate )
        candidate = new Candidate( candidate_text );

      candidates.push_back( candidate );
    }
  }

  return candidates;
}

#ifdef USE_CLANG_COMPLETER

std::vector< const Candidate * > CandidateRepository::GetCandidatesForStrings(
  const std::vector< CompletionData > &datas ) {
  std::vector< const Candidate * > candidates;
  candidates.reserve( datas.size() );

  {
    boost::lock_guard< boost::mutex > locker( holder_mutex_ );

    foreach ( const CompletionData & data, datas ) {
      const Candidate *&candidate = GetValueElseInsert( candidate_holder_,
                                                        data.original_string_,
                                                        NULL );

      if ( !candidate )
        candidate = new Candidate( data.original_string_ );

      candidates.push_back( candidate );
    }
  }

  return candidates;
}

#endif // USE_CLANG_COMPLETER

CandidateRepository::~CandidateRepository() {
  foreach ( const CandidateHolder::value_type & pair,
            candidate_holder_ ) {
    delete pair.second;
  }
}

} // namespace YouCompleteMe
<|endoftext|>


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

#include "cpu_instructions/util/system.h"

#include <sched.h>

#include "glog/logging.h"

namespace cpu_instructions {

void SetCoreAffinity(int core_id) {
  cpu_set_t affinity;
  CPU_ZERO(&affinity);
  CPU_SET(core_id, &affinity);
  QCHECK_EQ(0, sched_setaffinity(0, sizeof(affinity), &affinity));
}

void PinCoreAffinity() {
  cpu_set_t affinity;
  CPU_ZERO(&affinity);
  QCHECK_EQ(0, sched_getaffinity(0, sizeof(affinity), &affinity));
  constexpr int kMaxCores = 4096;  // "Ought to be enough for anybody".
  for (int core_id = 0; core_id < kMaxCores; ++core_id) {
    if (CPU_ISSET(core_id, &affinity)) {
      LOG(INFO) << "Selected core " << core_id;
      SetCoreAffinity(core_id);
      return;
    }
  }
}

}  // namespace cpu_instructions
<commit_msg>fix build<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cpu_instructions/util/system.h"

#include <sched.h>

#include "glog/logging.h"

namespace cpu_instructions {

void SetCoreAffinity(int core_id) {
  cpu_set_t affinity;
  CPU_ZERO(&affinity);
  CPU_SET(core_id, &affinity);
  CHECK_EQ(0, sched_setaffinity(0, sizeof(affinity), &affinity));
}

void PinCoreAffinity() {
  cpu_set_t affinity;
  CPU_ZERO(&affinity);
  CHECK_EQ(0, sched_getaffinity(0, sizeof(affinity), &affinity));
  constexpr int kMaxCores = 4096;  // "Ought to be enough for anybody".
  for (int core_id = 0; core_id < kMaxCores; ++core_id) {
    if (CPU_ISSET(core_id, &affinity)) {
      LOG(INFO) << "Selected core " << core_id;
      SetCoreAffinity(core_id);
      return;
    }
  }
}

}  // namespace cpu_instructions
<|endoftext|>