<commit_before>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "unit_tests.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace mfem;

namespace assembly_levels
{

enum class Problem { Mass,
                     Convection,
                     Diffusion
                   };

std::string getString(Problem pb)
{
   switch (pb)
   {
      case Problem::Mass:
         return "Mass";
         break;
      case Problem::Convection:
         return "Convection";
         break;
      case Problem::Diffusion:
         return "Diffusion";
         break;
   }
   MFEM_ABORT("Unknown Problem.");
   return "";
}

void velocity_function(const Vector &x, Vector &v)
{
   int dim = x.Size();
   switch (dim)
   {
      case 1: v(0) = 1.0; break;
      case 2: v(0) = x(1); v(1) = -x(0); break;
      case 3: v(0) = x(1); v(1) = -x(0); v(2) = x(0); break;
   }
}

void AddConvectionIntegrators(BilinearForm &k, VectorCoefficient &velocity,
                              bool dg)
{
   k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));

   if (dg)
   {
      k.AddInteriorFaceIntegrator(
         new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
      k.AddBdrFaceIntegrator(
         new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
   }
}

void test_assembly_level(const char *meshname, int order, bool dg,
                         const Problem pb, const AssemblyLevel assembly)
{
   INFO("mesh=" << meshname << ", order=" << order << ", DG=" << dg
        << ", pb=" << getString(pb) << ", assembly=" << int(assembly));
   Mesh mesh(meshname, 1, 1);
   mesh.EnsureNodes();
   int dim = mesh.Dimension();

   FiniteElementCollection *fec;
   if (dg)
   {
      fec = new L2_FECollection(order, dim, BasisType::GaussLobatto);
   }
   else
   {
      fec = new H1_FECollection(order, dim);
   }

   FiniteElementSpace fespace(&mesh, fec);

   BilinearForm k_test(&fespace);
   BilinearForm k_ref(&fespace);

   ConstantCoefficient one(1.0);
   VectorFunctionCoefficient vel_coeff(dim, velocity_function);

   switch (pb)
   {
      case Problem::Mass:
         k_ref.AddDomainIntegrator(new MassIntegrator(one));
         k_test.AddDomainIntegrator(new MassIntegrator(one));
         break;
      case Problem::Convection:
         AddConvectionIntegrators(k_ref, vel_coeff, dg);
         AddConvectionIntegrators(k_test, vel_coeff, dg);
         break;
      case Problem::Diffusion:
         k_ref.AddDomainIntegrator(new DiffusionIntegrator(one));
         k_test.AddDomainIntegrator(new DiffusionIntegrator(one));
         break;
   }

   k_ref.Assemble();
   k_ref.Finalize();

   k_test.SetAssemblyLevel(assembly);
   k_test.Assemble();

   GridFunction x(&fespace), y_ref(&fespace), y_test(&fespace);

   x.Randomize(1);

   k_ref.Mult(x,y_ref);
   k_test.Mult(x,y_test);

   y_test -= y_ref;

   REQUIRE(y_test.Norml2() < 1.e-12);

   delete fec;
}

TEST_CASE("H1 Assembly Levels", "[AssemblyLevel], [PartialAssembly]")
{
   const bool dg = false;
   auto pb = GENERATE(Problem::Mass,Problem::Convection,Problem::Diffusion);
   auto assembly = GENERATE(AssemblyLevel::PARTIAL, AssemblyLevel::ELEMENT,
                            AssemblyLevel::FULL);

   SECTION("Conforming")
   {
      SECTION("2D")
      {
         auto order = GENERATE(2, 3);
         auto dg = GENERATE(true, false);
         test_assembly_level("../../data/periodic-square.mesh",
                             order, dg, pb, assembly);
         test_assembly_level("../../data/periodic-hexagon.mesh",
                             order, dg, pb, assembly);
         test_assembly_level("../../data/star-q3.mesh",
                             order, dg, pb, assembly);
      }

      SECTION("3D")
      {
         int order = 2;
         auto dg = GENERATE(true, false);
         test_assembly_level("../../data/periodic-cube.mesh",
                             order, dg, pb, assembly);
         test_assembly_level("../../data/fichera-q3.mesh",
                             order, dg, pb, assembly);
      }
   }

   SECTION("Nonconforming")
   {
      // Test AMR cases (DG not implemented)
      SECTION("AMR 2D")
      {
         auto order = GENERATE(2, 3);
         test_assembly_level("../../data/amr-quad.mesh",
                             order, dg, pb, assembly);
      }
      SECTION("AMR 3D")
      {
         int order = 2;
         test_assembly_level("../../data/fichera-amr.mesh",
                             order, dg, pb, assembly);
      }
   }
} // test case

TEST_CASE("L2 Assembly Levels", "[AssemblyLevel], [PartialAssembly]")
{
   const bool dg = true;
   auto pb = GENERATE(Problem::Mass,Problem::Convection);

   SECTION("Conforming")
   {
      auto assembly = GENERATE(AssemblyLevel::PARTIAL,
                               AssemblyLevel::ELEMENT,
                               AssemblyLevel::FULL);

      SECTION("2D")
      {
         auto order = GENERATE(2, 3);
         test_assembly_level("../../data/periodic-square.mesh",
                             order, dg, pb, assembly);
         test_assembly_level("../../data/periodic-hexagon.mesh",
                             order, dg, pb, assembly);
         test_assembly_level("../../data/star-q3.mesh",
                             order, dg, pb, assembly);
      }

      SECTION("3D")
      {
         int order = 2;
         test_assembly_level("../../data/periodic-cube.mesh",
                             order, dg, pb, assembly);
         test_assembly_level("../../data/fichera-q3.mesh",
                             order, dg, pb, assembly);
      }
   }

   SECTION("Nonconforming")
   {
      // Full assembly DG not implemented on NCMesh
      auto assembly = GENERATE(AssemblyLevel::PARTIAL,
                               AssemblyLevel::ELEMENT);

      SECTION("AMR 2D")
      {
         auto order = GENERATE(2, 3);
         test_assembly_level("../../data/amr-quad.mesh",
                             order, dg, pb, assembly);
      }
      SECTION("AMR 3D")
      {
         int order = 2;
         test_assembly_level("../../data/fichera-amr.mesh",
                             order, dg, pb, assembly);
      }
   }
} // test case

} // namespace assembly_levels
<commit_msg>Remove `dg` in H1 tests.<commit_after>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "unit_tests.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace mfem;

namespace assembly_levels
{

enum class Problem { Mass,
                     Convection,
                     Diffusion
                   };

std::string getString(Problem pb)
{
   switch (pb)
   {
      case Problem::Mass:
         return "Mass";
         break;
      case Problem::Convection:
         return "Convection";
         break;
      case Problem::Diffusion:
         return "Diffusion";
         break;
   }
   MFEM_ABORT("Unknown Problem.");
   return "";
}

void velocity_function(const Vector &x, Vector &v)
{
   int dim = x.Size();
   switch (dim)
   {
      case 1: v(0) = 1.0; break;
      case 2: v(0) = x(1); v(1) = -x(0); break;
      case 3: v(0) = x(1); v(1) = -x(0); v(2) = x(0); break;
   }
}

void AddConvectionIntegrators(BilinearForm &k, VectorCoefficient &velocity,
                              bool dg)
{
   k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));

   if (dg)
   {
      k.AddInteriorFaceIntegrator(
         new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
      k.AddBdrFaceIntegrator(
         new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
   }
}

void test_assembly_level(const char *meshname, int order, bool dg,
                         const Problem pb, const AssemblyLevel assembly)
{
   INFO("mesh=" << meshname << ", order=" << order << ", DG=" << dg
        << ", pb=" << getString(pb) << ", assembly=" << int(assembly));
   Mesh mesh(meshname, 1, 1);
   mesh.EnsureNodes();
   int dim = mesh.Dimension();

   FiniteElementCollection *fec;
   if (dg)
   {
      fec = new L2_FECollection(order, dim, BasisType::GaussLobatto);
   }
   else
   {
      fec = new H1_FECollection(order, dim);
   }

   FiniteElementSpace fespace(&mesh, fec);

   BilinearForm k_test(&fespace);
   BilinearForm k_ref(&fespace);

   ConstantCoefficient one(1.0);
   VectorFunctionCoefficient vel_coeff(dim, velocity_function);

   switch (pb)
   {
      case Problem::Mass:
         k_ref.AddDomainIntegrator(new MassIntegrator(one));
         k_test.AddDomainIntegrator(new MassIntegrator(one));
         break;
      case Problem::Convection:
         AddConvectionIntegrators(k_ref, vel_coeff, dg);
         AddConvectionIntegrators(k_test, vel_coeff, dg);
         break;
      case Problem::Diffusion:
         k_ref.AddDomainIntegrator(new DiffusionIntegrator(one));
         k_test.AddDomainIntegrator(new DiffusionIntegrator(one));
         break;
   }

   k_ref.Assemble();
   k_ref.Finalize();

   k_test.SetAssemblyLevel(assembly);
   k_test.Assemble();

   GridFunction x(&fespace), y_ref(&fespace), y_test(&fespace);

   x.Randomize(1);

   k_ref.Mult(x,y_ref);
   k_test.Mult(x,y_test);

   y_test -= y_ref;

   REQUIRE(y_test.Norml2() < 1.e-12);

   delete fec;
}

TEST_CASE("H1 Assembly Levels", "[AssemblyLevel], [PartialAssembly]")
{
   const bool dg = false;
   auto pb = GENERATE(Problem::Mass,Problem::Convection,Problem::Diffusion);
   auto assembly = GENERATE(AssemblyLevel::PARTIAL, AssemblyLevel::ELEMENT,
                            AssemblyLevel::FULL);

   SECTION("Conforming")
   {
      SECTION("2D")
      {
         auto order = GENERATE(2, 3);
         test_assembly_level("../../data/periodic-square.mesh",
                             order, dg, pb, assembly);
         test_assembly_level("../../data/periodic-hexagon.mesh",
                             order, dg, pb, assembly);
         test_assembly_level("../../data/star-q3.mesh",
                             order, dg, pb, assembly);
      }

      SECTION("3D")
      {
         int order = 2;
         test_assembly_level("../../data/periodic-cube.mesh",
                             order, dg, pb, assembly);
         test_assembly_level("../../data/fichera-q3.mesh",
                             order, dg, pb, assembly);
      }
   }

   SECTION("Nonconforming")
   {
      // Test AMR cases (DG not implemented)
      SECTION("AMR 2D")
      {
         auto order = GENERATE(2, 3);
         test_assembly_level("../../data/amr-quad.mesh",
                             order, dg, pb, assembly);
      }
      SECTION("AMR 3D")
      {
         int order = 2;
         test_assembly_level("../../data/fichera-amr.mesh",
                             order, dg, pb, assembly);
      }
   }
} // test case

TEST_CASE("L2 Assembly Levels", "[AssemblyLevel], [PartialAssembly]")
{
   const bool dg = true;
   auto pb = GENERATE(Problem::Mass,Problem::Convection);

   SECTION("Conforming")
   {
      auto assembly = GENERATE(AssemblyLevel::PARTIAL,
                               AssemblyLevel::ELEMENT,
                               AssemblyLevel::FULL);

      SECTION("2D")
      {
         auto order = GENERATE(2, 3);
         test_assembly_level("../../data/periodic-square.mesh",
                             order, dg, pb, assembly);
         test_assembly_level("../../data/periodic-hexagon.mesh",
                             order, dg, pb, assembly);
         test_assembly_level("../../data/star-q3.mesh",
                             order, dg, pb, assembly);
      }

      SECTION("3D")
      {
         int order = 2;
         test_assembly_level("../../data/periodic-cube.mesh",
                             order, dg, pb, assembly);
         test_assembly_level("../../data/fichera-q3.mesh",
                             order, dg, pb, assembly);
      }
   }

   SECTION("Nonconforming")
   {
      // Full assembly DG not implemented on NCMesh
      auto assembly = GENERATE(AssemblyLevel::PARTIAL,
                               AssemblyLevel::ELEMENT);

      SECTION("AMR 2D")
      {
         auto order = GENERATE(2, 3);
         test_assembly_level("../../data/amr-quad.mesh",
                             order, dg, pb, assembly);
      }
      SECTION("AMR 3D")
      {
         int order = 2;
         test_assembly_level("../../data/fichera-amr.mesh",
                             order, dg, pb, assembly);
      }
   }
} // test case

} // namespace assembly_levels
<|endoftext|>


<commit_before>//===- Writer.cpp ---------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Chunks.h"
#include "Config.h"
#include "Error.h"
#include "SymbolTable.h"
#include "Writer.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/FileOutputBuffer.h"

using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;

using namespace lld;
using namespace lld::elf2;

static const int PageSize = 4096;

namespace {
// OutputSection represents a section in an output file. It's a
// container of chunks. OutputSection and Chunk are 1:N relationship.
// Chunks cannot belong to more than one OutputSections. The writer
// creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs.
template <class ELFT> class OutputSection {
public:
  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
  typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;

  OutputSection(StringRef Name) : Name(Name) {
    memset(&Header, 0, sizeof(Elf_Shdr));
  }
  void setVA(uintX_t);
  void setFileOffset(uintX_t);
  void addSectionChunk(SectionChunk<ELFT> *C);
  std::vector<Chunk *> &getChunks() { return Chunks; }
  void writeHeaderTo(Elf_Shdr *SHdr);
  StringRef getName() { return Name; }
  void setNameOffset(uintX_t Offset) { Header.sh_name = Offset; }

  // Returns the size of the section in the output file.
  uintX_t getSize() { return Header.sh_size; }
  uintX_t getFlags() { return Header.sh_flags; }
  uintX_t getOffset() { return Header.sh_offset; }

private:
  StringRef Name;
  Elf_Shdr Header;
  std::vector<Chunk *> Chunks;
};

// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
  typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
  Writer(SymbolTable *T) : Symtab(T) {}
  void run();

private:
  void createSections();
  void assignAddresses();
  void openFile(StringRef OutputPath);
  void writeHeader();
  void writeSections();

  SymbolTable *Symtab;
  std::unique_ptr<llvm::FileOutputBuffer> Buffer;
  llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
  std::vector<OutputSection<ELFT> *> OutputSections;

  uintX_t FileSize;
  uintX_t SizeOfHeaders;
  uintX_t SectionHeaderOff;
  uintX_t StringTableOff;
  unsigned StringTableIndex;
  StringTableBuilder StrTabBuilder;
  unsigned NumSections;

  std::vector<std::unique_ptr<Chunk>> Chunks;
};
} // anonymous namespace

namespace lld {
namespace elf2 {

template <class ELFT>
void writeResult(SymbolTable *Symtab) { Writer<ELFT>(Symtab).run(); }

template void writeResult<ELF32LE>(SymbolTable *);
template void writeResult<ELF32BE>(SymbolTable *);
template void writeResult<ELF64LE>(SymbolTable *);
template void writeResult<ELF64BE>(SymbolTable *);

} // namespace elf2
} // namespace lld

// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
  createSections();
  assignAddresses();
  openFile(Config->OutputFile);
  writeHeader();
  writeSections();
  error(Buffer->commit());
}

template <class ELFT> void OutputSection<ELFT>::setVA(uintX_t VA) {
  Header.sh_addr = VA;
}

template <class ELFT> void OutputSection<ELFT>::setFileOffset(uintX_t Off) {
  if (Header.sh_size == 0)
    return;
  Header.sh_offset = Off;
}

template <class ELFT>
void OutputSection<ELFT>::addSectionChunk(SectionChunk<ELFT> *C) {
  Chunks.push_back(C);
  uintX_t Off = Header.sh_size;
  Off = RoundUpToAlignment(Off, C->getAlign());
  C->setOutputSectionOff(Off);
  Off += C->getSize();
  Header.sh_size = Off;
  Header.sh_type = C->getSectionHdr()->sh_type;
  Header.sh_flags |= C->getSectionHdr()->sh_flags;
}

template <class ELFT> void OutputSection<ELFT>::writeHeaderTo(Elf_Shdr *SHdr) {
  *SHdr = Header;
}

namespace {
template <bool Is64Bits> struct SectionKey {
  typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
  StringRef Name;
  uint32_t sh_type;
  uintX_t sh_flags;
};
}
namespace llvm {
template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
  static SectionKey<Is64Bits> getEmptyKey() {
    return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
  }
  static SectionKey<Is64Bits> getTombstoneKey() {
    return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0,
                                0};
  }
  static unsigned getHashValue(const SectionKey<Is64Bits> &Val) {
    return hash_combine(Val.Name, Val.sh_type, Val.sh_flags);
  }
  static bool isEqual(const SectionKey<Is64Bits> &LHS,
                      const SectionKey<Is64Bits> &RHS) {
    return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
           LHS.sh_type == RHS.sh_type && LHS.sh_flags == RHS.sh_flags;
  }
};
}

// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::createSections() {
  SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSection<ELFT> *> Map;
  for (std::unique_ptr<ObjectFileBase> &FileB : Symtab->ObjectFiles) {
    auto &File = cast<ObjectFile<ELFT>>(*FileB);
    for (SectionChunk<ELFT> *C : File.getChunks()) {
      const Elf_Shdr *H = C->getSectionHdr();
      SectionKey<ELFT::Is64Bits> Key{C->getSectionName(), H->sh_type,
                                     H->sh_flags};
      OutputSection<ELFT> *&Sec = Map[Key];
      if (!Sec) {
        Sec = new (CAlloc.Allocate()) OutputSection<ELFT>(C->getSectionName());
        OutputSections.push_back(Sec);
      }
      Sec->addSectionChunk(C);
    }
  }
}

template <class ELFT>
static bool compSec(OutputSection<ELFT> *A, OutputSection<ELFT> *B) {
  // Place SHF_ALLOC sections first.
  return (A->getFlags() & SHF_ALLOC) && !(B->getFlags() & SHF_ALLOC);
}

// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
template <class ELFT> void Writer<ELFT>::assignAddresses() {
  SizeOfHeaders = RoundUpToAlignment(sizeof(Elf_Ehdr_Impl<ELFT>), PageSize);
  uintX_t VA = 0x1000; // The first page is kept unmapped.
  uintX_t FileOff = SizeOfHeaders;

  std::stable_sort(OutputSections.begin(), OutputSections.end(), compSec<ELFT>);

  for (OutputSection<ELFT> *Sec : OutputSections) {
    if (Sec->getFlags() & SHF_ALLOC) {
      Sec->setVA(VA);
      VA += RoundUpToAlignment(Sec->getSize(), PageSize);
    }
    Sec->setFileOffset(FileOff);
    FileOff += RoundUpToAlignment(Sec->getSize(), 8);
    StrTabBuilder.add(Sec->getName());
  }

  // Regular sections.
  NumSections = OutputSections.size();

  // First dummy section.
  NumSections++;

  // String table.
  StrTabBuilder.add(".strtab");
  StringTableIndex = NumSections;
  StringTableOff = FileOff;
  StrTabBuilder.finalize(StringTableBuilder::ELF);
  FileOff += StrTabBuilder.data().size();
  NumSections++;

  FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4);

  // Add space for section headers.
  SectionHeaderOff = FileOff;
  FileOff += NumSections * sizeof(Elf_Shdr_Impl<ELFT>);
  FileSize = SizeOfHeaders + RoundUpToAlignment(FileOff - SizeOfHeaders, 8);
}

template <class ELFT> void Writer<ELFT>::writeHeader() {
  uint8_t *Buf = Buffer->getBufferStart();
  auto *EHdr = reinterpret_cast<Elf_Ehdr_Impl<ELFT> *>(Buf);
  EHdr->e_ident[EI_MAG0] = 0x7F;
  EHdr->e_ident[EI_MAG1] = 0x45;
  EHdr->e_ident[EI_MAG2] = 0x4C;
  EHdr->e_ident[EI_MAG3] = 0x46;
  EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
  EHdr->e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little
                               ? ELFDATA2LSB
                               : ELFDATA2MSB;
  EHdr->e_ident[EI_VERSION] = EV_CURRENT;
  EHdr->e_ident[EI_OSABI] = ELFOSABI_NONE;

  EHdr->e_type = ET_EXEC;
  auto &FirstObj = cast<ObjectFile<ELFT>>(*Symtab->ObjectFiles[0]);
  EHdr->e_machine = FirstObj.getObj()->getHeader()->e_machine;
  EHdr->e_version = EV_CURRENT;
  EHdr->e_entry = 0x401000;
  EHdr->e_phoff = sizeof(Elf_Ehdr_Impl<ELFT>);
  EHdr->e_shoff = SectionHeaderOff;
  EHdr->e_ehsize = sizeof(Elf_Ehdr_Impl<ELFT>);
  EHdr->e_phentsize = sizeof(Elf_Phdr_Impl<ELFT>);
  EHdr->e_phnum = 1;
  EHdr->e_shentsize = sizeof(Elf_Shdr_Impl<ELFT>);
  EHdr->e_shnum = NumSections;
  EHdr->e_shstrndx = StringTableIndex;

  auto PHdrs = reinterpret_cast<Elf_Phdr_Impl<ELFT> *>(Buf + EHdr->e_phoff);
  PHdrs->p_type = PT_LOAD;
  PHdrs->p_flags = PF_R | PF_X;
  PHdrs->p_offset = 0x0000;
  PHdrs->p_vaddr = 0x400000;
  PHdrs->p_paddr = PHdrs->p_vaddr;
  PHdrs->p_filesz = FileSize;
  PHdrs->p_memsz = FileSize;
  PHdrs->p_align = 0x4000;

  auto SHdrs = reinterpret_cast<Elf_Shdr_Impl<ELFT> *>(Buf + EHdr->e_shoff);
  // First entry is null.
  ++SHdrs;
  for (OutputSection<ELFT> *Sec : OutputSections) {
    Sec->setNameOffset(StrTabBuilder.getOffset(Sec->getName()));
    Sec->writeHeaderTo(SHdrs++);
  }

  // String table.
  SHdrs->sh_name = StrTabBuilder.getOffset(".strtab");
  SHdrs->sh_type = SHT_STRTAB;
  SHdrs->sh_flags = 0;
  SHdrs->sh_addr = 0;
  SHdrs->sh_offset = StringTableOff;
  SHdrs->sh_size = StrTabBuilder.data().size();
  SHdrs->sh_link = 0;
  SHdrs->sh_info = 0;
  SHdrs->sh_addralign = 1;
  SHdrs->sh_entsize = 0;
}

template <class ELFT> void Writer<ELFT>::openFile(StringRef Path) {
  ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
      FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable);
  error(BufferOrErr, Twine("failed to open ") + Path);
  Buffer = std::move(*BufferOrErr);
}

// Write section contents to a mmap'ed file.
template <class ELFT> void Writer<ELFT>::writeSections() {
  uint8_t *Buf = Buffer->getBufferStart();
  for (OutputSection<ELFT> *Sec : OutputSections) {
    uint8_t *SecBuf = Buf + Sec->getOffset();
    for (Chunk *C : Sec->getChunks())
      C->writeTo(SecBuf);
  }

  // String table.
  StringRef Data = StrTabBuilder.data();
  memcpy(Buf + StringTableOff, Data.data(), Data.size());
}
<commit_msg>Pass the type and flags to the OutputSection constructor. NFC.<commit_after>//===- Writer.cpp ---------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Chunks.h"
#include "Config.h"
#include "Error.h"
#include "SymbolTable.h"
#include "Writer.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/FileOutputBuffer.h"

using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;

using namespace lld;
using namespace lld::elf2;

static const int PageSize = 4096;

namespace {
// OutputSection represents a section in an output file. It's a
// container of chunks. OutputSection and Chunk are 1:N relationship.
// Chunks cannot belong to more than one OutputSections. The writer
// creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs.
template <class ELFT> class OutputSection {
public:
  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
  typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;

  OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags)
      : Name(Name) {
    memset(&Header, 0, sizeof(Elf_Shdr));
    Header.sh_type = sh_type;
    Header.sh_flags = sh_flags;
  }
  void setVA(uintX_t);
  void setFileOffset(uintX_t);
  void addSectionChunk(SectionChunk<ELFT> *C);
  std::vector<Chunk *> &getChunks() { return Chunks; }
  void writeHeaderTo(Elf_Shdr *SHdr);
  StringRef getName() { return Name; }
  void setNameOffset(uintX_t Offset) { Header.sh_name = Offset; }

  // Returns the size of the section in the output file.
  uintX_t getSize() { return Header.sh_size; }
  uintX_t getFlags() { return Header.sh_flags; }
  uintX_t getOffset() { return Header.sh_offset; }

private:
  StringRef Name;
  Elf_Shdr Header;
  std::vector<Chunk *> Chunks;
};

// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
  typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
  Writer(SymbolTable *T) : Symtab(T) {}
  void run();

private:
  void createSections();
  void assignAddresses();
  void openFile(StringRef OutputPath);
  void writeHeader();
  void writeSections();

  SymbolTable *Symtab;
  std::unique_ptr<llvm::FileOutputBuffer> Buffer;
  llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
  std::vector<OutputSection<ELFT> *> OutputSections;

  uintX_t FileSize;
  uintX_t SizeOfHeaders;
  uintX_t SectionHeaderOff;
  uintX_t StringTableOff;
  unsigned StringTableIndex;
  StringTableBuilder StrTabBuilder;
  unsigned NumSections;

  std::vector<std::unique_ptr<Chunk>> Chunks;
};
} // anonymous namespace

namespace lld {
namespace elf2 {

template <class ELFT>
void writeResult(SymbolTable *Symtab) { Writer<ELFT>(Symtab).run(); }

template void writeResult<ELF32LE>(SymbolTable *);
template void writeResult<ELF32BE>(SymbolTable *);
template void writeResult<ELF64LE>(SymbolTable *);
template void writeResult<ELF64BE>(SymbolTable *);

} // namespace elf2
} // namespace lld

// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
  createSections();
  assignAddresses();
  openFile(Config->OutputFile);
  writeHeader();
  writeSections();
  error(Buffer->commit());
}

template <class ELFT> void OutputSection<ELFT>::setVA(uintX_t VA) {
  Header.sh_addr = VA;
}

template <class ELFT> void OutputSection<ELFT>::setFileOffset(uintX_t Off) {
  if (Header.sh_size == 0)
    return;
  Header.sh_offset = Off;
}

template <class ELFT>
void OutputSection<ELFT>::addSectionChunk(SectionChunk<ELFT> *C) {
  Chunks.push_back(C);
  uintX_t Off = Header.sh_size;
  Off = RoundUpToAlignment(Off, C->getAlign());
  C->setOutputSectionOff(Off);
  Off += C->getSize();
  Header.sh_size = Off;
}

template <class ELFT> void OutputSection<ELFT>::writeHeaderTo(Elf_Shdr *SHdr) {
  *SHdr = Header;
}

namespace {
template <bool Is64Bits> struct SectionKey {
  typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
  StringRef Name;
  uint32_t sh_type;
  uintX_t sh_flags;
};
}
namespace llvm {
template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
  static SectionKey<Is64Bits> getEmptyKey() {
    return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
  }
  static SectionKey<Is64Bits> getTombstoneKey() {
    return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0,
                                0};
  }
  static unsigned getHashValue(const SectionKey<Is64Bits> &Val) {
    return hash_combine(Val.Name, Val.sh_type, Val.sh_flags);
  }
  static bool isEqual(const SectionKey<Is64Bits> &LHS,
                      const SectionKey<Is64Bits> &RHS) {
    return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
           LHS.sh_type == RHS.sh_type && LHS.sh_flags == RHS.sh_flags;
  }
};
}

// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::createSections() {
  SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSection<ELFT> *> Map;
  for (std::unique_ptr<ObjectFileBase> &FileB : Symtab->ObjectFiles) {
    auto &File = cast<ObjectFile<ELFT>>(*FileB);
    for (SectionChunk<ELFT> *C : File.getChunks()) {
      const Elf_Shdr *H = C->getSectionHdr();
      SectionKey<ELFT::Is64Bits> Key{C->getSectionName(), H->sh_type,
                                     H->sh_flags};
      OutputSection<ELFT> *&Sec = Map[Key];
      if (!Sec) {
        Sec = new (CAlloc.Allocate())
            OutputSection<ELFT>(Key.Name, Key.sh_type, Key.sh_flags);
        OutputSections.push_back(Sec);
      }
      Sec->addSectionChunk(C);
    }
  }
}

template <class ELFT>
static bool compSec(OutputSection<ELFT> *A, OutputSection<ELFT> *B) {
  // Place SHF_ALLOC sections first.
  return (A->getFlags() & SHF_ALLOC) && !(B->getFlags() & SHF_ALLOC);
}

// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
template <class ELFT> void Writer<ELFT>::assignAddresses() {
  SizeOfHeaders = RoundUpToAlignment(sizeof(Elf_Ehdr_Impl<ELFT>), PageSize);
  uintX_t VA = 0x1000; // The first page is kept unmapped.
  uintX_t FileOff = SizeOfHeaders;

  std::stable_sort(OutputSections.begin(), OutputSections.end(), compSec<ELFT>);

  for (OutputSection<ELFT> *Sec : OutputSections) {
    if (Sec->getFlags() & SHF_ALLOC) {
      Sec->setVA(VA);
      VA += RoundUpToAlignment(Sec->getSize(), PageSize);
    }
    Sec->setFileOffset(FileOff);
    FileOff += RoundUpToAlignment(Sec->getSize(), 8);
    StrTabBuilder.add(Sec->getName());
  }

  // Regular sections.
  NumSections = OutputSections.size();

  // First dummy section.
  NumSections++;

  // String table.
  StrTabBuilder.add(".strtab");
  StringTableIndex = NumSections;
  StringTableOff = FileOff;
  StrTabBuilder.finalize(StringTableBuilder::ELF);
  FileOff += StrTabBuilder.data().size();
  NumSections++;

  FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4);

  // Add space for section headers.
  SectionHeaderOff = FileOff;
  FileOff += NumSections * sizeof(Elf_Shdr_Impl<ELFT>);
  FileSize = SizeOfHeaders + RoundUpToAlignment(FileOff - SizeOfHeaders, 8);
}

template <class ELFT> void Writer<ELFT>::writeHeader() {
  uint8_t *Buf = Buffer->getBufferStart();
  auto *EHdr = reinterpret_cast<Elf_Ehdr_Impl<ELFT> *>(Buf);
  EHdr->e_ident[EI_MAG0] = 0x7F;
  EHdr->e_ident[EI_MAG1] = 0x45;
  EHdr->e_ident[EI_MAG2] = 0x4C;
  EHdr->e_ident[EI_MAG3] = 0x46;
  EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
  EHdr->e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little
                               ? ELFDATA2LSB
                               : ELFDATA2MSB;
  EHdr->e_ident[EI_VERSION] = EV_CURRENT;
  EHdr->e_ident[EI_OSABI] = ELFOSABI_NONE;

  EHdr->e_type = ET_EXEC;
  auto &FirstObj = cast<ObjectFile<ELFT>>(*Symtab->ObjectFiles[0]);
  EHdr->e_machine = FirstObj.getObj()->getHeader()->e_machine;
  EHdr->e_version = EV_CURRENT;
  EHdr->e_entry = 0x401000;
  EHdr->e_phoff = sizeof(Elf_Ehdr_Impl<ELFT>);
  EHdr->e_shoff = SectionHeaderOff;
  EHdr->e_ehsize = sizeof(Elf_Ehdr_Impl<ELFT>);
  EHdr->e_phentsize = sizeof(Elf_Phdr_Impl<ELFT>);
  EHdr->e_phnum = 1;
  EHdr->e_shentsize = sizeof(Elf_Shdr_Impl<ELFT>);
  EHdr->e_shnum = NumSections;
  EHdr->e_shstrndx = StringTableIndex;

  auto PHdrs = reinterpret_cast<Elf_Phdr_Impl<ELFT> *>(Buf + EHdr->e_phoff);
  PHdrs->p_type = PT_LOAD;
  PHdrs->p_flags = PF_R | PF_X;
  PHdrs->p_offset = 0x0000;
  PHdrs->p_vaddr = 0x400000;
  PHdrs->p_paddr = PHdrs->p_vaddr;
  PHdrs->p_filesz = FileSize;
  PHdrs->p_memsz = FileSize;
  PHdrs->p_align = 0x4000;

  auto SHdrs = reinterpret_cast<Elf_Shdr_Impl<ELFT> *>(Buf + EHdr->e_shoff);
  // First entry is null.
  ++SHdrs;
  for (OutputSection<ELFT> *Sec : OutputSections) {
    Sec->setNameOffset(StrTabBuilder.getOffset(Sec->getName()));
    Sec->writeHeaderTo(SHdrs++);
  }

  // String table.
  SHdrs->sh_name = StrTabBuilder.getOffset(".strtab");
  SHdrs->sh_type = SHT_STRTAB;
  SHdrs->sh_flags = 0;
  SHdrs->sh_addr = 0;
  SHdrs->sh_offset = StringTableOff;
  SHdrs->sh_size = StrTabBuilder.data().size();
  SHdrs->sh_link = 0;
  SHdrs->sh_info = 0;
  SHdrs->sh_addralign = 1;
  SHdrs->sh_entsize = 0;
}

template <class ELFT> void Writer<ELFT>::openFile(StringRef Path) {
  ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
      FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable);
  error(BufferOrErr, Twine("failed to open ") + Path);
  Buffer = std::move(*BufferOrErr);
}

// Write section contents to a mmap'ed file.
template <class ELFT> void Writer<ELFT>::writeSections() {
  uint8_t *Buf = Buffer->getBufferStart();
  for (OutputSection<ELFT> *Sec : OutputSections) {
    uint8_t *SecBuf = Buf + Sec->getOffset();
    for (Chunk *C : Sec->getChunks())
      C->writeTo(SecBuf);
  }

  // String table.
  StringRef Data = StrTabBuilder.data();
  memcpy(Buf + StringTableOff, Data.data(), Data.size());
}
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2019, The Regents of the University of California
// All rights reserved.
//
// BSD 3-Clause License
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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 <array>
#include <stdio.h>
#include <tcl.h>
#include <stdlib.h>
#include <signal.h>
#include <limits.h>
#include <string>
#include <libgen.h>
// We have had too many problems with this std::filesytem on various platforms
// so it is disabled but kept for future reference
#ifdef USE_STD_FILESYSTEM
#include <filesystem>
#endif
#ifdef ENABLE_READLINE
  // If you get an error on this include be sure you have
  //   the package tcl-tclreadline-devel installed
  #include <tclreadline.h>
#endif
#ifdef ENABLE_PYTHON3
  #define PY_SSIZE_T_CLEAN
  #include "Python.h"
#endif

#ifdef ENABLE_TCLX
  #include <tclExtend.h>
#endif

#include "sta/StringUtil.hh"
#include "sta/StaMain.hh"
#include "ord/Version.hh"
#include "ord/InitOpenRoad.hh"
#include "ord/OpenRoad.hh"
#include "utl/Logger.h"
#include "gui/gui.h"

using std::string;
using sta::stringEq;
using sta::findCmdLineFlag;
using sta::findCmdLineKey;
using sta::sourceTclFile;
using sta::is_regular_file;

#ifdef ENABLE_PYTHON3
extern "C"
{
    extern PyObject* PyInit__openroad_swig_py();
    extern PyObject* PyInit__odbpy();
}
#endif

int cmd_argc;
char **cmd_argv;
const char* log_filename = nullptr;
const char* metrics_filename = nullptr;

static const char *init_filename = ".openroad";

static void
showUsage(const char *prog, const char *init_filename);
static void
showSplash();

#ifdef ENABLE_PYTHON3
namespace sta {
extern const char *odbpy_python_inits[];
extern const char *openroad_swig_py_python_inits[];
}

static void
initPython()
{
  if (PyImport_AppendInittab("_odbpy", PyInit__odbpy) == -1) {
    fprintf(stderr, "Error: could not add module odbpy\n");
    exit(1);
  }

  if (PyImport_AppendInittab("_openroad_swig_py", PyInit__openroad_swig_py) == -1) {
    fprintf(stderr, "Error: could not add module openroadpy\n");
    exit(1);
  }

  Py_Initialize();

  char *unencoded = sta::unencode(sta::odbpy_python_inits);

  PyObject* odb_code = Py_CompileString(unencoded, "odbpy.py", Py_file_input);
  if (odb_code == nullptr) {
    PyErr_Print();
    fprintf(stderr, "Error: could not compile odbpy\n");
    exit(1);
  }

  if (PyImport_ExecCodeModule("odb", odb_code) == nullptr) {
    PyErr_Print();
    fprintf(stderr, "Error: could not add module odb\n");
    exit(1);
  }

  delete [] unencoded;

  unencoded = sta::unencode(sta::openroad_swig_py_python_inits);

  PyObject* ord_code = Py_CompileString(unencoded, "openroad.py", Py_file_input);
  if (ord_code == nullptr) {
    PyErr_Print();
    fprintf(stderr, "Error: could not compile openroad.py\n");
    exit(1);
  }

  if (PyImport_ExecCodeModule("openroad", ord_code) == nullptr) {
    PyErr_Print();
    fprintf(stderr, "Error: could not add module openroad\n");
    exit(1);
  }

  delete [] unencoded;
}
#endif

int
main(int argc,
     char *argv[])
{
  if (argc == 2 && stringEq(argv[1], "-help")) {
    showUsage(argv[0], init_filename);
    return 0;
  }
  if (argc == 2 && stringEq(argv[1], "-version")) {
    printf("%s %s\n", OPENROAD_VERSION, OPENROAD_GIT_DESCRIBE);
    return 0;
  }

  log_filename = findCmdLineKey(argc, argv, "-log");
  if (log_filename) {
    remove(log_filename);
  }

  metrics_filename = findCmdLineKey(argc, argv, "-metrics");
  if (metrics_filename) {
    remove(metrics_filename);
  }

  cmd_argc = argc;
  cmd_argv = argv;
#ifdef ENABLE_PYTHON3
  // Capture the current SIGINT handler before python changes it.
  struct sigaction orig_sigint_handler;
  sigaction(SIGINT, NULL, &orig_sigint_handler);

  initPython();

  if (findCmdLineFlag(cmd_argc, cmd_argv, "-python")) {
    std::vector<wchar_t*> args;
    for(int i = 0; i < cmd_argc; i++) {
      size_t sz = strlen(cmd_argv[i]);
      args.push_back(new wchar_t[sz+1]);
      args[i][sz] = '\0';
      for(size_t j = 0;j < sz; j++) {
        args[i][j] = (wchar_t) cmd_argv[i][j];
      }
    }

    // Setup the app with tcl
    auto* interp = Tcl_CreateInterp();
    Tcl_Init(interp);
    ord::initOpenRoad(interp);
    if (!findCmdLineFlag(cmd_argc, cmd_argv, "-no_splash")) {
      showSplash();
    }

    return Py_Main(cmd_argc, args.data());
  } else {
    // Python wants to install its own SIGINT handler to print KeyboardInterrupt
    // on ctrl-C. We don't want that if python is not the main interpreter.
    // We restore the handler from before initPython.
    sigaction(SIGINT, &orig_sigint_handler, NULL);
  }
#endif

  // Set argc to 1 so Tcl_Main doesn't source any files.
  // Tcl_Main never returns.
  Tcl_Main(1, argv, ord::tclAppInit);
  return 0;
}

#ifdef ENABLE_READLINE
static int
tclReadlineInit(Tcl_Interp *interp)
{
  std::array<const char *, 7> readline_cmds = {
    "history event",
    "eval $auto_index(::tclreadline::ScriptCompleter)",
    "::tclreadline::readline builtincompleter true",
    "::tclreadline::readline customcompleter ::tclreadline::ScriptCompleter",
    "proc ::tclreadline::prompt1 {} { return \"openroad> \" }",
    "proc ::tclreadline::prompt2 {} { return \"...> \" }",
    "::tclreadline::Loop"
  };

  for (auto cmd : readline_cmds) {
    if (TCL_ERROR == Tcl_Eval(interp, cmd)) {
      return TCL_ERROR;
    }
  }
  return TCL_OK;
}
#endif

// Tcl init executed inside Tcl_Main.
static int
tclAppInit(int& argc,
           char *argv[],
           const char *init_filename,
           Tcl_Interp *interp)
{
  // first check if gui was requested and launch.
  // gui will call this function again as part of setup
  // ensuring the else {} will be utilized to initialize tcl and OR.
  if (findCmdLineFlag(argc, argv, "-gui")) {
    gui::startGui(argc, argv, interp);
  } else {
    // init tcl
    if (Tcl_Init(interp) == TCL_ERROR) {
      return TCL_ERROR;
    }
#ifdef ENABLE_TCLX
    if (Tclx_Init(interp) == TCL_ERROR) {
      return TCL_ERROR;
    }
#endif
#ifdef ENABLE_READLINE
    if (Tclreadline_Init(interp) == TCL_ERROR) {
      return TCL_ERROR;
    }
    Tcl_StaticPackage(interp, "tclreadline", Tclreadline_Init, Tclreadline_SafeInit);
    if (Tcl_EvalFile(interp, TCLRL_LIBRARY "/tclreadlineInit.tcl") != TCL_OK) {
      printf("Failed to load tclreadline\n");
    }
#endif

    ord::initOpenRoad(interp);

    if (!findCmdLineFlag(argc, argv, "-no_splash")) {
      showSplash();
    }

    const char* threads = findCmdLineKey(argc, argv, "-threads");
    if (threads) {
      ord::OpenRoad::openRoad()->setThreadCount(threads);
    } else {
      // set to default number of threads
      ord::OpenRoad::openRoad()->setThreadCount(ord::OpenRoad::openRoad()->getThreadCount(), false);
    }

    bool exit_after_cmd_file = findCmdLineFlag(argc, argv, "-exit");

    const bool gui_enabled = gui::Gui::enabled();

    if (!findCmdLineFlag(argc, argv, "-no_init")) {
      const char* restore_state_cmd = "source -echo -verbose {{{}}}";
#ifdef USE_STD_FILESYSTEM
      std::filesystem::path init(getenv("HOME"));
      init /= init_filename;
      if (std::filesystem::is_regular_file(init)) {
        if (!gui_enabled) {
          sourceTclFile(init.c_str(), true, true, interp);
        } else {
          // need to delay loading of file until after GUI is completed initialized
          gui::Gui::get()->addRestoreStateCommand(fmt::format(restore_state_cmd, init.string()));
        }
      }
#else
      string init_path = getenv("HOME");
      init_path += "/";
      init_path += init_filename;
      if (is_regular_file(init_path.c_str())) {
        if (!gui_enabled) {
          sourceTclFile(init_path.c_str(), true, true, interp);
        } else {
          // need to delay loading of file until after GUI is completed initialized
          gui::Gui::get()->addRestoreStateCommand(fmt::format(restore_state_cmd, init_path));
        }
      }
#endif
    }

    if (argc > 2 || (argc > 1 && argv[1][0] == '-')) {
      showUsage(argv[0], init_filename);
    }
    else {
      if (argc == 2) {
        char *cmd_file = argv[1];
        if (cmd_file) {
          if (!gui_enabled) {
            int result = sourceTclFile(cmd_file, false, false, interp);
            if (exit_after_cmd_file) {
              int exit_code = (result == TCL_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
              exit(exit_code);
            }
          } else {
            // need to delay loading of file until after GUI is completed initialized
            const char* restore_state_cmd = "source {{{}}}";
            gui::Gui::get()->addRestoreStateCommand(fmt::format(restore_state_cmd, cmd_file));
            if (exit_after_cmd_file) {
              gui::Gui::get()->addRestoreStateCommand("exit");
            }
          }
        }
      }
    }
  }
#ifdef ENABLE_READLINE
  if (!gui::Gui::enabled()) {
    return tclReadlineInit(interp);
  }
#endif
  return TCL_OK;
}

int
ord::tclAppInit(Tcl_Interp *interp)
{
  return tclAppInit(cmd_argc, cmd_argv, init_filename, interp);
}

static void
showUsage(const char *prog, const char *init_filename)
{
  printf("Usage: %s [-help] [-version] [-no_init] [-exit] [-gui] [-threads count|max] [-log file_name] cmd_file\n", prog);
  printf("  -help              show help and exit\n");
  printf("  -version           show version and exit\n");
  printf("  -no_init           do not read %s init file\n", init_filename);
  printf("  -threads count|max use count threads\n");
  printf("  -no_splash         do not show the license splash at startup\n");
  printf("  -exit              exit after reading cmd_file\n");
  printf("  -gui               start in gui mode\n");
#ifdef ENABLE_PYTHON3
  printf("  -python            start with python interpreter [limited to db operations]\n");
#endif
  printf("  -log <file_name>   write a log in <file_name>\n");
  printf("  cmd_file           source cmd_file\n");
}

static void
showSplash()
{
  utl::Logger *logger = ord::OpenRoad::openRoad()->getLogger();
  string sha = OPENROAD_GIT_DESCRIBE;
  logger->report("OpenROAD {} {}",
                 OPENROAD_VERSION,
                 sha.c_str());
  logger->report("This program is licensed under the BSD-3 license. See the LICENSE file for details.");
  logger->report("Components of this program may be licensed under more restrictive licenses which must be honored.");
}
<commit_msg>Force LC_ALL and LANG to C to avoid problem with localization.<commit_after>/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2019, The Regents of the University of California
// All rights reserved.
//
// BSD 3-Clause License
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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 <array>
#include <stdio.h>
#include <tcl.h>
#include <stdlib.h>
#include <signal.h>
#include <limits.h>
#include <string>
#include <libgen.h>
// We have had too many problems with this std::filesytem on various platforms
// so it is disabled but kept for future reference
#ifdef USE_STD_FILESYSTEM
#include <filesystem>
#endif
#ifdef ENABLE_READLINE
  // If you get an error on this include be sure you have
  //   the package tcl-tclreadline-devel installed
  #include <tclreadline.h>
#endif
#ifdef ENABLE_PYTHON3
  #define PY_SSIZE_T_CLEAN
  #include "Python.h"
#endif

#ifdef ENABLE_TCLX
  #include <tclExtend.h>
#endif

#include "sta/StringUtil.hh"
#include "sta/StaMain.hh"
#include "ord/Version.hh"
#include "ord/InitOpenRoad.hh"
#include "ord/OpenRoad.hh"
#include "utl/Logger.h"
#include "gui/gui.h"

using std::string;
using sta::stringEq;
using sta::findCmdLineFlag;
using sta::findCmdLineKey;
using sta::sourceTclFile;
using sta::is_regular_file;

#ifdef ENABLE_PYTHON3
extern "C"
{
    extern PyObject* PyInit__openroad_swig_py();
    extern PyObject* PyInit__odbpy();
}
#endif

int cmd_argc;
char **cmd_argv;
const char* log_filename = nullptr;
const char* metrics_filename = nullptr;

static const char *init_filename = ".openroad";

static void
showUsage(const char *prog, const char *init_filename);
static void
showSplash();

#ifdef ENABLE_PYTHON3
namespace sta {
extern const char *odbpy_python_inits[];
extern const char *openroad_swig_py_python_inits[];
}

static void
initPython()
{
  if (PyImport_AppendInittab("_odbpy", PyInit__odbpy) == -1) {
    fprintf(stderr, "Error: could not add module odbpy\n");
    exit(1);
  }

  if (PyImport_AppendInittab("_openroad_swig_py", PyInit__openroad_swig_py) == -1) {
    fprintf(stderr, "Error: could not add module openroadpy\n");
    exit(1);
  }

  Py_Initialize();

  char *unencoded = sta::unencode(sta::odbpy_python_inits);

  PyObject* odb_code = Py_CompileString(unencoded, "odbpy.py", Py_file_input);
  if (odb_code == nullptr) {
    PyErr_Print();
    fprintf(stderr, "Error: could not compile odbpy\n");
    exit(1);
  }

  if (PyImport_ExecCodeModule("odb", odb_code) == nullptr) {
    PyErr_Print();
    fprintf(stderr, "Error: could not add module odb\n");
    exit(1);
  }

  delete [] unencoded;

  unencoded = sta::unencode(sta::openroad_swig_py_python_inits);

  PyObject* ord_code = Py_CompileString(unencoded, "openroad.py", Py_file_input);
  if (ord_code == nullptr) {
    PyErr_Print();
    fprintf(stderr, "Error: could not compile openroad.py\n");
    exit(1);
  }

  if (PyImport_ExecCodeModule("openroad", ord_code) == nullptr) {
    PyErr_Print();
    fprintf(stderr, "Error: could not add module openroad\n");
    exit(1);
  }

  delete [] unencoded;
}
#endif

int
main(int argc,
     char *argv[])
{
  // This avoids problems with locale setting dependent
  // C functions like strtod (e.g. 0.5 vs 0,5).
  setenv("LC_ALL", "C", /* override */ 1);
  setenv("LANG", "C", /* override */ 1);

  if (argc == 2 && stringEq(argv[1], "-help")) {
    showUsage(argv[0], init_filename);
    return 0;
  }
  if (argc == 2 && stringEq(argv[1], "-version")) {
    printf("%s %s\n", OPENROAD_VERSION, OPENROAD_GIT_DESCRIBE);
    return 0;
  }

  log_filename = findCmdLineKey(argc, argv, "-log");
  if (log_filename) {
    remove(log_filename);
  }

  metrics_filename = findCmdLineKey(argc, argv, "-metrics");
  if (metrics_filename) {
    remove(metrics_filename);
  }

  cmd_argc = argc;
  cmd_argv = argv;
#ifdef ENABLE_PYTHON3
  // Capture the current SIGINT handler before python changes it.
  struct sigaction orig_sigint_handler;
  sigaction(SIGINT, NULL, &orig_sigint_handler);

  initPython();

  if (findCmdLineFlag(cmd_argc, cmd_argv, "-python")) {
    std::vector<wchar_t*> args;
    for(int i = 0; i < cmd_argc; i++) {
      size_t sz = strlen(cmd_argv[i]);
      args.push_back(new wchar_t[sz+1]);
      args[i][sz] = '\0';
      for(size_t j = 0;j < sz; j++) {
        args[i][j] = (wchar_t) cmd_argv[i][j];
      }
    }

    // Setup the app with tcl
    auto* interp = Tcl_CreateInterp();
    Tcl_Init(interp);
    ord::initOpenRoad(interp);
    if (!findCmdLineFlag(cmd_argc, cmd_argv, "-no_splash")) {
      showSplash();
    }

    return Py_Main(cmd_argc, args.data());
  } else {
    // Python wants to install its own SIGINT handler to print KeyboardInterrupt
    // on ctrl-C. We don't want that if python is not the main interpreter.
    // We restore the handler from before initPython.
    sigaction(SIGINT, &orig_sigint_handler, NULL);
  }
#endif

  // Set argc to 1 so Tcl_Main doesn't source any files.
  // Tcl_Main never returns.
  Tcl_Main(1, argv, ord::tclAppInit);
  return 0;
}

#ifdef ENABLE_READLINE
static int
tclReadlineInit(Tcl_Interp *interp)
{
  std::array<const char *, 7> readline_cmds = {
    "history event",
    "eval $auto_index(::tclreadline::ScriptCompleter)",
    "::tclreadline::readline builtincompleter true",
    "::tclreadline::readline customcompleter ::tclreadline::ScriptCompleter",
    "proc ::tclreadline::prompt1 {} { return \"openroad> \" }",
    "proc ::tclreadline::prompt2 {} { return \"...> \" }",
    "::tclreadline::Loop"
  };

  for (auto cmd : readline_cmds) {
    if (TCL_ERROR == Tcl_Eval(interp, cmd)) {
      return TCL_ERROR;
    }
  }
  return TCL_OK;
}
#endif

// Tcl init executed inside Tcl_Main.
static int
tclAppInit(int& argc,
           char *argv[],
           const char *init_filename,
           Tcl_Interp *interp)
{
  // first check if gui was requested and launch.
  // gui will call this function again as part of setup
  // ensuring the else {} will be utilized to initialize tcl and OR.
  if (findCmdLineFlag(argc, argv, "-gui")) {
    gui::startGui(argc, argv, interp);
  } else {
    // init tcl
    if (Tcl_Init(interp) == TCL_ERROR) {
      return TCL_ERROR;
    }
#ifdef ENABLE_TCLX
    if (Tclx_Init(interp) == TCL_ERROR) {
      return TCL_ERROR;
    }
#endif
#ifdef ENABLE_READLINE
    if (Tclreadline_Init(interp) == TCL_ERROR) {
      return TCL_ERROR;
    }
    Tcl_StaticPackage(interp, "tclreadline", Tclreadline_Init, Tclreadline_SafeInit);
    if (Tcl_EvalFile(interp, TCLRL_LIBRARY "/tclreadlineInit.tcl") != TCL_OK) {
      printf("Failed to load tclreadline\n");
    }
#endif

    ord::initOpenRoad(interp);

    if (!findCmdLineFlag(argc, argv, "-no_splash")) {
      showSplash();
    }

    const char* threads = findCmdLineKey(argc, argv, "-threads");
    if (threads) {
      ord::OpenRoad::openRoad()->setThreadCount(threads);
    } else {
      // set to default number of threads
      ord::OpenRoad::openRoad()->setThreadCount(ord::OpenRoad::openRoad()->getThreadCount(), false);
    }

    bool exit_after_cmd_file = findCmdLineFlag(argc, argv, "-exit");

    const bool gui_enabled = gui::Gui::enabled();

    if (!findCmdLineFlag(argc, argv, "-no_init")) {
      const char* restore_state_cmd = "source -echo -verbose {{{}}}";
#ifdef USE_STD_FILESYSTEM
      std::filesystem::path init(getenv("HOME"));
      init /= init_filename;
      if (std::filesystem::is_regular_file(init)) {
        if (!gui_enabled) {
          sourceTclFile(init.c_str(), true, true, interp);
        } else {
          // need to delay loading of file until after GUI is completed initialized
          gui::Gui::get()->addRestoreStateCommand(fmt::format(restore_state_cmd, init.string()));
        }
      }
#else
      string init_path = getenv("HOME");
      init_path += "/";
      init_path += init_filename;
      if (is_regular_file(init_path.c_str())) {
        if (!gui_enabled) {
          sourceTclFile(init_path.c_str(), true, true, interp);
        } else {
          // need to delay loading of file until after GUI is completed initialized
          gui::Gui::get()->addRestoreStateCommand(fmt::format(restore_state_cmd, init_path));
        }
      }
#endif
    }

    if (argc > 2 || (argc > 1 && argv[1][0] == '-')) {
      showUsage(argv[0], init_filename);
    }
    else {
      if (argc == 2) {
        char *cmd_file = argv[1];
        if (cmd_file) {
          if (!gui_enabled) {
            int result = sourceTclFile(cmd_file, false, false, interp);
            if (exit_after_cmd_file) {
              int exit_code = (result == TCL_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
              exit(exit_code);
            }
          } else {
            // need to delay loading of file until after GUI is completed initialized
            const char* restore_state_cmd = "source {{{}}}";
            gui::Gui::get()->addRestoreStateCommand(fmt::format(restore_state_cmd, cmd_file));
            if (exit_after_cmd_file) {
              gui::Gui::get()->addRestoreStateCommand("exit");
            }
          }
        }
      }
    }
  }
#ifdef ENABLE_READLINE
  if (!gui::Gui::enabled()) {
    return tclReadlineInit(interp);
  }
#endif
  return TCL_OK;
}

int
ord::tclAppInit(Tcl_Interp *interp)
{
  return tclAppInit(cmd_argc, cmd_argv, init_filename, interp);
}

static void
showUsage(const char *prog, const char *init_filename)
{
  printf("Usage: %s [-help] [-version] [-no_init] [-exit] [-gui] [-threads count|max] [-log file_name] cmd_file\n", prog);
  printf("  -help              show help and exit\n");
  printf("  -version           show version and exit\n");
  printf("  -no_init           do not read %s init file\n", init_filename);
  printf("  -threads count|max use count threads\n");
  printf("  -no_splash         do not show the license splash at startup\n");
  printf("  -exit              exit after reading cmd_file\n");
  printf("  -gui               start in gui mode\n");
#ifdef ENABLE_PYTHON3
  printf("  -python            start with python interpreter [limited to db operations]\n");
#endif
  printf("  -log <file_name>   write a log in <file_name>\n");
  printf("  cmd_file           source cmd_file\n");
}

static void
showSplash()
{
  utl::Logger *logger = ord::OpenRoad::openRoad()->getLogger();
  string sha = OPENROAD_GIT_DESCRIBE;
  logger->report("OpenROAD {} {}",
                 OPENROAD_VERSION,
                 sha.c_str());
  logger->report("This program is licensed under the BSD-3 license. See the LICENSE file for details.");
  logger->report("Components of this program may be licensed under more restrictive licenses which must be honored.");
}
<|endoftext|>


<commit_before>//
//###################################################################
//#        EPOS 1.67     K. WERNER, T. PIEROG, S. PORTEBOEUF.       #
//#                      Contact: werner@subatech.in2p3.fr          #
//###################################################################
//
// TEpos.cxx
//
// Wraper class for interfacing EPOS model, derived from ROOT's TGenerator.
// It generates temporary input file for the model, providing user with
// ability to add his/hers own lines to the input.
// Output is read directly from common blocks.
//
//      Author: Piotr Ostrowski, postrow@if.pw.edu.pl
//

#include <TClonesArray.h>
#include <TDatabasePDG.h>
#include <TObjArray.h>
#include <TParticle.h>
#include <TROOT.h>
#include <TRandom.h>
#include <TMath.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "eposproc.h"
#include "EPOScommon.h"
#include "AliGenEposIsajetToPdgConverter.h"
#include "TEpos.h"

using namespace std;

ClassImp(TEpos)

TEpos::TEpos()  : TGenerator("EPOS", "Epos event generator"),
		fLaproj(0),
		fMaproj(0),
		fLatarg(0),
		fMatarg(0),
		fBminim(0.0),
		fBmaxim(10000.0),
		fPhimin(0.0),
		fPhimax(TMath::TwoPi()),
		fEcms(-1),
		fSplitting(kFALSE),
		fNoDecays(),
		fExtraInputLines(),
		fIdConverter()
{
	fIdConverter=new AliGenEposIsajetToPdgConverter();
}

TEpos::TEpos(const TEpos&)  : TGenerator("EPOS", "Epos event generator"),
		fLaproj(0),
		fMaproj(0),
		fLatarg(0),
		fMatarg(0),
		fBminim(0.0),
		fBmaxim(10000.0),
		fPhimin(0.0),
		fPhimax(TMath::TwoPi()),
		fEcms(-1),
		fSplitting(kFALSE),
		fNoDecays(),
		fExtraInputLines(),
		fIdConverter()
{
	fIdConverter = new AliGenEposIsajetToPdgConverter();
}

TEpos::~TEpos() {
	delete fIdConverter;
}

TEpos& TEpos::operator=(const TEpos&) {
  //operator=
	if (!fIdConverter) {
		fIdConverter = new AliGenEposIsajetToPdgConverter();
	}
	return *this;
}

void TEpos::Initialize() {
  // Generates input file and prepares EPOS to read from it.
	Int_t nopeno = 0;
	GenerateInputFile();
	aaset(0);
	atitle();
	xiniall();

	const char *inputFileName = GetInputFileName();
	Int_t nameLength = strlen(inputFileName);
	setinp(inputFileName, nameLength, nameLength);
	aread();
	while(copen.nopen == -1) {
		copen.nopen=nopeno;
	    prnt1.iecho=1;
		xiniall();
	    aread();
	}
	Int_t ishini;
	utpri("aamain",prnt1.ish,ishini,4,6);
	if(appli.model != 1)
		IniModel(appli.model);
	ebin.nrebin = 1;
	ainit();
	aseed(2);
}

void TEpos::GenerateEvent() {
//	cseed.seedj = gRandom->Rndm() * 1e10;
	Int_t n = 1;
	evgen(n);
}

Int_t TEpos::ImportParticles(TClonesArray *particles, Option_t *) {
  //Fills provided ClonesArray with generated particles
	particles->Clear();
	if (!cevt.nevt) return 0;
	Int_t numpart = cptl.nptl;
	printf("%d particles generated\n", numpart);
	for (Int_t iPart=0; iPart<numpart; iPart++) {
		Int_t tFather = cptl.iorptl[iPart] - 1;
		tFather = tFather < -1 ? -1 : tFather;
		if (tFather> -1) {
			TParticle *mother = (TParticle*) (particles->UncheckedAt(tFather));
      			mother->SetLastDaughter(iPart);
      			if (mother->GetFirstDaughter()==-1)
 				mother->SetFirstDaughter(iPart);
    		}
		Int_t status = cptl.istptl[iPart] + 1;
		Int_t pdg = fIdConverter->ConvertIsajetToPdg(cptl.idptl[iPart]);
    		new((*particles)[iPart]) TParticle(pdg, status,
				 tFather, -1, -1, -1,
				 cptl.pptl[iPart][0], cptl.pptl[iPart][1],cptl.pptl[iPart][2],cptl.pptl[iPart][3],
				 cptl.xorptl[iPart][0]*1.e-12, cptl.xorptl[iPart][1]*1.e-12, cptl.xorptl[iPart][2]*1.e-12, cptl.xorptl[iPart][3]*1e-12);
    		(*particles)[iPart]->SetUniqueID(iPart);
  	}

  	return numpart;
}

TObjArray*  TEpos::ImportParticles(Option_t *) {
  //Creates new particle array
	fParticles->Clear();
	if (!cevt.nevt) return NULL;
	Int_t numpart = cptl.nptl;
	printf("%d particles generated\n", numpart);
	for (Int_t iPart=0; iPart<numpart; iPart++) {
		Int_t tFather = cptl.iorptl[iPart] - 1;
		tFather = tFather < -1 ? -1 : tFather;
		if (tFather> -1) {
			TParticle *mother = (TParticle*) (fParticles->UncheckedAt(tFather));
      			mother->SetLastDaughter(iPart);
      			if (mother->GetFirstDaughter()==-1)
 				mother->SetFirstDaughter(iPart);
    		}
		Int_t status = cptl.istptl[iPart] + 1;
		Int_t pdg = fIdConverter->ConvertIsajetToPdg(cptl.idptl[iPart]);
    		TParticle* p = new TParticle(pdg, status,
				 tFather, -1, -1, -1,
				 cptl.pptl[iPart][0], cptl.pptl[iPart][1],cptl.pptl[iPart][2],cptl.pptl[iPart][3],
				 cptl.xorptl[iPart][0]*1.e-12, cptl.xorptl[iPart][1]*1.e-12, cptl.xorptl[iPart][2]*1.e-12, cptl.xorptl[iPart][3]*1e-12);
    		p->SetUniqueID(iPart);
    		fParticles->Add(p);
  	}

  	return fParticles;
}

void TEpos::AddNoDecay(Int_t nodecay) {
	fNoDecays.push_back(nodecay);
}

void TEpos::AddExtraInputLine(const char *line) {
	fExtraInputLines.push_back(line);
}

void TEpos::GenerateInputFile() {
  // Generate input file in EPOS format
	ofstream file(GetInputFileName(), ios_base::out | ios_base::trunc);
	char epo[256];
	char *epoEnv = getenv("EPO");
	if (epoEnv) {
		strncpy(epo, epoEnv, 255);
	} else {
		strncpy(epo, getenv("ALICE_ROOT"), 255);
	}
	strncat(epo, "/EPOS/epos167", 256);

	file << "fname pathnx " << epo << "/" << endl;
	file << "fname histo none" << endl;
	file << "fname copy none" << endl;
	file << "fname log none" << endl;
	file << "fname check none" << endl;
//	file << "fname data /tmp/epos.out" << endl;
	file << "fname initl " << epo << "/epos.initl" << endl;
	file << "fname inidi " << epo << "/epos.inidi" << endl;
	file << "fname inidr " << epo << "/epos.inidr" << endl;
	file << "fname iniev " << epo << "/epos.iniev" << endl;
	file << "fname inirj " << epo << "/epos.inirj" << endl;
	file << "fname inics " << epo << "/epos.inics" << endl;
	file << "fname inigrv " << epo << "/epos.inigrv" << endl;
	file << "fqgsjet dat " << epo << "/qgsjet/qgsjet.dat" << endl;
	file << "fqgsjet ncs " << epo << "/qgsjet/qgsjet.ncs" << endl;
	file << "fqgsjetII dat " << epo << "/qgsjetII/qgsdat-II-03" << endl;
	file << "fqgsjetII ncs " << epo << "/qgsjetII/sectnu-II-03" << endl;
	file << "nodecay 120" << endl;
	file << "nodecay -120" << endl;
	file << "nodecay 130" << endl;
	file << "nodecay -130" << endl;
	file << "nodecay -20" << endl;
	file << "nodecay 20" << endl;
	file << "nodecay 14" << endl;
	file << "nodecay -14" << endl;
	file << "set ndecay 1111110" << endl;
	file << "echo on" << endl;

//	.optns file
	int precision = file.precision();
	file.precision(15);
	file << "set seedj " << (gRandom->Rndm() * 1e14) << endl;
	file.precision(precision);
	file << "application hadron" << endl;
	file << "set laproj " << fLaproj << endl;
	file << "set maproj " << fMaproj << endl;
	file << "set latarg " << fLatarg << endl;
	file << "set matarg " << fMatarg << endl;
	file << "set bminim " << fBminim << endl;
	file << "set bmaxim " << fBmaxim << endl;
	file << "set phimin " << fPhimin << endl;
	file << "set phimax " << fPhimax << endl;
	file << "set ecms " << fEcms << endl;

	for(unsigned int i = 0; i < fNoDecays.size(); ++i) {
		file << "nodecay " << fNoDecays[i] << endl;
	}

	file << "switch splitting " << (fSplitting ? "on" : "off") << endl;

	file << "frame nucleon-nucleon" << endl;

	for(unsigned int i = 0; i < fExtraInputLines.size(); ++i) {
		file << fExtraInputLines[i] << endl;
	}

//    file << "output epos" << endl;
//    file << "record event nevt nptl b endrecord" << endl;
//    file << "record particle i id fa mo c1 c2 st endrecord" << endl;

	file << "input " << epo << "/epos.param" << endl;
	file << "runprogram" << endl;
	file.close();
}

Float_t TEpos::GetBimevt() const { return cevt.bimevt; }
Float_t TEpos::GetPhievt() const { return cevt.phievt; }
Int_t TEpos::GetKolevt() const { return cevt.kolevt; }
Int_t TEpos::GetKoievt() const { return cevt.koievt; }
Float_t TEpos::GetPmxevt() const { return cevt.pmxevt; }
Float_t TEpos::GetEgyevt() const { return cevt.egyevt; }
Int_t TEpos::GetNpjevt() const { return cevt.npjevt; }
Int_t TEpos::GetNtgevt() const { return cevt.ntgevt; }
Int_t TEpos::GetNpnevt() const { return cevt.npnevt; }
Int_t TEpos::GetNppevt() const { return cevt.nppevt; }
Int_t TEpos::GetNtnevt() const { return cevt.ntnevt; }
Int_t TEpos::GetNtpevt() const { return cevt.ntpevt; }
Int_t TEpos::GetJpnevt() const { return cevt.jpnevt; }
Int_t TEpos::GetJppevt() const { return cevt.jppevt; }
Int_t TEpos::GetJtnevt() const { return cevt.jtnevt; }
Int_t TEpos::GetJtpevt() const { return cevt.jtpevt; }
Float_t TEpos::GetXbjevt() const { return cevt.xbjevt; }
Float_t TEpos::GetQsqevt() const { return cevt.qsqevt; }
Int_t TEpos::GetNglevt() const { return cevt.nglevt; }
Float_t TEpos::GetZppevt() const { return cevt.zppevt; }
Float_t TEpos::GetZptevt() const { return cevt.zptevt; }

<commit_msg>Coverity 16763 Out-of-bounds access corrected.<commit_after>//
//###################################################################
//#        EPOS 1.67     K. WERNER, T. PIEROG, S. PORTEBOEUF.       #
//#                      Contact: werner@subatech.in2p3.fr          #
//###################################################################
//
// TEpos.cxx
//
// Wraper class for interfacing EPOS model, derived from ROOT's TGenerator.
// It generates temporary input file for the model, providing user with
// ability to add his/hers own lines to the input.
// Output is read directly from common blocks.
//
//      Author: Piotr Ostrowski, postrow@if.pw.edu.pl
//

#include <TClonesArray.h>
#include <TDatabasePDG.h>
#include <TObjArray.h>
#include <TParticle.h>
#include <TROOT.h>
#include <TRandom.h>
#include <TMath.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "eposproc.h"
#include "EPOScommon.h"
#include "AliGenEposIsajetToPdgConverter.h"
#include "TEpos.h"

using namespace std;

ClassImp(TEpos)

TEpos::TEpos()  : TGenerator("EPOS", "Epos event generator"),
		fLaproj(0),
		fMaproj(0),
		fLatarg(0),
		fMatarg(0),
		fBminim(0.0),
		fBmaxim(10000.0),
		fPhimin(0.0),
		fPhimax(TMath::TwoPi()),
		fEcms(-1),
		fSplitting(kFALSE),
		fNoDecays(),
		fExtraInputLines(),
		fIdConverter()
{
	fIdConverter=new AliGenEposIsajetToPdgConverter();
}

TEpos::TEpos(const TEpos&)  : TGenerator("EPOS", "Epos event generator"),
		fLaproj(0),
		fMaproj(0),
		fLatarg(0),
		fMatarg(0),
		fBminim(0.0),
		fBmaxim(10000.0),
		fPhimin(0.0),
		fPhimax(TMath::TwoPi()),
		fEcms(-1),
		fSplitting(kFALSE),
		fNoDecays(),
		fExtraInputLines(),
		fIdConverter()
{
	fIdConverter = new AliGenEposIsajetToPdgConverter();
}

TEpos::~TEpos() {
	delete fIdConverter;
}

TEpos& TEpos::operator=(const TEpos&) {
  //operator=
	if (!fIdConverter) {
		fIdConverter = new AliGenEposIsajetToPdgConverter();
	}
	return *this;
}

void TEpos::Initialize() {
  // Generates input file and prepares EPOS to read from it.
	Int_t nopeno = 0;
	GenerateInputFile();
	aaset(0);
	atitle();
	xiniall();

	const char *inputFileName = GetInputFileName();
	Int_t nameLength = strlen(inputFileName);
	setinp(inputFileName, nameLength, nameLength);
	aread();
	while(copen.nopen == -1) {
		copen.nopen=nopeno;
	    prnt1.iecho=1;
		xiniall();
	    aread();
	}
	Int_t ishini;
	utpri("aamain",prnt1.ish,ishini,4,6);
	if(appli.model != 1)
		IniModel(appli.model);
	ebin.nrebin = 1;
	ainit();
	aseed(2);
}

void TEpos::GenerateEvent() {
//	cseed.seedj = gRandom->Rndm() * 1e10;
	Int_t n = 1;
	evgen(n);
}

Int_t TEpos::ImportParticles(TClonesArray *particles, Option_t *) {
  //Fills provided ClonesArray with generated particles
	particles->Clear();
	if (!cevt.nevt) return 0;
	Int_t numpart = cptl.nptl;
	printf("%d particles generated\n", numpart);
	for (Int_t iPart=0; iPart<numpart; iPart++) {
		Int_t tFather = cptl.iorptl[iPart] - 1;
		tFather = tFather < -1 ? -1 : tFather;
		if (tFather> -1) {
			TParticle *mother = (TParticle*) (particles->UncheckedAt(tFather));
      			mother->SetLastDaughter(iPart);
      			if (mother->GetFirstDaughter()==-1)
 				mother->SetFirstDaughter(iPart);
    		}
		Int_t status = cptl.istptl[iPart] + 1;
		Int_t pdg = fIdConverter->ConvertIsajetToPdg(cptl.idptl[iPart]);
    		new((*particles)[iPart]) TParticle(pdg, status,
				 tFather, -1, -1, -1,
				 cptl.pptl[iPart][0], cptl.pptl[iPart][1],cptl.pptl[iPart][2],cptl.pptl[iPart][3],
				 cptl.xorptl[iPart][0]*1.e-12, cptl.xorptl[iPart][1]*1.e-12, cptl.xorptl[iPart][2]*1.e-12, cptl.xorptl[iPart][3]*1e-12);
    		(*particles)[iPart]->SetUniqueID(iPart);
  	}

  	return numpart;
}

TObjArray*  TEpos::ImportParticles(Option_t *) {
  //Creates new particle array
	fParticles->Clear();
	if (!cevt.nevt) return NULL;
	Int_t numpart = cptl.nptl;
	printf("%d particles generated\n", numpart);
	for (Int_t iPart=0; iPart<numpart; iPart++) {
		Int_t tFather = cptl.iorptl[iPart] - 1;
		tFather = tFather < -1 ? -1 : tFather;
		if (tFather> -1) {
			TParticle *mother = (TParticle*) (fParticles->UncheckedAt(tFather));
      			mother->SetLastDaughter(iPart);
      			if (mother->GetFirstDaughter()==-1)
 				mother->SetFirstDaughter(iPart);
    		}
		Int_t status = cptl.istptl[iPart] + 1;
		Int_t pdg = fIdConverter->ConvertIsajetToPdg(cptl.idptl[iPart]);
    		TParticle* p = new TParticle(pdg, status,
				 tFather, -1, -1, -1,
				 cptl.pptl[iPart][0], cptl.pptl[iPart][1],cptl.pptl[iPart][2],cptl.pptl[iPart][3],
				 cptl.xorptl[iPart][0]*1.e-12, cptl.xorptl[iPart][1]*1.e-12, cptl.xorptl[iPart][2]*1.e-12, cptl.xorptl[iPart][3]*1e-12);
    		p->SetUniqueID(iPart);
    		fParticles->Add(p);
  	}

  	return fParticles;
}

void TEpos::AddNoDecay(Int_t nodecay) {
	fNoDecays.push_back(nodecay);
}

void TEpos::AddExtraInputLine(const char *line) {
	fExtraInputLines.push_back(line);
}

void TEpos::GenerateInputFile() {
  // Generate input file in EPOS format
	ofstream file(GetInputFileName(), ios_base::out | ios_base::trunc);
	char epo[256];
	char *epoEnv = getenv("EPO");
	if (epoEnv) {
		strncpy(epo, epoEnv, 255);
	} else {
		strncpy(epo, getenv("ALICE_ROOT"), 255);
	}
	strncat(epo, "/EPOS/epos167", 255);

	file << "fname pathnx " << epo << "/" << endl;
	file << "fname histo none" << endl;
	file << "fname copy none" << endl;
	file << "fname log none" << endl;
	file << "fname check none" << endl;
//	file << "fname data /tmp/epos.out" << endl;
	file << "fname initl " << epo << "/epos.initl" << endl;
	file << "fname inidi " << epo << "/epos.inidi" << endl;
	file << "fname inidr " << epo << "/epos.inidr" << endl;
	file << "fname iniev " << epo << "/epos.iniev" << endl;
	file << "fname inirj " << epo << "/epos.inirj" << endl;
	file << "fname inics " << epo << "/epos.inics" << endl;
	file << "fname inigrv " << epo << "/epos.inigrv" << endl;
	file << "fqgsjet dat " << epo << "/qgsjet/qgsjet.dat" << endl;
	file << "fqgsjet ncs " << epo << "/qgsjet/qgsjet.ncs" << endl;
	file << "fqgsjetII dat " << epo << "/qgsjetII/qgsdat-II-03" << endl;
	file << "fqgsjetII ncs " << epo << "/qgsjetII/sectnu-II-03" << endl;
	file << "nodecay 120" << endl;
	file << "nodecay -120" << endl;
	file << "nodecay 130" << endl;
	file << "nodecay -130" << endl;
	file << "nodecay -20" << endl;
	file << "nodecay 20" << endl;
	file << "nodecay 14" << endl;
	file << "nodecay -14" << endl;
	file << "set ndecay 1111110" << endl;
	file << "echo on" << endl;

//	.optns file
	int precision = file.precision();
	file.precision(15);
	file << "set seedj " << (gRandom->Rndm() * 1e14) << endl;
	file.precision(precision);
	file << "application hadron" << endl;
	file << "set laproj " << fLaproj << endl;
	file << "set maproj " << fMaproj << endl;
	file << "set latarg " << fLatarg << endl;
	file << "set matarg " << fMatarg << endl;
	file << "set bminim " << fBminim << endl;
	file << "set bmaxim " << fBmaxim << endl;
	file << "set phimin " << fPhimin << endl;
	file << "set phimax " << fPhimax << endl;
	file << "set ecms " << fEcms << endl;

	for(unsigned int i = 0; i < fNoDecays.size(); ++i) {
		file << "nodecay " << fNoDecays[i] << endl;
	}

	file << "switch splitting " << (fSplitting ? "on" : "off") << endl;

	file << "frame nucleon-nucleon" << endl;

	for(unsigned int i = 0; i < fExtraInputLines.size(); ++i) {
		file << fExtraInputLines[i] << endl;
	}

//    file << "output epos" << endl;
//    file << "record event nevt nptl b endrecord" << endl;
//    file << "record particle i id fa mo c1 c2 st endrecord" << endl;

	file << "input " << epo << "/epos.param" << endl;
	file << "runprogram" << endl;
	file.close();
}

Float_t TEpos::GetBimevt() const { return cevt.bimevt; }
Float_t TEpos::GetPhievt() const { return cevt.phievt; }
Int_t TEpos::GetKolevt() const { return cevt.kolevt; }
Int_t TEpos::GetKoievt() const { return cevt.koievt; }
Float_t TEpos::GetPmxevt() const { return cevt.pmxevt; }
Float_t TEpos::GetEgyevt() const { return cevt.egyevt; }
Int_t TEpos::GetNpjevt() const { return cevt.npjevt; }
Int_t TEpos::GetNtgevt() const { return cevt.ntgevt; }
Int_t TEpos::GetNpnevt() const { return cevt.npnevt; }
Int_t TEpos::GetNppevt() const { return cevt.nppevt; }
Int_t TEpos::GetNtnevt() const { return cevt.ntnevt; }
Int_t TEpos::GetNtpevt() const { return cevt.ntpevt; }
Int_t TEpos::GetJpnevt() const { return cevt.jpnevt; }
Int_t TEpos::GetJppevt() const { return cevt.jppevt; }
Int_t TEpos::GetJtnevt() const { return cevt.jtnevt; }
Int_t TEpos::GetJtpevt() const { return cevt.jtpevt; }
Float_t TEpos::GetXbjevt() const { return cevt.xbjevt; }
Float_t TEpos::GetQsqevt() const { return cevt.qsqevt; }
Int_t TEpos::GetNglevt() const { return cevt.nglevt; }
Float_t TEpos::GetZppevt() const { return cevt.zppevt; }
Float_t TEpos::GetZptevt() const { return cevt.zptevt; }

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: Currency.hxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: obo $ $Date: 2007-03-09 13:22:37 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _FORMS_CURRENCY_HXX_
#define _FORMS_CURRENCY_HXX_

#ifndef _FORMS_EDITBASE_HXX_
#include "EditBase.hxx"
#endif

//.........................................................................
namespace frm
{
//.........................................................................

//==================================================================
//= OCurrencyModel
//==================================================================
class OCurrencyModel
                :public OEditBaseModel
{
    ::com::sun::star::uno::Any          m_aSaveValue;

protected:
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> _getTypes();

public:
    DECLARE_DEFAULT_LEAF_XTOR( OCurrencyModel );

    // ::com::sun::star::lang::XServiceInfo
    IMPLEMENTATION_NAME(OCurrencyModel);
    virtual StringSequence SAL_CALL getSupportedServiceNames() throw();

    // ::com::sun::star::io::XPersistObject
    virtual ::rtl::OUString SAL_CALL getServiceName() throw ( ::com::sun ::star::uno::RuntimeException);

    // OControlModel's property handling
    virtual void describeFixedProperties(
        ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rProps
    ) const;

protected:
    // OBoundControlModel overridables
    virtual ::com::sun::star::uno::Any
                            translateDbColumnToControlValue( );
    virtual sal_Bool        commitControlValueToDbColumn( bool _bPostReset );

    virtual ::com::sun::star::uno::Any
                            getDefaultForReset() const;

protected:
    DECLARE_XCLONEABLE();

    void implConstruct();
};

//==================================================================
//= OCurrencyControl
//==================================================================
class OCurrencyControl: public OBoundControl
{
protected:
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> _getTypes();

public:
    OCurrencyControl(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory>& _rxFactory);
    // ::com::sun::star::lang::XServiceInfo
    IMPLEMENTATION_NAME(OCurrencyControl);
    virtual StringSequence SAL_CALL getSupportedServiceNames() throw();
};

//.........................................................................
}   // namespace frm
//.........................................................................

#endif // _FORMS_CURRENCY_HXX_

<commit_msg>INTEGRATION: CWS changefileheader (1.8.82); FILE MERGED 2008/04/01 12:30:20 thb 1.8.82.2: #i85898# Stripping all external header guards 2008/03/31 13:11:32 rt 1.8.82.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: Currency.hxx,v $
 * $Revision: 1.9 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _FORMS_CURRENCY_HXX_
#define _FORMS_CURRENCY_HXX_

#include "EditBase.hxx"

//.........................................................................
namespace frm
{
//.........................................................................

//==================================================================
//= OCurrencyModel
//==================================================================
class OCurrencyModel
                :public OEditBaseModel
{
    ::com::sun::star::uno::Any          m_aSaveValue;

protected:
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> _getTypes();

public:
    DECLARE_DEFAULT_LEAF_XTOR( OCurrencyModel );

    // ::com::sun::star::lang::XServiceInfo
    IMPLEMENTATION_NAME(OCurrencyModel);
    virtual StringSequence SAL_CALL getSupportedServiceNames() throw();

    // ::com::sun::star::io::XPersistObject
    virtual ::rtl::OUString SAL_CALL getServiceName() throw ( ::com::sun ::star::uno::RuntimeException);

    // OControlModel's property handling
    virtual void describeFixedProperties(
        ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property >& /* [out] */ _rProps
    ) const;

protected:
    // OBoundControlModel overridables
    virtual ::com::sun::star::uno::Any
                            translateDbColumnToControlValue( );
    virtual sal_Bool        commitControlValueToDbColumn( bool _bPostReset );

    virtual ::com::sun::star::uno::Any
                            getDefaultForReset() const;

protected:
    DECLARE_XCLONEABLE();

    void implConstruct();
};

//==================================================================
//= OCurrencyControl
//==================================================================
class OCurrencyControl: public OBoundControl
{
protected:
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type> _getTypes();

public:
    OCurrencyControl(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory>& _rxFactory);
    // ::com::sun::star::lang::XServiceInfo
    IMPLEMENTATION_NAME(OCurrencyControl);
    virtual StringSequence SAL_CALL getSupportedServiceNames() throw();
};

//.........................................................................
}   // namespace frm
//.........................................................................

#endif // _FORMS_CURRENCY_HXX_

<|endoftext|>


<commit_before>#ifndef _DERANDOM_HPP
#define _DERANDOM_HPP
/*-------------------------------------------------------------------------
 * drawElements C++ Base Library
 * -----------------------------
 *
 * Copyright 2014 The Android Open Source Project
 *
 * 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.
 *
 *//*!
 * \file
 * \brief Random number generator utilities.
 *//*--------------------------------------------------------------------*/

#include "deDefs.hpp"
#include "deRandom.h"

#include <iterator>		// std::distance()
#include <algorithm>	// std::swap()

namespace de
{

//! Random self-test - compare returned values against hard-coded values.
void Random_selfTest (void);

class Random
{
public:
					Random				(deUint32 seed)	{ deRandom_init(&m_rnd, seed);					}
					~Random				(void)			{}

	float			getFloat			(void)			{ return deRandom_getFloat(&m_rnd);				}
	double			getDouble			(void)			{ return deRandom_getDouble(&m_rnd);			}
	bool			getBool				(void)			{ return deRandom_getBool(&m_rnd) == DE_TRUE;	}

	float			getFloat			(float min, float max);
	double			getDouble			(double min, double max);
	int				getInt				(int min, int max);

	deInt64			getInt64			(void)			{ deUint32 upper = getUint32(); return static_cast<deInt64>((deUint64)upper << 32ull | (deUint64)getUint32() ); }
	deUint64		getUint64			(void)			{ deUint32 upper = getUint32(); return (deUint64)upper << 32ull | (deUint64)getUint32(); }
	deInt32			getInt32			(void)			{ return static_cast<deInt32>(getUint32());		}
	deUint32		getUint32			(void)			{ return deRandom_getUint32(&m_rnd);			}
	deUint16		getUint16			(void)			{ return (deUint16)deRandom_getUint32(&m_rnd);	}
	deUint8			getUint8			(void)			{ return (deUint8)deRandom_getUint32(&m_rnd);	}

	template <class InputIter, class OutputIter>
	void			choose				(InputIter first, InputIter last, OutputIter result, int numItems);

	template <typename T, class InputIter>
	T				choose				(InputIter first, InputIter last);

	// \note Weights must be floats
	template <typename T, class InputIter, class WeightIter>
	T				chooseWeighted		(InputIter first, InputIter last, WeightIter weight);

	template <class Iterator>
	void			shuffle				(Iterator first, Iterator last);

	bool			operator==			(const Random& other) const;
	bool			operator!=			(const Random& other) const;

private:
	deRandom		m_rnd;
} DE_WARN_UNUSED_TYPE;

// Inline implementations

inline float Random::getFloat (float min, float max)
{
	DE_ASSERT(min <= max);
	return min + (max-min)*getFloat();
}

inline double Random::getDouble (double min, double max)
{
	DE_ASSERT(min <= max);
	return min + (max-min)*getDouble();
}

inline int Random::getInt (int min, int max)
{
	DE_ASSERT(min <= max);
	if (min == (int)0x80000000 && max == (int)0x7fffffff)
		return (int)getUint32();
	else
		return min + (int)(getUint32() % (deUint32)(max-min+1));
}

// Template implementations

template <class InputIter, class OutputIter>
void Random::choose (InputIter first, InputIter last, OutputIter result, int numItems)
{
	// Algorithm: Reservoir sampling
	// http://en.wikipedia.org/wiki/Reservoir_sampling
	// \note Will not work for suffling an array. Use suffle() instead.

	int ndx;
	for (ndx = 0; first != last; ++first, ++ndx)
	{
		if (ndx < numItems)
			*(result + ndx) = *first;
		else
		{
			int r = getInt(0, ndx);
			if (r < numItems)
				*(result + r) = *first;
		}
	}

	DE_ASSERT(ndx >= numItems);
}

template <typename T, class InputIter>
T Random::choose (InputIter first, InputIter last)
{
	T val = T();
	DE_ASSERT(first != last);
	choose(first, last, &val, 1);
	return val;
}

template <typename T, class InputIter, class WeightIter>
T Random::chooseWeighted (InputIter first, InputIter last, WeightIter weight)
{
	// Compute weight sum
	float	weightSum	= 0.0f;
	int		ndx;
	for (ndx = 0; (first + ndx) != last; ndx++)
		weightSum += *(weight + ndx);

	// Random point in 0..weightSum
	float p = getFloat(0.0f, weightSum);

	// Find item in range
	InputIter	lastNonZero	= last;
	float		curWeight	= 0.0f;
	for (ndx = 0; (first + ndx) != last; ndx++)
	{
		float w = *(weight + ndx);

		curWeight += w;

		if (p < curWeight)
			return *(first + ndx);
		else if (w > 0.0f)
			lastNonZero = first + ndx;
	}

	DE_ASSERT(lastNonZero != last);
	return *lastNonZero;
}

template <class Iterator>
void Random::shuffle (Iterator first, Iterator last)
{
	using std::swap;

	// Fisher-Yates suffle
	int numItems = (int)std::distance(first, last);

	for (int i = numItems-1; i >= 1; i--)
	{
		int j = getInt(0, i);
		swap(*(first + i), *(first + j));
	}
}

template<typename T>	T			randomScalar	(de::Random& rnd, T minValue, T maxValue);
template<> inline		float		randomScalar	(de::Random& rnd, float minValue, float maxValue)		{ return rnd.getFloat(minValue, maxValue); }
template<> inline		deInt32		randomScalar	(de::Random& rnd, deInt32 minValue, deInt32 maxValue)	{ return rnd.getInt(minValue, maxValue); }
template<> inline		deUint32	randomScalar	(de::Random& rnd, deUint32 minValue, deUint32 maxValue)	{ if (minValue == 0 && maxValue == 0xffffffff) return rnd.getUint32();
																											  return minValue + rnd.getUint32() % (maxValue - minValue + 1); }
template<> inline		deInt16		randomScalar	(de::Random& rnd, deInt16 minValue, deInt16 maxValue)	{ return (deInt16)rnd.getInt(minValue, maxValue); }
template<> inline		deUint16	randomScalar	(de::Random& rnd, deUint16 minValue, deUint16 maxValue)	{ return (deUint16)(minValue + rnd.getUint16() % (maxValue - minValue + 1)); }
template<> inline		deInt8		randomScalar	(de::Random& rnd, deInt8 minValue, deInt8 maxValue)		{ return (deInt8)rnd.getInt(minValue, maxValue); }
template<> inline		deUint8		randomScalar	(de::Random& rnd, deUint8 minValue, deUint8 maxValue)	{ return (deUint8)(minValue + rnd.getUint8() % (maxValue - minValue + 1)); }

} // de

#endif // _DERANDOM_HPP
<commit_msg>Fix integer overflow in Random::getInt()<commit_after>#ifndef _DERANDOM_HPP
#define _DERANDOM_HPP
/*-------------------------------------------------------------------------
 * drawElements C++ Base Library
 * -----------------------------
 *
 * Copyright 2014 The Android Open Source Project
 *
 * 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.
 *
 *//*!
 * \file
 * \brief Random number generator utilities.
 *//*--------------------------------------------------------------------*/

#include "deDefs.hpp"
#include "deRandom.h"

#include <iterator>		// std::distance()
#include <algorithm>	// std::swap()

namespace de
{

//! Random self-test - compare returned values against hard-coded values.
void Random_selfTest (void);

class Random
{
public:
					Random				(deUint32 seed)	{ deRandom_init(&m_rnd, seed);					}
					~Random				(void)			{}

	float			getFloat			(void)			{ return deRandom_getFloat(&m_rnd);				}
	double			getDouble			(void)			{ return deRandom_getDouble(&m_rnd);			}
	bool			getBool				(void)			{ return deRandom_getBool(&m_rnd) == DE_TRUE;	}

	float			getFloat			(float min, float max);
	double			getDouble			(double min, double max);
	int				getInt				(int min, int max);

	deInt64			getInt64			(void)			{ deUint32 upper = getUint32(); return static_cast<deInt64>((deUint64)upper << 32ull | (deUint64)getUint32() ); }
	deUint64		getUint64			(void)			{ deUint32 upper = getUint32(); return (deUint64)upper << 32ull | (deUint64)getUint32(); }
	deInt32			getInt32			(void)			{ return static_cast<deInt32>(getUint32());		}
	deUint32		getUint32			(void)			{ return deRandom_getUint32(&m_rnd);			}
	deUint16		getUint16			(void)			{ return (deUint16)deRandom_getUint32(&m_rnd);	}
	deUint8			getUint8			(void)			{ return (deUint8)deRandom_getUint32(&m_rnd);	}

	template <class InputIter, class OutputIter>
	void			choose				(InputIter first, InputIter last, OutputIter result, int numItems);

	template <typename T, class InputIter>
	T				choose				(InputIter first, InputIter last);

	// \note Weights must be floats
	template <typename T, class InputIter, class WeightIter>
	T				chooseWeighted		(InputIter first, InputIter last, WeightIter weight);

	template <class Iterator>
	void			shuffle				(Iterator first, Iterator last);

	bool			operator==			(const Random& other) const;
	bool			operator!=			(const Random& other) const;

private:
	deRandom		m_rnd;
} DE_WARN_UNUSED_TYPE;

// Inline implementations

inline float Random::getFloat (float min, float max)
{
	DE_ASSERT(min <= max);
	return min + (max-min)*getFloat();
}

inline double Random::getDouble (double min, double max)
{
	DE_ASSERT(min <= max);
	return min + (max-min)*getDouble();
}

inline int Random::getInt (int min, int max)
{
	DE_ASSERT(min <= max);
	if (min == (int)0x80000000 && max == (int)0x7fffffff)
		return (int)getUint32();
	else
		return min + (int)(getUint32() % ((deUint32)max - (deUint32)min + 1u));
}

// Template implementations

template <class InputIter, class OutputIter>
void Random::choose (InputIter first, InputIter last, OutputIter result, int numItems)
{
	// Algorithm: Reservoir sampling
	// http://en.wikipedia.org/wiki/Reservoir_sampling
	// \note Will not work for suffling an array. Use suffle() instead.

	int ndx;
	for (ndx = 0; first != last; ++first, ++ndx)
	{
		if (ndx < numItems)
			*(result + ndx) = *first;
		else
		{
			int r = getInt(0, ndx);
			if (r < numItems)
				*(result + r) = *first;
		}
	}

	DE_ASSERT(ndx >= numItems);
}

template <typename T, class InputIter>
T Random::choose (InputIter first, InputIter last)
{
	T val = T();
	DE_ASSERT(first != last);
	choose(first, last, &val, 1);
	return val;
}

template <typename T, class InputIter, class WeightIter>
T Random::chooseWeighted (InputIter first, InputIter last, WeightIter weight)
{
	// Compute weight sum
	float	weightSum	= 0.0f;
	int		ndx;
	for (ndx = 0; (first + ndx) != last; ndx++)
		weightSum += *(weight + ndx);

	// Random point in 0..weightSum
	float p = getFloat(0.0f, weightSum);

	// Find item in range
	InputIter	lastNonZero	= last;
	float		curWeight	= 0.0f;
	for (ndx = 0; (first + ndx) != last; ndx++)
	{
		float w = *(weight + ndx);

		curWeight += w;

		if (p < curWeight)
			return *(first + ndx);
		else if (w > 0.0f)
			lastNonZero = first + ndx;
	}

	DE_ASSERT(lastNonZero != last);
	return *lastNonZero;
}

template <class Iterator>
void Random::shuffle (Iterator first, Iterator last)
{
	using std::swap;

	// Fisher-Yates suffle
	int numItems = (int)std::distance(first, last);

	for (int i = numItems-1; i >= 1; i--)
	{
		int j = getInt(0, i);
		swap(*(first + i), *(first + j));
	}
}

template<typename T>	T			randomScalar	(de::Random& rnd, T minValue, T maxValue);
template<> inline		float		randomScalar	(de::Random& rnd, float minValue, float maxValue)		{ return rnd.getFloat(minValue, maxValue); }
template<> inline		deInt32		randomScalar	(de::Random& rnd, deInt32 minValue, deInt32 maxValue)	{ return rnd.getInt(minValue, maxValue); }
template<> inline		deUint32	randomScalar	(de::Random& rnd, deUint32 minValue, deUint32 maxValue)	{ if (minValue == 0 && maxValue == 0xffffffff) return rnd.getUint32();
																											  return minValue + rnd.getUint32() % (maxValue - minValue + 1); }
template<> inline		deInt16		randomScalar	(de::Random& rnd, deInt16 minValue, deInt16 maxValue)	{ return (deInt16)rnd.getInt(minValue, maxValue); }
template<> inline		deUint16	randomScalar	(de::Random& rnd, deUint16 minValue, deUint16 maxValue)	{ return (deUint16)(minValue + rnd.getUint16() % (maxValue - minValue + 1)); }
template<> inline		deInt8		randomScalar	(de::Random& rnd, deInt8 minValue, deInt8 maxValue)		{ return (deInt8)rnd.getInt(minValue, maxValue); }
template<> inline		deUint8		randomScalar	(de::Random& rnd, deUint8 minValue, deUint8 maxValue)	{ return (deUint8)(minValue + rnd.getUint8() % (maxValue - minValue + 1)); }

} // de

#endif // _DERANDOM_HPP
<|endoftext|>