<commit_before>//===- CodeGenTarget.cpp - CodeGen Target Class Wrapper ---------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class wrap target description classes used by the various code
// generation TableGen backends.  This makes it easier to access the data and
// provides a single place that needs to check it for validity.  All of these
// classes throw exceptions on error conditions.
//
//===----------------------------------------------------------------------===//

#include "CodeGenTarget.h"
#include "Record.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include <set>
#include <algorithm>
using namespace llvm;

static cl::opt<unsigned>
AsmWriterNum("asmwriternum", cl::init(0),
             cl::desc("Make -gen-asm-writer emit assembly writer #N"));

/// getValueType - Return the MCV::ValueType that the specified TableGen record
/// corresponds to.
MVT::ValueType llvm::getValueType(Record *Rec) {
  return (MVT::ValueType)Rec->getValueAsInt("Value");
}

std::string llvm::getName(MVT::ValueType T) {
  switch (T) {
  case MVT::Other: return "UNKNOWN";
  case MVT::i1:    return "i1";
  case MVT::i8:    return "i8";
  case MVT::i16:   return "i16";
  case MVT::i32:   return "i32";
  case MVT::i64:   return "i64";
  case MVT::i128:  return "i128";
  case MVT::f32:   return "f32";
  case MVT::f64:   return "f64";
  case MVT::f80:   return "f80";
  case MVT::f128:  return "f128";
  case MVT::Flag:  return "Flag";
  case MVT::isVoid:return "void";
  case MVT::v8i8:  return "v8i8";
  case MVT::v4i16: return "v4i16";
  case MVT::v2i32: return "v2i32";
  case MVT::v16i8: return "v16i8";
  case MVT::v8i16: return "v8i16";
  case MVT::v4i32: return "v4i32";
  case MVT::v2i64: return "v2i64";
  case MVT::v2f32: return "v2f32";
  case MVT::v4f32: return "v4f32";
  case MVT::v2f64: return "v2f64";
  default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
  }
}

std::string llvm::getEnumName(MVT::ValueType T) {
  switch (T) {
  case MVT::Other: return "Other";
  case MVT::i1:    return "i1";
  case MVT::i8:    return "i8";
  case MVT::i16:   return "i16";
  case MVT::i32:   return "i32";
  case MVT::i64:   return "i64";
  case MVT::i128:  return "i128";
  case MVT::f32:   return "f32";
  case MVT::f64:   return "f64";
  case MVT::f80:   return "f80";
  case MVT::f128:  return "f128";
  case MVT::Flag:  return "Flag";
  case MVT::isVoid:return "isVoid";
  case MVT::v16i8: return "v16i8";
  case MVT::v8i16: return "v8i16";
  case MVT::v4i32: return "v4i32";
  case MVT::v2i64: return "v2i64";
  case MVT::v2f32: return "v2f32";
  case MVT::v4f32: return "v4f32";
  case MVT::v2f64: return "v2f64";
  default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
  }
}

std::ostream &llvm::operator<<(std::ostream &OS, MVT::ValueType T) {
  return OS << getName(T);
}

/// getTarget - Return the current instance of the Target class.
///
CodeGenTarget::CodeGenTarget() : PointerType(MVT::Other) {
  std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target");
  if (Targets.size() == 0)
    throw std::string("ERROR: No 'Target' subclasses defined!");
  if (Targets.size() != 1)
    throw std::string("ERROR: Multiple subclasses of Target defined!");
  TargetRec = Targets[0];

  // Read in all of the CalleeSavedRegisters.
  CalleeSavedRegisters =TargetRec->getValueAsListOfDefs("CalleeSavedRegisters");
  PointerType = getValueType(TargetRec->getValueAsDef("PointerType"));
}

const std::string &CodeGenTarget::getName() const {
  return TargetRec->getName();
}

Record *CodeGenTarget::getInstructionSet() const {
  return TargetRec->getValueAsDef("InstructionSet");
}

/// getAsmWriter - Return the AssemblyWriter definition for this target.
///
Record *CodeGenTarget::getAsmWriter() const {
  std::vector<Record*> LI = TargetRec->getValueAsListOfDefs("AssemblyWriters");
  if (AsmWriterNum >= LI.size())
    throw "Target does not have an AsmWriter #" + utostr(AsmWriterNum) + "!";
  return LI[AsmWriterNum];
}

void CodeGenTarget::ReadRegisters() const {
  std::vector<Record*> Regs = Records.getAllDerivedDefinitions("Register");
  if (Regs.empty())
    throw std::string("No 'Register' subclasses defined!");

  Registers.reserve(Regs.size());
  Registers.assign(Regs.begin(), Regs.end());
}

CodeGenRegister::CodeGenRegister(Record *R) : TheDef(R) {
  DeclaredSpillSize = R->getValueAsInt("SpillSize");
  DeclaredSpillAlignment = R->getValueAsInt("SpillAlignment");
}

const std::string &CodeGenRegister::getName() const {
  return TheDef->getName();
}

void CodeGenTarget::ReadRegisterClasses() const {
  std::vector<Record*> RegClasses =
    Records.getAllDerivedDefinitions("RegisterClass");
  if (RegClasses.empty())
    throw std::string("No 'RegisterClass' subclasses defined!");

  RegisterClasses.reserve(RegClasses.size());
  RegisterClasses.assign(RegClasses.begin(), RegClasses.end());
}

CodeGenRegisterClass::CodeGenRegisterClass(Record *R) : TheDef(R) {
  // Rename anonymous register classes.
  if (R->getName().size() > 9 && R->getName()[9] == '.') {
    static unsigned AnonCounter = 0;
    R->setName("AnonRegClass_"+utostr(AnonCounter++));
  }

  std::vector<Record*> TypeList = R->getValueAsListOfDefs("RegTypes");
  for (unsigned i = 0, e = TypeList.size(); i != e; ++i) {
    Record *Type = TypeList[i];
    if (!Type->isSubClassOf("ValueType"))
      throw "RegTypes list member '" + Type->getName() +
        "' does not derive from the ValueType class!";
    VTs.push_back(getValueType(Type));
  }
  assert(!VTs.empty() && "RegisterClass must contain at least one ValueType!");

  std::vector<Record*> RegList = R->getValueAsListOfDefs("MemberList");
  for (unsigned i = 0, e = RegList.size(); i != e; ++i) {
    Record *Reg = RegList[i];
    if (!Reg->isSubClassOf("Register"))
      throw "Register Class member '" + Reg->getName() +
            "' does not derive from the Register class!";
    Elements.push_back(Reg);
  }

  // Allow targets to override the size in bits of the RegisterClass.
  unsigned Size = R->getValueAsInt("Size");

  Namespace = R->getValueAsString("Namespace");
  SpillSize = Size ? Size : MVT::getSizeInBits(VTs[0]);
  SpillAlignment = R->getValueAsInt("Alignment");
  MethodBodies = R->getValueAsCode("MethodBodies");
  MethodProtos = R->getValueAsCode("MethodProtos");
}

const std::string &CodeGenRegisterClass::getName() const {
  return TheDef->getName();
}

void CodeGenTarget::ReadLegalValueTypes() const {
  const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses();
  for (unsigned i = 0, e = RCs.size(); i != e; ++i)
    for (unsigned ri = 0, re = RCs[i].VTs.size(); ri != re; ++ri)
      LegalValueTypes.push_back(RCs[i].VTs[ri]);

  // Remove duplicates.
  std::sort(LegalValueTypes.begin(), LegalValueTypes.end());
  LegalValueTypes.erase(std::unique(LegalValueTypes.begin(),
                                    LegalValueTypes.end()),
                        LegalValueTypes.end());
}

void CodeGenTarget::ReadInstructions() const {
  std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
  if (Insts.size() <= 2)
    throw std::string("No 'Instruction' subclasses defined!");

  // Parse the instructions defined in the .td file.
  std::string InstFormatName =
    getAsmWriter()->getValueAsString("InstFormatName");

  for (unsigned i = 0, e = Insts.size(); i != e; ++i) {
    std::string AsmStr = Insts[i]->getValueAsString(InstFormatName);
    Instructions.insert(std::make_pair(Insts[i]->getName(),
                                       CodeGenInstruction(Insts[i], AsmStr)));
  }
}

/// getInstructionsByEnumValue - Return all of the instructions defined by the
/// target, ordered by their enum value.
void CodeGenTarget::
getInstructionsByEnumValue(std::vector<const CodeGenInstruction*>
                                                 &NumberedInstructions) {
  std::map<std::string, CodeGenInstruction>::const_iterator I;
  I = getInstructions().find("PHI");
  if (I == Instructions.end()) throw "Could not find 'PHI' instruction!";
  const CodeGenInstruction *PHI = &I->second;

  I = getInstructions().find("INLINEASM");
  if (I == Instructions.end()) throw "Could not find 'INLINEASM' instruction!";
  const CodeGenInstruction *INLINEASM = &I->second;

  // Print out the rest of the instructions now.
  NumberedInstructions.push_back(PHI);
  NumberedInstructions.push_back(INLINEASM);
  for (inst_iterator II = inst_begin(), E = inst_end(); II != E; ++II)
    if (&II->second != PHI &&&II->second != INLINEASM)
      NumberedInstructions.push_back(&II->second);
}

/// isLittleEndianEncoding - Return whether this target encodes its instruction
/// in little-endian format, i.e. bits laid out in the order [0..n]
///
bool CodeGenTarget::isLittleEndianEncoding() const {
  return getInstructionSet()->getValueAsBit("isLittleEndianEncoding");
}

CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
  : TheDef(R), AsmString(AsmStr) {
  Name      = R->getValueAsString("Name");
  Namespace = R->getValueAsString("Namespace");

  isReturn     = R->getValueAsBit("isReturn");
  isBranch     = R->getValueAsBit("isBranch");
  isBarrier    = R->getValueAsBit("isBarrier");
  isCall       = R->getValueAsBit("isCall");
  isLoad       = R->getValueAsBit("isLoad");
  isStore      = R->getValueAsBit("isStore");
  isTwoAddress = R->getValueAsBit("isTwoAddress");
  isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress");
  isCommutable = R->getValueAsBit("isCommutable");
  isTerminator = R->getValueAsBit("isTerminator");
  hasDelaySlot = R->getValueAsBit("hasDelaySlot");
  usesCustomDAGSchedInserter = R->getValueAsBit("usesCustomDAGSchedInserter");
  hasCtrlDep   = R->getValueAsBit("hasCtrlDep");
  noResults    = R->getValueAsBit("noResults");
  hasVariableNumberOfOperands = false;

  DagInit *DI;
  try {
    DI = R->getValueAsDag("OperandList");
  } catch (...) {
    // Error getting operand list, just ignore it (sparcv9).
    AsmString.clear();
    OperandList.clear();
    return;
  }

  unsigned MIOperandNo = 0;
  std::set<std::string> OperandNames;
  for (unsigned i = 0, e = DI->getNumArgs(); i != e; ++i) {
    DefInit *Arg = dynamic_cast<DefInit*>(DI->getArg(i));
    if (!Arg)
      throw "Illegal operand for the '" + R->getName() + "' instruction!";

    Record *Rec = Arg->getDef();
    std::string PrintMethod = "printOperand";
    unsigned NumOps = 1;
    DagInit *MIOpInfo = 0;
    if (Rec->isSubClassOf("Operand")) {
      PrintMethod = Rec->getValueAsString("PrintMethod");
      NumOps = Rec->getValueAsInt("NumMIOperands");
      MIOpInfo = Rec->getValueAsDag("MIOperandInfo");
    } else if (Rec->getName() == "variable_ops") {
      hasVariableNumberOfOperands = true;
      continue;
    } else if (!Rec->isSubClassOf("RegisterClass"))
      throw "Unknown operand class '" + Rec->getName() +
            "' in instruction '" + R->getName() + "' instruction!";

    // Check that the operand has a name and that it's unique.
    if (DI->getArgName(i).empty())
      throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
        " has no name!";
    if (!OperandNames.insert(DI->getArgName(i)).second)
      throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
        " has the same name as a previous operand!";

    OperandList.push_back(OperandInfo(Rec, DI->getArgName(i), PrintMethod,
                                      MIOperandNo, NumOps, MIOpInfo));
    MIOperandNo += NumOps;
  }
}

/// getOperandNamed - Return the index of the operand with the specified
/// non-empty name.  If the instruction does not have an operand with the
/// specified name, throw an exception.
///
unsigned CodeGenInstruction::getOperandNamed(const std::string &Name) const {
  assert(!Name.empty() && "Cannot search for operand with no name!");
  for (unsigned i = 0, e = OperandList.size(); i != e; ++i)
    if (OperandList[i].Name == Name) return i;
  throw "Instruction '" + TheDef->getName() +
        "' does not have an operand named '$" + Name + "'!";
}

//===----------------------------------------------------------------------===//
// ComplexPattern implementation
//
ComplexPattern::ComplexPattern(Record *R) {
  Ty          = ::getValueType(R->getValueAsDef("Ty"));
  NumOperands = R->getValueAsInt("NumOperands");
  SelectFunc  = R->getValueAsString("SelectFunc");
  RootNodes   = R->getValueAsListOfDefs("RootNodes");
}

<commit_msg>getEnumName() missed v8i8, v4i16, and v2i32 types<commit_after>//===- CodeGenTarget.cpp - CodeGen Target Class Wrapper ---------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class wrap target description classes used by the various code
// generation TableGen backends.  This makes it easier to access the data and
// provides a single place that needs to check it for validity.  All of these
// classes throw exceptions on error conditions.
//
//===----------------------------------------------------------------------===//

#include "CodeGenTarget.h"
#include "Record.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include <set>
#include <algorithm>
using namespace llvm;

static cl::opt<unsigned>
AsmWriterNum("asmwriternum", cl::init(0),
             cl::desc("Make -gen-asm-writer emit assembly writer #N"));

/// getValueType - Return the MCV::ValueType that the specified TableGen record
/// corresponds to.
MVT::ValueType llvm::getValueType(Record *Rec) {
  return (MVT::ValueType)Rec->getValueAsInt("Value");
}

std::string llvm::getName(MVT::ValueType T) {
  switch (T) {
  case MVT::Other: return "UNKNOWN";
  case MVT::i1:    return "i1";
  case MVT::i8:    return "i8";
  case MVT::i16:   return "i16";
  case MVT::i32:   return "i32";
  case MVT::i64:   return "i64";
  case MVT::i128:  return "i128";
  case MVT::f32:   return "f32";
  case MVT::f64:   return "f64";
  case MVT::f80:   return "f80";
  case MVT::f128:  return "f128";
  case MVT::Flag:  return "Flag";
  case MVT::isVoid:return "void";
  case MVT::v8i8:  return "v8i8";
  case MVT::v4i16: return "v4i16";
  case MVT::v2i32: return "v2i32";
  case MVT::v16i8: return "v16i8";
  case MVT::v8i16: return "v8i16";
  case MVT::v4i32: return "v4i32";
  case MVT::v2i64: return "v2i64";
  case MVT::v2f32: return "v2f32";
  case MVT::v4f32: return "v4f32";
  case MVT::v2f64: return "v2f64";
  default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
  }
}

std::string llvm::getEnumName(MVT::ValueType T) {
  switch (T) {
  case MVT::Other: return "Other";
  case MVT::i1:    return "i1";
  case MVT::i8:    return "i8";
  case MVT::i16:   return "i16";
  case MVT::i32:   return "i32";
  case MVT::i64:   return "i64";
  case MVT::i128:  return "i128";
  case MVT::f32:   return "f32";
  case MVT::f64:   return "f64";
  case MVT::f80:   return "f80";
  case MVT::f128:  return "f128";
  case MVT::Flag:  return "Flag";
  case MVT::isVoid:return "isVoid";
  case MVT::v8i8:  return "v8i8";
  case MVT::v4i16: return "v4i16";
  case MVT::v2i32: return "v2i32";
  case MVT::v16i8: return "v16i8";
  case MVT::v8i16: return "v8i16";
  case MVT::v4i32: return "v4i32";
  case MVT::v2i64: return "v2i64";
  case MVT::v2f32: return "v2f32";
  case MVT::v4f32: return "v4f32";
  case MVT::v2f64: return "v2f64";
  default: assert(0 && "ILLEGAL VALUE TYPE!"); return "";
  }
}

std::ostream &llvm::operator<<(std::ostream &OS, MVT::ValueType T) {
  return OS << getName(T);
}

/// getTarget - Return the current instance of the Target class.
///
CodeGenTarget::CodeGenTarget() : PointerType(MVT::Other) {
  std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target");
  if (Targets.size() == 0)
    throw std::string("ERROR: No 'Target' subclasses defined!");
  if (Targets.size() != 1)
    throw std::string("ERROR: Multiple subclasses of Target defined!");
  TargetRec = Targets[0];

  // Read in all of the CalleeSavedRegisters.
  CalleeSavedRegisters =TargetRec->getValueAsListOfDefs("CalleeSavedRegisters");
  PointerType = getValueType(TargetRec->getValueAsDef("PointerType"));
}

const std::string &CodeGenTarget::getName() const {
  return TargetRec->getName();
}

Record *CodeGenTarget::getInstructionSet() const {
  return TargetRec->getValueAsDef("InstructionSet");
}

/// getAsmWriter - Return the AssemblyWriter definition for this target.
///
Record *CodeGenTarget::getAsmWriter() const {
  std::vector<Record*> LI = TargetRec->getValueAsListOfDefs("AssemblyWriters");
  if (AsmWriterNum >= LI.size())
    throw "Target does not have an AsmWriter #" + utostr(AsmWriterNum) + "!";
  return LI[AsmWriterNum];
}

void CodeGenTarget::ReadRegisters() const {
  std::vector<Record*> Regs = Records.getAllDerivedDefinitions("Register");
  if (Regs.empty())
    throw std::string("No 'Register' subclasses defined!");

  Registers.reserve(Regs.size());
  Registers.assign(Regs.begin(), Regs.end());
}

CodeGenRegister::CodeGenRegister(Record *R) : TheDef(R) {
  DeclaredSpillSize = R->getValueAsInt("SpillSize");
  DeclaredSpillAlignment = R->getValueAsInt("SpillAlignment");
}

const std::string &CodeGenRegister::getName() const {
  return TheDef->getName();
}

void CodeGenTarget::ReadRegisterClasses() const {
  std::vector<Record*> RegClasses =
    Records.getAllDerivedDefinitions("RegisterClass");
  if (RegClasses.empty())
    throw std::string("No 'RegisterClass' subclasses defined!");

  RegisterClasses.reserve(RegClasses.size());
  RegisterClasses.assign(RegClasses.begin(), RegClasses.end());
}

CodeGenRegisterClass::CodeGenRegisterClass(Record *R) : TheDef(R) {
  // Rename anonymous register classes.
  if (R->getName().size() > 9 && R->getName()[9] == '.') {
    static unsigned AnonCounter = 0;
    R->setName("AnonRegClass_"+utostr(AnonCounter++));
  }

  std::vector<Record*> TypeList = R->getValueAsListOfDefs("RegTypes");
  for (unsigned i = 0, e = TypeList.size(); i != e; ++i) {
    Record *Type = TypeList[i];
    if (!Type->isSubClassOf("ValueType"))
      throw "RegTypes list member '" + Type->getName() +
        "' does not derive from the ValueType class!";
    VTs.push_back(getValueType(Type));
  }
  assert(!VTs.empty() && "RegisterClass must contain at least one ValueType!");

  std::vector<Record*> RegList = R->getValueAsListOfDefs("MemberList");
  for (unsigned i = 0, e = RegList.size(); i != e; ++i) {
    Record *Reg = RegList[i];
    if (!Reg->isSubClassOf("Register"))
      throw "Register Class member '" + Reg->getName() +
            "' does not derive from the Register class!";
    Elements.push_back(Reg);
  }

  // Allow targets to override the size in bits of the RegisterClass.
  unsigned Size = R->getValueAsInt("Size");

  Namespace = R->getValueAsString("Namespace");
  SpillSize = Size ? Size : MVT::getSizeInBits(VTs[0]);
  SpillAlignment = R->getValueAsInt("Alignment");
  MethodBodies = R->getValueAsCode("MethodBodies");
  MethodProtos = R->getValueAsCode("MethodProtos");
}

const std::string &CodeGenRegisterClass::getName() const {
  return TheDef->getName();
}

void CodeGenTarget::ReadLegalValueTypes() const {
  const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses();
  for (unsigned i = 0, e = RCs.size(); i != e; ++i)
    for (unsigned ri = 0, re = RCs[i].VTs.size(); ri != re; ++ri)
      LegalValueTypes.push_back(RCs[i].VTs[ri]);

  // Remove duplicates.
  std::sort(LegalValueTypes.begin(), LegalValueTypes.end());
  LegalValueTypes.erase(std::unique(LegalValueTypes.begin(),
                                    LegalValueTypes.end()),
                        LegalValueTypes.end());
}

void CodeGenTarget::ReadInstructions() const {
  std::vector<Record*> Insts = Records.getAllDerivedDefinitions("Instruction");
  if (Insts.size() <= 2)
    throw std::string("No 'Instruction' subclasses defined!");

  // Parse the instructions defined in the .td file.
  std::string InstFormatName =
    getAsmWriter()->getValueAsString("InstFormatName");

  for (unsigned i = 0, e = Insts.size(); i != e; ++i) {
    std::string AsmStr = Insts[i]->getValueAsString(InstFormatName);
    Instructions.insert(std::make_pair(Insts[i]->getName(),
                                       CodeGenInstruction(Insts[i], AsmStr)));
  }
}

/// getInstructionsByEnumValue - Return all of the instructions defined by the
/// target, ordered by their enum value.
void CodeGenTarget::
getInstructionsByEnumValue(std::vector<const CodeGenInstruction*>
                                                 &NumberedInstructions) {
  std::map<std::string, CodeGenInstruction>::const_iterator I;
  I = getInstructions().find("PHI");
  if (I == Instructions.end()) throw "Could not find 'PHI' instruction!";
  const CodeGenInstruction *PHI = &I->second;

  I = getInstructions().find("INLINEASM");
  if (I == Instructions.end()) throw "Could not find 'INLINEASM' instruction!";
  const CodeGenInstruction *INLINEASM = &I->second;

  // Print out the rest of the instructions now.
  NumberedInstructions.push_back(PHI);
  NumberedInstructions.push_back(INLINEASM);
  for (inst_iterator II = inst_begin(), E = inst_end(); II != E; ++II)
    if (&II->second != PHI &&&II->second != INLINEASM)
      NumberedInstructions.push_back(&II->second);
}

/// isLittleEndianEncoding - Return whether this target encodes its instruction
/// in little-endian format, i.e. bits laid out in the order [0..n]
///
bool CodeGenTarget::isLittleEndianEncoding() const {
  return getInstructionSet()->getValueAsBit("isLittleEndianEncoding");
}

CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr)
  : TheDef(R), AsmString(AsmStr) {
  Name      = R->getValueAsString("Name");
  Namespace = R->getValueAsString("Namespace");

  isReturn     = R->getValueAsBit("isReturn");
  isBranch     = R->getValueAsBit("isBranch");
  isBarrier    = R->getValueAsBit("isBarrier");
  isCall       = R->getValueAsBit("isCall");
  isLoad       = R->getValueAsBit("isLoad");
  isStore      = R->getValueAsBit("isStore");
  isTwoAddress = R->getValueAsBit("isTwoAddress");
  isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress");
  isCommutable = R->getValueAsBit("isCommutable");
  isTerminator = R->getValueAsBit("isTerminator");
  hasDelaySlot = R->getValueAsBit("hasDelaySlot");
  usesCustomDAGSchedInserter = R->getValueAsBit("usesCustomDAGSchedInserter");
  hasCtrlDep   = R->getValueAsBit("hasCtrlDep");
  noResults    = R->getValueAsBit("noResults");
  hasVariableNumberOfOperands = false;

  DagInit *DI;
  try {
    DI = R->getValueAsDag("OperandList");
  } catch (...) {
    // Error getting operand list, just ignore it (sparcv9).
    AsmString.clear();
    OperandList.clear();
    return;
  }

  unsigned MIOperandNo = 0;
  std::set<std::string> OperandNames;
  for (unsigned i = 0, e = DI->getNumArgs(); i != e; ++i) {
    DefInit *Arg = dynamic_cast<DefInit*>(DI->getArg(i));
    if (!Arg)
      throw "Illegal operand for the '" + R->getName() + "' instruction!";

    Record *Rec = Arg->getDef();
    std::string PrintMethod = "printOperand";
    unsigned NumOps = 1;
    DagInit *MIOpInfo = 0;
    if (Rec->isSubClassOf("Operand")) {
      PrintMethod = Rec->getValueAsString("PrintMethod");
      NumOps = Rec->getValueAsInt("NumMIOperands");
      MIOpInfo = Rec->getValueAsDag("MIOperandInfo");
    } else if (Rec->getName() == "variable_ops") {
      hasVariableNumberOfOperands = true;
      continue;
    } else if (!Rec->isSubClassOf("RegisterClass"))
      throw "Unknown operand class '" + Rec->getName() +
            "' in instruction '" + R->getName() + "' instruction!";

    // Check that the operand has a name and that it's unique.
    if (DI->getArgName(i).empty())
      throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
        " has no name!";
    if (!OperandNames.insert(DI->getArgName(i)).second)
      throw "In instruction '" + R->getName() + "', operand #" + utostr(i) +
        " has the same name as a previous operand!";

    OperandList.push_back(OperandInfo(Rec, DI->getArgName(i), PrintMethod,
                                      MIOperandNo, NumOps, MIOpInfo));
    MIOperandNo += NumOps;
  }
}

/// getOperandNamed - Return the index of the operand with the specified
/// non-empty name.  If the instruction does not have an operand with the
/// specified name, throw an exception.
///
unsigned CodeGenInstruction::getOperandNamed(const std::string &Name) const {
  assert(!Name.empty() && "Cannot search for operand with no name!");
  for (unsigned i = 0, e = OperandList.size(); i != e; ++i)
    if (OperandList[i].Name == Name) return i;
  throw "Instruction '" + TheDef->getName() +
        "' does not have an operand named '$" + Name + "'!";
}

//===----------------------------------------------------------------------===//
// ComplexPattern implementation
//
ComplexPattern::ComplexPattern(Record *R) {
  Ty          = ::getValueType(R->getValueAsDef("Ty"));
  NumOperands = R->getValueAsInt("NumOperands");
  SelectFunc  = R->getValueAsString("SelectFunc");
  RootNodes   = R->getValueAsListOfDefs("RootNodes");
}

<|endoftext|>


<commit_before>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2014 Michael Fink
//
/// \file CdsdkSourceInfoImpl.hpp CDSDK - SourceInfo impl
//
#pragma once

// includes
#include "SourceInfo.hpp"
#include "SourceDevice.hpp"
#include "CdsdkCommon.hpp"
#include "CdsdkSourceDeviceImpl.hpp"

namespace CDSDK
{

/// source info impl for CDSDK
class SourceInfoImpl: public SourceInfo
{
public:
   /// ctor
   SourceInfoImpl(RefSp spRef)
      :m_spRef(spRef)
   {
      ZeroMemory(&m_sourceInfo, sizeof(m_sourceInfo));
   }

   /// dtor
   virtual ~SourceInfoImpl() throw() {}

   virtual CString Name() const override
   {
      return m_sourceInfo.Name;
   }

   virtual std::shared_ptr<SourceDevice> Open() override
   {
      cdHSource hSource = 0;

      LOG_TRACE(_T("about to call CDOpenSource...\n"));

      // may return cdINVALID_PARAMETER, cdMEM_ALLOC_FAILED, cdDEVICE_NOT_FOUND, cdDEVICE_NOT_INSTALLED
      cdError err = CDOpenSource(&m_sourceInfo, &hSource);
      LOG_TRACE(_T("CDOpenSource(&si = \"%hs\") returned %08x\n"), m_sourceInfo.Name, err);
      CheckError(_T("CDOpenSource"), err, __FILE__, __LINE__);

      return std::shared_ptr<SourceDevice>(new SourceDeviceImpl(m_spRef, hSource));
   }

   /// returns source info
   cdSourceInfo& GetSourceInfo() throw() { return m_sourceInfo; }

private:
   /// source info
   cdSourceInfo m_sourceInfo;

   /// SDK ref
   RefSp m_spRef;
};

} // namespace EDSDK
<commit_msg>added more logging infos for CDOpenSource<commit_after>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2014 Michael Fink
//
/// \file CdsdkSourceInfoImpl.hpp CDSDK - SourceInfo impl
//
#pragma once

// includes
#include "SourceInfo.hpp"
#include "SourceDevice.hpp"
#include "CdsdkCommon.hpp"
#include "CdsdkSourceDeviceImpl.hpp"

namespace CDSDK
{

/// source info impl for CDSDK
class SourceInfoImpl: public SourceInfo
{
public:
   /// ctor
   SourceInfoImpl(RefSp spRef)
      :m_spRef(spRef)
   {
      ZeroMemory(&m_sourceInfo, sizeof(m_sourceInfo));
   }

   /// dtor
   virtual ~SourceInfoImpl() throw() {}

   virtual CString Name() const override
   {
      return m_sourceInfo.Name;
   }

   virtual std::shared_ptr<SourceDevice> Open() override
   {
      cdHSource hSource = 0;

      LOG_TRACE(_T("about to call CDOpenSource...\n"));

      // may return cdINVALID_PARAMETER, cdMEM_ALLOC_FAILED, cdDEVICE_NOT_FOUND, cdDEVICE_NOT_INSTALLED
      cdError err = CDOpenSource(&m_sourceInfo, &hSource);
      LOG_TRACE(_T("CDOpenSource(&si = \"%hs\", hSource=%08x) returned %08x\n"),
         m_sourceInfo.Name, hSource, err);
      CheckError(_T("CDOpenSource"), err, __FILE__, __LINE__);

      return std::shared_ptr<SourceDevice>(new SourceDeviceImpl(m_spRef, hSource));
   }

   /// returns source info
   cdSourceInfo& GetSourceInfo() throw() { return m_sourceInfo; }

private:
   /// source info
   cdSourceInfo m_sourceInfo;

   /// SDK ref
   RefSp m_spRef;
};

} // namespace EDSDK
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>
#include <vector>
#include <sstream>
#include <algorithm>
using namespace std;

int main()
{
    freopen ("input.txt","r",stdin);
    freopen ("output.txt","w",stdout);
    int n;
    cin >> n;
    getchar();
    while(n--) {
        vector<int> v;
        string line;
        getline(cin, line);
        stringstream ss(line);
        int tmp;
        while(ss >> tmp) {
            //int tmp; ss >> tmp;
            v.push_back(tmp);
        }
        //v.pop_back();
        sort(v.begin(),v.end());
        for(int i = 0; i < v.size(); ++i) cout << v[i] << ' ';
        cout << endl;
    }
    fclose (stdout);
    fclose (stdin);
    return 0;
}
<commit_msg>All C vi<commit_after>#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int main()
{
    FILE * oFile, * iFile;
    iFile = fopen ("input.txt","r");
    oFile = fopen ("output.txt","w");
    int n;
    char enter;
    fscanf(iFile, "%d", &n);
    fscanf(iFile, "%c", &enter);
    while(n--) {
        int v[100010];
        char line[100000];
        int o = 0;
        for(o = 0;; ++o) {
            fscanf(iFile, "%c", line+o);
            if(line[o] == '\n') break;
        }
        int tmp = 0;
        int ord = 0;
        for(int i = 0; i < o; ++i) {
            if(line[i] >= '0' && line[i] <= '9') {
                tmp *= 10;
                tmp += line[i] - '0';
                continue;
            } else {
                if(tmp) v[ord++] = tmp;
                tmp = 0;
            }
        }
        if(tmp) v[ord++] = tmp;
        sort(v,v+ord);
        for(int i = 0; i < ord; ++i) fprintf(oFile, "%d ", v[i]);
        fprintf(oFile,"\n");
    }
    fclose (iFile);
    fclose (oFile);
    return 0;
}
<|endoftext|>


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

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#define MAIN

#include "otbImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"
#include "otbForwardFourierMellinTransformImageFilter.h"
#include "itkLinearInterpolateImageFunction.h"

int otbForwardFourierMellinTransformImageFilterNew(int argc, char* argv[])
{

  typedef double                                          PixelType;
  const   unsigned int        	                          Dimension = 2;

  typedef otb::Image< PixelType, Dimension >        InputImageType;
  typedef otb::Image< PixelType, Dimension >        OutputImageType;

  typedef itk::LinearInterpolateImageFunction< InputImageType, double >		InterpolatorType;
  typedef otb::ForwardFourierMellinTransformImageFilter<PixelType,
  				InterpolatorType,Dimension> 			FourierMellinTransformType;
  try
    {
     FourierMellinTransformType::Pointer fourierMellinTransform = FourierMellinTransformType::New();
    }
  catch( itk::ExceptionObject & err )
    {
    std::cerr << "itk::Exception detected: "  << err.GetDescription();
    return EXIT_FAILURE;
    }
  catch( ... )
    {
    std::cout << "unknown exception detected !" << std::endl;
    return EXIT_FAILURE;
    }

  return EXIT_SUCCESS;
}
<commit_msg>otbForwardFourierMellinTransformImageFilter : implémentation de la classe + tests<commit_after><|endoftext|>


<commit_before>#ifndef SILICIUM_THREAD_HPP
#define SILICIUM_THREAD_HPP

#include <silicium/config.hpp>
#include <functional>

namespace Si
{
	template <class SuccessElement, class ThreadingAPI>
	struct thread_observable
	{
		typedef typename ThreadingAPI::template future<SuccessElement>::type element_type;

		thread_observable()
		    : m_has_finished(false)
		{
		}

		explicit thread_observable(std::function<SuccessElement ()> action)
			: m_action(std::move(action))
			, m_has_finished(false)
		{
		}

		template <class Observer>
		void async_get_one(Observer &&observer)
		{
			if (m_has_finished)
			{
				return std::forward<Observer>(observer).ended();
			}
			assert(m_action);
			auto action = std::move(m_action);
			m_worker = ThreadingAPI::launch_async([
				this,
				observer
#if SILICIUM_COMPILER_HAS_EXTENDED_CAPTURE
					= std::forward<Observer>(observer)
#endif
				,
				action
#if SILICIUM_COMPILER_HAS_EXTENDED_CAPTURE
					= std::move(action)
#endif
				]() mutable
			{
				m_has_finished = true;
				typename ThreadingAPI::template packaged_task<SuccessElement>::type task(action);
				auto result = task.get_future();
				task();
				auto observer_ = std::forward<Observer>(observer);
				std::forward<Observer>(observer_).got_element(std::move(result));
			});
		}

#if SILICIUM_COMPILER_GENERATES_MOVES
		thread_observable(thread_observable &&) = default;
		thread_observable &operator = (thread_observable &&) = default;
#else
		thread_observable(thread_observable &&other)
			: m_action(std::move(other.m_action))
			, m_worker(std::move(other.m_worker))
			, m_has_finished(std::move(other.m_has_finished))
		{
		}

		thread_observable &operator = (thread_observable &&other)
		{
			m_action = std::move(other.m_action);
			m_worker = std::move(other.m_worker);
			m_has_finished = std::move(other.m_has_finished);
			return *this;
		}
#endif

	private:

		typedef typename ThreadingAPI::template future<void>::type worker_type;

		std::function<SuccessElement ()> m_action;
		worker_type m_worker;
		bool m_has_finished;

		SILICIUM_DELETED_FUNCTION(thread_observable(thread_observable const &))
		SILICIUM_DELETED_FUNCTION(thread_observable &operator = (thread_observable const &))
	};

	template <class ThreadingAPI, class Action>
	auto make_thread_observable(Action &&action)
#if !SILICIUM_COMPILER_HAS_AUTO_RETURN_TYPE
		-> thread_observable<decltype(action()), ThreadingAPI>
#endif
	{
		return thread_observable<decltype(action()), ThreadingAPI>(std::forward<Action>(action));
	}
}

#endif
<commit_msg>thread_observable does not keep resources unnecessarily long alive (solves a deadlock on VC++)<commit_after>#ifndef SILICIUM_THREAD_HPP
#define SILICIUM_THREAD_HPP

#include <silicium/config.hpp>
#include <functional>

namespace Si
{
	template <class SuccessElement, class ThreadingAPI>
	struct thread_observable
	{
		typedef typename ThreadingAPI::template future<SuccessElement>::type element_type;

		thread_observable()
		    : m_has_finished(false)
		{
		}

		explicit thread_observable(std::function<SuccessElement ()> action)
			: m_action(std::move(action))
			, m_has_finished(false)
		{
		}

		template <class Observer>
		void async_get_one(Observer &&observer)
		{
			if (m_has_finished)
			{
				return std::forward<Observer>(observer).ended();
			}
			assert(m_action);
			auto action = std::move(m_action);
			optional<typename std::decay<Observer>::type> maybe_observer{std::forward<Observer>(observer)};
			m_worker = ThreadingAPI::launch_async([
				this,
					maybe_observer
#if SILICIUM_COMPILER_HAS_EXTENDED_CAPTURE
					= std::forward<Observer>(maybe_observer)
#endif
				,
				action
#if SILICIUM_COMPILER_HAS_EXTENDED_CAPTURE
					= std::move(action)
#endif
				]() mutable
			{
				m_has_finished = true;
				typename ThreadingAPI::template packaged_task<SuccessElement>::type task(action);
				auto result = task.get_future();
				task();
				assert(maybe_observer);
				auto observer_ = std::forward<Observer>(*maybe_observer);
				std::forward<Observer>(observer_).got_element(std::move(result));
				//kill the observer with fire so that it cannot keep any shared state alive
				maybe_observer = none;
			});
		}

#if SILICIUM_COMPILER_GENERATES_MOVES
		thread_observable(thread_observable &&) = default;
		thread_observable &operator = (thread_observable &&) = default;
#else
		thread_observable(thread_observable &&other)
			: m_action(std::move(other.m_action))
			, m_worker(std::move(other.m_worker))
			, m_has_finished(std::move(other.m_has_finished))
		{
		}

		thread_observable &operator = (thread_observable &&other)
		{
			m_action = std::move(other.m_action);
			m_worker = std::move(other.m_worker);
			m_has_finished = std::move(other.m_has_finished);
			return *this;
		}
#endif

	private:

		typedef typename ThreadingAPI::template future<void>::type worker_type;

		std::function<SuccessElement ()> m_action;
		worker_type m_worker;
		bool m_has_finished;

		SILICIUM_DELETED_FUNCTION(thread_observable(thread_observable const &))
		SILICIUM_DELETED_FUNCTION(thread_observable &operator = (thread_observable const &))
	};

	template <class ThreadingAPI, class Action>
	auto make_thread_observable(Action &&action)
#if !SILICIUM_COMPILER_HAS_AUTO_RETURN_TYPE
		-> thread_observable<decltype(action()), ThreadingAPI>
#endif
	{
		return thread_observable<decltype(action()), ThreadingAPI>(std::forward<Action>(action));
	}
}

#endif
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// 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 "google/cloud/storage/client.h"
#include "google/cloud/storage/testing/storage_integration_test.h"
#include "google/cloud/internal/getenv.h"
#include "google/cloud/internal/random.h"
#include "google/cloud/log.h"
#include "google/cloud/testing_util/status_matchers.h"
#include "absl/strings/str_split.h"
#include <gmock/gmock.h>
#include <future>
#include <thread>

namespace google {
namespace cloud {
namespace storage {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
namespace {
using ObjectNameList = std::vector<std::string>;

// This is basically a smoke test, if the test does not crash it was
// successful. Its main value is when running with the *Sanitizers.
// Synchronization and memory management problems are often revealed by this
// type of test.
class ThreadIntegrationTest
    : public google::cloud::storage::testing::StorageIntegrationTest {
 public:
  static void CreateObjects(std::string const& bucket_name,
                            ObjectNameList const& group,
                            std::string const& contents) {
    // Create our own client so no state is shared with the other threads.
    StatusOr<Client> client = MakeIntegrationTestClient();
    ASSERT_STATUS_OK(client);
    for (auto const& object_name : group) {
      (void)client->InsertObject(bucket_name, object_name, contents,
                                 IfGenerationMatch(0));
    }
  }

  static void DeleteObjects(std::string const& bucket_name,
                            ObjectNameList const& group) {
    // Create our own client so no state is shared with the other threads.
    StatusOr<Client> client = MakeIntegrationTestClient();
    ASSERT_STATUS_OK(client);
    for (auto const& object_name : group) {
      (void)client->DeleteObject(bucket_name, object_name);
    }
  }

 protected:
  void SetUp() override {
    project_id_ =
        google::cloud::internal::GetEnv("GOOGLE_CLOUD_PROJECT").value_or("");
    ASSERT_FALSE(project_id_.empty());
    region_id_ = google::cloud::internal::GetEnv(
                     "GOOGLE_CLOUD_CPP_STORAGE_TEST_REGION_ID")
                     .value_or("");
    ASSERT_FALSE(region_id_.empty());
  }

  std::string project_id_;
  std::string region_id_;
};

/**
 * Divides @p source in to @p count groups of approximately equal size.
 */
std::vector<ObjectNameList> DivideIntoEqualSizedGroups(
    ObjectNameList const& source, unsigned int count) {
  std::vector<ObjectNameList> groups(count);
  std::size_t index = 0;
  for (auto const& name : source) {
    auto group_id = index % count;
    groups[group_id].push_back(name);
  }
  return groups;
}

}  // anonymous namespace

TEST_F(ThreadIntegrationTest, Unshared) {
  std::string bucket_name = MakeRandomBucketName();
  auto bucket_client = MakeBucketIntegrationTestClient();
  ASSERT_STATUS_OK(bucket_client);

  StatusOr<Client> client = MakeIntegrationTestClient();
  ASSERT_STATUS_OK(client);

  StatusOr<BucketMetadata> meta = bucket_client->CreateBucketForProject(
      bucket_name, project_id_,
      BucketMetadata()
          .set_storage_class(storage_class::Standard())
          .set_location(region_id_)
          .disable_versioning(),
      PredefinedAcl("private"), PredefinedDefaultObjectAcl("projectPrivate"),
      Projection("full"));
  ASSERT_STATUS_OK(meta);
  EXPECT_EQ(bucket_name, meta->name());

  auto const thread_count = (std::max)(std::thread::hardware_concurrency(), 8U);
  auto const object_count = 100 * thread_count;
  std::vector<std::string> objects(object_count);
  std::generate(objects.begin(), objects.end(),
                [this] { return MakeRandomObjectName(); });

  auto const groups = DivideIntoEqualSizedGroups(objects, thread_count);
  std::vector<std::future<void>> tasks(groups.size());
  std::transform(groups.begin(), groups.end(), tasks.begin(),
                 [&](ObjectNameList const& g) {
                   return std::async(std::launch::async,
                                     &ThreadIntegrationTest::CreateObjects,
                                     bucket_name, g, LoremIpsum());
                 });
  for (auto& t : tasks) t.get();
  // Verify at least 1/2 of the objects were successfully created, note that
  // with the default policies an object may be successfully created, but
  // `InsertObject()` returns an error due to retries.
  std::size_t found = 0;
  for (auto& o : client->ListObjects(bucket_name)) {
    if (!o.ok()) break;
    ++found;
  }
  EXPECT_GE(found, object_count / 2);
  std::transform(groups.begin(), groups.end(), tasks.begin(),
                 [&](ObjectNameList const& g) {
                   return std::async(std::launch::async,
                                     &ThreadIntegrationTest::DeleteObjects,
                                     bucket_name, g);
                 });
  for (auto& t : tasks) t.get();

  auto delete_status = bucket_client->DeleteBucket(bucket_name);
  ASSERT_STATUS_OK(delete_status);
}

class CaptureSendHeaderBackend : public LogBackend {
 public:
  std::vector<std::string> log_lines;

  void Process(LogRecord const& lr) override {
    // Break the records in lines, because we will analyze the output per line.
    std::vector<std::string> lines = absl::StrSplit(lr.message, '\n');
    log_lines.insert(log_lines.end(), lines.begin(), lines.end());
  }

  void ProcessWithOwnership(LogRecord lr) override { Process(lr); }
};

TEST_F(ThreadIntegrationTest, ReuseConnections) {
  auto log_backend = std::make_shared<CaptureSendHeaderBackend>();

  Client client(Options{}.set<TracingComponentsOption>({"raw-client", "http"}));

  std::string bucket_name = MakeRandomBucketName();

  auto id = LogSink::Instance().AddBackend(log_backend);
  StatusOr<BucketMetadata> meta = client.CreateBucketForProject(
      bucket_name, project_id_,
      BucketMetadata()
          .set_storage_class(storage_class::Standard())
          .set_location(region_id_)
          .disable_versioning(),
      PredefinedAcl("private"), PredefinedDefaultObjectAcl("projectPrivate"),
      Projection("full"));
  ASSERT_STATUS_OK(meta);
  EXPECT_EQ(bucket_name, meta->name());

  constexpr int kObjectCount = 100;
  std::vector<std::string> objects;
  objects.reserve(kObjectCount);
  std::generate_n(std::back_inserter(objects), kObjectCount,
                  [this] { return MakeRandomObjectName(); });

  std::vector<std::chrono::steady_clock::duration> create_elapsed;
  std::vector<std::chrono::steady_clock::duration> delete_elapsed;
  for (auto const& name : objects) {
    auto start = std::chrono::steady_clock::now();
    StatusOr<ObjectMetadata> insert = client.InsertObject(
        bucket_name, name, LoremIpsum(), IfGenerationMatch(0));
    ASSERT_STATUS_OK(insert);
    create_elapsed.emplace_back(std::chrono::steady_clock::now() - start);
  }
  for (auto const& name : objects) {
    auto start = std::chrono::steady_clock::now();
    (void)client.DeleteObject(bucket_name, name);
    delete_elapsed.emplace_back(std::chrono::steady_clock::now() - start);
  }
  LogSink::Instance().RemoveBackend(id);
  auto delete_status = client.DeleteBucket(bucket_name);
  ASSERT_STATUS_OK(delete_status);

  std::set<std::string> connected;
  std::copy_if(
      log_backend->log_lines.begin(), log_backend->log_lines.end(),
      std::inserter(connected, connected.end()), [](std::string const& line) {
        // libcurl prints established connections using this format:
        //   Connected to <hostname> (<ipaddress>) port <num> (#<connection>)
        // We capturing the different lines in that form tells us how many
        // different connections were used.
        return line.find("== curl(Info): Connected to ") != std::string::npos;
      });
  // We expect that at most 5% of the requests required a new connection,
  // ideally it should be 1 connection, but anything small is acceptable. Recall
  // that we make two requests per connection, so:
  std::size_t max_expected_connections = kObjectCount * 2 * 5 / 100;
  EXPECT_GE(max_expected_connections, connected.size()) << [&log_backend] {
    return std::accumulate(log_backend->log_lines.begin(),
                           log_backend->log_lines.end(), std::string{},
                           [](std::string const& x, std::string const& y) {
                             return x + "\n" + y;
                           });
  }();
  // Zero connections indicates a bug in the test, the client should have
  // connected at least once.
  EXPECT_LT(0U, connected.size());
}

GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
}  // namespace storage
}  // namespace cloud
}  // namespace google
<commit_msg>test(storage): speed up thread_integration_test (#7576)<commit_after>// Copyright 2018 Google LLC
//
// 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 "google/cloud/storage/client.h"
#include "google/cloud/storage/testing/storage_integration_test.h"
#include "google/cloud/internal/getenv.h"
#include "google/cloud/internal/random.h"
#include "google/cloud/log.h"
#include "google/cloud/testing_util/status_matchers.h"
#include "absl/strings/str_split.h"
#include <gmock/gmock.h>
#include <algorithm>
#include <future>
#include <thread>

namespace google {
namespace cloud {
namespace storage {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
namespace {
using ObjectNameList = std::vector<std::string>;

// This is basically a smoke test, if the test does not crash it was
// successful. Its main value is when running with the *Sanitizers.
// Synchronization and memory management problems are often revealed by this
// type of test.
class ThreadIntegrationTest
    : public google::cloud::storage::testing::StorageIntegrationTest {
 public:
  static void CreateObjects(std::string const& bucket_name,
                            ObjectNameList const& group,
                            std::string const& contents) {
    // Create our own client so no state is shared with the other threads.
    StatusOr<Client> client = MakeIntegrationTestClient();
    ASSERT_STATUS_OK(client);
    for (auto const& object_name : group) {
      (void)client->InsertObject(bucket_name, object_name, contents,
                                 IfGenerationMatch(0));
    }
  }

  static void DeleteObjects(std::string const& bucket_name,
                            ObjectNameList const& group) {
    // Create our own client so no state is shared with the other threads.
    StatusOr<Client> client = MakeIntegrationTestClient();
    ASSERT_STATUS_OK(client);
    for (auto const& object_name : group) {
      (void)client->DeleteObject(bucket_name, object_name);
    }
  }

 protected:
  void SetUp() override {
    project_id_ =
        google::cloud::internal::GetEnv("GOOGLE_CLOUD_PROJECT").value_or("");
    ASSERT_FALSE(project_id_.empty());
    region_id_ = google::cloud::internal::GetEnv(
                     "GOOGLE_CLOUD_CPP_STORAGE_TEST_REGION_ID")
                     .value_or("");
    ASSERT_FALSE(region_id_.empty());
  }

  std::string project_id_;
  std::string region_id_;
};

/**
 * Divides @p source in to @p count groups of approximately equal size.
 */
std::vector<ObjectNameList> DivideIntoEqualSizedGroups(
    ObjectNameList const& source, unsigned int count) {
  std::vector<ObjectNameList> groups(count);
  std::size_t index = 0;
  for (auto const& name : source) {
    auto group_id = index % count;
    groups[group_id].push_back(name);
  }
  return groups;
}

}  // anonymous namespace

TEST_F(ThreadIntegrationTest, Unshared) {
  std::string bucket_name = MakeRandomBucketName();
  auto bucket_client = MakeBucketIntegrationTestClient();
  ASSERT_STATUS_OK(bucket_client);

  StatusOr<Client> client = MakeIntegrationTestClient();
  ASSERT_STATUS_OK(client);

  StatusOr<BucketMetadata> meta = bucket_client->CreateBucketForProject(
      bucket_name, project_id_,
      BucketMetadata()
          .set_storage_class(storage_class::Standard())
          .set_location(region_id_)
          .disable_versioning(),
      PredefinedAcl("private"), PredefinedDefaultObjectAcl("projectPrivate"),
      Projection("full"));
  ASSERT_STATUS_OK(meta);
  EXPECT_EQ(bucket_name, meta->name());

  // Clamp the thread count to the [8, 32] range. Sadly, `std::clamp` is a C++17
  // feature.
  auto const thread_count =
      (std::min)(32U, (std::max)(8U, std::thread::hardware_concurrency()));
  auto const object_count = 100 * thread_count;
  std::vector<std::string> objects(object_count);
  std::generate(objects.begin(), objects.end(),
                [this] { return MakeRandomObjectName(); });

  auto const groups = DivideIntoEqualSizedGroups(objects, thread_count);
  std::vector<std::future<void>> tasks(groups.size());
  std::transform(groups.begin(), groups.end(), tasks.begin(),
                 [&](ObjectNameList const& g) {
                   return std::async(std::launch::async,
                                     &ThreadIntegrationTest::CreateObjects,
                                     bucket_name, g, LoremIpsum());
                 });
  for (auto& t : tasks) t.get();
  // Verify at least 1/2 of the objects were successfully created, note that
  // with the default policies an object may be successfully created, but
  // `InsertObject()` returns an error due to retries.
  std::size_t found = 0;
  for (auto& o : client->ListObjects(bucket_name)) {
    if (!o.ok()) break;
    ++found;
  }
  EXPECT_GE(found, object_count / 2);
  std::transform(groups.begin(), groups.end(), tasks.begin(),
                 [&](ObjectNameList const& g) {
                   return std::async(std::launch::async,
                                     &ThreadIntegrationTest::DeleteObjects,
                                     bucket_name, g);
                 });
  for (auto& t : tasks) t.get();

  auto delete_status = bucket_client->DeleteBucket(bucket_name);
  ASSERT_STATUS_OK(delete_status);
}

class CaptureSendHeaderBackend : public LogBackend {
 public:
  std::vector<std::string> log_lines;

  void Process(LogRecord const& lr) override {
    // Break the records in lines, because we will analyze the output per line.
    std::vector<std::string> lines = absl::StrSplit(lr.message, '\n');
    log_lines.insert(log_lines.end(), lines.begin(), lines.end());
  }

  void ProcessWithOwnership(LogRecord lr) override { Process(lr); }
};

TEST_F(ThreadIntegrationTest, ReuseConnections) {
  auto log_backend = std::make_shared<CaptureSendHeaderBackend>();

  Client client(Options{}.set<TracingComponentsOption>({"raw-client", "http"}));

  std::string bucket_name = MakeRandomBucketName();

  auto id = LogSink::Instance().AddBackend(log_backend);
  StatusOr<BucketMetadata> meta = client.CreateBucketForProject(
      bucket_name, project_id_,
      BucketMetadata()
          .set_storage_class(storage_class::Standard())
          .set_location(region_id_)
          .disable_versioning(),
      PredefinedAcl("private"), PredefinedDefaultObjectAcl("projectPrivate"),
      Projection("full"));
  ASSERT_STATUS_OK(meta);
  EXPECT_EQ(bucket_name, meta->name());

  constexpr int kObjectCount = 100;
  std::vector<std::string> objects;
  objects.reserve(kObjectCount);
  std::generate_n(std::back_inserter(objects), kObjectCount,
                  [this] { return MakeRandomObjectName(); });

  std::vector<std::chrono::steady_clock::duration> create_elapsed;
  std::vector<std::chrono::steady_clock::duration> delete_elapsed;
  for (auto const& name : objects) {
    auto start = std::chrono::steady_clock::now();
    StatusOr<ObjectMetadata> insert = client.InsertObject(
        bucket_name, name, LoremIpsum(), IfGenerationMatch(0));
    ASSERT_STATUS_OK(insert);
    create_elapsed.emplace_back(std::chrono::steady_clock::now() - start);
  }
  for (auto const& name : objects) {
    auto start = std::chrono::steady_clock::now();
    (void)client.DeleteObject(bucket_name, name);
    delete_elapsed.emplace_back(std::chrono::steady_clock::now() - start);
  }
  LogSink::Instance().RemoveBackend(id);
  auto delete_status = client.DeleteBucket(bucket_name);
  ASSERT_STATUS_OK(delete_status);

  std::set<std::string> connected;
  std::copy_if(
      log_backend->log_lines.begin(), log_backend->log_lines.end(),
      std::inserter(connected, connected.end()), [](std::string const& line) {
        // libcurl prints established connections using this format:
        //   Connected to <hostname> (<ipaddress>) port <num> (#<connection>)
        // We capturing the different lines in that form tells us how many
        // different connections were used.
        return line.find("== curl(Info): Connected to ") != std::string::npos;
      });
  // We expect that at most 5% of the requests required a new connection,
  // ideally it should be 1 connection, but anything small is acceptable. Recall
  // that we make two requests per connection, so:
  std::size_t max_expected_connections = kObjectCount * 2 * 5 / 100;
  EXPECT_GE(max_expected_connections, connected.size()) << [&log_backend] {
    return std::accumulate(log_backend->log_lines.begin(),
                           log_backend->log_lines.end(), std::string{},
                           [](std::string const& x, std::string const& y) {
                             return x + "\n" + y;
                           });
  }();
  // Zero connections indicates a bug in the test, the client should have
  // connected at least once.
  EXPECT_LT(0U, connected.size());
}

GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
}  // namespace storage
}  // namespace cloud
}  // namespace google
<|endoftext|>


<commit_before>// Copyright 2018 William Jagels
#pragma once

#include <memory>
#include <stdexcept>
#include <type_traits>
#include <variant>

namespace wijagels {
struct BadFunctionCall : std::runtime_error {
  using std::runtime_error::runtime_error;
};

namespace detail {
template <typename ResultType, typename... ArgumentTypes>
struct function_storage {
  function_storage() = default;
  function_storage(const function_storage &) = default;
  function_storage(function_storage &&) noexcept = default;
  virtual ~function_storage() = default;
  function_storage &operator=(const function_storage &) = default;
  function_storage &operator=(function_storage &&) noexcept = default;

  virtual std::unique_ptr<function_storage> clone() const = 0;
  virtual void clone_into(function_storage *) const = 0;
  virtual void move_into(function_storage *) noexcept = 0;
  virtual ResultType invoke(ArgumentTypes &&... args) = 0;
};

template <typename FunctionType, typename ResultType, typename... ArgumentTypes>
struct function_storage_impl : function_storage<ResultType, ArgumentTypes...> {
  function_storage_impl(FunctionType fn) : m_fn{fn} {}

  std::unique_ptr<function_storage<ResultType, ArgumentTypes...>> clone()
      const override {
    return std::make_unique<function_storage_impl>(m_fn);
  }

  void clone_into(
      function_storage<ResultType, ArgumentTypes...> *ptr) const override {
    new (ptr) function_storage_impl(*this);
  }

  void move_into(
      function_storage<ResultType, ArgumentTypes...> *ptr) noexcept override {
    new (ptr) function_storage_impl(std::move(*this));
  }

  ResultType invoke(ArgumentTypes &&... args) override {
    return m_fn(std::forward<ArgumentTypes>(args)...);
  }

  FunctionType m_fn;
};
}  // namespace detail

template <typename>
class Function;

template <typename ResultType, typename... ArgumentTypes>
class Function<ResultType(ArgumentTypes...)> {
  static constexpr std::size_t MAX_SIZE = 24;
  static constexpr std::size_t ALIGNMENT = 8;

  using ptr_t = typename std::unique_ptr<
      detail::function_storage<ResultType, ArgumentTypes...>>;
  using inline_storage = std::aligned_storage_t<MAX_SIZE, ALIGNMENT>;
  using base_fn_storage =
      detail::function_storage<ResultType, ArgumentTypes...>;

  std::variant<std::monostate, inline_storage, ptr_t> m_storage;

 public:
  constexpr Function() = default;
  ~Function() {
    if (auto *ptr = std::get_if<inline_storage>(&m_storage))
      std::destroy_at(reinterpret_cast<base_fn_storage *>(ptr));
  }

  template <typename FunctionType,
            typename = std::enable_if_t<std::is_invocable_r_v<
                ResultType, FunctionType, ArgumentTypes...>>>
  Function(FunctionType f) {
    if constexpr (sizeof(detail::function_storage_impl<FunctionType, ResultType,
                                                       ArgumentTypes...>) <=
                      MAX_SIZE &&
                  alignof(
                      detail::function_storage_impl<FunctionType, ResultType,
                                                    ArgumentTypes...>) <=
                      ALIGNMENT) {
      m_storage.template emplace<inline_storage>();
      auto *ptr = std::get_if<inline_storage>(&m_storage);
      new (ptr) detail::function_storage_impl<FunctionType, ResultType,
                                              ArgumentTypes...>{std::move(f)};
    } else {
      m_storage.template emplace<ptr_t>(
          std::make_unique<detail::function_storage_impl<
              FunctionType, ResultType, ArgumentTypes...>>(std::move(f)));
    }
  }

  Function(const Function &other) {
    if (auto ptr = std::get_if<ptr_t>(&other.m_storage))
      m_storage = (*ptr)->clone();
    else if (auto inline_ptr = std::get_if<inline_storage>(&other.m_storage)) {
      m_storage.template emplace<inline_storage>();
      reinterpret_cast<const base_fn_storage *>(inline_ptr)
          ->clone_into(reinterpret_cast<base_fn_storage *>(
              std::get_if<inline_storage>(&m_storage)));
    }
  }

  Function(Function &&other) noexcept {
    if (auto ptr = std::get_if<ptr_t>(&other.m_storage))
      m_storage = std::move(*ptr);
    else if (auto inline_ptr = std::get_if<inline_storage>(&other.m_storage)) {
      m_storage.template emplace<inline_storage>();
      reinterpret_cast<base_fn_storage *>(inline_ptr)
          ->move_into(reinterpret_cast<base_fn_storage *>(
              std::get_if<inline_storage>(&m_storage)));
    }
  }

  Function &operator=(const Function &other) {
    if (this != &other) {
      if (auto ptr = std::get_if<ptr_t>(&other.m_storage))
        m_storage = (*ptr)->clone();
      else if (auto inline_ptr =
                   std::get_if<inline_storage>(&other.m_storage)) {
        m_storage.template emplace<inline_storage>();
        reinterpret_cast<const base_fn_storage *>(inline_ptr)
            ->clone_into(reinterpret_cast<base_fn_storage *>(
                std::get_if<inline_storage>(&m_storage)));
      }
    }
    return *this;
  }

  Function &operator=(Function &&other) noexcept {
    if (this != &other) {
      if (auto ptr = std::get_if<ptr_t>(&other.m_storage))
        m_storage = std::move(*ptr);
      else if (auto inline_ptr =
                   std::get_if<inline_storage>(&other.m_storage)) {
        m_storage.template emplace<inline_storage>();
        reinterpret_cast<base_fn_storage *>(inline_ptr)
            ->move_into(reinterpret_cast<base_fn_storage *>(
                std::get_if<inline_storage>(&m_storage)));
      }
    }
    return *this;
  }

  ResultType operator()(ArgumentTypes &&... args) {
    if (auto ptr = std::get_if<ptr_t>(&m_storage))
      return (*ptr)->invoke(std::forward<ArgumentTypes>(args)...);
    else if (auto inline_ptr = std::get_if<inline_storage>(&m_storage))
      return reinterpret_cast<base_fn_storage *>(inline_ptr)
          ->invoke(std::forward<ArgumentTypes>(args)...);
    else
      throw BadFunctionCall{"No function stored"};
  }

  constexpr explicit operator bool() const { return m_storage.index() != 0; }

  constexpr friend bool operator==(
      const Function<ResultType(ArgumentTypes...)> &f, std::nullptr_t) {
    return !bool{f};
  }
  constexpr friend bool operator==(
      std::nullptr_t, const Function<ResultType(ArgumentTypes...)> &f) {
    return !bool{f};
  }
  constexpr friend bool operator!=(
      const Function<ResultType(ArgumentTypes...)> &f, std::nullptr_t) {
    return bool{f};
  }
  constexpr friend bool operator!=(
      std::nullptr_t, const Function<ResultType(ArgumentTypes...)> &f) {
    return bool{f};
  }
};

}  // namespace wijagels
<commit_msg>Cleanup function<commit_after>// Copyright 2018 William Jagels
#pragma once

#include <memory>
#include <stdexcept>
#include <type_traits>
#include <variant>

namespace wijagels {
struct BadFunctionCall : std::runtime_error {
  using std::runtime_error::runtime_error;
};

namespace detail {
template <typename ResultType, typename... ArgumentTypes>
struct function_storage {
  function_storage() = default;
  function_storage(const function_storage &) = default;
  function_storage(function_storage &&) noexcept = default;
  virtual ~function_storage() = default;
  function_storage &operator=(const function_storage &) = default;
  function_storage &operator=(function_storage &&) noexcept = default;

  virtual std::unique_ptr<function_storage> clone() const = 0;
  virtual void clone_into(function_storage *) const = 0;
  virtual void move_into(function_storage *) noexcept = 0;
  virtual ResultType invoke(ArgumentTypes &&... args) = 0;
};

template <typename FunctionType, typename ResultType, typename... ArgumentTypes>
struct function_storage_impl final
    : function_storage<ResultType, ArgumentTypes...> {
  function_storage_impl(FunctionType fn) : m_fn{fn} {}

  std::unique_ptr<function_storage<ResultType, ArgumentTypes...>> clone()
      const override {
    return std::make_unique<function_storage_impl>(m_fn);
  }

  void clone_into(
      function_storage<ResultType, ArgumentTypes...> *ptr) const override {
    new (ptr) function_storage_impl(*this);
  }

  void move_into(
      function_storage<ResultType, ArgumentTypes...> *ptr) noexcept override {
    new (ptr) function_storage_impl(std::move(*this));
  }

  ResultType invoke(ArgumentTypes &&... args) override {
    return m_fn(std::forward<ArgumentTypes>(args)...);
  }

  FunctionType m_fn;
};
}  // namespace detail

template <typename>
class Function;

template <typename ResultType, typename... ArgumentTypes>
class Function<ResultType(ArgumentTypes...)> {
  static constexpr std::size_t MAX_SIZE = 24;
  static constexpr std::size_t ALIGNMENT = 8;

  using ptr_t = typename std::unique_ptr<
      detail::function_storage<ResultType, ArgumentTypes...>>;
  using inline_storage = std::aligned_storage_t<MAX_SIZE, ALIGNMENT>;
  using base_fn_storage =
      detail::function_storage<ResultType, ArgumentTypes...>;

  std::variant<std::monostate, inline_storage, ptr_t> m_storage;

 public:
  constexpr Function() = default;
  ~Function() {
    if (auto *ptr = std::get_if<inline_storage>(&m_storage))
      std::destroy_at(reinterpret_cast<base_fn_storage *>(ptr));
  }

  template <typename FunctionType,
            typename = std::enable_if_t<std::is_invocable_r_v<
                ResultType, FunctionType, ArgumentTypes...>>>
  Function(FunctionType f) {
    using fn_storage_t = detail::function_storage_impl<FunctionType, ResultType,
                                                       ArgumentTypes...>;
    if constexpr (sizeof(fn_storage_t) <= MAX_SIZE &&
                  alignof(fn_storage_t) <= ALIGNMENT) {
      m_storage.template emplace<inline_storage>();
      auto *ptr = std::get_if<inline_storage>(&m_storage);
      new (ptr) fn_storage_t{std::move(f)};
    } else {
      m_storage.template emplace<ptr_t>(
          std::make_unique<fn_storage_t>(std::move(f)));
    }
  }

  Function(const Function &other) {
    if (auto ptr = std::get_if<ptr_t>(&other.m_storage))
      m_storage = (*ptr)->clone();
    else if (auto inline_ptr = std::get_if<inline_storage>(&other.m_storage)) {
      m_storage.template emplace<inline_storage>();
      reinterpret_cast<const base_fn_storage *>(inline_ptr)
          ->clone_into(reinterpret_cast<base_fn_storage *>(
              std::get_if<inline_storage>(&m_storage)));
    }
  }

  Function(Function &&other) noexcept {
    if (auto ptr = std::get_if<ptr_t>(&other.m_storage))
      m_storage = std::move(*ptr);
    else if (auto inline_ptr = std::get_if<inline_storage>(&other.m_storage)) {
      m_storage.template emplace<inline_storage>();
      reinterpret_cast<base_fn_storage *>(inline_ptr)
          ->move_into(reinterpret_cast<base_fn_storage *>(
              std::get_if<inline_storage>(&m_storage)));
    }
  }

  Function &operator=(const Function &other) {
    if (this != &other) {
      if (auto ptr = std::get_if<ptr_t>(&other.m_storage))
        m_storage = (*ptr)->clone();
      else if (auto inline_ptr =
                   std::get_if<inline_storage>(&other.m_storage)) {
        m_storage.template emplace<inline_storage>();
        reinterpret_cast<const base_fn_storage *>(inline_ptr)
            ->clone_into(reinterpret_cast<base_fn_storage *>(
                std::get_if<inline_storage>(&m_storage)));
      }
    }
    return *this;
  }

  Function &operator=(Function &&other) noexcept {
    if (this != &other) {
      if (auto ptr = std::get_if<ptr_t>(&other.m_storage))
        m_storage = std::move(*ptr);
      else if (auto inline_ptr =
                   std::get_if<inline_storage>(&other.m_storage)) {
        m_storage.template emplace<inline_storage>();
        reinterpret_cast<base_fn_storage *>(inline_ptr)
            ->move_into(reinterpret_cast<base_fn_storage *>(
                std::get_if<inline_storage>(&m_storage)));
      }
    }
    return *this;
  }

  ResultType operator()(ArgumentTypes &&... args) {
    if (auto ptr = std::get_if<ptr_t>(&m_storage))
      return (*ptr)->invoke(std::forward<ArgumentTypes>(args)...);
    else if (auto inline_ptr = std::get_if<inline_storage>(&m_storage))
      return reinterpret_cast<base_fn_storage *>(inline_ptr)
          ->invoke(std::forward<ArgumentTypes>(args)...);
    else
      throw BadFunctionCall{"No function stored"};
  }

  constexpr explicit operator bool() const { return m_storage.index() != 0; }

  constexpr friend bool operator==(
      const Function<ResultType(ArgumentTypes...)> &f, std::nullptr_t) {
    return !bool{f};
  }
  constexpr friend bool operator==(
      std::nullptr_t, const Function<ResultType(ArgumentTypes...)> &f) {
    return !bool{f};
  }
  constexpr friend bool operator!=(
      const Function<ResultType(ArgumentTypes...)> &f, std::nullptr_t) {
    return bool{f};
  }
  constexpr friend bool operator!=(
      std::nullptr_t, const Function<ResultType(ArgumentTypes...)> &f) {
    return bool{f};
  }
};

}  // namespace wijagels
<|endoftext|>


<commit_before>// Copyright 2017 Netherlands Institute for Radio Astronomy (ASTRON)
// Copyright 2017 Netherlands eScience Center
//
// 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 <fstream>
#include <vector>
#include <set>
#include <string>
#include <cstring>
#include <cmath>
#include <exception>
#ifdef HAVE_HDF5
#include <H5Cpp.h>
#endif // HAVE_HDF5
#ifdef HAVE_PSRDADA
#include <dada_hdu.h>
#include <ascii_header.h>
#endif // HAVE_PSRDADA

#include <utils.hpp>
#include "Observation.hpp"
#include "Platform.hpp"

#pragma once

namespace AstroData {

// Exception: the PSRDADA ring buffer does not work
class RingBufferError : public std::exception {
public:
  explicit RingBufferError(std::string message);
  ~RingBufferError() throw ();

  const char * what() const throw ();
private:
  std::string message;
};

// Zapped channels (excluded from computation)
void readZappedChannels(Observation & observation, const std::string & inputFileName, std::vector<unsigned int> & zappedChannels);
// Integration steps
void readIntegrationSteps(const Observation & observation, const std::string  & inputFileName, std::set< unsigned int > & integrationSteps);
// SIGPROC data
template< typename T > void readSIGPROC(const Observation & observation, const unsigned int padding, const uint8_t inputBits, const unsigned int bytesToSkip, const std::string & inputFilename, std::vector< std::vector< T > * > & data, const unsigned int firstBatch = 0);
#ifdef HAVE_HDF5
// LOFAR data
template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, const unsigned int padding, std::vector< std::vector< T > * > & data, unsigned int nrBatches = 0, unsigned int firstBatch = 0);
#endif // HAVE_HDF5
#ifdef HAVE_PSRDADA
// PSRDADA buffer
void readPSRDADAHeader(Observation & observation, dada_hdu_t & ringBuffer) throw(RingBufferError);
template< typename T > inline void readPSRDADA(dada_hdu_t & ringBuffer, std::vector< T > * data) throw(RingBufferError);
#endif // HAVE_PSRDADA

// Implementations

template< typename T > void readSIGPROC(const Observation & observation, const unsigned int padding, const uint8_t inputBits, const unsigned int bytesToSkip, const std::string & inputFilename, std::vector< std::vector< T > * > & data, const unsigned int firstBatch) {
  std::ifstream inputFile;
  const unsigned int BUFFER_DIM = sizeof(T);
  char * buffer = new char [BUFFER_DIM];

  inputFile.open(inputFilename.c_str(), std::ios::binary);
  if ( ! inputFile ) {
    delete [] buffer;
    throw FileError("Impossible to open " + inputFilename);
  }
  inputFile.sync_with_stdio(false);
  inputFile.seekg(bytesToSkip, std::ios::beg);
  for ( unsigned int batch = 0; batch < observation.getNrBatches(); batch++ ) {
    if ( inputBits >= 8 ) {
      data.at(batch) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerBatch(padding / sizeof(T)));
      for ( unsigned int sample = 0; sample < observation.getNrSamplesPerBatch(); sample++ ) {
        for ( unsigned int channel = observation.getNrChannels(); channel > 0; channel-- ) {
          inputFile.read(buffer, BUFFER_DIM);
          data.at(batch)->at((static_cast< uint64_t >(channel - 1) * observation.getNrSamplesPerBatch(padding / sizeof(T))) + sample) = *(reinterpret_cast< T * >(buffer));
        }
      }
    } else {
      uint64_t bytesToRead = static_cast< uint64_t >(observation.getNrSamplesPerBatch() * (observation.getNrChannels() / (8.0 / inputBits)));

      data.at(batch) = new std::vector< T >(observation.getNrChannels() * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T)));
      for ( uint64_t byte = 0; byte < bytesToRead; byte++ ) {
        unsigned int channel = (observation.getNrChannels() - 1) - ((byte * (8 / inputBits)) % observation.getNrChannels());
        unsigned int sample = (byte * (8 / inputBits)) / observation.getNrChannels();
        unsigned int sampleByte = sample / (8 / inputBits);
        uint8_t sampleFirstBit = (sample % (8 / inputBits)) * inputBits;

        inputFile.read(buffer, BUFFER_DIM);
        for ( unsigned int item = 0; item < 8 / inputBits; item++ ) {
          uint8_t channelFirstBit = item * inputBits;
          uint8_t sampleBuffer = 0;

          if ( item > channel ) {
            // All channels read, the remaining elements are from the next sample
            unsigned int channelOffset = 0;
            channel = (observation.getNrChannels() - 1);
            sample += 1;
            sampleByte = sample / (8 / inputBits);
            sampleFirstBit = (sample % (8 / inputBits)) * inputBits;

            while ( item < (8 / inputBits) ) {
              channelFirstBit = item * inputBits;
              sampleBuffer = data.at(batch)->at((static_cast< uint64_t >(channel - channelOffset) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte);
              for ( uint8_t bit = 0; bit < inputBits; bit++ ) {
                isa::utils::setBit(sampleBuffer, isa::utils::getBit(*buffer, channelFirstBit + bit), sampleFirstBit + bit);
              }
              data.at(batch)->at((static_cast< uint64_t >(channel - channelOffset) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte) = sampleBuffer;
              item++;
              channelOffset++;
            }

            break;
          }
          sampleBuffer = data.at(batch)->at((static_cast< uint64_t >(channel - item) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte);
          for ( uint8_t bit = 0; bit < inputBits; bit++ ) {
            isa::utils::setBit(sampleBuffer, isa::utils::getBit(*buffer, channelFirstBit + bit), sampleFirstBit + bit);
          }
          data.at(batch)->at((static_cast< uint64_t >(channel - item) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte) = sampleBuffer;
        }
      }
    }
  }
  inputFile.close();

  delete [] buffer;
}

#ifdef HAVE_HDF5
template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, const unsigned int padding, std::vector< std::vector< T > * > & data, unsigned int nrBatches, unsigned int firstBatch) {
  unsigned int nrSubbands, nrChannels;
  float minFreq, channelBandwidth;
  // Read the HDF5 file with the metadata
  H5::H5File headerFile = H5::H5File(headerFilename, H5F_ACC_RDONLY);
  H5::FloatType typeDouble = H5::FloatType(H5::PredType::NATIVE_DOUBLE);
  double valueDouble = 0.0;
  H5::IntType typeUInt = H5::IntType(H5::PredType::NATIVE_UINT);
  unsigned int valueUInt = 0;

  H5::Group currentNode = headerFile.openGroup("/");
  currentNode.openAttribute("OBSERVATION_FREQUENCY_MIN").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  minFreq = valueDouble;
  currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
  currentNode.openAttribute("TOTAL_INTEGRATION_TIME").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  double totalIntegrationTime = valueDouble;
  currentNode.openAttribute("NOF_BEAMS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  observation.setNrBeams(valueUInt);
  currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
  currentNode.openAttribute("NOF_SAMPLES").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  unsigned int totalSamples = valueUInt;
  currentNode.openAttribute("NOF_STATIONS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  observation.setNrStations(valueUInt);
  currentNode.openAttribute("CHANNELS_PER_SUBBAND").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  nrChannels = valueUInt;
  currentNode.openAttribute("CHANNEL_WIDTH").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  channelBandwidth = valueDouble / 1000000;
  H5::DataSet currentData = currentNode.openDataSet("STOKES_0");
  currentData.openAttribute("NOF_SUBBANDS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  nrSubbands = valueUInt;
  headerFile.close();

  observation.setNrSamplesPerBatch(static_cast< unsigned int >(totalSamples / totalIntegrationTime));
  if ( nrBatches == 0 ) {
    observation.setNrBatches(static_cast< unsigned int >(totalIntegrationTime));
  } else {
    if ( static_cast< unsigned int >(totalIntegrationTime) >= (firstBatch + nrBatches) ) {
      observation.setNrBatches(nrBatches);
    } else {
      observation.setNrBatches(static_cast< unsigned int >(totalIntegrationTime) - firstBatch);
    }
  }
  observation.setFrequencyRange(1, nrSubbands * nrChannels, minFreq, channelBandwidth);

  // Read the raw file with the actual data
  std::ifstream rawFile;
  rawFile.open(rawFilename.c_str(), std::ios::binary);
  if ( !rawFile ) {
    throw FileError("Impossible to open " + rawFilename);
  }
  rawFile.sync_with_stdio(false);
  if ( firstBatch > 0 ) {
    rawFile.seekg(firstBatch * observation.getNrSamplesPerBatch() * nrSubbands * nrChannels, std::ios::beg);
  }
  data.resize(observation.getNrBatches());

  char * word = new char [4];
  for ( unsigned int batch = 0; batch < observation.getNrBatches(); batch++ ) {
    data.at(batch) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerBatch(padding / sizeof(T)));
    for ( unsigned int sample = 0; sample < observation.getNrSamplesPerBatch(); sample++ ) {
      for ( unsigned int subband = 0; subband < nrSubbands; subband++ ) {
        for ( unsigned int channel = 0; channel < nrChannels; channel++ ) {
          unsigned int globalChannel = (subband * nrChannels) + channel;

          rawFile.read(word, 4);
          isa::utils::bigEndianToLittleEndian(word);
          data.at(batch)->at((globalChannel * observation.getNrSamplesPerBatch(padding / sizeof(T))) + sample) = *(reinterpret_cast< T * >(word));
        }
      }
    }
  }
  rawFile.close();
  delete [] word;
}
#endif // HAVE_HDF5

#ifdef HAVE_PSRDADA
template< typename T > inline void readPSRDADA(dada_hdu_t & ringBuffer, std::vector< T > * data) throw(RingBufferError) {
  char * buffer = 0;
  uint64_t bufferBytes = 0;

  buffer = ipcbuf_get_next_read(reinterpret_cast< ipcbuf_t * >(ringBuffer.data_block), &bufferBytes);
  if ( (buffer == 0) || (bufferBytes == 0) ) {
    throw RingBufferError("Impossible to read the PSRDADA buffer.");
  }
  std::memcpy(reinterpret_cast< void * >(data->data()), reinterpret_cast< const void * >(buffer), data->size() * sizeof(T));
  if ( ipcbuf_mark_cleared(reinterpret_cast< ipcbuf_t * >(ringBuffer.data_block)) < 0 ) {
    throw RingBufferError("Impossible to mark the PSRDADA buffer as cleared.");
  }
}
#endif // HAVE_PSRDADA

} // AstroData

<commit_msg>Wrong use of Observation interface.<commit_after>// Copyright 2017 Netherlands Institute for Radio Astronomy (ASTRON)
// Copyright 2017 Netherlands eScience Center
//
// 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 <fstream>
#include <vector>
#include <set>
#include <string>
#include <cstring>
#include <cmath>
#include <exception>
#ifdef HAVE_HDF5
#include <H5Cpp.h>
#endif // HAVE_HDF5
#ifdef HAVE_PSRDADA
#include <dada_hdu.h>
#include <ascii_header.h>
#endif // HAVE_PSRDADA

#include <utils.hpp>
#include "Observation.hpp"
#include "Platform.hpp"

#pragma once

namespace AstroData {

// Exception: the PSRDADA ring buffer does not work
class RingBufferError : public std::exception {
public:
  explicit RingBufferError(std::string message);
  ~RingBufferError() throw ();

  const char * what() const throw ();
private:
  std::string message;
};

// Zapped channels (excluded from computation)
void readZappedChannels(Observation & observation, const std::string & inputFileName, std::vector<unsigned int> & zappedChannels);
// Integration steps
void readIntegrationSteps(const Observation & observation, const std::string  & inputFileName, std::set< unsigned int > & integrationSteps);
// SIGPROC data
template< typename T > void readSIGPROC(const Observation & observation, const unsigned int padding, const uint8_t inputBits, const unsigned int bytesToSkip, const std::string & inputFilename, std::vector< std::vector< T > * > & data, const unsigned int firstBatch = 0);
#ifdef HAVE_HDF5
// LOFAR data
template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, const unsigned int padding, std::vector< std::vector< T > * > & data, unsigned int nrBatches = 0, unsigned int firstBatch = 0);
#endif // HAVE_HDF5
#ifdef HAVE_PSRDADA
// PSRDADA buffer
void readPSRDADAHeader(Observation & observation, dada_hdu_t & ringBuffer) throw(RingBufferError);
template< typename T > inline void readPSRDADA(dada_hdu_t & ringBuffer, std::vector< T > * data) throw(RingBufferError);
#endif // HAVE_PSRDADA

// Implementations

template< typename T > void readSIGPROC(const Observation & observation, const unsigned int padding, const uint8_t inputBits, const unsigned int bytesToSkip, const std::string & inputFilename, std::vector< std::vector< T > * > & data, const unsigned int firstBatch) {
  std::ifstream inputFile;
  const unsigned int BUFFER_DIM = sizeof(T);
  char * buffer = new char [BUFFER_DIM];

  inputFile.open(inputFilename.c_str(), std::ios::binary);
  if ( ! inputFile ) {
    delete [] buffer;
    throw FileError("Impossible to open " + inputFilename);
  }
  inputFile.sync_with_stdio(false);
  inputFile.seekg(bytesToSkip, std::ios::beg);
  for ( unsigned int batch = 0; batch < observation.getNrBatches(); batch++ ) {
    if ( inputBits >= 8 ) {
      data.at(batch) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerBatch(false, padding / sizeof(T)));
      for ( unsigned int sample = 0; sample < observation.getNrSamplesPerBatch(); sample++ ) {
        for ( unsigned int channel = observation.getNrChannels(); channel > 0; channel-- ) {
          inputFile.read(buffer, BUFFER_DIM);
          data.at(batch)->at((static_cast< uint64_t >(channel - 1) * observation.getNrSamplesPerBatch(false, padding / sizeof(T))) + sample) = *(reinterpret_cast< T * >(buffer));
        }
      }
    } else {
      uint64_t bytesToRead = static_cast< uint64_t >(observation.getNrSamplesPerBatch() * (observation.getNrChannels() / (8.0 / inputBits)));

      data.at(batch) = new std::vector< T >(observation.getNrChannels() * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T)));
      for ( uint64_t byte = 0; byte < bytesToRead; byte++ ) {
        unsigned int channel = (observation.getNrChannels() - 1) - ((byte * (8 / inputBits)) % observation.getNrChannels());
        unsigned int sample = (byte * (8 / inputBits)) / observation.getNrChannels();
        unsigned int sampleByte = sample / (8 / inputBits);
        uint8_t sampleFirstBit = (sample % (8 / inputBits)) * inputBits;

        inputFile.read(buffer, BUFFER_DIM);
        for ( unsigned int item = 0; item < 8 / inputBits; item++ ) {
          uint8_t channelFirstBit = item * inputBits;
          uint8_t sampleBuffer = 0;

          if ( item > channel ) {
            // All channels read, the remaining elements are from the next sample
            unsigned int channelOffset = 0;
            channel = (observation.getNrChannels() - 1);
            sample += 1;
            sampleByte = sample / (8 / inputBits);
            sampleFirstBit = (sample % (8 / inputBits)) * inputBits;

            while ( item < (8 / inputBits) ) {
              channelFirstBit = item * inputBits;
              sampleBuffer = data.at(batch)->at((static_cast< uint64_t >(channel - channelOffset) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte);
              for ( uint8_t bit = 0; bit < inputBits; bit++ ) {
                isa::utils::setBit(sampleBuffer, isa::utils::getBit(*buffer, channelFirstBit + bit), sampleFirstBit + bit);
              }
              data.at(batch)->at((static_cast< uint64_t >(channel - channelOffset) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte) = sampleBuffer;
              item++;
              channelOffset++;
            }

            break;
          }
          sampleBuffer = data.at(batch)->at((static_cast< uint64_t >(channel - item) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte);
          for ( uint8_t bit = 0; bit < inputBits; bit++ ) {
            isa::utils::setBit(sampleBuffer, isa::utils::getBit(*buffer, channelFirstBit + bit), sampleFirstBit + bit);
          }
          data.at(batch)->at((static_cast< uint64_t >(channel - item) * isa::utils::pad(observation.getNrSamplesPerBatch() / (8 / inputBits), padding / sizeof(T))) + sampleByte) = sampleBuffer;
        }
      }
    }
  }
  inputFile.close();

  delete [] buffer;
}

#ifdef HAVE_HDF5
template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, const unsigned int padding, std::vector< std::vector< T > * > & data, unsigned int nrBatches, unsigned int firstBatch) {
  unsigned int nrSubbands, nrChannels;
  float minFreq, channelBandwidth;
  // Read the HDF5 file with the metadata
  H5::H5File headerFile = H5::H5File(headerFilename, H5F_ACC_RDONLY);
  H5::FloatType typeDouble = H5::FloatType(H5::PredType::NATIVE_DOUBLE);
  double valueDouble = 0.0;
  H5::IntType typeUInt = H5::IntType(H5::PredType::NATIVE_UINT);
  unsigned int valueUInt = 0;

  H5::Group currentNode = headerFile.openGroup("/");
  currentNode.openAttribute("OBSERVATION_FREQUENCY_MIN").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  minFreq = valueDouble;
  currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
  currentNode.openAttribute("TOTAL_INTEGRATION_TIME").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  double totalIntegrationTime = valueDouble;
  currentNode.openAttribute("NOF_BEAMS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  observation.setNrBeams(valueUInt);
  currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
  currentNode.openAttribute("NOF_SAMPLES").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  unsigned int totalSamples = valueUInt;
  currentNode.openAttribute("NOF_STATIONS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  observation.setNrStations(valueUInt);
  currentNode.openAttribute("CHANNELS_PER_SUBBAND").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  nrChannels = valueUInt;
  currentNode.openAttribute("CHANNEL_WIDTH").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  channelBandwidth = valueDouble / 1000000;
  H5::DataSet currentData = currentNode.openDataSet("STOKES_0");
  currentData.openAttribute("NOF_SUBBANDS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
  nrSubbands = valueUInt;
  headerFile.close();

  observation.setNrSamplesPerBatch(static_cast< unsigned int >(totalSamples / totalIntegrationTime));
  if ( nrBatches == 0 ) {
    observation.setNrBatches(static_cast< unsigned int >(totalIntegrationTime));
  } else {
    if ( static_cast< unsigned int >(totalIntegrationTime) >= (firstBatch + nrBatches) ) {
      observation.setNrBatches(nrBatches);
    } else {
      observation.setNrBatches(static_cast< unsigned int >(totalIntegrationTime) - firstBatch);
    }
  }
  observation.setFrequencyRange(1, nrSubbands * nrChannels, minFreq, channelBandwidth);

  // Read the raw file with the actual data
  std::ifstream rawFile;
  rawFile.open(rawFilename.c_str(), std::ios::binary);
  if ( !rawFile ) {
    throw FileError("Impossible to open " + rawFilename);
  }
  rawFile.sync_with_stdio(false);
  if ( firstBatch > 0 ) {
    rawFile.seekg(firstBatch * observation.getNrSamplesPerBatch() * nrSubbands * nrChannels, std::ios::beg);
  }
  data.resize(observation.getNrBatches());

  char * word = new char [4];
  for ( unsigned int batch = 0; batch < observation.getNrBatches(); batch++ ) {
    data.at(batch) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerBatch(false, padding / sizeof(T)));
    for ( unsigned int sample = 0; sample < observation.getNrSamplesPerBatch(); sample++ ) {
      for ( unsigned int subband = 0; subband < nrSubbands; subband++ ) {
        for ( unsigned int channel = 0; channel < nrChannels; channel++ ) {
          unsigned int globalChannel = (subband * nrChannels) + channel;

          rawFile.read(word, 4);
          isa::utils::bigEndianToLittleEndian(word);
          data.at(batch)->at((globalChannel * observation.getNrSamplesPerBatch(false, padding / sizeof(T))) + sample) = *(reinterpret_cast< T * >(word));
        }
      }
    }
  }
  rawFile.close();
  delete [] word;
}
#endif // HAVE_HDF5

#ifdef HAVE_PSRDADA
template< typename T > inline void readPSRDADA(dada_hdu_t & ringBuffer, std::vector< T > * data) throw(RingBufferError) {
  char * buffer = 0;
  uint64_t bufferBytes = 0;

  buffer = ipcbuf_get_next_read(reinterpret_cast< ipcbuf_t * >(ringBuffer.data_block), &bufferBytes);
  if ( (buffer == 0) || (bufferBytes == 0) ) {
    throw RingBufferError("Impossible to read the PSRDADA buffer.");
  }
  std::memcpy(reinterpret_cast< void * >(data->data()), reinterpret_cast< const void * >(buffer), data->size() * sizeof(T));
  if ( ipcbuf_mark_cleared(reinterpret_cast< ipcbuf_t * >(ringBuffer.data_block)) < 0 ) {
    throw RingBufferError("Impossible to mark the PSRDADA buffer as cleared.");
  }
}
#endif // HAVE_PSRDADA

} // AstroData

<|endoftext|>