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

#include "PDB.h"
#include "Chunks.h"
#include "Config.h"
#include "Error.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/DebugInfo/MSF/ByteStream.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
#include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h"
#include "llvm/DebugInfo/PDB/Raw/StringTableBuilder.h"
#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/ScopedPrinter.h"
#include <memory>

using namespace lld;
using namespace lld::coff;
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::support;
using namespace llvm::support::endian;

using llvm::object::coff_section;

static ExitOnError ExitOnErr;

// Returns a list of all SectionChunks.
static std::vector<coff_section> getInputSections(SymbolTable *Symtab) {
  std::vector<coff_section> V;
  for (Chunk *C : Symtab->getChunks())
    if (auto *SC = dyn_cast<SectionChunk>(C))
      V.push_back(*SC->Header);
  return V;
}

static SectionChunk *findByName(std::vector<SectionChunk *> &Sections,
                                StringRef Name) {
  for (SectionChunk *C : Sections)
    if (C->getSectionName() == Name)
      return C;
  return nullptr;
}

static ArrayRef<uint8_t> getDebugSection(ObjectFile *File, StringRef SecName) {
  SectionChunk *Sec = findByName(File->getDebugChunks(), SecName);
  if (!Sec)
    return {};

  // First 4 bytes are section magic.
  ArrayRef<uint8_t> Data = Sec->getContents();
  if (Data.size() < 4)
    fatal(SecName + " too short");
  if (read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC)
    fatal(SecName + " has an invalid magic");
  return Data.slice(4);
}

// Merge .debug$T sections and returns it.
static std::vector<uint8_t> mergeDebugT(SymbolTable *Symtab) {
  ScopedPrinter W(outs());

  // Visit all .debug$T sections to add them to Builder.
  codeview::TypeTableBuilder Builder(BAlloc);
  for (ObjectFile *File : Symtab->ObjectFiles) {
    ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
    if (Data.empty())
      continue;

    msf::ByteStream Stream(Data);
    codeview::CVTypeArray Types;
    msf::StreamReader Reader(Stream);
    if (auto EC = Reader.readArray(Types, Reader.getLength()))
      fatal(EC, "Reader::readArray failed");
    if (!codeview::mergeTypeStreams(Builder, Types))
      fatal("codeview::mergeTypeStreams failed");
  }

  // Construct section contents.
  std::vector<uint8_t> V;
  Builder.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
    V.insert(V.end(), Rec.begin(), Rec.end());
  });
  return V;
}

static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
  ListScope LS(W, "DebugT");
  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
  if (Data.empty())
    return;

  TypeDatabase TDB;
  TypeDumpVisitor TDV(TDB, &W, false);
  CVTypeDumper TypeDumper(TDB);
  if (auto EC = TypeDumper.dump(Data, TDV))
    fatal(EC, "CVTypeDumper::dump failed");
}

static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) {
  ListScope LS(W, "DebugS");
  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$S");
  if (Data.empty())
    return;

  msf::ByteStream Stream(Data);
  CVSymbolArray Symbols;
  msf::StreamReader Reader(Stream);
  if (auto EC = Reader.readArray(Symbols, Reader.getLength()))
    fatal(EC, "StreamReader.readArray<CVSymbolArray> failed");

  TypeDatabase TDB;
  CVSymbolDumper SymbolDumper(W, TDB, nullptr, false);
  if (auto EC = SymbolDumper.dump(Symbols))
    fatal(EC, "CVSymbolDumper::dump failed");
}

// Dump CodeView debug info. This is for debugging.
static void dumpCodeView(SymbolTable *Symtab) {
  ScopedPrinter W(outs());

  for (ObjectFile *File : Symtab->ObjectFiles) {
    dumpDebugT(W, File);
    dumpDebugS(W, File);
  }
}

static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
                        ArrayRef<uint8_t> Data) {
  msf::ByteStream Stream(Data);
  codeview::CVTypeArray Records;
  msf::StreamReader Reader(Stream);
  if (auto EC = Reader.readArray(Records, Reader.getLength()))
    fatal(EC, "Reader.readArray failed");
  for (const codeview::CVType &Rec : Records)
    TpiBuilder.addTypeRecord(Rec);
}

// Creates a PDB file.
void coff::createPDB(StringRef Path, SymbolTable *Symtab,
                     ArrayRef<uint8_t> SectionTable,
                     const llvm::codeview::DebugInfo *DI) {
  if (Config->DumpPdb)
    dumpCodeView(Symtab);

  BumpPtrAllocator Alloc;
  pdb::PDBFileBuilder Builder(Alloc);
  ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize

  // Create streams in MSF for predefined streams, namely
  // PDB, TPI, DBI and IPI.
  for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I)
    ExitOnErr(Builder.getMsfBuilder().addStream(0));

  // Add an Info stream.
  auto &InfoBuilder = Builder.getInfoBuilder();
  InfoBuilder.setAge(DI->PDB70.Age);
  InfoBuilder.setGuid(
      *reinterpret_cast<const pdb::PDB_UniqueId *>(&DI->PDB70.Signature));
  // Should be the current time, but set 0 for reproducibilty.
  InfoBuilder.setSignature(0);
  InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);

  // Add an empty DPI stream.
  auto &DbiBuilder = Builder.getDbiBuilder();
  DbiBuilder.setVersionHeader(pdb::PdbDbiV110);

  // Add an empty TPI stream.
  auto &TpiBuilder = Builder.getTpiBuilder();
  TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
  std::vector<uint8_t> TpiData;
  if (Config->DebugPdb) {
    TpiData = mergeDebugT(Symtab);
    addTypeInfo(TpiBuilder, TpiData);
  }

  // Add an empty IPI stream.
  auto &IpiBuilder = Builder.getIpiBuilder();
  IpiBuilder.setVersionHeader(pdb::PdbTpiV80);

  // Add Section Contributions.
  std::vector<pdb::SectionContrib> Contribs =
      pdb::DbiStreamBuilder::createSectionContribs(getInputSections(Symtab));
  DbiBuilder.setSectionContribs(Contribs);

  // Add Section Map stream.
  ArrayRef<object::coff_section> Sections = {
      (const object::coff_section *)SectionTable.data(),
      SectionTable.size() / sizeof(object::coff_section)};
  std::vector<pdb::SecMapEntry> SectionMap =
      pdb::DbiStreamBuilder::createSectionMap(Sections);
  DbiBuilder.setSectionMap(SectionMap);

  ExitOnErr(DbiBuilder.addModuleInfo("", "* Linker *"));

  // Add COFF section header stream.
  ExitOnErr(
      DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));

  // Write to a file.
  ExitOnErr(Builder.commit(Path));
}
<commit_msg>NFC:  Rename (PDB) RawSession to NativeSession<commit_after>//===- PDB.cpp ------------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "PDB.h"
#include "Chunks.h"
#include "Config.h"
#include "Error.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/DebugInfo/MSF/ByteStream.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/ScopedPrinter.h"
#include <memory>

using namespace lld;
using namespace lld::coff;
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::support;
using namespace llvm::support::endian;

using llvm::object::coff_section;

static ExitOnError ExitOnErr;

// Returns a list of all SectionChunks.
static std::vector<coff_section> getInputSections(SymbolTable *Symtab) {
  std::vector<coff_section> V;
  for (Chunk *C : Symtab->getChunks())
    if (auto *SC = dyn_cast<SectionChunk>(C))
      V.push_back(*SC->Header);
  return V;
}

static SectionChunk *findByName(std::vector<SectionChunk *> &Sections,
                                StringRef Name) {
  for (SectionChunk *C : Sections)
    if (C->getSectionName() == Name)
      return C;
  return nullptr;
}

static ArrayRef<uint8_t> getDebugSection(ObjectFile *File, StringRef SecName) {
  SectionChunk *Sec = findByName(File->getDebugChunks(), SecName);
  if (!Sec)
    return {};

  // First 4 bytes are section magic.
  ArrayRef<uint8_t> Data = Sec->getContents();
  if (Data.size() < 4)
    fatal(SecName + " too short");
  if (read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC)
    fatal(SecName + " has an invalid magic");
  return Data.slice(4);
}

// Merge .debug$T sections and returns it.
static std::vector<uint8_t> mergeDebugT(SymbolTable *Symtab) {
  ScopedPrinter W(outs());

  // Visit all .debug$T sections to add them to Builder.
  codeview::TypeTableBuilder Builder(BAlloc);
  for (ObjectFile *File : Symtab->ObjectFiles) {
    ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
    if (Data.empty())
      continue;

    msf::ByteStream Stream(Data);
    codeview::CVTypeArray Types;
    msf::StreamReader Reader(Stream);
    if (auto EC = Reader.readArray(Types, Reader.getLength()))
      fatal(EC, "Reader::readArray failed");
    if (!codeview::mergeTypeStreams(Builder, Types))
      fatal("codeview::mergeTypeStreams failed");
  }

  // Construct section contents.
  std::vector<uint8_t> V;
  Builder.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
    V.insert(V.end(), Rec.begin(), Rec.end());
  });
  return V;
}

static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
  ListScope LS(W, "DebugT");
  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
  if (Data.empty())
    return;

  TypeDatabase TDB;
  TypeDumpVisitor TDV(TDB, &W, false);
  CVTypeDumper TypeDumper(TDB);
  if (auto EC = TypeDumper.dump(Data, TDV))
    fatal(EC, "CVTypeDumper::dump failed");
}

static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) {
  ListScope LS(W, "DebugS");
  ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$S");
  if (Data.empty())
    return;

  msf::ByteStream Stream(Data);
  CVSymbolArray Symbols;
  msf::StreamReader Reader(Stream);
  if (auto EC = Reader.readArray(Symbols, Reader.getLength()))
    fatal(EC, "StreamReader.readArray<CVSymbolArray> failed");

  TypeDatabase TDB;
  CVSymbolDumper SymbolDumper(W, TDB, nullptr, false);
  if (auto EC = SymbolDumper.dump(Symbols))
    fatal(EC, "CVSymbolDumper::dump failed");
}

// Dump CodeView debug info. This is for debugging.
static void dumpCodeView(SymbolTable *Symtab) {
  ScopedPrinter W(outs());

  for (ObjectFile *File : Symtab->ObjectFiles) {
    dumpDebugT(W, File);
    dumpDebugS(W, File);
  }
}

static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
                        ArrayRef<uint8_t> Data) {
  msf::ByteStream Stream(Data);
  codeview::CVTypeArray Records;
  msf::StreamReader Reader(Stream);
  if (auto EC = Reader.readArray(Records, Reader.getLength()))
    fatal(EC, "Reader.readArray failed");
  for (const codeview::CVType &Rec : Records)
    TpiBuilder.addTypeRecord(Rec);
}

// Creates a PDB file.
void coff::createPDB(StringRef Path, SymbolTable *Symtab,
                     ArrayRef<uint8_t> SectionTable,
                     const llvm::codeview::DebugInfo *DI) {
  if (Config->DumpPdb)
    dumpCodeView(Symtab);

  BumpPtrAllocator Alloc;
  pdb::PDBFileBuilder Builder(Alloc);
  ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize

  // Create streams in MSF for predefined streams, namely
  // PDB, TPI, DBI and IPI.
  for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I)
    ExitOnErr(Builder.getMsfBuilder().addStream(0));

  // Add an Info stream.
  auto &InfoBuilder = Builder.getInfoBuilder();
  InfoBuilder.setAge(DI->PDB70.Age);
  InfoBuilder.setGuid(
      *reinterpret_cast<const pdb::PDB_UniqueId *>(&DI->PDB70.Signature));
  // Should be the current time, but set 0 for reproducibilty.
  InfoBuilder.setSignature(0);
  InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);

  // Add an empty DPI stream.
  auto &DbiBuilder = Builder.getDbiBuilder();
  DbiBuilder.setVersionHeader(pdb::PdbDbiV110);

  // Add an empty TPI stream.
  auto &TpiBuilder = Builder.getTpiBuilder();
  TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
  std::vector<uint8_t> TpiData;
  if (Config->DebugPdb) {
    TpiData = mergeDebugT(Symtab);
    addTypeInfo(TpiBuilder, TpiData);
  }

  // Add an empty IPI stream.
  auto &IpiBuilder = Builder.getIpiBuilder();
  IpiBuilder.setVersionHeader(pdb::PdbTpiV80);

  // Add Section Contributions.
  std::vector<pdb::SectionContrib> Contribs =
      pdb::DbiStreamBuilder::createSectionContribs(getInputSections(Symtab));
  DbiBuilder.setSectionContribs(Contribs);

  // Add Section Map stream.
  ArrayRef<object::coff_section> Sections = {
      (const object::coff_section *)SectionTable.data(),
      SectionTable.size() / sizeof(object::coff_section)};
  std::vector<pdb::SecMapEntry> SectionMap =
      pdb::DbiStreamBuilder::createSectionMap(Sections);
  DbiBuilder.setSectionMap(SectionMap);

  ExitOnErr(DbiBuilder.addModuleInfo("", "* Linker *"));

  // Add COFF section header stream.
  ExitOnErr(
      DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));

  // Write to a file.
  ExitOnErr(Builder.commit(Path));
}
<|endoftext|>


<commit_before><commit_msg>Fixed a bug.<commit_after><|endoftext|>


<commit_before>// --------------------------------------------------------
// Code generated by Papyrus C++
// --------------------------------------------------------

#define Annotator_AnnotatorLib_Annotation_BODY

/************************************************************
 Annotation class body
 ************************************************************/

#include <assert.h>
#include <algorithm>
// include associated header file
#include "AnnotatorLib/Annotation.h"
#include "AnnotatorLib/Frame.h"
#include "AnnotatorLib/Object.h"

namespace AnnotatorLib {

////////////////// statics /////////////////////

unsigned long Annotation::genId(const std::shared_ptr<Frame> frame, const std::shared_ptr<Object> obj) {
  //Cantor’s Pairing Function
  return ( std::pow(frame->getId(),2)
           + 3 * frame->getId()
           + 2 * frame->getId() * obj->getId()
           + obj->getId()
           + std::pow(obj->getId(), 2) ) / 2 ;
}

//////////////// constructors ///////////////////

Annotation::Annotation( shared_ptr<Frame> frame,
                        shared_ptr<Object> obj,
                        AnnotationType type)
    : Annotation(genId(frame, obj), frame, obj, type) {}

Annotation::Annotation( shared_ptr<Annotation> a,
                        shared_ptr<Frame> frame,
                        bool isInterpolated)
    : Annotation(genId(frame, a->getObject()), frame, a->getObject(), a->getType(), isInterpolated) {
  this->setPosition(a->getX(), a->getY(), a->getWidth(), a->getHeight());
}

Annotation::Annotation(unsigned long id,
           const shared_ptr<Frame>& frame,
           const shared_ptr<Object>& obj,
           const AnnotationType type,
           bool isInterpolated)
  : id(id), frame(frame), object(obj), type(type), is_temporary(isInterpolated) { }

//////////////// public methods ///////////////////

bool Annotation::operator>(const Annotation &right) const {
  return *this->frame > *right.frame;
}

bool Annotation::operator<(const Annotation &right) const {
  return *this->frame < *right.frame;
}

bool Annotation::operator<=(const Annotation &right) const {
  return *this->frame <= *right.frame;
}

bool Annotation::operator>=(const Annotation &right) const {
  return *this->frame >= *right.frame;
}

bool Annotation::operator==(const Annotation &right) const {
  return *this->frame == *right.frame;
}

bool Annotation::operator!=(const Annotation &right) const {
  return *this->frame != *right.frame;
}

unsigned long Annotation::getId() const { return id; }

std::vector<shared_ptr<Attribute>> const& Annotation::getAttributes() const {
  return attributes;
}

bool Annotation::addAttribute(shared_ptr<Attribute> attribute) {
  if (attribute && std::find(attributes.begin(), attributes.end(), attribute) == attributes.end()) {
    attributes.push_back(attribute);
    return true;
  }
  return false;
}

bool Annotation::removeAttribute(shared_ptr<Attribute> attribute) {
  std::vector<shared_ptr<Attribute>>::const_iterator position =
      std::find(attributes.begin(), attributes.end(), attribute);
  if (position != attributes.end()) {
    attributes.erase(position);
    return true;
  }
  return false;
}

shared_ptr<Frame> Annotation::getFrame() const { return frame; }

shared_ptr<Object> Annotation::getObject() const { return object; }

AnnotationType Annotation::getType() const { return this->type; }

void Annotation::setCenterPosition(float x, float y, float hradius,
                                   float vradius) {
  setX(x);
  setY(y);
  setHRadius(hradius);
  setVRadius(vradius);
}

float Annotation::getX() const { return x; }

void Annotation::setX(float x) { this->x = x; }

float Annotation::getY() const { return y; }

void Annotation::setY(float y) { this->y = y; }

float Annotation::getWidth() const { return width; }

void Annotation::setWidth(float width) {
  assert(width > 0);
  this->width = width;
}

float Annotation::getHeight() const { return height; }

void Annotation::setHeight(float height) {
  assert(height > 0);
  this->height = height;
}

float Annotation::getHRadius() const { return width / 2; }

void Annotation::setHRadius(float hradius) {
  assert(hradius > 0);
  if (hradius < 0) hradius *= -1;
  this->width = hradius * 2;
}

float Annotation::getVRadius() const { return height / 2; }

void Annotation::setVRadius(float vradius) {
  assert(vradius > 0);
  if (vradius < 0) vradius *= -1;
  this->height = vradius * 2;
}

void Annotation::setSelf(weak_ptr<Annotation> self) {
  this->self_ = self;
}

void Annotation::setNext(weak_ptr<Annotation> next) {
  assert(!next.lock() || *this->frame <= *next.lock()->getFrame());
  this->next = next;
}

shared_ptr<Annotation> Annotation::getNext() const {
  if ( next.expired()) return shared_ptr<Annotation>(nullptr);
  return next.lock();
}

bool Annotation::hasNext() const { return (next.lock().get() != nullptr && next.lock().get() != this); }

void Annotation::setPrevious(weak_ptr<Annotation> previous) {
  assert(!previous.lock() || *this->frame >= *previous.lock()->getFrame());
  this->previous = previous;
}

shared_ptr<Annotation> Annotation::getPrevious() const {
  if (previous.expired()) return shared_ptr<Annotation>(nullptr);
  return previous.lock();
}

shared_ptr<Annotation> Annotation::getFirst() {
  return object->getFirstAnnotation();
}

shared_ptr<Annotation> Annotation::getLast() {
  return object->getLastAnnotation();
}

bool Annotation::isLast() const {
  return !this->next.lock() || this->next.lock().get() == this;
}

bool Annotation::isFirst() const { return !this->previous.lock(); }

bool Annotation::isTemporary() const { return is_temporary; }

bool Annotation::isRegistered() const { return registered; }

bool Annotation::setRegistered(bool do_register)  {
  if (isTemporary())
    return false;
  if (do_register && !registered) {
    this->getObject()->addAnnotation(self_);
    this->getFrame()->addAnnotation(self_);
  }
  if (!do_register && registered) {
    this->getObject()->removeAnnotation(frame->getFrameNumber());
    this->getFrame()->removeAnnotation(id);
  }
  registered = do_register;
  return true;
}

void Annotation::setPosition(float x, float y) {
  this->x = x;
  this->y = y;
}

void Annotation::setPosition(float x, float y, float width, float height) {
  setX(x);
  setY(y);
  setWidth(width);
  setHeight(height);
}

//////////////// private static methods ///////////////////

void Annotation::registerAnnotation(const shared_ptr<Annotation> a, bool r) {
  a->setRegistered(r);
}

void Annotation::registerAnnotation(const shared_ptr<Annotation> a) {
  a->setRegistered(true);
}

void Annotation::unregisterAnnotation(const shared_ptr<Annotation> a) {
  a->setRegistered(false);
}

}  // of namespace AnnotatorLib

/************************************************************
 End of Annotation class body
 ************************************************************/
<commit_msg>include cmath to fix travis build errors<commit_after>// --------------------------------------------------------
// Code generated by Papyrus C++
// --------------------------------------------------------

#define Annotator_AnnotatorLib_Annotation_BODY

/************************************************************
 Annotation class body
 ************************************************************/

#include <assert.h>
#include <algorithm>
#include <cmath>
// include associated header file
#include "AnnotatorLib/Annotation.h"
#include "AnnotatorLib/Frame.h"
#include "AnnotatorLib/Object.h"

namespace AnnotatorLib {

////////////////// statics /////////////////////

unsigned long Annotation::genId(const std::shared_ptr<Frame> frame, const std::shared_ptr<Object> obj) {
  //Cantor’s Pairing Function
  return ( std::pow(frame->getId(),2)
           + 3 * frame->getId()
           + 2 * frame->getId() * obj->getId()
           + obj->getId()
           + std::pow(obj->getId(), 2) ) / 2 ;
}

//////////////// constructors ///////////////////

Annotation::Annotation( shared_ptr<Frame> frame,
                        shared_ptr<Object> obj,
                        AnnotationType type)
    : Annotation(genId(frame, obj), frame, obj, type) {}

Annotation::Annotation( shared_ptr<Annotation> a,
                        shared_ptr<Frame> frame,
                        bool isInterpolated)
    : Annotation(genId(frame, a->getObject()), frame, a->getObject(), a->getType(), isInterpolated) {
  this->setPosition(a->getX(), a->getY(), a->getWidth(), a->getHeight());
}

Annotation::Annotation(unsigned long id,
           const shared_ptr<Frame>& frame,
           const shared_ptr<Object>& obj,
           const AnnotationType type,
           bool isInterpolated)
  : id(id), frame(frame), object(obj), type(type), is_temporary(isInterpolated) { }

//////////////// public methods ///////////////////

bool Annotation::operator>(const Annotation &right) const {
  return *this->frame > *right.frame;
}

bool Annotation::operator<(const Annotation &right) const {
  return *this->frame < *right.frame;
}

bool Annotation::operator<=(const Annotation &right) const {
  return *this->frame <= *right.frame;
}

bool Annotation::operator>=(const Annotation &right) const {
  return *this->frame >= *right.frame;
}

bool Annotation::operator==(const Annotation &right) const {
  return *this->frame == *right.frame;
}

bool Annotation::operator!=(const Annotation &right) const {
  return *this->frame != *right.frame;
}

unsigned long Annotation::getId() const { return id; }

std::vector<shared_ptr<Attribute>> const& Annotation::getAttributes() const {
  return attributes;
}

bool Annotation::addAttribute(shared_ptr<Attribute> attribute) {
  if (attribute && std::find(attributes.begin(), attributes.end(), attribute) == attributes.end()) {
    attributes.push_back(attribute);
    return true;
  }
  return false;
}

bool Annotation::removeAttribute(shared_ptr<Attribute> attribute) {
  std::vector<shared_ptr<Attribute>>::const_iterator position =
      std::find(attributes.begin(), attributes.end(), attribute);
  if (position != attributes.end()) {
    attributes.erase(position);
    return true;
  }
  return false;
}

shared_ptr<Frame> Annotation::getFrame() const { return frame; }

shared_ptr<Object> Annotation::getObject() const { return object; }

AnnotationType Annotation::getType() const { return this->type; }

void Annotation::setCenterPosition(float x, float y, float hradius,
                                   float vradius) {
  setX(x);
  setY(y);
  setHRadius(hradius);
  setVRadius(vradius);
}

float Annotation::getX() const { return x; }

void Annotation::setX(float x) { this->x = x; }

float Annotation::getY() const { return y; }

void Annotation::setY(float y) { this->y = y; }

float Annotation::getWidth() const { return width; }

void Annotation::setWidth(float width) {
  assert(width > 0);
  this->width = width;
}

float Annotation::getHeight() const { return height; }

void Annotation::setHeight(float height) {
  assert(height > 0);
  this->height = height;
}

float Annotation::getHRadius() const { return width / 2; }

void Annotation::setHRadius(float hradius) {
  assert(hradius > 0);
  if (hradius < 0) hradius *= -1;
  this->width = hradius * 2;
}

float Annotation::getVRadius() const { return height / 2; }

void Annotation::setVRadius(float vradius) {
  assert(vradius > 0);
  if (vradius < 0) vradius *= -1;
  this->height = vradius * 2;
}

void Annotation::setSelf(weak_ptr<Annotation> self) {
  this->self_ = self;
}

void Annotation::setNext(weak_ptr<Annotation> next) {
  assert(!next.lock() || *this->frame <= *next.lock()->getFrame());
  this->next = next;
}

shared_ptr<Annotation> Annotation::getNext() const {
  if ( next.expired()) return shared_ptr<Annotation>(nullptr);
  return next.lock();
}

bool Annotation::hasNext() const { return (next.lock().get() != nullptr && next.lock().get() != this); }

void Annotation::setPrevious(weak_ptr<Annotation> previous) {
  assert(!previous.lock() || *this->frame >= *previous.lock()->getFrame());
  this->previous = previous;
}

shared_ptr<Annotation> Annotation::getPrevious() const {
  if (previous.expired()) return shared_ptr<Annotation>(nullptr);
  return previous.lock();
}

shared_ptr<Annotation> Annotation::getFirst() {
  return object->getFirstAnnotation();
}

shared_ptr<Annotation> Annotation::getLast() {
  return object->getLastAnnotation();
}

bool Annotation::isLast() const {
  return !this->next.lock() || this->next.lock().get() == this;
}

bool Annotation::isFirst() const { return !this->previous.lock(); }

bool Annotation::isTemporary() const { return is_temporary; }

bool Annotation::isRegistered() const { return registered; }

bool Annotation::setRegistered(bool do_register)  {
  if (isTemporary())
    return false;
  if (do_register && !registered) {
    this->getObject()->addAnnotation(self_);
    this->getFrame()->addAnnotation(self_);
  }
  if (!do_register && registered) {
    this->getObject()->removeAnnotation(frame->getFrameNumber());
    this->getFrame()->removeAnnotation(id);
  }
  registered = do_register;
  return true;
}

void Annotation::setPosition(float x, float y) {
  this->x = x;
  this->y = y;
}

void Annotation::setPosition(float x, float y, float width, float height) {
  setX(x);
  setY(y);
  setWidth(width);
  setHeight(height);
}

//////////////// private static methods ///////////////////

void Annotation::registerAnnotation(const shared_ptr<Annotation> a, bool r) {
  a->setRegistered(r);
}

void Annotation::registerAnnotation(const shared_ptr<Annotation> a) {
  a->setRegistered(true);
}

void Annotation::unregisterAnnotation(const shared_ptr<Annotation> a) {
  a->setRegistered(false);
}

}  // of namespace AnnotatorLib

/************************************************************
 End of Annotation class body
 ************************************************************/
<|endoftext|>


<commit_before>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "desktop/win/desktop_environment.h"

#include "base/win/scoped_impersonator.h"
#include "base/win/scoped_object.h"

#include <Windows.h>
#include <wtsapi32.h>

namespace desktop {

DesktopEnvironment::DesktopEnvironment()
{
    applyNewSettings();
}

DesktopEnvironment::~DesktopEnvironment()
{
    revertAll();
}

void DesktopEnvironment::setWallpaper(bool enable)
{
    if (wallpaper_ == enable)
        return;

    wallpaper_ = enable;

    revertAll();
    applyNewSettings();
}

void DesktopEnvironment::setFontSmoothing(bool enable)
{
    if (font_smoothing_ == enable)
        return;

    font_smoothing_ = enable;

    revertAll();
    applyNewSettings();
}

void DesktopEnvironment::setEffects(bool enable)
{
    if (effects_ == enable)
        return;

    effects_ = enable;

    revertAll();
    applyNewSettings();
}

void DesktopEnvironment::disableWallpaper()
{
    SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, L"", SPIF_SENDCHANGE);
}

void DesktopEnvironment::disableFontSmoothing()
{
    SystemParametersInfoW(SPI_SETFONTSMOOTHING, FALSE, 0, SPIF_SENDCHANGE);
}

void DesktopEnvironment::disableEffects()
{
    BOOL drop_shadow = TRUE;
    if (SystemParametersInfoW(SPI_GETDROPSHADOW, 0, &drop_shadow, 0))
    {
        if (drop_shadow)
        {
            SystemParametersInfoW(SPI_SETDROPSHADOW, 0, FALSE, SPIF_SENDCHANGE);
            drop_shadow_changed_ = true;
        }
    }

    ANIMATIONINFO animation;
    animation.cbSize = sizeof(animation);
    if (SystemParametersInfoW(SPI_GETANIMATION, sizeof(animation), &animation, 0))
    {
        if (animation.iMinAnimate)
        {
            animation.iMinAnimate = FALSE;
            SystemParametersInfoW(SPI_SETANIMATION, sizeof(animation), &animation, SPIF_SENDCHANGE);
            animation_changed_ = true;
        }
    }

    SystemParametersInfoW(SPI_SETDRAGFULLWINDOWS, FALSE, 0, SPIF_SENDCHANGE);
    SystemParametersInfoW(SPI_SETMENUANIMATION, 0, FALSE, SPIF_SENDCHANGE);
    SystemParametersInfoW(SPI_SETTOOLTIPANIMATION, 0, FALSE, SPIF_SENDCHANGE);
    SystemParametersInfoW(SPI_SETCOMBOBOXANIMATION, 0, FALSE, SPIF_SENDCHANGE);
    SystemParametersInfoW(SPI_SETSELECTIONFADE, 0, FALSE, SPIF_SENDCHANGE);
    SystemParametersInfoW(SPI_SETLISTBOXSMOOTHSCROLLING, 0, FALSE, SPIF_SENDCHANGE);
    SystemParametersInfoW(SPI_SETUIEFFECTS, 0, FALSE, SPIF_SENDCHANGE);
    SystemParametersInfoW(SPI_SETCLIENTAREAANIMATION, 0, FALSE, SPIF_SENDCHANGE);
    SystemParametersInfoW(SPI_SETGRADIENTCAPTIONS, 0, FALSE, SPIF_SENDCHANGE);
    SystemParametersInfoW(SPI_SETHOTTRACKING, 0, FALSE, SPIF_SENDCHANGE);
}

void DesktopEnvironment::revertAll()
{
    if (drop_shadow_changed_)
    {
        SystemParametersInfoW(SPI_SETDROPSHADOW, 0, reinterpret_cast<PVOID>(TRUE), SPIF_SENDCHANGE);
        drop_shadow_changed_ = false;
    }

    if (animation_changed_)
    {
        ANIMATIONINFO animation;
        animation.cbSize = sizeof(animation);
        animation.iMinAnimate = TRUE;

        SystemParametersInfoW(SPI_SETANIMATION, sizeof(animation), &animation, SPIF_SENDCHANGE);

        animation_changed_ = false;
    }

    base::win::ScopedHandle user_token;

    if (!WTSQueryUserToken(WTSGetActiveConsoleSessionId(), user_token.recieve()))
        return;

    base::win::ScopedImpersonator impersonator;

    // The process of the desktop session is running with "SYSTEM" account.
    // We need the current real user, not "SYSTEM".
    if (!impersonator.loggedOnUser(user_token))
        return;

    HMODULE module = GetModuleHandleW(L"user32.dll");
    if (module)
    {
        // The function prototype is relevant for versions starting from Windows Vista.
        // Older versions have a different prototype.
        typedef BOOL(WINAPI* UpdatePerUserSystemParametersFunc)(DWORD flags);

        UpdatePerUserSystemParametersFunc update_per_user_system_parameters =
            reinterpret_cast<UpdatePerUserSystemParametersFunc>(
                GetProcAddress(module, "UpdatePerUserSystemParameters"));
        if (update_per_user_system_parameters)
        {
            // WARNING! Undocumented function!
            // Any ideas how to update user settings without using it?
            update_per_user_system_parameters(0x06);
        }
    }
}

void DesktopEnvironment::applyNewSettings()
{
    if (!wallpaper_)
        disableWallpaper();

    if (!font_smoothing_)
        disableFontSmoothing();

    if (!effects_)
        disableEffects();
}

} // namespace desktop
<commit_msg>Remove unneeded calls (SPI_SETUIEFFECTS replaces them all).<commit_after>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "desktop/win/desktop_environment.h"

#include "base/win/scoped_impersonator.h"
#include "base/win/scoped_object.h"

#include <Windows.h>
#include <wtsapi32.h>

namespace desktop {

DesktopEnvironment::DesktopEnvironment()
{
    applyNewSettings();
}

DesktopEnvironment::~DesktopEnvironment()
{
    revertAll();
}

void DesktopEnvironment::setWallpaper(bool enable)
{
    if (wallpaper_ == enable)
        return;

    wallpaper_ = enable;

    revertAll();
    applyNewSettings();
}

void DesktopEnvironment::setFontSmoothing(bool enable)
{
    if (font_smoothing_ == enable)
        return;

    font_smoothing_ = enable;

    revertAll();
    applyNewSettings();
}

void DesktopEnvironment::setEffects(bool enable)
{
    if (effects_ == enable)
        return;

    effects_ = enable;

    revertAll();
    applyNewSettings();
}

void DesktopEnvironment::disableWallpaper()
{
    SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, L"", SPIF_SENDCHANGE);
}

void DesktopEnvironment::disableFontSmoothing()
{
    SystemParametersInfoW(SPI_SETFONTSMOOTHING, FALSE, 0, SPIF_SENDCHANGE);
}

void DesktopEnvironment::disableEffects()
{
    BOOL drop_shadow = TRUE;
    if (SystemParametersInfoW(SPI_GETDROPSHADOW, 0, &drop_shadow, 0))
    {
        if (drop_shadow)
        {
            SystemParametersInfoW(SPI_SETDROPSHADOW, 0, FALSE, SPIF_SENDCHANGE);
            drop_shadow_changed_ = true;
        }
    }

    ANIMATIONINFO animation;
    animation.cbSize = sizeof(animation);
    if (SystemParametersInfoW(SPI_GETANIMATION, sizeof(animation), &animation, 0))
    {
        if (animation.iMinAnimate)
        {
            animation.iMinAnimate = FALSE;
            SystemParametersInfoW(SPI_SETANIMATION, sizeof(animation), &animation, SPIF_SENDCHANGE);
            animation_changed_ = true;
        }
    }

    SystemParametersInfoW(SPI_SETDRAGFULLWINDOWS, FALSE, 0, SPIF_SENDCHANGE);
    SystemParametersInfoW(SPI_SETUIEFFECTS, 0, FALSE, SPIF_SENDCHANGE);
    SystemParametersInfoW(SPI_SETCLIENTAREAANIMATION, 0, FALSE, SPIF_SENDCHANGE);
}

void DesktopEnvironment::revertAll()
{
    if (drop_shadow_changed_)
    {
        SystemParametersInfoW(SPI_SETDROPSHADOW, 0, reinterpret_cast<PVOID>(TRUE), SPIF_SENDCHANGE);
        drop_shadow_changed_ = false;
    }

    if (animation_changed_)
    {
        ANIMATIONINFO animation;
        animation.cbSize = sizeof(animation);
        animation.iMinAnimate = TRUE;

        SystemParametersInfoW(SPI_SETANIMATION, sizeof(animation), &animation, SPIF_SENDCHANGE);

        animation_changed_ = false;
    }

    base::win::ScopedHandle user_token;

    if (!WTSQueryUserToken(WTSGetActiveConsoleSessionId(), user_token.recieve()))
        return;

    base::win::ScopedImpersonator impersonator;

    // The process of the desktop session is running with "SYSTEM" account.
    // We need the current real user, not "SYSTEM".
    if (!impersonator.loggedOnUser(user_token))
        return;

    HMODULE module = GetModuleHandleW(L"user32.dll");
    if (module)
    {
        // The function prototype is relevant for versions starting from Windows Vista.
        // Older versions have a different prototype.
        typedef BOOL(WINAPI* UpdatePerUserSystemParametersFunc)(DWORD flags);

        UpdatePerUserSystemParametersFunc update_per_user_system_parameters =
            reinterpret_cast<UpdatePerUserSystemParametersFunc>(
                GetProcAddress(module, "UpdatePerUserSystemParameters"));
        if (update_per_user_system_parameters)
        {
            // WARNING! Undocumented function!
            // Any ideas how to update user settings without using it?
            update_per_user_system_parameters(0x06);
        }
    }
}

void DesktopEnvironment::applyNewSettings()
{
    if (!wallpaper_)
        disableWallpaper();

    if (!font_smoothing_)
        disableFontSmoothing();

    if (!effects_)
        disableEffects();
}

} // namespace desktop
<|endoftext|>


<commit_before>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

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

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

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

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE data_manager_test

#include "kraken/data_manager.h"

#include <boost/test/unit_test.hpp>
#include <atomic>

namespace test {

//mock of Data class
class Data {
    public:

        void load_nav(const std::string&){}
        void load_disruptions(const std::string&,
                              const std::vector<std::string>& = {}){}
        void build_raptor(size_t){}
        mutable std::atomic<bool> loading;
        mutable std::atomic<bool> is_connected_to_rabbitmq;
        static bool load_status;
        static bool last_load_succeeded;
        static bool destructor_called;
        size_t data_identifier;

        Data(size_t data_identifier=0):
            data_identifier(data_identifier)
        {is_connected_to_rabbitmq = false;}

        ~Data(){Data::destructor_called = true;}
};
bool Data::load_status = true;
bool Data::last_load_succeeded = true;
bool Data::destructor_called = false;

} // namespace test

struct fixture{
    fixture(){
        test::Data::load_status = true;
        test::Data::destructor_called = false;
    }
};

BOOST_FIXTURE_TEST_CASE(get_data, fixture) {
    DataManager<test::Data> data_manager;
    auto data = data_manager.get_data();
    BOOST_REQUIRE(data);
    BOOST_CHECK_EQUAL(test::Data::destructor_called, false);
}

BOOST_FIXTURE_TEST_CASE(load, fixture) {
    DataManager<test::Data> data_manager;
    BOOST_CHECK(data_manager.get_data());
    auto first_data = data_manager.get_data();

    // Same pointer
    BOOST_CHECK_EQUAL(first_data, data_manager.get_data());

    // True because fake data don't failed
    BOOST_CHECK(data_manager.load("fake path"));

    // Load OK, so the internal shared pointer changes.
    // Data has changed.
    BOOST_CHECK_NE(first_data, data_manager.get_data());
}

BOOST_FIXTURE_TEST_CASE(destructor_called, fixture) {
    DataManager<test::Data> data_manager;
    {
        auto first_data = data_manager.get_data();
        // True because fake data don't failed
        BOOST_CHECK(data_manager.load("fake path"));
        // Load OK, so the internal shared pointer changes.
        // Data has changed.
        BOOST_CHECK_NE(first_data, data_manager.get_data());
    }
    // test::Data destructor is called because when load function is called,
    // new shared pointer is not used.
    BOOST_CHECK_EQUAL(test::Data::destructor_called, true);
    BOOST_CHECK(data_manager.get_data());
}

BOOST_FIXTURE_TEST_CASE(destructor_not_called, fixture) {
    DataManager<test::Data> data_manager;
    {
        auto first_data = data_manager.get_data();
        BOOST_CHECK_EQUAL(first_data, data_manager.get_data());
    }
    // type::Data destructor is not called.
    BOOST_CHECK_EQUAL(test::Data::destructor_called, false);
    BOOST_CHECK(data_manager.get_data());
}
<commit_msg>Update data_manager_test.cpp (old way)<commit_after>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

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

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

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

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE data_manager_test

#include "kraken/data_manager.h"

#include <boost/test/unit_test.hpp>
#include <atomic>

namespace test {

//mock of Data class
class Data {
    public:

        void load_nav(const std::string&){}
        void load_disruptions(const std::string&,
                              const std::vector<std::string>& = {}){}
        void build_raptor(size_t){}
        mutable std::atomic<bool> loading;
        mutable std::atomic<bool> is_connected_to_rabbitmq;
        static bool load_status;
        static bool last_load_succeeded;
        static bool destructor_called;
        size_t data_identifier;

        Data(size_t data_identifier=0):
            data_identifier(data_identifier)
        {is_connected_to_rabbitmq = false;}

        ~Data(){Data::destructor_called = true;}
};
bool Data::load_status = true;
bool Data::last_load_succeeded = true;
bool Data::destructor_called = false;

} // namespace test

struct fixture{
    fixture(){
        test::Data::load_status = true;
        test::Data::destructor_called = false;
    }
};

BOOST_FIXTURE_TEST_SUITE(s, fixture)

BOOST_AUTO_TEST_CASE(get_data) {
    DataManager<test::Data> data_manager;
    auto data = data_manager.get_data();
    BOOST_REQUIRE(data);
    BOOST_CHECK_EQUAL(test::Data::destructor_called, false);
}

BOOST_AUTO_TEST_CASE(load) {
    DataManager<test::Data> data_manager;
    BOOST_CHECK(data_manager.get_data());
    auto first_data = data_manager.get_data();

    // Same pointer
    BOOST_CHECK_EQUAL(first_data, data_manager.get_data());

    // True because fake data don't failed
    BOOST_CHECK(data_manager.load("fake path"));

    // Load OK, so the internal shared pointer changes.
    // Data has changed.
    BOOST_CHECK_NE(first_data, data_manager.get_data());
}

BOOST_AUTO_TEST_CASE(destructor_called) {
    DataManager<test::Data> data_manager;
    {
        auto first_data = data_manager.get_data();
        // True because fake data don't failed
        BOOST_CHECK(data_manager.load("fake path"));
        // Load OK, so the internal shared pointer changes.
        // Data has changed.
        BOOST_CHECK_NE(first_data, data_manager.get_data());
    }
    // test::Data destructor is called because when load function is called,
    // new shared pointer is not used.
    BOOST_CHECK_EQUAL(test::Data::destructor_called, true);
    BOOST_CHECK(data_manager.get_data());
}

BOOST_AUTO_TEST_CASE(destructor_not_called) {
    DataManager<test::Data> data_manager;
    {
        auto first_data = data_manager.get_data();
        BOOST_CHECK_EQUAL(first_data, data_manager.get_data());
    }
    // type::Data destructor is not called.
    BOOST_CHECK_EQUAL(test::Data::destructor_called, false);
    BOOST_CHECK(data_manager.get_data());
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include "tests-base.hpp"

#include "../helpers/helpers-locale.hpp"
#include "../helpers/helpers-strings.hpp"

class Utf8ToTitleGreek
	: public ::testing::Test
{

protected:

	void SetUp()
	{
		// Greek grammar rules are not exclusive to Greek locale

		SET_LOCALE_ENGLISH();
	}

	void TearDown()
	{
		RESET_LOCALE();
	}

};

TEST_F(Utf8ToTitleGreek, SingleCapitalLetterSigma)
{
	// 03A3
	// 03A3

	const char* c = "\xCE\xA3";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(2, utf8totitle(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xCE\xA3", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SingleSmallLetterSigma)
{
	// 03C3
	// 03A3

	const char* c = "\xCF\x83";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(2, utf8totitle(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xCE\xA3", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SingleSmallLetterFinalSigma)
{
	// 03C2
	// 03A3

	const char* c = "\xCF\x82";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(2, utf8totitle(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xCE\xA3", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, WordCapitalLetterSigma)
{
	// 03AB 03A3 039E 039A
	// 03AB 03C3 03BE 03BA

	const char* c = "\xCE\xAB\xCE\xA3\xCE\x9E\xCE\x9A";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, utf8totitle(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xCE\xAB\xCF\x83\xCE\xBE\xCE\xBA", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, WordCapitalLetterSigmaAtEnd)
{
	// 03A3 039F 0399 03A3
	// 03A3 03BF 03B9 03C2

	const char* c = "\xCE\xA3\xCE\x9F\xCE\x99\xCE\xA3";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, utf8totitle(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xCE\xA3\xCE\xBF\xCE\xB9\xCF\x82", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, WordSmallLetterSigma)
{
	// 03B5 03BB 03C0 03C3
	// 0395 03BB 03C0 03C3

	const char* c = "\xCE\xB5\xCE\xBB\xCF\x80\xCF\x83";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, utf8totitle(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xCE\x95\xCE\xBB\xCF\x80\xCF\x83", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, WordSmallLetterFinalSigma)
{
	// 03BE 03B2 039F 03AC 03C2
	// 039E 03B2 03BF 03AC 03C2

	const char* c = "\xCE\xBE\xCE\xB2\xCE\x9F\xCE\xAC\xCF\x82";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(10, utf8totitle(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xCE\x9E\xCE\xB2\xCE\xBF\xCE\xAC\xCF\x82", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SentenceCapitalLetterSigma)
{
	// 03A3 03A3 03A3 0020 03CD 03C4
	// 03A3 03C3 03C2 0020 038E 03C4

	const char* c = "\xCE\xA3\xCE\xA3\xCE\xA3 \xCF\x8D\xCF\x84";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(11, utf8totitle(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xCE\xA3\xCF\x83\xCF\x82 \xCE\x8E\xCF\x84", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SentenceSmallLetterSigma)
{
	// 03C1 03BC 03BE 03C3 0020 03C1 03C3 03C6 0020 03B9 03B1
	// 03A1 03BC 03BE 03C3 0020 03A1 03C3 03C6 0020 0399 03B1

	const char* c = "\xCF\x81\xCE\xBC\xCE\xBE\xCF\x83 \xCF\x81\xCF\x83\xCF\x86 \xCE\xB9\xCE\xB1";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(20, utf8totitle(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xCE\xA1\xCE\xBC\xCE\xBE\xCF\x83 \xCE\xA1\xCF\x83\xCF\x86 \xCE\x99\xCE\xB1", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SentenceSmallLetterFinalSigma)
{
	// 03B8 03C2 0020 03B4 03C8 03B7
	// 0398 03C2 0020 0394 03C8 03B7

	const char* c = "\xCE\xB8\xCF\x82 \xCE\xB4\xCF\x88\xCE\xB7";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(11, utf8totitle(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xCE\x98\xCF\x82 \xCE\x94\xCF\x88\xCE\xB7", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}<commit_msg>Add red tests for Greek titlecase case mapping.<commit_after>#include "tests-base.hpp"

#include "../helpers/helpers-locale.hpp"
#include "../helpers/helpers-strings.hpp"

class Utf8ToTitleGreek
	: public ::testing::Test
{

protected:

	void SetUp()
	{
		// Greek grammar rules are not exclusive to Greek locale

		SET_LOCALE_ENGLISH();
	}

	void TearDown()
	{
		RESET_LOCALE();
	}

};

TEST_F(Utf8ToTitleGreek, SingleCapitalLetterSigma)
{
	// 03A3
	// 03A3

	const char* c = "\xCE\xA3";
	const size_t s = 255;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(2, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\xA3", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SingleCapitalLetterSigmaNotEnoughSpace)
{
	const char* c = "\xCE\xA3";
	const size_t s = 1;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(0, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("", b);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST_F(Utf8ToTitleGreek, SingleCapitalLetterSigmaAmountOfBytes)
{
	const char* c = "\xCE\xA3";
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(2, utf8totitle(c, strlen(c), nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SingleSmallLetterSigma)
{
	// 03C3
	// 03A3

	const char* c = "\xCF\x83";
	const size_t s = 255;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(2, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\xA3", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SingleSmallLetterSigmaNotEnoughSpace)
{
	const char* c = "\xCF\x83";
	const size_t s = 1;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(0, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("", b);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST_F(Utf8ToTitleGreek, SingleSmallLetterSigmaAmountOfBytes)
{
	const char* c = "\xCF\x83";
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(2, utf8totitle(c, strlen(c), nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SingleSmallLetterFinalSigma)
{
	// 03C2
	// 03A3

	const char* c = "\xCF\x82";
	const size_t s = 255;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(2, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\xA3", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SingleSmallLetterFinalSigmaNotEnoughSpace)
{
	const char* c = "\xCF\x82";
	const size_t s = 1;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(0, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("", b);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST_F(Utf8ToTitleGreek, SingleSmallLetterFinalSigmaAmountOfBytes)
{
	const char* c = "\xCF\x82";
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(2, utf8totitle(c, strlen(c), nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, WordCapitalLetterSigma)
{
	// 03AB 03A3 039E 039A
	// 03AB 03C3 03BE 03BA

	const char* c = "\xCE\xAB\xCE\xA3\xCE\x9E\xCE\x9A";
	const size_t s = 255;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\xAB\xCF\x83\xCE\xBE\xCE\xBA", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, WordCapitalLetterSigmaNotEnoughSpace)
{
	const char* c = "\xCE\xAB\xCE\xA3\xCE\x9E\xCE\x9A";
	const size_t s = 5;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(4, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\xAB\xCF\x83", b);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST_F(Utf8ToTitleGreek, WordCapitalLetterSigmaAmountOfBytes)
{
	const char* c = "\xCE\xAB\xCE\xA3\xCE\x9E\xCE\x9A";
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, utf8totitle(c, strlen(c), nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, WordCapitalLetterSigmaAtEnd)
{
	// 03A3 039F 0399 03A3
	// 03A3 03BF 03B9 03C2

	const char* c = "\xCE\xA3\xCE\x9F\xCE\x99\xCE\xA3";
	const size_t s = 255;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\xA3\xCE\xBF\xCE\xB9\xCF\x82", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, WordCapitalLetterSigmaAtEndNotEnoughSpace)
{
	const char* c = "\xCE\xA3\xCE\x9F\xCE\x99\xCE\xA3";
	const size_t s = 6;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(6, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\xA3\xCE\xBF\xCE\xB9", b);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST_F(Utf8ToTitleGreek, WordCapitalLetterSigmaAtEndAmountOfBytes)
{
	const char* c = "\xCE\xA3\xCE\x9F\xCE\x99\xCE\xA3";
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, utf8totitle(c, strlen(c), nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, WordSmallLetterSigma)
{
	// 03B5 03BB 03C0 03C3
	// 0395 03BB 03C0 03C3

	const char* c = "\xCE\xB5\xCE\xBB\xCF\x80\xCF\x83";
	const size_t s = 255;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\x95\xCE\xBB\xCF\x80\xCF\x83", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, WordSmallLetterSigmaNotEnoughSpace)
{
	const char* c = "\xCE\xB5\xCE\xBB\xCF\x80\xCF\x83";
	const size_t s = 5;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(4, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\x95\xCE\xBB", b);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST_F(Utf8ToTitleGreek, WordSmallLetterSigmaAmountOfBytes)
{
	const char* c = "\xCE\xB5\xCE\xBB\xCF\x80\xCF\x83";
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(8, utf8totitle(c, strlen(c), nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, WordSmallLetterFinalSigma)
{
	// 03BE 03B2 039F 03AC 03C2
	// 039E 03B2 03BF 03AC 03C2

	const char* c = "\xCE\xBE\xCE\xB2\xCE\x9F\xCE\xAC\xCF\x82";
	const size_t s = 255;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(10, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\x9E\xCE\xB2\xCE\xBF\xCE\xAC\xCF\x82", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, WordSmallLetterFinalSigmaNotEnoughSpace)
{
	const char* c = "\xCE\xBE\xCE\xB2\xCE\x9F\xCE\xAC\xCF\x82";
	const size_t s = 4;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(4, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\x9E\xCE\xB2", b);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST_F(Utf8ToTitleGreek, WordSmallLetterFinalSigmaAmountOfBytes)
{
	const char* c = "\xCE\xBE\xCE\xB2\xCE\x9F\xCE\xAC\xCF\x82";
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(10, utf8totitle(c, strlen(c), nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SentenceCapitalLetterSigma)
{
	// 03A3 03A3 03A3 0020 03CD 03C4
	// 03A3 03C3 03C2 0020 038E 03C4

	const char* c = "\xCE\xA3\xCE\xA3\xCE\xA3 \xCF\x8D\xCF\x84";
	const size_t s = 255;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(11, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\xA3\xCF\x83\xCF\x82 \xCE\x8E\xCF\x84", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SentenceCapitalLetterSigmaNotEnoughSpace)
{
	const char* c = "\xCE\xA3\xCE\xA3\xCE\xA3 \xCF\x8D\xCF\x84";
	const size_t s = 4;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(4, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\xA3\xCF\x83", b);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST_F(Utf8ToTitleGreek, SentenceCapitalLetterSigmaAmountOfBytes)
{
	const char* c = "\xCE\xA3\xCE\xA3\xCE\xA3 \xCF\x8D\xCF\x84";
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(11, utf8totitle(c, strlen(c), nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SentenceSmallLetterSigma)
{
	// 03C1 03BC 03BE 03C3 0020 03C1 03C3 03C6 0020 03B9 03B1
	// 03A1 03BC 03BE 03C3 0020 03A1 03C3 03C6 0020 0399 03B1

	const char* c = "\xCF\x81\xCE\xBC\xCE\xBE\xCF\x83 \xCF\x81\xCF\x83\xCF\x86 \xCE\xB9\xCE\xB1";
	const size_t s = 255;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(20, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\xA1\xCE\xBC\xCE\xBE\xCF\x83 \xCE\xA1\xCF\x83\xCF\x86 \xCE\x99\xCE\xB1", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SentenceSmallLetterSigmaNotEnoughSpace)
{
	const char* c = "\xCF\x81\xCE\xBC\xCE\xBE\xCF\x83 \xCF\x81\xCF\x83\xCF\x86 \xCE\xB9\xCE\xB1";
	const size_t s = 7;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(6, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\xA1\xCE\xBC\xCE\xBE", b);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST_F(Utf8ToTitleGreek, SentenceSmallLetterSigmaAmountOfBytes)
{
	const char* c = "\xCF\x81\xCE\xBC\xCE\xBE\xCF\x83 \xCF\x81\xCF\x83\xCF\x86 \xCE\xB9\xCE\xB1";
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(20, utf8totitle(c, strlen(c), nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SentenceSmallLetterFinalSigma)
{
	// 03B8 03C2 0020 03B4 03C8 03B7
	// 0398 03C2 0020 0394 03C8 03B7

	const char* c = "\xCE\xB8\xCF\x82 \xCE\xB4\xCF\x88\xCE\xB7";
	const size_t s = 255;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(11, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\x98\xCF\x82 \xCE\x94\xCF\x88\xCE\xB7", b);
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}

TEST_F(Utf8ToTitleGreek, SentenceSmallLetterFinalSigmaNotEnoughSpace)
{
	const char* c = "\xCE\xB8\xCF\x82 \xCE\xB4\xCF\x88\xCE\xB7";
	const size_t s = 6;
	char b[256] = { 0 };
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(5, utf8totitle(c, strlen(c), b, s, &errors));
	EXPECT_UTF8EQ("\xCE\x98\xCF\x82 ", b);
	EXPECT_ERROREQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST_F(Utf8ToTitleGreek, SentenceSmallLetterFinalSigmaAmountOfBytes)
{
	const char* c = "\xCE\xB8\xCF\x82 \xCE\xB4\xCF\x88\xCE\xB7";
	int32_t errors = UTF8_ERR_NONE;

	EXPECT_EQ(11, utf8totitle(c, strlen(c), nullptr, 0, &errors));
	EXPECT_ERROREQ(UTF8_ERR_NONE, errors);
}<|endoftext|>


<commit_before>
#include "LCMSystem.h"
#include "RigidBodySystem.h"
#include "BotVisualizer.h"
#include "drakeAppUtil.h"

using namespace std;
using namespace Eigen;
using namespace Drake;

/** @page urdfLCMNode urdfLCMNode Application
 * @ingroup simulation
 * @brief Loads a urdf and simulates it, subscribing to LCM inputs and publishing LCM outputs
 *
 * This application loads a robot from urdf and runs a simulation, with every input
 * with an LCM type defined subscribed to the associated LCM channels, and every
 * output with an LCM type defined publishing on the associate channels.  See @ref lcm_vector_concept.
 *
 *
@verbatim
Usage:  urdfLCMNode [options] full_path_to_urdf_file
  with (case sensitive) options:
    --base [floating_type]  // can be "FIXED, ROLLPITCHYAW,or QUATERNION" (default: QUATERNION)
@endverbatim
 */

int main(int argc, char* argv[]) {
  if (argc < 2) {
    std::cerr << "Usage: " << argv[0] << " [options] full_path_to_urdf_file" << std::endl;
    return 1;
  }

  // todo: consider moving this logic into the RigidBodySystem class so it can be reused
  DrakeJoint::FloatingBaseType floating_base_type = DrakeJoint::QUATERNION;
  char* floating_base_option = getCommandLineOption(argv,argc+argv,"--base");
  if (floating_base_option) {
    if (strcmp(floating_base_option,"FIXED")==0) { floating_base_type = DrakeJoint::FIXED; }
    else if (strcmp(floating_base_option,"RPY")==0) { floating_base_type = DrakeJoint::ROLLPITCHYAW; }
    else if (strcmp(floating_base_option,"QUAT")==0) { floating_base_type = DrakeJoint::QUATERNION; }
    else { throw std::runtime_error(string("Unknown base type") + floating_base_option + "; must be FIXED,RPY, or QUAT"); }
  }

  auto rigid_body_sys = make_shared<RigidBodySystem>(argv[argc-1],floating_base_type);
  auto const & tree = rigid_body_sys->getRigidBodyTree();

  if (commandLineOptionExists(argv,argc+argv,"--add_flat_terrain")) {
    double box_width = 1000;
    double box_depth = 10;
    DrakeShapes::Box geom(Vector3d(box_width, box_width, box_depth));
    Matrix4d T_element_to_link = Matrix4d::Identity();
    T_element_to_link(2,3) = -box_depth/2;  // top of the box is at z=0
    auto & world = tree->bodies[0];
    Vector4d color;  color <<  0.9297, 0.7930, 0.6758, 1;  // was hex2dec({'ee','cb','ad'})'/256 in matlab
    world->addVisualElement(DrakeShapes::VisualElement(geom,T_element_to_link,color));
    tree->addCollisionElement(RigidBody::CollisionElement(geom,T_element_to_link,world),world,"terrain");
    tree->updateStaticCollisionElements();
  }

  shared_ptr<lcm::LCM> lcm = make_shared<lcm::LCM>();
  auto rigid_body_sys = make_shared<RigidBodySystem>(tree);
  auto visualizer = make_shared<BotVisualizer<RigidBodySystem::StateVector>>(lcm,tree);
  auto sys = cascade(rigid_body_sys, visualizer);

  SimulationOptions options = default_simulation_options;
  options.realtime_factor = 0.0;
  options.initial_step_size = 5e-3;

  runLCM(sys,lcm,0,std::numeric_limits<double>::max(),getInitialState(*sys),options);
//  simulate(*sys,0,std::numeric_limits<double>::max(),getInitialState(*sys),options);

  return 0;
}<commit_msg>fix build<commit_after>
#include "LCMSystem.h"
#include "RigidBodySystem.h"
#include "BotVisualizer.h"
#include "drakeAppUtil.h"

using namespace std;
using namespace Eigen;
using namespace Drake;

/** @page urdfLCMNode urdfLCMNode Application
 * @ingroup simulation
 * @brief Loads a urdf and simulates it, subscribing to LCM inputs and publishing LCM outputs
 *
 * This application loads a robot from urdf and runs a simulation, with every input
 * with an LCM type defined subscribed to the associated LCM channels, and every
 * output with an LCM type defined publishing on the associate channels.  See @ref lcm_vector_concept.
 *
 *
@verbatim
Usage:  urdfLCMNode [options] full_path_to_urdf_file
  with (case sensitive) options:
    --base [floating_type]  // can be "FIXED, ROLLPITCHYAW,or QUATERNION" (default: QUATERNION)
@endverbatim
 */

int main(int argc, char* argv[]) {
  if (argc < 2) {
    std::cerr << "Usage: " << argv[0] << " [options] full_path_to_urdf_file" << std::endl;
    return 1;
  }

  // todo: consider moving this logic into the RigidBodySystem class so it can be reused
  DrakeJoint::FloatingBaseType floating_base_type = DrakeJoint::QUATERNION;
  char* floating_base_option = getCommandLineOption(argv,argc+argv,"--base");
  if (floating_base_option) {
    if (strcmp(floating_base_option,"FIXED")==0) { floating_base_type = DrakeJoint::FIXED; }
    else if (strcmp(floating_base_option,"RPY")==0) { floating_base_type = DrakeJoint::ROLLPITCHYAW; }
    else if (strcmp(floating_base_option,"QUAT")==0) { floating_base_type = DrakeJoint::QUATERNION; }
    else { throw std::runtime_error(string("Unknown base type") + floating_base_option + "; must be FIXED,RPY, or QUAT"); }
  }

  auto rigid_body_sys = make_shared<RigidBodySystem>(argv[argc-1],floating_base_type);
  auto const & tree = rigid_body_sys->getRigidBodyTree();

  if (commandLineOptionExists(argv,argc+argv,"--add_flat_terrain")) {
    double box_width = 1000;
    double box_depth = 10;
    DrakeShapes::Box geom(Vector3d(box_width, box_width, box_depth));
    Matrix4d T_element_to_link = Matrix4d::Identity();
    T_element_to_link(2,3) = -box_depth/2;  // top of the box is at z=0
    auto & world = tree->bodies[0];
    Vector4d color;  color <<  0.9297, 0.7930, 0.6758, 1;  // was hex2dec({'ee','cb','ad'})'/256 in matlab
    world->addVisualElement(DrakeShapes::VisualElement(geom,T_element_to_link,color));
    tree->addCollisionElement(RigidBody::CollisionElement(geom,T_element_to_link,world),world,"terrain");
    tree->updateStaticCollisionElements();
  }

  shared_ptr<lcm::LCM> lcm = make_shared<lcm::LCM>();
  auto visualizer = make_shared<BotVisualizer<RigidBodySystem::StateVector>>(lcm,tree);
  auto sys = cascade(rigid_body_sys, visualizer);

  SimulationOptions options = default_simulation_options;
  options.realtime_factor = 0.0;
  options.initial_step_size = 5e-3;

  runLCM(sys,lcm,0,std::numeric_limits<double>::max(),getInitialState(*sys),options);
//  simulate(*sys,0,std::numeric_limits<double>::max(),getInitialState(*sys),options);

  return 0;
}<|endoftext|>


<commit_before>// This file is part of the ustl library, an STL implementation.
//
// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
//

#include <ustl.h>
#include <time.h>
using namespace ustl;

//----------------------------------------------------------------------
// Copy functions
//----------------------------------------------------------------------

#if __i386__
extern "C" void movsb_copy (const char* src, size_t nBytes, char* dest)
{
    asm volatile (
	"cld		\n\t"
	"rep movsb"
	: "=&S"(src), "=&D"(dest)
	: "0"(src), "1"(dest), "c"(nBytes)
	: "memory");
}

extern "C" void movsd_copy (const char* src, size_t nBytes, char* dest)
{
    asm volatile (
	"shr $2, %%ecx	\n\t"
	"cld		\n\t"
	"rep movsl"
	: "=&S"(src), "=&D"(dest)
	: "0"(src), "1"(dest), "c"(nBytes)
	: "memory");
}

extern "C" void risc_copy (const char* src, size_t nBytes, char* dest)
{
    asm volatile (
	"shr $2, %%ecx		\n\t"
	"1:			\n\t"
	"mov (%%esi), %%eax	\n\t"
	"add $4, %%esi		\n\t"
	"mov %%eax, (%%edi)	\n\t"
	"add $4, %%edi		\n\t"
	"dec %%ecx		\n\t"
	"jnz 1b"
	: "=&S"(src), "=&D"(dest)
	: "0"(src), "1"(dest), "c"(nBytes)
	: "memory", "eax");
}

extern "C" void unroll_copy (const char* src, size_t nBytes, char* dest)
{
    asm volatile (
	"shr $4, %%ecx		\n\t"
	"1:			\n\t"
	"mov (%%esi), %%eax	\n\t"
	"mov 4(%%esi), %%edx	\n\t"
	"mov %%eax, (%%edi)	\n\t"
	"mov %%edx, 4(%%edi)	\n\t"
	"mov 8(%%esi), %%eax	\n\t"
	"mov 12(%%esi), %%edx	\n\t"
	"mov %%eax, 8(%%edi)	\n\t"
	"mov %%edx, 12(%%edi)	\n\t"
	"add $16, %%esi		\n\t"
	"add $16, %%edi		\n\t"
	"dec %%ecx		\n\t"
	"jnz 1b"
	: "=&S"(src), "=&D"(dest)
	: "0"(src), "1"(dest), "c"(nBytes)
	: "memory", "eax", "edx");
}

#if CPU_HAS_MMX
extern "C" void mmx_copy (const char* src, size_t nBytes, char* dest)
{
    asm volatile (
	"shr $5, %%ecx		\n\t"
	"1:			\n\t"
#if CPU_HAS_3DNOW
	"prefetch 512(%%esi)	\n\t"
#else
	"prefetchnta 512(%%esi)	\n\t"
#endif
	"movq (%%esi), %%mm0	\n\t"
	"movq 8(%%esi), %%mm1	\n\t"
	"movq 16(%%esi), %%mm2	\n\t"
	"movq 24(%%esi), %%mm3	\n\t"
	"movq %%mm0, (%%edi)	\n\t"
	"movq %%mm1, 8(%%edi)	\n\t"
	"movq %%mm2, 16(%%edi)	\n\t"
	"movq %%mm3, 24(%%edi)	\n\t"
	"add $32, %%esi		\n\t"
	"add $32, %%edi		\n\t"
	"dec %%ecx		\n\t"
	"jnz 1b"
	: "=&S"(src), "=&D"(dest)
	: "0"(src), "1"(dest), "c"(nBytes)
	: "memory", "mm0", "mm1", "mm2", "mm3");
    simd::reset_mmx();
}
#endif // CPU_HAS_MMX

#if CPU_HAS_SSE
extern "C" void sse_copy (const char* src, size_t nBytes, char* dest)
{
    const size_t nHeadBytes = min (nBytes, Align(uintptr_t(src), 16U) - uintptr_t(src));
    for (uoff_t i = 0; i < nHeadBytes; ++ i)
	*dest++ = *src++;
    nBytes -= nHeadBytes;
    if (!(uintptr_t(dest) % 16)) {
	const size_t nMiddleBlocks = nBytes / 32;
	for (uoff_t i = 0; i < nMiddleBlocks; ++ i) {
	    prefetch (src + 512, 0, 0);
	    asm volatile (
		"movaps (%%esi), %%xmm0		\n\t"
		"movaps 16(%%esi), %%xmm1	\n\t"
		"movntps %%xmm0, (%%edi)	\n\t"
		"movntps %%xmm1, 16(%%edi)"
		: : "S"(src), "D"(dest)
		: "memory", "xmm0", "xmm1", "xmm2", "xmm3");
	    src += 32;
	    dest += 32;
	}
	nBytes %= 32;
    }
    for (uoff_t i = 0; i < nBytes; ++ i)
	*dest++ = *src++;
}
#endif // CPU_HAS_SSE
#endif // __i386__

extern "C" void memcpy_copy (const char* src, size_t nBytes, char* dest)
{
    memcpy (dest, src, nBytes);
}

template <typename CopyFunction>
void TestCopyFunction (const char* name, CopyFunction pfn)
{
    const uoff_t misalignment = 0;
    const uoff_t headBytes = 0;
    const uoff_t tailBytes = 0;

    const size_t nIter = 128;
    const size_t nBytes = 1024 * 1024 + misalignment;

    string buf1 (nBytes), buf2 (nBytes);
    iota (buf1.begin(), buf1.end(), '\x1');
    fill (buf2, 0);
    const clock_t first = clock();
    for (uoff_t i = 0; i < nIter; ++ i)
	(*pfn)(buf1.cdata() + headBytes, nBytes - headBytes - tailBytes, buf2.data() + headBytes + misalignment);
    clock_t last = clock();
    last += (last == first);
    const size_t mbps = nIter * CLOCKS_PER_SEC / (last - first);
    cout << name << " transfer rate is " << mbps << " Mbps, data is ";
    size_t nBad = 0;
    for (uoff_t i = headBytes; i < buf1.size() - tailBytes; ++ i)
	nBad += (buf1[i] != buf2[i + misalignment]);
    if (!nBad)
	cout << "GOOD" << endl;
    else {
	cout << "BAD" << endl;
	for (uoff_t i = headBytes; i < buf1.size() - tailBytes; ++ i)
	    if (buf1[i] != buf2[i + misalignment])
		cout << "\t\t" << i << "\tbuf1: " << (int) buf1[i] << ", buf2: " << (int) buf2[i + misalignment] << endl;
    }
    cout.flush();
}

//----------------------------------------------------------------------
// Fill functions
//----------------------------------------------------------------------

#if __i386__
extern "C" void stosb_fill (const char* dest, size_t nBytes, char v)
{
    asm volatile (
	"cld		\n\t"
	"rep stosb	\n\t"
	: "=&D"(dest)
	: "0"(dest), "a"(v), "c"(nBytes)
	: "memory");
}

extern "C" void stosd_fill (const char* dest, size_t nBytes, char v)
{
    uint32_t lv;
    pack_type (v, lv);
    asm volatile (
	"shr $2, %%ecx		\n\t"
	"cld			\n\t"
	"rep stosl		\n\t"
	: "=&D"(dest)
	: "0"(dest), "a"(lv), "c"(nBytes)
	: "memory");
}

extern "C" void risc_fill (const char* dest, size_t nBytes, char v)
{
    uint32_t lv;
    pack_type (v, lv);
    asm volatile (
	"shr $2, %%ecx		\n\t"
	"1:			\n\t"
	"mov %%eax, (%%edi)	\n\t"
	"add $4, %%edi		\n\t"
	"dec %%ecx		\n\t"
	"jnz 1b			\n\t"
	: "=&D"(dest)
	: "0"(dest), "a"(lv), "c"(nBytes)
	: "memory");
}

extern "C" void unroll_fill (const char* dest, size_t nBytes, char v)
{
    uint32_t lv;
    pack_type (v, lv);
    asm volatile (
	"shr $4, %%ecx		\n\t"
	"1:			\n\t"
	"mov %%eax, (%%edi)	\n\t"
	"mov %%eax, 4(%%edi)	\n\t"
	"mov %%eax, 8(%%edi)	\n\t"
	"mov %%eax, 12(%%edi)	\n\t"
	"add $16, %%edi		\n\t"
	"dec %%ecx		\n\t"
	"jnz 1b			\n\t"
	: "=&D"(dest)
	: "0"(dest), "a"(lv), "c"(nBytes)
	: "memory");
}

#if CPU_HAS_MMX && HAVE_INT64_T
extern "C" void mmx_fill (const char* dest, size_t nBytes, char v)
{
    uint64_t lv;
    pack_type (v, lv);
    asm volatile (
	"shr $5, %%ecx		\n\t"
#if CPU_HAS_3DNOW
	"prefetchw 512(%%edi)	\n\t"
#endif
	"1:			\n\t"
	"movq %2, (%%edi)	\n\t"
	"movq %2, 8(%%edi)	\n\t"
	"movq %2, 16(%%edi)	\n\t"
	"movq %2, 24(%%edi)	\n\t"
	"add $32, %%esi		\n\t"
	"add $32, %%edi		\n\t"
	"dec %%ecx		\n\t"
	"jnz 1b			\n\t"
	"emms"
	: "=&D"(dest)
	: "0"(dest), "y"(lv), "c"(nBytes)
	: "memory");
}
#endif // CPU_HAS_MMX
#endif // __i386__

template <typename FillFunction>
void TestFillFunction (const char* name, FillFunction pfn)
{
    const size_t nIter = 256;
    const size_t nBytes = 1024 * 1024;
    string buf1 (nBytes), buf2 (nBytes);
    iota (buf1.begin(), buf1.end(), '\x1');
    fill (buf2, 42);
    clock_t first = clock();
    for (uoff_t i = 0; i < nIter; ++ i)
	(*pfn)(buf1.data(), nBytes, char(42));
    clock_t last = clock();
    last += (last == first);
    const size_t mbps = nIter * CLOCKS_PER_SEC / (last - first);
    cout << name << " transfer rate is " << mbps << " Mbps, data is ";
    if (buf1 == buf2)
	cout << "GOOD" << endl;
    else
	cout << "BAD" << endl;
    cout.flush();
}

//----------------------------------------------------------------------

int main (void)
{
    cout << "Testing fill" << endl;
    cout << "---------------------------------------------------------" << endl;
    TestFillFunction ("fill_n\t\t", &fill_n<char*, char>);
#if __i386__
#if CPU_HAS_MMX && HAVE_INT64_T
    TestFillFunction ("mmx_fill\t", &mmx_fill);
#endif
    TestFillFunction ("stosb_fill\t", &stosb_fill);
    TestFillFunction ("stosd_fill\t", &stosd_fill);
    TestFillFunction ("unroll_fill\t", &unroll_fill);
    TestFillFunction ("risc_fill\t", &risc_fill);
#endif

    cout << endl;
    cout << "Testing copy" << endl;
    cout << "---------------------------------------------------------" << endl;
    TestCopyFunction ("copy_n\t\t", &copy_n<const char*, char*>);
#if __i386__
#if CPU_HAS_SSE
    TestCopyFunction ("sse_copy\t", &sse_copy);
#endif
#if CPU_HAS_MMX
    TestCopyFunction ("mmx_copy\t", &mmx_copy);
#endif
    TestCopyFunction ("movsb_copy\t", &movsb_copy);
    TestCopyFunction ("movsd_copy\t", &movsd_copy);
    TestCopyFunction ("risc_copy\t", &risc_copy);
    TestCopyFunction ("unroll_copy\t", &unroll_copy);
#endif
    TestCopyFunction ("memcpy_copy\t", &memcpy_copy);

    return (EXIT_SUCCESS);
}

<commit_msg>Fixed mmx_fill benchmark to not clobber esi<commit_after>// This file is part of the ustl library, an STL implementation.
//
// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
//

#include <ustl.h>
#include <time.h>
using namespace ustl;

//----------------------------------------------------------------------
// Copy functions
//----------------------------------------------------------------------

#if __i386__
extern "C" void movsb_copy (const char* src, size_t nBytes, char* dest)
{
    asm volatile (
	"cld		\n\t"
	"rep movsb"
	: "=&S"(src), "=&D"(dest)
	: "0"(src), "1"(dest), "c"(nBytes)
	: "memory");
}

extern "C" void movsd_copy (const char* src, size_t nBytes, char* dest)
{
    asm volatile (
	"shr $2, %%ecx	\n\t"
	"cld		\n\t"
	"rep movsl"
	: "=&S"(src), "=&D"(dest)
	: "0"(src), "1"(dest), "c"(nBytes)
	: "memory");
}

extern "C" void risc_copy (const char* src, size_t nBytes, char* dest)
{
    asm volatile (
	"shr $2, %%ecx		\n\t"
	"1:			\n\t"
	"mov (%%esi), %%eax	\n\t"
	"add $4, %%esi		\n\t"
	"mov %%eax, (%%edi)	\n\t"
	"add $4, %%edi		\n\t"
	"dec %%ecx		\n\t"
	"jnz 1b"
	: "=&S"(src), "=&D"(dest)
	: "0"(src), "1"(dest), "c"(nBytes)
	: "memory", "eax");
}

extern "C" void unroll_copy (const char* src, size_t nBytes, char* dest)
{
    asm volatile (
	"shr $4, %%ecx		\n\t"
	"1:			\n\t"
	"mov (%%esi), %%eax	\n\t"
	"mov 4(%%esi), %%edx	\n\t"
	"mov %%eax, (%%edi)	\n\t"
	"mov %%edx, 4(%%edi)	\n\t"
	"mov 8(%%esi), %%eax	\n\t"
	"mov 12(%%esi), %%edx	\n\t"
	"mov %%eax, 8(%%edi)	\n\t"
	"mov %%edx, 12(%%edi)	\n\t"
	"add $16, %%esi		\n\t"
	"add $16, %%edi		\n\t"
	"dec %%ecx		\n\t"
	"jnz 1b"
	: "=&S"(src), "=&D"(dest)
	: "0"(src), "1"(dest), "c"(nBytes)
	: "memory", "eax", "edx");
}

#if CPU_HAS_MMX
extern "C" void mmx_copy (const char* src, size_t nBytes, char* dest)
{
    asm volatile (
	"shr $5, %%ecx		\n\t"
	"1:			\n\t"
#if CPU_HAS_3DNOW
	"prefetch 512(%%esi)	\n\t"
#else
	"prefetchnta 512(%%esi)	\n\t"
#endif
	"movq (%%esi), %%mm0	\n\t"
	"movq 8(%%esi), %%mm1	\n\t"
	"movq 16(%%esi), %%mm2	\n\t"
	"movq 24(%%esi), %%mm3	\n\t"
	"movq %%mm0, (%%edi)	\n\t"
	"movq %%mm1, 8(%%edi)	\n\t"
	"movq %%mm2, 16(%%edi)	\n\t"
	"movq %%mm3, 24(%%edi)	\n\t"
	"add $32, %%esi		\n\t"
	"add $32, %%edi		\n\t"
	"dec %%ecx		\n\t"
	"jnz 1b"
	: "=&S"(src), "=&D"(dest)
	: "0"(src), "1"(dest), "c"(nBytes)
	: "memory", "mm0", "mm1", "mm2", "mm3");
    simd::reset_mmx();
}
#endif // CPU_HAS_MMX

#if CPU_HAS_SSE
extern "C" void sse_copy (const char* src, size_t nBytes, char* dest)
{
    const size_t nHeadBytes = min (nBytes, Align(uintptr_t(src), 16U) - uintptr_t(src));
    for (uoff_t i = 0; i < nHeadBytes; ++ i)
	*dest++ = *src++;
    nBytes -= nHeadBytes;
    if (!(uintptr_t(dest) % 16)) {
	const size_t nMiddleBlocks = nBytes / 32;
	for (uoff_t i = 0; i < nMiddleBlocks; ++ i) {
	    prefetch (src + 512, 0, 0);
	    asm volatile (
		"movaps (%%esi), %%xmm0		\n\t"
		"movaps 16(%%esi), %%xmm1	\n\t"
		"movntps %%xmm0, (%%edi)	\n\t"
		"movntps %%xmm1, 16(%%edi)"
		: : "S"(src), "D"(dest)
		: "memory", "xmm0", "xmm1", "xmm2", "xmm3");
	    src += 32;
	    dest += 32;
	}
	nBytes %= 32;
    }
    for (uoff_t i = 0; i < nBytes; ++ i)
	*dest++ = *src++;
}
#endif // CPU_HAS_SSE
#endif // __i386__

extern "C" void memcpy_copy (const char* src, size_t nBytes, char* dest)
{
    memcpy (dest, src, nBytes);
}

template <typename CopyFunction>
void TestCopyFunction (const char* name, CopyFunction pfn)
{
    const uoff_t misalignment = 0;
    const uoff_t headBytes = 0;
    const uoff_t tailBytes = 0;

    const size_t nIter = 128;
    const size_t nBytes = 1024 * 1024 + misalignment;

    string buf1 (nBytes), buf2 (nBytes);
    iota (buf1.begin(), buf1.end(), '\x1');
    fill (buf2, 0);
    const clock_t first = clock();
    for (uoff_t i = 0; i < nIter; ++ i)
	(*pfn)(buf1.cdata() + headBytes, nBytes - headBytes - tailBytes, buf2.data() + headBytes + misalignment);
    clock_t last = clock();
    last += (last == first);
    const size_t mbps = nIter * CLOCKS_PER_SEC / (last - first);
    cout << name << " transfer rate is " << mbps << " Mbps, data is ";
    size_t nBad = 0;
    for (uoff_t i = headBytes; i < buf1.size() - tailBytes; ++ i)
	nBad += (buf1[i] != buf2[i + misalignment]);
    if (!nBad)
	cout << "GOOD" << endl;
    else {
	cout << "BAD" << endl;
	for (uoff_t i = headBytes; i < buf1.size() - tailBytes; ++ i)
	    if (buf1[i] != buf2[i + misalignment])
		cout << "\t\t" << i << "\tbuf1: " << (int) buf1[i] << ", buf2: " << (int) buf2[i + misalignment] << endl;
    }
    cout.flush();
}

//----------------------------------------------------------------------
// Fill functions
//----------------------------------------------------------------------

#if __i386__
extern "C" void stosb_fill (const char* dest, size_t nBytes, char v)
{
    asm volatile (
	"cld		\n\t"
	"rep stosb	\n\t"
	: "=&D"(dest)
	: "0"(dest), "a"(v), "c"(nBytes)
	: "memory");
}

extern "C" void stosd_fill (const char* dest, size_t nBytes, char v)
{
    uint32_t lv;
    pack_type (v, lv);
    asm volatile (
	"shr $2, %%ecx		\n\t"
	"cld			\n\t"
	"rep stosl		\n\t"
	: "=&D"(dest)
	: "0"(dest), "a"(lv), "c"(nBytes)
	: "memory");
}

extern "C" void risc_fill (const char* dest, size_t nBytes, char v)
{
    uint32_t lv;
    pack_type (v, lv);
    asm volatile (
	"shr $2, %%ecx		\n\t"
	"1:			\n\t"
	"mov %%eax, (%%edi)	\n\t"
	"add $4, %%edi		\n\t"
	"dec %%ecx		\n\t"
	"jnz 1b			\n\t"
	: "=&D"(dest)
	: "0"(dest), "a"(lv), "c"(nBytes)
	: "memory");
}

extern "C" void unroll_fill (const char* dest, size_t nBytes, char v)
{
    uint32_t lv;
    pack_type (v, lv);
    asm volatile (
	"shr $4, %%ecx		\n\t"
	"1:			\n\t"
	"mov %%eax, (%%edi)	\n\t"
	"mov %%eax, 4(%%edi)	\n\t"
	"mov %%eax, 8(%%edi)	\n\t"
	"mov %%eax, 12(%%edi)	\n\t"
	"add $16, %%edi		\n\t"
	"dec %%ecx		\n\t"
	"jnz 1b			\n\t"
	: "=&D"(dest)
	: "0"(dest), "a"(lv), "c"(nBytes)
	: "memory");
}

#if CPU_HAS_MMX
extern "C" void mmx_fill (const char* dest, size_t nBytes, char v)
{
    prefetch (dest + 512, 1, 0);
    asm volatile (
	"movd %0, %%mm0		\n\t"
	"punpcklbw %%mm0, %%mm0	\n\t"
	"punpcklwd %%mm0, %%mm0	\n\t"
	"punpckldq %%mm0, %%mm0"
	::"r"(uint32_t(v))
	: "mm0", "st");
    const size_t nBlocks (nBytes / 32);
    for (uoff_t i = 0; i < nBlocks; ++ i) {
	asm volatile (
	    "movq %%mm0, (%%edi)	\n\t"
	    "movq %%mm0, 8(%%edi)	\n\t"
	    "movq %%mm0, 16(%%edi)	\n\t"
	    "movq %%mm0, 24(%%edi)"
	    :: "D"(dest)
	    : "memory");
	dest += 32;
    }
    simd::reset_mmx();
}
#endif // CPU_HAS_MMX
#endif // __i386__

template <typename FillFunction>
void TestFillFunction (const char* name, FillFunction pfn)
{
    const size_t nIter = 256;
    const size_t nBytes = 1024 * 1024;
    string buf1 (nBytes), buf2 (nBytes);
    iota (buf1.begin(), buf1.end(), '\x1');
    fill (buf2, 42);
    clock_t first = clock();
    for (uoff_t i = 0; i < nIter; ++ i)
	(*pfn)(buf1.data(), nBytes, char(42));
    clock_t last = clock();
    last += (last == first);
    const size_t mbps = nIter * CLOCKS_PER_SEC / (last - first);
    cout << name << " transfer rate is " << mbps << " Mbps, data is ";
    if (buf1 == buf2)
	cout << "GOOD" << endl;
    else
	cout << "BAD" << endl;
    cout.flush();
}

//----------------------------------------------------------------------

int main (void)
{
    cout << "Testing fill" << endl;
    cout << "---------------------------------------------------------" << endl;
    TestFillFunction ("fill_n\t\t", &fill_n<char*, char>);
#if __i386__
#if CPU_HAS_MMX && HAVE_INT64_T
    TestFillFunction ("mmx_fill\t", &mmx_fill);
#endif
    TestFillFunction ("stosb_fill\t", &stosb_fill);
    TestFillFunction ("stosd_fill\t", &stosd_fill);
    TestFillFunction ("unroll_fill\t", &unroll_fill);
    TestFillFunction ("risc_fill\t", &risc_fill);
#endif

    cout << endl;
    cout << "Testing copy" << endl;
    cout << "---------------------------------------------------------" << endl;
    TestCopyFunction ("copy_n\t\t", &copy_n<const char*, char*>);
#if __i386__
#if CPU_HAS_SSE
    TestCopyFunction ("sse_copy\t", &sse_copy);
#endif
#if CPU_HAS_MMX
    TestCopyFunction ("mmx_copy\t", &mmx_copy);
#endif
    TestCopyFunction ("movsb_copy\t", &movsb_copy);
    TestCopyFunction ("movsd_copy\t", &movsd_copy);
    TestCopyFunction ("risc_copy\t", &risc_copy);
    TestCopyFunction ("unroll_copy\t", &unroll_copy);
#endif
    TestCopyFunction ("memcpy_copy\t", &memcpy_copy);

    return (EXIT_SUCCESS);
}

<|endoftext|>