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

#include <string>

#include "base/basictypes.h"
#include "base/pickle.h"
#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

const int testint = 2093847192;
const std::string teststr("Hello world"); // note non-aligned string length
const std::wstring testwstr(L"Hello, world");
const char testdata[] = "AAA\0BBB\0";
const int testdatalen = arraysize(testdata) - 1;
const bool testbool1 = false;
const bool testbool2 = true;

// checks that the result
void VerifyResult(const Pickle& pickle) {
  void* iter = NULL;

  int outint;
  EXPECT_TRUE(pickle.ReadInt(&iter, &outint));
  EXPECT_EQ(testint, outint);

  std::string outstr;
  EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
  EXPECT_EQ(teststr, outstr);

  std::wstring outwstr;
  EXPECT_TRUE(pickle.ReadWString(&iter, &outwstr));
  EXPECT_EQ(testwstr, outwstr);

  bool outbool;
  EXPECT_TRUE(pickle.ReadBool(&iter, &outbool));
  EXPECT_EQ(testbool1, outbool);
  EXPECT_TRUE(pickle.ReadBool(&iter, &outbool));
  EXPECT_EQ(testbool2, outbool);

  const char* outdata;
  int outdatalen;
  EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen));
  EXPECT_EQ(testdatalen, outdatalen);
  EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0);

  EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen));
  EXPECT_EQ(testdatalen, outdatalen);
  EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0);

  // reads past the end should fail
  EXPECT_FALSE(pickle.ReadInt(&iter, &outint));
}

}  // namespace

TEST(PickleTest, EncodeDecode) {
  Pickle pickle;

  EXPECT_TRUE(pickle.WriteInt(testint));
  EXPECT_TRUE(pickle.WriteString(teststr));
  EXPECT_TRUE(pickle.WriteWString(testwstr));
  EXPECT_TRUE(pickle.WriteBool(testbool1));
  EXPECT_TRUE(pickle.WriteBool(testbool2));
  EXPECT_TRUE(pickle.WriteData(testdata, testdatalen));

  // Over allocate BeginWriteData so we can test TrimWriteData.
  char* dest = pickle.BeginWriteData(testdatalen + 100);
  EXPECT_TRUE(dest);
  memcpy(dest, testdata, testdatalen);

  pickle.TrimWriteData(testdatalen);

  VerifyResult(pickle);

  // test copy constructor
  Pickle pickle2(pickle);
  VerifyResult(pickle2);

  // test operator=
  Pickle pickle3;
  pickle3 = pickle;
  VerifyResult(pickle3);
}

TEST(PickleTest, ZeroLenStr) {
  Pickle pickle;
  EXPECT_TRUE(pickle.WriteString(""));

  void* iter = NULL;
  std::string outstr;
  EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
  EXPECT_EQ("", outstr);
}

TEST(PickleTest, ZeroLenWStr) {
  Pickle pickle;
  EXPECT_TRUE(pickle.WriteWString(L""));

  void* iter = NULL;
  std::string outstr;
  EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
  EXPECT_EQ("", outstr);
}

TEST(PickleTest, BadLenStr) {
  Pickle pickle;
  EXPECT_TRUE(pickle.WriteInt(-2));

  void* iter = NULL;
  std::string outstr;
  EXPECT_FALSE(pickle.ReadString(&iter, &outstr));
}

TEST(PickleTest, BadLenWStr) {
  Pickle pickle;
  EXPECT_TRUE(pickle.WriteInt(-1));

  void* iter = NULL;
  std::wstring woutstr;
  EXPECT_FALSE(pickle.ReadWString(&iter, &woutstr));
}

TEST(PickleTest, FindNext) {
  Pickle pickle;
  EXPECT_TRUE(pickle.WriteInt(1));
  EXPECT_TRUE(pickle.WriteString("Domo"));

  const char* start = reinterpret_cast<const char*>(pickle.data());
  const char* end = start + pickle.size();

  EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end));
  EXPECT_TRUE(NULL == Pickle::FindNext(pickle.header_size_, start, end - 1));
  EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1));
}

TEST(PickleTest, IteratorHasRoom) {
  Pickle pickle;
  EXPECT_TRUE(pickle.WriteInt(1));
  EXPECT_TRUE(pickle.WriteInt(2));

  const void* iter = 0;
  EXPECT_FALSE(pickle.IteratorHasRoomFor(iter, 1));
  iter = pickle.payload();
  EXPECT_TRUE(pickle.IteratorHasRoomFor(iter, 0));
  EXPECT_TRUE(pickle.IteratorHasRoomFor(iter, 1));
  EXPECT_FALSE(pickle.IteratorHasRoomFor(iter, -1));
  EXPECT_TRUE(pickle.IteratorHasRoomFor(iter, sizeof(int) * 2));
  EXPECT_FALSE(pickle.IteratorHasRoomFor(iter, (sizeof(int) * 2) + 1));
}

TEST(PickleTest, Resize) {
  size_t unit = Pickle::kPayloadUnit;
  scoped_array<char> data(new char[unit]);
  char* data_ptr = data.get();
  for (size_t i = 0; i < unit; i++)
    data_ptr[i] = 'G';

  // construct a message that will be exactly the size of one payload unit,
  // note that any data will have a 4-byte header indicating the size
  const size_t payload_size_after_header = unit - sizeof(uint32);
  Pickle pickle;
  pickle.WriteData(data_ptr,
      static_cast<int>(payload_size_after_header - sizeof(uint32)));
  size_t cur_payload = payload_size_after_header;

  // note: we assume 'unit' is a power of 2
  EXPECT_EQ(unit, pickle.capacity());
  EXPECT_EQ(pickle.payload_size(), payload_size_after_header);

  // fill out a full page (noting data header)
  pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32)));
  cur_payload += unit;
  EXPECT_EQ(unit * 2, pickle.capacity());
  EXPECT_EQ(cur_payload, pickle.payload_size());

  // one more byte should double the capacity
  pickle.WriteData(data_ptr, 1);
  cur_payload += 5;
  EXPECT_EQ(unit * 4, pickle.capacity());
  EXPECT_EQ(cur_payload, pickle.payload_size());
}

namespace {

struct CustomHeader : Pickle::Header {
  int blah;
};

}  // namespace

TEST(PickleTest, HeaderPadding) {
  const uint32 kMagic = 0x12345678;

  Pickle pickle(sizeof(CustomHeader));
  pickle.WriteInt(kMagic);

  // this should not overwrite the 'int' payload
  pickle.headerT<CustomHeader>()->blah = 10;

  void* iter = NULL;
  int result;
  ASSERT_TRUE(pickle.ReadInt(&iter, &result));

  EXPECT_EQ(static_cast<uint32>(result), kMagic);
}

TEST(PickleTest, EqualsOperator) {
  Pickle source;
  source.WriteInt(1);

  Pickle copy_refs_source_buffer(static_cast<const char*>(source.data()),
                                 source.size());
  Pickle copy;
  copy = copy_refs_source_buffer;
  ASSERT_EQ(source.size(), copy.size());
}

TEST(PickleTest, EvilLengths) {
  Pickle source;
  std::string str(10000, 'A');
  source.WriteData(str.c_str(), 100000);
  // ReadString16 used to have its read buffer length calculation wrong leading
  // to out-of-bounds reading.
  void* iter = NULL;
  string16 str16;
  EXPECT_FALSE(source.ReadString16(&iter, &str16));

  // And check we didn't break ReadString16.
  str16 = (wchar_t) 'A';
  Pickle str16_pickle;
  str16_pickle.WriteString16(str16);
  iter = NULL;
  EXPECT_TRUE(str16_pickle.ReadString16(&iter, &str16));
  EXPECT_EQ(1U, str16.length());

  // Check we don't fail in a length check with large WStrings.
  Pickle big_len;
  big_len.WriteInt(1 << 30);
  iter = NULL;
  std::wstring wstr;
  EXPECT_FALSE(big_len.ReadWString(&iter, &wstr));
}

<commit_msg>Fix embarassing purify error due to length mismatch.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>

#include "base/basictypes.h"
#include "base/pickle.h"
#include "base/scoped_ptr.h"
#include "base/string16.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

const int testint = 2093847192;
const std::string teststr("Hello world"); // note non-aligned string length
const std::wstring testwstr(L"Hello, world");
const char testdata[] = "AAA\0BBB\0";
const int testdatalen = arraysize(testdata) - 1;
const bool testbool1 = false;
const bool testbool2 = true;

// checks that the result
void VerifyResult(const Pickle& pickle) {
  void* iter = NULL;

  int outint;
  EXPECT_TRUE(pickle.ReadInt(&iter, &outint));
  EXPECT_EQ(testint, outint);

  std::string outstr;
  EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
  EXPECT_EQ(teststr, outstr);

  std::wstring outwstr;
  EXPECT_TRUE(pickle.ReadWString(&iter, &outwstr));
  EXPECT_EQ(testwstr, outwstr);

  bool outbool;
  EXPECT_TRUE(pickle.ReadBool(&iter, &outbool));
  EXPECT_EQ(testbool1, outbool);
  EXPECT_TRUE(pickle.ReadBool(&iter, &outbool));
  EXPECT_EQ(testbool2, outbool);

  const char* outdata;
  int outdatalen;
  EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen));
  EXPECT_EQ(testdatalen, outdatalen);
  EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0);

  EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen));
  EXPECT_EQ(testdatalen, outdatalen);
  EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0);

  // reads past the end should fail
  EXPECT_FALSE(pickle.ReadInt(&iter, &outint));
}

}  // namespace

TEST(PickleTest, EncodeDecode) {
  Pickle pickle;

  EXPECT_TRUE(pickle.WriteInt(testint));
  EXPECT_TRUE(pickle.WriteString(teststr));
  EXPECT_TRUE(pickle.WriteWString(testwstr));
  EXPECT_TRUE(pickle.WriteBool(testbool1));
  EXPECT_TRUE(pickle.WriteBool(testbool2));
  EXPECT_TRUE(pickle.WriteData(testdata, testdatalen));

  // Over allocate BeginWriteData so we can test TrimWriteData.
  char* dest = pickle.BeginWriteData(testdatalen + 100);
  EXPECT_TRUE(dest);
  memcpy(dest, testdata, testdatalen);

  pickle.TrimWriteData(testdatalen);

  VerifyResult(pickle);

  // test copy constructor
  Pickle pickle2(pickle);
  VerifyResult(pickle2);

  // test operator=
  Pickle pickle3;
  pickle3 = pickle;
  VerifyResult(pickle3);
}

TEST(PickleTest, ZeroLenStr) {
  Pickle pickle;
  EXPECT_TRUE(pickle.WriteString(""));

  void* iter = NULL;
  std::string outstr;
  EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
  EXPECT_EQ("", outstr);
}

TEST(PickleTest, ZeroLenWStr) {
  Pickle pickle;
  EXPECT_TRUE(pickle.WriteWString(L""));

  void* iter = NULL;
  std::string outstr;
  EXPECT_TRUE(pickle.ReadString(&iter, &outstr));
  EXPECT_EQ("", outstr);
}

TEST(PickleTest, BadLenStr) {
  Pickle pickle;
  EXPECT_TRUE(pickle.WriteInt(-2));

  void* iter = NULL;
  std::string outstr;
  EXPECT_FALSE(pickle.ReadString(&iter, &outstr));
}

TEST(PickleTest, BadLenWStr) {
  Pickle pickle;
  EXPECT_TRUE(pickle.WriteInt(-1));

  void* iter = NULL;
  std::wstring woutstr;
  EXPECT_FALSE(pickle.ReadWString(&iter, &woutstr));
}

TEST(PickleTest, FindNext) {
  Pickle pickle;
  EXPECT_TRUE(pickle.WriteInt(1));
  EXPECT_TRUE(pickle.WriteString("Domo"));

  const char* start = reinterpret_cast<const char*>(pickle.data());
  const char* end = start + pickle.size();

  EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end));
  EXPECT_TRUE(NULL == Pickle::FindNext(pickle.header_size_, start, end - 1));
  EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1));
}

TEST(PickleTest, IteratorHasRoom) {
  Pickle pickle;
  EXPECT_TRUE(pickle.WriteInt(1));
  EXPECT_TRUE(pickle.WriteInt(2));

  const void* iter = 0;
  EXPECT_FALSE(pickle.IteratorHasRoomFor(iter, 1));
  iter = pickle.payload();
  EXPECT_TRUE(pickle.IteratorHasRoomFor(iter, 0));
  EXPECT_TRUE(pickle.IteratorHasRoomFor(iter, 1));
  EXPECT_FALSE(pickle.IteratorHasRoomFor(iter, -1));
  EXPECT_TRUE(pickle.IteratorHasRoomFor(iter, sizeof(int) * 2));
  EXPECT_FALSE(pickle.IteratorHasRoomFor(iter, (sizeof(int) * 2) + 1));
}

TEST(PickleTest, Resize) {
  size_t unit = Pickle::kPayloadUnit;
  scoped_array<char> data(new char[unit]);
  char* data_ptr = data.get();
  for (size_t i = 0; i < unit; i++)
    data_ptr[i] = 'G';

  // construct a message that will be exactly the size of one payload unit,
  // note that any data will have a 4-byte header indicating the size
  const size_t payload_size_after_header = unit - sizeof(uint32);
  Pickle pickle;
  pickle.WriteData(data_ptr,
      static_cast<int>(payload_size_after_header - sizeof(uint32)));
  size_t cur_payload = payload_size_after_header;

  // note: we assume 'unit' is a power of 2
  EXPECT_EQ(unit, pickle.capacity());
  EXPECT_EQ(pickle.payload_size(), payload_size_after_header);

  // fill out a full page (noting data header)
  pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32)));
  cur_payload += unit;
  EXPECT_EQ(unit * 2, pickle.capacity());
  EXPECT_EQ(cur_payload, pickle.payload_size());

  // one more byte should double the capacity
  pickle.WriteData(data_ptr, 1);
  cur_payload += 5;
  EXPECT_EQ(unit * 4, pickle.capacity());
  EXPECT_EQ(cur_payload, pickle.payload_size());
}

namespace {

struct CustomHeader : Pickle::Header {
  int blah;
};

}  // namespace

TEST(PickleTest, HeaderPadding) {
  const uint32 kMagic = 0x12345678;

  Pickle pickle(sizeof(CustomHeader));
  pickle.WriteInt(kMagic);

  // this should not overwrite the 'int' payload
  pickle.headerT<CustomHeader>()->blah = 10;

  void* iter = NULL;
  int result;
  ASSERT_TRUE(pickle.ReadInt(&iter, &result));

  EXPECT_EQ(static_cast<uint32>(result), kMagic);
}

TEST(PickleTest, EqualsOperator) {
  Pickle source;
  source.WriteInt(1);

  Pickle copy_refs_source_buffer(static_cast<const char*>(source.data()),
                                 source.size());
  Pickle copy;
  copy = copy_refs_source_buffer;
  ASSERT_EQ(source.size(), copy.size());
}

TEST(PickleTest, EvilLengths) {
  Pickle source;
  std::string str(100000, 'A');
  source.WriteData(str.c_str(), 100000);
  // ReadString16 used to have its read buffer length calculation wrong leading
  // to out-of-bounds reading.
  void* iter = NULL;
  string16 str16;
  EXPECT_FALSE(source.ReadString16(&iter, &str16));

  // And check we didn't break ReadString16.
  str16 = (wchar_t) 'A';
  Pickle str16_pickle;
  str16_pickle.WriteString16(str16);
  iter = NULL;
  EXPECT_TRUE(str16_pickle.ReadString16(&iter, &str16));
  EXPECT_EQ(1U, str16.length());

  // Check we don't fail in a length check with large WStrings.
  Pickle big_len;
  big_len.WriteInt(1 << 30);
  iter = NULL;
  std::wstring wstr;
  EXPECT_FALSE(big_len.ReadWString(&iter, &wstr));
}

<|endoftext|>


<commit_before>// @(#)root/cont:$Name:  $:$Id: TProcessID.cxx,v 1.23 2003/07/29 19:27:09 brun Exp $
// Author: Rene Brun   28/09/2001

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//
// TProcessID
//
// A TProcessID identifies a ROOT job in a unique way in time and space.
// The TProcessID title consists of a TUUID object which provides a globally
// unique identifier (for more see TUUID.h).
//
// A TProcessID is automatically created by the TROOT constructor.
// When a TFile contains referenced objects (see TRef), the TProcessID
// object is written to the file.
// If a file has been written in multiple sessions (same machine or not),
// a TProcessID is written for each session.
// These objects are used by the class TRef to uniquely identified
// any TObject pointed by a TRef.
//
// When a referenced object is read from a file (its bit kIsReferenced is set),
// this object is entered into the objects table of the corresponding TProcessID.
// Each TFile has a list of TProcessIDs (see TFile::fProcessIDs) also
// accessible via TProcessID::fgPIDs (for all files).
// When this object is deleted, it is removed from the table via the cleanup
// mechanism invoked by the TObject destructor.
//
// Each TProcessID has a table (TObjArray *fObjects) that keeps track
// of all referenced objects. If a referenced object has a fUniqueID set,
// a pointer to this unique object may be found via fObjects->At(fUniqueID).
// In the same way, when a TRef::GetObject is called, GetObject uses
// its own fUniqueID to find the pointer to the referenced object.
// See TProcessID::GetObjectWithID and PutObjectWithID.
//
// When a referenced object is deleted, its slot in fObjects is set to null.
//
// See also TProcessUUID: a specialized TProcessID to manage the single list
// of TUUIDs.
//
//////////////////////////////////////////////////////////////////////////

#include "TProcessID.h"
#include "TROOT.h"
#include "TFile.h"
#include "TObjArray.h"
#include "TExMap.h"

TObjArray  *TProcessID::fgPIDs   = 0; //pointer to the list of TProcessID
TProcessID *TProcessID::fgPID    = 0; //pointer to the TProcessID of the current session
UInt_t      TProcessID::fgNumber = 0; //Current referenced object instance count
TExMap     *TProcessID::fgObjPIDs= 0; //Table (pointer,pids)
ClassImp(TProcessID)

//______________________________________________________________________________
static inline ULong_t Void_Hash(const void *ptr)
{
   // Return hash value for this object.

   return TMath::Hash(&ptr, sizeof(void*));
}

//______________________________________________________________________________
TProcessID::TProcessID()
{
   fCount = 0;
   fObjects = 0;
}

//______________________________________________________________________________
TProcessID::~TProcessID()
{

   delete fObjects;
   fObjects = 0;
   fgPIDs->Remove(this);
}

//______________________________________________________________________________
TProcessID::TProcessID(const TProcessID &ref) : TNamed(ref)
{
   // TProcessID copy ctor.
}

//______________________________________________________________________________
TProcessID *TProcessID::AddProcessID()
{
// static function to add a new TProcessID to the list of PIDs

   TProcessID *pid = new TProcessID();

   if (!fgPIDs) {
      fgPID  = pid;
      fgPIDs = new TObjArray(10);
      gROOT->GetListOfCleanups()->Add(fgPIDs);
   }
   UShort_t apid = fgPIDs->GetEntriesFast();
   pid->IncrementCount();

   fgPIDs->Add(pid);
   char name[20];
   sprintf(name,"ProcessID%d",apid);
   pid->SetName(name);
   TUUID u;
   apid = fgPIDs->GetEntriesFast();
   pid->SetTitle(u.AsString());
   return pid;
}

//______________________________________________________________________________
UInt_t TProcessID::AssignID(TObject *obj)
{
// static function returning the ID assigned to obj
// If the object is not yet referenced, its kIsReferenced bit is set
// and its fUniqueID set to the current number of referenced objects so far.

   UInt_t uid = obj->GetUniqueID() & 0xffffff;
   if (obj == fgPID->GetObjectWithID(uid)) return uid;
   if (obj->TestBit(kIsReferenced)) {
      fgPID->PutObjectWithID(obj,uid);
      return uid;
   }
   fgNumber++;
   obj->SetBit(kIsReferenced);
   uid = fgNumber;
   obj->SetUniqueID(uid);
   fgPID->PutObjectWithID(obj,uid);
   return uid;
}

//______________________________________________________________________________
void TProcessID::Cleanup()
{
   // static function (called by TROOT destructor) to delete all TProcessIDs

   fgPIDs->Delete();
   gROOT->GetListOfCleanups()->Remove(fgPIDs);
   delete fgPIDs;
}

//______________________________________________________________________________
void TProcessID::Clear(Option_t *)
{
// delete the TObjArray pointing to referenced objects
// this function is called by TFile::Close("R")

   delete fObjects; fObjects = 0;
}

//______________________________________________________________________________
Int_t TProcessID::DecrementCount()
{

   // the reference fCount is used to delete the TProcessID
   // in the TFile destructor when fCount = 0

   fCount--;
   if (fCount < 0) fCount = 0;
   return fCount;
}

//______________________________________________________________________________
TProcessID *TProcessID::GetProcessID(UShort_t pid)
{
// static function returning a pointer to TProcessID number pid in fgPIDs

   return (TProcessID*)fgPIDs->At(pid);
}

//______________________________________________________________________________
TProcessID *TProcessID::GetProcessWithUID(UInt_t uid, void *obj)
{
// static function returning a pointer to TProcessID with its pid
// encoded in the highest byte of uid

   Int_t pid = (uid>>24)&0xff;
   if (pid==0xff) {
      // Look up the pid in the table (pointer,pid)
      if (fgObjPIDs==0) return 0;
      ULong_t hash = Void_Hash(obj);
      pid = fgObjPIDs->GetValue(hash,(Long_t)obj);
   }
   return (TProcessID*)fgPIDs->At(pid);
}

//______________________________________________________________________________
TProcessID *TProcessID::GetSessionProcessID()
{
// static function returning the pointer to the session TProcessID

   return fgPID;
}

//______________________________________________________________________________
Int_t TProcessID::IncrementCount()
{

   if (!fObjects) fObjects = new TObjArray(100);
   fCount++;
   return fCount;
}

//______________________________________________________________________________
UInt_t TProcessID::GetObjectCount()
{
// Return the current referenced object count
// fgNumber is incremented everytime a new object is referenced

   return fgNumber;
}

//______________________________________________________________________________
TObject *TProcessID::GetObjectWithID(UInt_t uidd)
{
   //returns the TObject with unique identifier uid in the table of objects
   //if (!fObjects) fObjects = new TObjArray(100);

   Int_t uid = uidd & 0xffffff;  //take only the 24 lower bits

   if (uid >= fObjects->GetSize()) return 0;
   return fObjects->UncheckedAt(uid);
}

//______________________________________________________________________________
Bool_t TProcessID::IsValid(TProcessID *pid)
{
   // static function. return kTRUE if pid is a valid TProcessID

   if (fgPIDs->IndexOf(pid) >= 0) return kTRUE;
   if (pid == (TProcessID*)gROOT->GetUUIDs())  return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
void TProcessID::PutObjectWithID(TObject *obj, UInt_t uid)
{
   //stores the object at the uid th slot in the table of objects
   //The object uniqueid is set as well as its kMustCleanup bit
   //if (!fObjects) fObjects = new TObjArray(100);

   if (uid == 0) uid = obj->GetUniqueID() & 0xffffff;
   fObjects->AddAtAndExpand(obj,uid);
   obj->SetBit(kMustCleanup);
   if ( (obj->GetUniqueID()&0xff000000)==0xff000000 ) {
      // We have more than 255 pids we need to store this
      // pointer in the table(pointer,pid) since there is no
      // more space in fUniqueID
      if (fgObjPIDs==0) fgObjPIDs = new TExMap;
      ULong_t hash = Void_Hash(obj);
      fgObjPIDs->Add(hash, (Long_t)obj, GetUniqueID());
   }
}

//______________________________________________________________________________
TProcessID  *TProcessID::ReadProcessID(UShort_t pidf, TFile *file)
{
// static function

   //The TProcessID with number pidf is read from file.
   //If the object is not already entered in the gROOT list, it is added.

   if (!file) {
      if (!pidf) return fgPID; //may happen when cloning an object
      return 0;
   }
   TObjArray *pids = file->GetListOfProcessIDs();
   TProcessID *pid = 0;
   if (pidf < pids->GetSize()) pid = (TProcessID *)pids->UncheckedAt(pidf);
   if (pid) {
      if (!pid->fObjects) pid->fObjects = new TObjArray(100);
      return pid;
   }

   //check if fProcessIDs[uid] is set in file
   //if not set, read the process uid from file
   char pidname[32];
   sprintf(pidname,"ProcessID%d",pidf);
   TDirectory *dirsav = gDirectory;
   file->cd();
   pid = (TProcessID *)file->Get(pidname);
   if (dirsav) dirsav->cd();
   if (gDebug > 0) {
      printf("ReadProcessID, name=%s, file=%s, pid=%lx\n",pidname,file->GetName(),(Long_t)pid);
   }
   if (!pid) {
      //file->Error("ReadProcessID","Cannot find %s in file %s",pidname,file->GetName());
      return 0;
   }
      //check that a similar pid is not already registered in fgPIDs
   TIter next(fgPIDs);
   TProcessID *p;
   while ((p = (TProcessID*)next())) {
      if (!strcmp(p->GetTitle(),pid->GetTitle())) {
         delete pid;
         pids->AddAtAndExpand(p,pidf);
         p->IncrementCount();
         return p;
      }
   }
   pids->AddAtAndExpand(pid,pidf);
   pid->IncrementCount();
   fgPIDs->Add(pid);
   Int_t ind = fgPIDs->IndexOf(pid);
   pid->SetUniqueID((UInt_t)ind);
   return pid;
}

//______________________________________________________________________________
void TProcessID::RecursiveRemove(TObject *obj)
{
   // called by the object destructor
   // remove reference to obj from the current table if it is referenced

   if (!fObjects) return;
   if (!obj->TestBit(kIsReferenced)) return;
   UInt_t uid = obj->GetUniqueID() & 0xffffff;
   if (obj == GetObjectWithID(uid)) fObjects->RemoveAt(uid);
}

//______________________________________________________________________________
void TProcessID::SetObjectCount(UInt_t number)
{
// static function to set the current referenced object count
// fgNumber is incremented everytime a new object is referenced

   fgNumber = number;
}

//______________________________________________________________________________
UShort_t TProcessID::WriteProcessID(TProcessID *pidd, TFile *file)
{
// static function
// Check if the ProcessID pid is already in the file.
// if not, add it and return the index  number in the local file list

   if (!file) return 0;
   TProcessID *pid = pidd;
   if (!pid) pid = fgPID;
   TObjArray *pids = file->GetListOfProcessIDs();
   Int_t npids = file->GetNProcessIDs();
   for (Int_t i=0;i<npids;i++) {
      if (pids->At(i) == pid) return (UShort_t)i;
   }

   TDirectory *dirsav = gDirectory;
   file->cd();
   file->SetBit(TFile::kHasReferences);
   pids->AddAtAndExpand(pid,npids);
   pid->IncrementCount();
   char name[32];
   sprintf(name,"ProcessID%d",npids);
   pid->Write(name);
   file->IncrementProcessIDs();
   if (gDebug > 0) {
      printf("WriteProcessID, name=%s, file=%s\n",name,file->GetName());
   }
   if (dirsav) dirsav->cd();
   return (UShort_t)npids;
}
<commit_msg>From Philippe: When the number of processIds is greater than 255 and an address is re-used, we should not issue an error, just update the pids registered in fObjPIDs.<commit_after>// @(#)root/cont:$Name:  $:$Id: TProcessID.cxx,v 1.24 2005/01/28 05:45:41 brun Exp $
// Author: Rene Brun   28/09/2001

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//
// TProcessID
//
// A TProcessID identifies a ROOT job in a unique way in time and space.
// The TProcessID title consists of a TUUID object which provides a globally
// unique identifier (for more see TUUID.h).
//
// A TProcessID is automatically created by the TROOT constructor.
// When a TFile contains referenced objects (see TRef), the TProcessID
// object is written to the file.
// If a file has been written in multiple sessions (same machine or not),
// a TProcessID is written for each session.
// These objects are used by the class TRef to uniquely identified
// any TObject pointed by a TRef.
//
// When a referenced object is read from a file (its bit kIsReferenced is set),
// this object is entered into the objects table of the corresponding TProcessID.
// Each TFile has a list of TProcessIDs (see TFile::fProcessIDs) also
// accessible via TProcessID::fgPIDs (for all files).
// When this object is deleted, it is removed from the table via the cleanup
// mechanism invoked by the TObject destructor.
//
// Each TProcessID has a table (TObjArray *fObjects) that keeps track
// of all referenced objects. If a referenced object has a fUniqueID set,
// a pointer to this unique object may be found via fObjects->At(fUniqueID).
// In the same way, when a TRef::GetObject is called, GetObject uses
// its own fUniqueID to find the pointer to the referenced object.
// See TProcessID::GetObjectWithID and PutObjectWithID.
//
// When a referenced object is deleted, its slot in fObjects is set to null.
//
// See also TProcessUUID: a specialized TProcessID to manage the single list
// of TUUIDs.
//
//////////////////////////////////////////////////////////////////////////

#include "TProcessID.h"
#include "TROOT.h"
#include "TFile.h"
#include "TObjArray.h"
#include "TExMap.h"

TObjArray  *TProcessID::fgPIDs   = 0; //pointer to the list of TProcessID
TProcessID *TProcessID::fgPID    = 0; //pointer to the TProcessID of the current session
UInt_t      TProcessID::fgNumber = 0; //Current referenced object instance count
TExMap     *TProcessID::fgObjPIDs= 0; //Table (pointer,pids)
ClassImp(TProcessID)

//______________________________________________________________________________
static inline ULong_t Void_Hash(const void *ptr)
{
   // Return hash value for this object.

   return TMath::Hash(&ptr, sizeof(void*));
}

//______________________________________________________________________________
TProcessID::TProcessID()
{
   fCount = 0;
   fObjects = 0;
}

//______________________________________________________________________________
TProcessID::~TProcessID()
{

   delete fObjects;
   fObjects = 0;
   fgPIDs->Remove(this);
}

//______________________________________________________________________________
TProcessID::TProcessID(const TProcessID &ref) : TNamed(ref)
{
   // TProcessID copy ctor.
}

//______________________________________________________________________________
TProcessID *TProcessID::AddProcessID()
{
// static function to add a new TProcessID to the list of PIDs

   TProcessID *pid = new TProcessID();

   if (!fgPIDs) {
      fgPID  = pid;
      fgPIDs = new TObjArray(10);
      gROOT->GetListOfCleanups()->Add(fgPIDs);
   }
   UShort_t apid = fgPIDs->GetEntriesFast();
   pid->IncrementCount();

   fgPIDs->Add(pid);
   char name[20];
   sprintf(name,"ProcessID%d",apid);
   pid->SetName(name);
   TUUID u;
   apid = fgPIDs->GetEntriesFast();
   pid->SetTitle(u.AsString());
   return pid;
}

//______________________________________________________________________________
UInt_t TProcessID::AssignID(TObject *obj)
{
// static function returning the ID assigned to obj
// If the object is not yet referenced, its kIsReferenced bit is set
// and its fUniqueID set to the current number of referenced objects so far.

   UInt_t uid = obj->GetUniqueID() & 0xffffff;
   if (obj == fgPID->GetObjectWithID(uid)) return uid;
   if (obj->TestBit(kIsReferenced)) {
      fgPID->PutObjectWithID(obj,uid);
      return uid;
   }
   fgNumber++;
   obj->SetBit(kIsReferenced);
   uid = fgNumber;
   obj->SetUniqueID(uid);
   fgPID->PutObjectWithID(obj,uid);
   return uid;
}

//______________________________________________________________________________
void TProcessID::Cleanup()
{
   // static function (called by TROOT destructor) to delete all TProcessIDs

   fgPIDs->Delete();
   gROOT->GetListOfCleanups()->Remove(fgPIDs);
   delete fgPIDs;
}

//______________________________________________________________________________
void TProcessID::Clear(Option_t *)
{
// delete the TObjArray pointing to referenced objects
// this function is called by TFile::Close("R")

   delete fObjects; fObjects = 0;
}

//______________________________________________________________________________
Int_t TProcessID::DecrementCount()
{

   // the reference fCount is used to delete the TProcessID
   // in the TFile destructor when fCount = 0

   fCount--;
   if (fCount < 0) fCount = 0;
   return fCount;
}

//______________________________________________________________________________
TProcessID *TProcessID::GetProcessID(UShort_t pid)
{
// static function returning a pointer to TProcessID number pid in fgPIDs

   return (TProcessID*)fgPIDs->At(pid);
}

//______________________________________________________________________________
TProcessID *TProcessID::GetProcessWithUID(UInt_t uid, void *obj)
{
// static function returning a pointer to TProcessID with its pid
// encoded in the highest byte of uid

   Int_t pid = (uid>>24)&0xff;
   if (pid==0xff) {
      // Look up the pid in the table (pointer,pid)
      if (fgObjPIDs==0) return 0;
      ULong_t hash = Void_Hash(obj);
      pid = fgObjPIDs->GetValue(hash,(Long_t)obj);
   }
   return (TProcessID*)fgPIDs->At(pid);
}

//______________________________________________________________________________
TProcessID *TProcessID::GetSessionProcessID()
{
// static function returning the pointer to the session TProcessID

   return fgPID;
}

//______________________________________________________________________________
Int_t TProcessID::IncrementCount()
{

   if (!fObjects) fObjects = new TObjArray(100);
   fCount++;
   return fCount;
}

//______________________________________________________________________________
UInt_t TProcessID::GetObjectCount()
{
// Return the current referenced object count
// fgNumber is incremented everytime a new object is referenced

   return fgNumber;
}

//______________________________________________________________________________
TObject *TProcessID::GetObjectWithID(UInt_t uidd)
{
   //returns the TObject with unique identifier uid in the table of objects
   //if (!fObjects) fObjects = new TObjArray(100);

   Int_t uid = uidd & 0xffffff;  //take only the 24 lower bits

   if (uid >= fObjects->GetSize()) return 0;
   return fObjects->UncheckedAt(uid);
}

//______________________________________________________________________________
Bool_t TProcessID::IsValid(TProcessID *pid)
{
   // static function. return kTRUE if pid is a valid TProcessID

   if (fgPIDs->IndexOf(pid) >= 0) return kTRUE;
   if (pid == (TProcessID*)gROOT->GetUUIDs())  return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
void TProcessID::PutObjectWithID(TObject *obj, UInt_t uid)
{
   //stores the object at the uid th slot in the table of objects
   //The object uniqueid is set as well as its kMustCleanup bit
   //if (!fObjects) fObjects = new TObjArray(100);

   if (uid == 0) uid = obj->GetUniqueID() & 0xffffff;
   fObjects->AddAtAndExpand(obj,uid);
   obj->SetBit(kMustCleanup);
   if ( (obj->GetUniqueID()&0xff000000)==0xff000000 ) {
      // We have more than 255 pids we need to store this
      // pointer in the table(pointer,pid) since there is no
      // more space in fUniqueID
      if (fgObjPIDs==0) fgObjPIDs = new TExMap;
      ULong_t hash = Void_Hash(obj);

      // We use operator() rather than Add() because
      // if the address has already been registered, we want to
      // update it's uniqueID (this can easily happen when the
      // referenced obejct have been stored in a TClonesArray.
      (*fgObjPIDs)(hash, (Long_t)obj) = GetUniqueID();
   }
}

//______________________________________________________________________________
TProcessID  *TProcessID::ReadProcessID(UShort_t pidf, TFile *file)
{
// static function

   //The TProcessID with number pidf is read from file.
   //If the object is not already entered in the gROOT list, it is added.

   if (!file) {
      if (!pidf) return fgPID; //may happen when cloning an object
      return 0;
   }
   TObjArray *pids = file->GetListOfProcessIDs();
   TProcessID *pid = 0;
   if (pidf < pids->GetSize()) pid = (TProcessID *)pids->UncheckedAt(pidf);
   if (pid) {
      if (!pid->fObjects) pid->fObjects = new TObjArray(100);
      return pid;
   }

   //check if fProcessIDs[uid] is set in file
   //if not set, read the process uid from file
   char pidname[32];
   sprintf(pidname,"ProcessID%d",pidf);
   TDirectory *dirsav = gDirectory;
   file->cd();
   pid = (TProcessID *)file->Get(pidname);
   if (dirsav) dirsav->cd();
   if (gDebug > 0) {
      printf("ReadProcessID, name=%s, file=%s, pid=%lx\n",pidname,file->GetName(),(Long_t)pid);
   }
   if (!pid) {
      //file->Error("ReadProcessID","Cannot find %s in file %s",pidname,file->GetName());
      return 0;
   }
      //check that a similar pid is not already registered in fgPIDs
   TIter next(fgPIDs);
   TProcessID *p;
   while ((p = (TProcessID*)next())) {
      if (!strcmp(p->GetTitle(),pid->GetTitle())) {
         delete pid;
         pids->AddAtAndExpand(p,pidf);
         p->IncrementCount();
         return p;
      }
   }
   pids->AddAtAndExpand(pid,pidf);
   pid->IncrementCount();
   fgPIDs->Add(pid);
   Int_t ind = fgPIDs->IndexOf(pid);
   pid->SetUniqueID((UInt_t)ind);
   return pid;
}

//______________________________________________________________________________
void TProcessID::RecursiveRemove(TObject *obj)
{
   // called by the object destructor
   // remove reference to obj from the current table if it is referenced

   if (!fObjects) return;
   if (!obj->TestBit(kIsReferenced)) return;
   UInt_t uid = obj->GetUniqueID() & 0xffffff;
   if (obj == GetObjectWithID(uid)) fObjects->RemoveAt(uid);
}

//______________________________________________________________________________
void TProcessID::SetObjectCount(UInt_t number)
{
// static function to set the current referenced object count
// fgNumber is incremented everytime a new object is referenced

   fgNumber = number;
}

//______________________________________________________________________________
UShort_t TProcessID::WriteProcessID(TProcessID *pidd, TFile *file)
{
// static function
// Check if the ProcessID pid is already in the file.
// if not, add it and return the index  number in the local file list

   if (!file) return 0;
   TProcessID *pid = pidd;
   if (!pid) pid = fgPID;
   TObjArray *pids = file->GetListOfProcessIDs();
   Int_t npids = file->GetNProcessIDs();
   for (Int_t i=0;i<npids;i++) {
      if (pids->At(i) == pid) return (UShort_t)i;
   }

   TDirectory *dirsav = gDirectory;
   file->cd();
   file->SetBit(TFile::kHasReferences);
   pids->AddAtAndExpand(pid,npids);
   pid->IncrementCount();
   char name[32];
   sprintf(name,"ProcessID%d",npids);
   pid->Write(name);
   file->IncrementProcessIDs();
   if (gDebug > 0) {
      printf("WriteProcessID, name=%s, file=%s\n",name,file->GetName());
   }
   if (dirsav) dirsav->cd();
   return (UShort_t)npids;
}
<|endoftext|>


<commit_before>/**
	\file bmpfile.cpp
	\brief LightEngine 3D: Windows bitmap file importer / exporter
	\brief All platforms implementation
	\author Frederic Meslin (fred@fredslab.net)
	\twitter @marzacdev
	\website http://fredslab.net
	\copyright Frederic Meslin 2015 - 2018
	\version 1.6

	The MIT License (MIT)
	Copyright (c) 2015-2018 Frédéric Meslin

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
	SOFTWARE.
*/

#include "bmpfile.h"

#include "global.h"
#include "config.h"

#include <stdlib.h>
#include <string.h>

#ifdef AMIGA
inline void from_little_endian(uint16_t &v) {
	v = (v << 8) | (v >> 8);
}

inline void from_little_endian(uint32_t &v) {
	v = (v<<24) | ((v<<8) & 0x00ff0000) |
          ((v>>8) & 0x0000ff00) | (v>>24);
}

// probably ineffecient but should work for now :)
inline void from_little_endian(int16_t &v) {
	uint16_t v1 = (uint16_t) v;
	from_little_endian(v1);
	v = (int16_t) v1;
}

inline void from_little_endian(int32_t &v) {
	uint32_t v1 = (uint32_t) v;
	from_little_endian(v1);
	v = (int32_t) v1;
}
#else
inline void from_little_endian(uint16_t &v) {
}

inline void from_little_endian(uint32_t &v) {
}

inline void from_little_endian(int16_t &v) {
}

inline void from_little_endian(int32_t &v) {
}
#endif

/*****************************************************************************/
#pragma pack(push, 1)
typedef struct {
	uint16_t bfType;
	uint32_t bfSize;
	int16_t	 bfReserved1;
	int16_t	 bfReserved2;
	uint32_t bfOffBits;
} BMPFILEHEADER;
#pragma pack(pop)

#pragma pack(push, 1)
typedef struct {
	uint32_t biSize;
	int32_t	 biWidth;
	int32_t	 biHeight;
	uint16_t	 biPlanes;
	uint16_t	 biBitCount;
	uint32_t biCompression;
	uint32_t biSizeImage;
	int32_t	 biXPelsPerMeter;
	int32_t	 biYPelsPerMeter;
	uint32_t biClrUsed;
	uint32_t biClrImportant;
} BMPINFOHEADER;
#pragma pack(pop)

#pragma pack(push, 1)
typedef struct {
	uint32_t CSType;
	uint32_t Endpoints[9];
	uint32_t GammaRed;
	uint32_t GammaGreen;
	uint32_t GammaBlue;
} BMPCOLORSPACE;

#pragma pack(push, 1)
typedef struct {
	uint32_t mR;
	uint32_t mG;
	uint32_t mB;
	uint32_t mA;
} BMPCOLORMASK;
#pragma pack(pop)

/*****************************************************************************/
#define BI_RGB				0
#define BI_BITFIELDS		3
#define BI_ALPHABITFIELDS	6

/*****************************************************************************/
LeBmpFile::LeBmpFile(const char * filename) :
	path(NULL)
{
#ifdef _MSC_VER
	if (filename) path = _strdup(filename);
#else
	if (filename) path = strdup(filename);
#endif
}

LeBmpFile::~LeBmpFile()
{
	if (path) free(path);
}

/*****************************************************************************/
/**
	\fn LeBitmap * LeBmpFile::load()
	\brief Load bitmap data from the file
	\return pointer to a new loaded bitmap, else NULL (error)
*/
LeBitmap * LeBmpFile::load()
{
	FILE * file = fopen(path, "rb");
	if (!file) {
		printf("bmpFile: file not found %s!\n", path);
		return NULL;
	}

	LeBitmap * bitmap = new LeBitmap();
	if (!bitmap) {
		fclose(file);
		return NULL;
	}

	readBitmap(file, bitmap);
	fclose(file);
	return bitmap;
}

/**
	\fn void LeBmpFile::save(LeBitmap * bitmap)
	\brief Save bitmap data into the file
	\param[in] bitmap pointer a valid bitmap
*/
void LeBmpFile::save(const LeBitmap * bitmap)
{
	FILE * file = fopen(path, "wb");
	if (!file) {
		printf("bmpFile: file cannot be opened %s!\n", path);
		return;
	}

	writeBitmap(file, bitmap);
	fclose(file);
}

/*****************************************************************************/
int LeBmpFile::readBitmap(FILE * file, LeBitmap * bitmap)
{
	BMPFILEHEADER header;
	BMPINFOHEADER info;
	BMPCOLORMASK  mask = {
		0x00FF0000,
		0x0000FF00,
		0x000000FF,
		0xFF000000
	};

// Read the headers
	fread(&header, sizeof(BMPFILEHEADER), 1, file);
	from_little_endian(header.bfSize);
	from_little_endian(header.bfReserved1);
	from_little_endian(header.bfReserved2);
	from_little_endian(header.bfOffBits);
	fread(&info, sizeof(BMPINFOHEADER), 1, file);
	from_little_endian(info.biSize);
	from_little_endian(info.biWidth);
	from_little_endian(info.biHeight);
	from_little_endian(info.biPlanes);
	from_little_endian(info.biBitCount);
	from_little_endian(info.biCompression);
	from_little_endian(info.biSizeImage);
	from_little_endian(info.biXPelsPerMeter);
	from_little_endian(info.biYPelsPerMeter);
	from_little_endian(info.biClrUsed);
	from_little_endian(info.biClrImportant);

// Check bitmap format
	if (strncmp((char *) &header.bfType, "BM", 2)){
		printf("bmpFile: file not a bitmap!\n");
		return 0;
	}
	if (info.biBitCount != 24 && info.biBitCount != 32) {
		printf("bmpFile: only 24bit or 32bit bitmaps are supported %d %ld!\n", info.biBitCount, info.biWidth);
		return 0;
	}
	if (info.biCompression != BI_RGB && info.biCompression != BI_BITFIELDS){
		printf("bmpFile: only uncompressed formats are supported!\n");
		return 0;
	}

// Load the bitmasks
	int shiftA = 24;
	int shiftR = 16;
	int shiftG = 8;
	int shiftB = 0;
	if (info.biCompression == BI_BITFIELDS) {
		fread(&mask, sizeof(BMPCOLORMASK), 1, file);
		from_little_endian(mask.mR);
		from_little_endian(mask.mG);
		from_little_endian(mask.mB);
		from_little_endian(mask.mA);
		shiftR = __builtin_ffs(mask.mR) - 1;
		shiftG = __builtin_ffs(mask.mG) - 1;
		shiftB = __builtin_ffs(mask.mB) - 1;
		shiftA = __builtin_ffs(mask.mA) - 1;
	}

// Retrieve bitmap size
	bitmap->tx = info.biWidth;
	bitmap->ty = info.biHeight;
	bitmap->txP2 = LeGlobal::log2i32(bitmap->tx);
	bitmap->tyP2 = LeGlobal::log2i32(bitmap->ty);

	int upsidedown = 1;
	if (bitmap->ty < 0) {
		bitmap->ty = -bitmap->ty;
		upsidedown = 0;
	}

// Set bitmap flags
	bitmap->flags = LE_BITMAP_RGB;
	if (info.biBitCount == 32)
		bitmap->flags |= LE_BITMAP_RGBA;

// Allocate bitmap memory
	int srcScan;
	srcScan = bitmap->tx * (info.biBitCount >> 3);
	srcScan = (srcScan + 0x3) & ~0x3;

	bitmap->data = new LeColor[bitmap->tx * bitmap->ty];
	bitmap->dataAllocated = true;

// Load bitmap data
#if _MSC_VER && !defined(__MINGW32__)
	uint8_t * buffer = (uint8_t *) alloca(srcScan);
#else
	uint8_t buffer[srcScan];
#endif
	uint8_t * data = (uint8_t *) bitmap->data;

	int dstScan = bitmap->tx * sizeof(uint32_t);
	fseek(file, header.bfOffBits, SEEK_SET);
	if (upsidedown)
		data += dstScan * (bitmap->ty - 1);

	bool doit = true;
	if (info.biBitCount == 32) {
	// Parse a 32 bits image
		for (int y = 0; y < bitmap->ty; y ++) {
			fread(buffer, srcScan, 1, file);
			uint32_t * d = (uint32_t *) data;
			uint32_t * s = (uint32_t *) buffer;
			for (int i = 0; i < bitmap->tx; i ++) {
				uint32_t c = *s++;
				uint32_t a, r, g, b;
				a = (c & mask.mA) >> shiftA;
				r = (c & mask.mR) >> shiftR;
				g = (c & mask.mG) >> shiftG;
				b = (c & mask.mB) >> shiftB;
				*d++ = (a << 24) | (r << 16) | (g << 8) | b;
			}
			if (upsidedown) data -= dstScan;
			else data += dstScan;
		}
	}else{
	// Parse a 24 bits image
		for (int y = 0; y < bitmap->ty; y ++) {
			fread(buffer, srcScan, 1, file);
			LeColor * d = (LeColor *) data;
			uint8_t	 * s = buffer;
			for (int i = 0; i < bitmap->tx; i ++) {
				d->b = * s++;
				d->g = * s++;
				d->r = * s++;
				d++;
			}
			if (upsidedown) data -= dstScan;
			else data += dstScan;
		}
	}

	return 1;
}

/*****************************************************************************/
#define HEAD_LEN sizeof(BMPFILEHEADER) + sizeof(BMPINFOHEADER) + sizeof(BMPCOLORMASK)
int LeBmpFile::writeBitmap(FILE * file, const LeBitmap * bitmap)
{
// Prepare the headers
	size_t size = bitmap->tx * bitmap->ty * sizeof(uint32_t);
	BMPFILEHEADER header;
	header.bfType = 0x4D42;
	header.bfSize = HEAD_LEN + size;
	header.bfReserved1 = 0;
	header.bfReserved2 = 0;
	header.bfOffBits = HEAD_LEN;

	BMPINFOHEADER info;
	info.biSize = sizeof(BMPINFOHEADER) + sizeof(BMPCOLORMASK);
	info.biWidth = bitmap->tx;
	info.biHeight = bitmap->ty;
	info.biPlanes = 1;
	info.biBitCount = 32;
	info.biCompression = BI_BITFIELDS;
	info.biSizeImage = 0;
	info.biXPelsPerMeter = 96;
	info.biYPelsPerMeter = 96;
	info.biClrUsed = 0;
	info.biClrImportant = 0;

	BMPCOLORMASK mask = {
		0x00FF0000,
		0x0000FF00,
		0x000000FF,
		0xFF000000
	};

// Write the headers
	fwrite(&header, sizeof(BMPFILEHEADER), 1, file);
	fwrite(&info, sizeof(BMPINFOHEADER), 1, file);
	fwrite(&mask, sizeof(BMPCOLORMASK), 1, file);

// Save the picture
	uint32_t scan = bitmap->tx * sizeof(uint32_t);
	uint8_t * data = (uint8_t *) bitmap->data;
	for (int y = 0; y < bitmap->ty; y ++) {
		fwrite(data, scan, 1, file);
		data += scan;
	}
	return 0;
}
<commit_msg>Handling endianness problems 2<commit_after>/**
	\file bmpfile.cpp
	\brief LightEngine 3D: Windows bitmap file importer / exporter
	\brief All platforms implementation
	\author Frederic Meslin (fred@fredslab.net)
	\twitter @marzacdev
	\website http://fredslab.net
	\copyright Frederic Meslin 2015 - 2018
	\version 1.6

	The MIT License (MIT)
	Copyright (c) 2015-2018 Frédéric Meslin

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
	SOFTWARE.
*/

#include "bmpfile.h"

#include "global.h"
#include "config.h"

#include <stdlib.h>
#include <string.h>

/*****************************************************************************/
#pragma pack(push, 1)
typedef struct {
	uint16_t bfType;
	uint32_t bfSize;
	int16_t  bfReserved1;
	int16_t  bfReserved2;
	uint32_t bfOffBits;
} BMPFILEHEADER;
#pragma pack(pop)

#pragma pack(push, 1)
typedef struct {
	uint32_t biSize;
	int32_t  biWidth;
	int32_t  biHeight;
	uint16_t biPlanes;
	uint16_t biBitCount;
	uint32_t biCompression;
	uint32_t biSizeImage;
	int32_t  biXPelsPerMeter;
	int32_t  biYPelsPerMeter;
	uint32_t biClrUsed;
	uint32_t biClrImportant;
} BMPINFOHEADER;
#pragma pack(pop)

#pragma pack(push, 1)
typedef struct {
	uint32_t CSType;
	uint32_t Endpoints[9];
	uint32_t GammaRed;
	uint32_t GammaGreen;
	uint32_t GammaBlue;
} BMPCOLORSPACE;

#pragma pack(push, 1)
typedef struct {
	uint32_t mR;
	uint32_t mG;
	uint32_t mB;
	uint32_t mA;
} BMPCOLORMASK;
#pragma pack(pop)

/*****************************************************************************/
#define BI_RGB				0
#define BI_BITFIELDS		3
#define BI_ALPHABITFIELDS	6

/*****************************************************************************/
LeBmpFile::LeBmpFile(const char * filename) :
	path(NULL)
{
	if (filename) path = strdup(filename);
}

LeBmpFile::~LeBmpFile()
{
	if (path) free(path);
}

/*****************************************************************************/
/**
	\fn LeBitmap * LeBmpFile::load()
	\brief Load bitmap data from the file
	\return pointer to a new loaded bitmap, else NULL (error)
*/
LeBitmap * LeBmpFile::load()
{
	FILE * file = fopen(path, "rb");
	if (!file) {
		printf("bmpFile: file not found %s!\n", path);
		return NULL;
	}

	LeBitmap * bitmap = new LeBitmap();
	if (!bitmap) {
		fclose(file);
		return NULL;
	}

	readBitmap(file, bitmap);
	fclose(file);
	return bitmap;
}

/**
	\fn void LeBmpFile::save(LeBitmap * bitmap)
	\brief Save bitmap data into the file
	\param[in] bitmap pointer a valid bitmap
*/
void LeBmpFile::save(const LeBitmap * bitmap)
{
	FILE * file = fopen(path, "wb");
	if (!file) {
		printf("bmpFile: file cannot be opened %s!\n", path);
		return;
	}

	writeBitmap(file, bitmap);
	fclose(file);
}

/*****************************************************************************/
int LeBmpFile::readBitmap(FILE * file, LeBitmap * bitmap)
{
	BMPFILEHEADER fileHeader;
	BMPINFOHEADER infoHeader;
	BMPCOLORMASK  mask = {
		0x00FF0000,
		0x0000FF00,
		0x000000FF,
		0xFF000000
	};

// Read the headers
	fread(&fileHeader, sizeof(BMPFILEHEADER), 1, file);
	fread(&infoHeader, sizeof(BMPINFOHEADER), 1, file);

// Format the data (little-endianness)
	FROM_LEU16(fileHeader.bfType);
	FROM_LEU32(fileHeader.bfSize);
	FROM_LEU32(fileHeader.bfOffBits);
	FROM_LEU32(infoHeader.biSize);
	FROM_LES32(infoHeader.biWidth);
	FROM_LES32(infoHeader.biHeight);
	FROM_LEU16(infoHeader.biPlanes);
	FROM_LEU16(infoHeader.biBitCount);
	FROM_LEU32(infoHeader.biCompression);
	FROM_LEU32(infoHeader.biSizeImage);
	FROM_LES32(infoHeader.biXPelsPerMeter);
	FROM_LES32(infoHeader.biYPelsPerMeter);
	FROM_LEU32(infoHeader.biClrUsed);
	FROM_LEU32(infoHeader.biClrImportant);

// Check the headers
	if (strncmp((char *) &fileHeader.bfType, "BM", 2)){
		printf("bmpFile: file not a bitmap!\n");
		return 0;
	}
	if (infoHeader.biBitCount != 24 && infoHeader.biBitCount != 32) {
		printf("bmpFile: only 24bit or 32bit bitmaps are supported %d!\n", infoHeader.biBitCount);
		return 0;
	}
	if (infoHeader.biCompression != BI_RGB && infoHeader.biCompression != BI_BITFIELDS){
		printf("bmpFile: only uncompressed formats are supported!\n");
		return 0;
	}

// Load the bitmasks
	int shiftA = 24;
	int shiftR = 16;
	int shiftG = 8;
	int shiftB = 0;
	if (infoHeader.biCompression == BI_BITFIELDS) {
		fread(&mask, sizeof(BMPCOLORMASK), 1, file);
		FROM_LEU32(mask.mR);
		FROM_LEU32(mask.mG);
		FROM_LEU32(mask.mB);
		FROM_LEU32(mask.mA);
		shiftR = __builtin_ffs(mask.mR) - 1;
		shiftG = __builtin_ffs(mask.mG) - 1;
		shiftB = __builtin_ffs(mask.mB) - 1;
		shiftA = __builtin_ffs(mask.mA) - 1;
	}

// Retrieve bitmap size
	bitmap->tx = infoHeader.biWidth;
	bitmap->ty = infoHeader.biHeight;
	bitmap->txP2 = LeGlobal::log2i32(bitmap->tx);
	bitmap->tyP2 = LeGlobal::log2i32(bitmap->ty);

	int upsidedown = 1;
	if (bitmap->ty < 0) {
		bitmap->ty = -bitmap->ty;
		upsidedown = 0;
	}

// Set bitmap flags
	bitmap->flags = LE_BITMAP_RGB;
	if (infoHeader.biBitCount == 32)
		bitmap->flags |= LE_BITMAP_RGBA;

// Allocate bitmap memory
	int srcScan;
	srcScan = bitmap->tx * (infoHeader.biBitCount >> 3);
	srcScan = (srcScan + 0x3) & ~0x3;

	bitmap->data = new LeColor[bitmap->tx * bitmap->ty];
	bitmap->dataAllocated = true;

// Load bitmap data
	uint8_t * buffer = (uint8_t *) alloca(srcScan);
	uint8_t * data = (uint8_t *) bitmap->data;

	int dstScan = bitmap->tx * sizeof(uint32_t);
	fseek(file, fileHeader.bfOffBits, SEEK_SET);
	if (upsidedown)
		data += dstScan * (bitmap->ty - 1);

	if (infoHeader.biBitCount == 32) {
	// Parse a 32 bits image
		for (int y = 0; y < bitmap->ty; y ++) {
			fread(buffer, srcScan, 1, file);
			uint32_t * d = (uint32_t *) data;
			uint32_t * s = (uint32_t *) buffer;
			for (int i = 0; i < bitmap->tx; i ++) {
				uint32_t c = *s++;
				uint32_t a, r, g, b;
				a = (c & mask.mA) >> shiftA;
				r = (c & mask.mR) >> shiftR;
				g = (c & mask.mG) >> shiftG;
				b = (c & mask.mB) >> shiftB;
				*d++ = (a << 24) | (r << 16) | (g << 8) | b;
			}
			if (upsidedown) data -= dstScan;
			else data += dstScan;
		}
	}else{
	// Parse a 24 bits image
		for (int y = 0; y < bitmap->ty; y ++) {
			fread(buffer, srcScan, 1, file);
			LeColor * d = (LeColor *) data;
			uint8_t	 * s = buffer;
			for (int i = 0; i < bitmap->tx; i ++) {
				d->b = * s++;
				d->g = * s++;
				d->r = * s++;
				d++;
			}
			if (upsidedown) data -= dstScan;
			else data += dstScan;
		}
	}

	return 1;
}

/*****************************************************************************/
#define HEAD_LEN sizeof(BMPFILEHEADER) + sizeof(BMPINFOHEADER) + sizeof(BMPCOLORMASK)
int LeBmpFile::writeBitmap(FILE * file, const LeBitmap * bitmap)
{
// Prepare the headers
	size_t size = bitmap->tx * bitmap->ty * sizeof(uint32_t);
	BMPFILEHEADER fileHeader;
	fileHeader.bfType = 0x4D42;
	fileHeader.bfSize = HEAD_LEN + size;
	fileHeader.bfReserved1 = 0;
	fileHeader.bfReserved2 = 0;
	fileHeader.bfOffBits = HEAD_LEN;

	BMPINFOHEADER infoHeader;
	infoHeader.biSize = sizeof(BMPINFOHEADER) + sizeof(BMPCOLORMASK);
	infoHeader.biWidth = bitmap->tx;
	infoHeader.biHeight = bitmap->ty;
	infoHeader.biPlanes = 1;
	infoHeader.biBitCount = 32;
	infoHeader.biCompression = BI_BITFIELDS;
	infoHeader.biSizeImage = 0;
	infoHeader.biXPelsPerMeter = 96;
	infoHeader.biYPelsPerMeter = 96;
	infoHeader.biClrUsed = 0;
	infoHeader.biClrImportant = 0;

	BMPCOLORMASK mask = {
		0x00FF0000,
		0x0000FF00,
		0x000000FF,
		0xFF000000
	};

// Format the data (little-endianness)
	TO_LEU16(fileHeader.bfType);
	TO_LEU32(fileHeader.bfSize);
	TO_LEU32(fileHeader.bfOffBits);
	TO_LEU32(infoHeader.biSize);
	TO_LES32(infoHeader.biWidth);
	TO_LES32(infoHeader.biHeight);
	TO_LEU16(infoHeader.biPlanes);
	TO_LEU16(infoHeader.biBitCount);
	TO_LEU32(infoHeader.biCompression);
	TO_LEU32(infoHeader.biSizeImage);
	TO_LES32(infoHeader.biXPelsPerMeter);
	TO_LES32(infoHeader.biYPelsPerMeter);
	TO_LEU32(infoHeader.biClrUsed);
	TO_LEU32(infoHeader.biClrImportant);
	//TO_LEU32(mask[0]);
	//TO_LEU32(mask[1]);
	//TO_LEU32(mask[2]);
	//TO_LEU32(mask[3]);

// Write the headers
	fwrite(&fileHeader, sizeof(BMPFILEHEADER), 1, file);
	fwrite(&infoHeader, sizeof(BMPINFOHEADER), 1, file);
	fwrite(&mask, sizeof(BMPCOLORMASK), 1, file);

// Save the picture
	uint32_t scan = bitmap->tx * sizeof(uint32_t);
	uint8_t * data = (uint8_t *) bitmap->data;
	for (int y = 0; y < bitmap->ty; y ++) {
		fwrite(data, scan, 1, file);
		data += scan;
	}
	return 0;
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/base/asyncinvoker.h"
#include "webrtc/base/asyncudpsocket.h"
#include "webrtc/base/event.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/physicalsocketserver.h"
#include "webrtc/base/socketaddress.h"
#include "webrtc/base/thread.h"
#include "webrtc/test/testsupport/gtest_disable.h"

#if defined(WEBRTC_WIN)
#include <comdef.h>  // NOLINT
#endif

using namespace rtc;

// Generates a sequence of numbers (collaboratively).
class TestGenerator {
 public:
  TestGenerator() : last(0), count(0) {}

  int Next(int prev) {
    int result = prev + last;
    last = result;
    count += 1;
    return result;
  }

  int last;
  int count;
};

struct TestMessage : public MessageData {
  explicit TestMessage(int v) : value(v) {}
  virtual ~TestMessage() {}

  int value;
};

// Receives on a socket and sends by posting messages.
class SocketClient : public TestGenerator, public sigslot::has_slots<> {
 public:
  SocketClient(AsyncSocket* socket, const SocketAddress& addr,
               Thread* post_thread, MessageHandler* phandler)
      : socket_(AsyncUDPSocket::Create(socket, addr)),
        post_thread_(post_thread),
        post_handler_(phandler) {
    socket_->SignalReadPacket.connect(this, &SocketClient::OnPacket);
  }

  ~SocketClient() {
    delete socket_;
  }

  SocketAddress address() const { return socket_->GetLocalAddress(); }

  void OnPacket(AsyncPacketSocket* socket, const char* buf, size_t size,
                const SocketAddress& remote_addr,
                const PacketTime& packet_time) {
    EXPECT_EQ(size, sizeof(uint32));
    uint32 prev = reinterpret_cast<const uint32*>(buf)[0];
    uint32 result = Next(prev);

    post_thread_->PostDelayed(200, post_handler_, 0, new TestMessage(result));
  }

 private:
  AsyncUDPSocket* socket_;
  Thread* post_thread_;
  MessageHandler* post_handler_;
};

// Receives messages and sends on a socket.
class MessageClient : public MessageHandler, public TestGenerator {
 public:
  MessageClient(Thread* pth, Socket* socket)
      : socket_(socket) {
  }

  virtual ~MessageClient() {
    delete socket_;
  }

  virtual void OnMessage(Message *pmsg) {
    TestMessage* msg = static_cast<TestMessage*>(pmsg->pdata);
    int result = Next(msg->value);
    EXPECT_GE(socket_->Send(&result, sizeof(result)), 0);
    delete msg;
  }

 private:
  Socket* socket_;
};

class CustomThread : public rtc::Thread {
 public:
  CustomThread() {}
  virtual ~CustomThread() { Stop(); }
  bool Start() { return false; }

  bool WrapCurrent() {
    return Thread::WrapCurrent();
  }
  void UnwrapCurrent() {
    Thread::UnwrapCurrent();
  }
};

// A thread that does nothing when it runs and signals an event
// when it is destroyed.
class SignalWhenDestroyedThread : public Thread {
 public:
  SignalWhenDestroyedThread(Event* event)
      : event_(event) {
  }

  virtual ~SignalWhenDestroyedThread() {
    Stop();
    event_->Set();
  }

  virtual void Run() {
    // Do nothing.
  }

 private:
  Event* event_;
};

// Function objects to test Thread::Invoke.
struct FunctorA {
  int operator()() { return 42; }
};
class FunctorB {
 public:
  explicit FunctorB(bool* flag) : flag_(flag) {}
  void operator()() { if (flag_) *flag_ = true; }
 private:
  bool* flag_;
};
struct FunctorC {
  int operator()() {
    Thread::Current()->ProcessMessages(50);
    return 24;
  }
};

// See: https://code.google.com/p/webrtc/issues/detail?id=2409
TEST(ThreadTest, DISABLED_Main) {
  const SocketAddress addr("127.0.0.1", 0);

  // Create the messaging client on its own thread.
  Thread th1;
  Socket* socket = th1.socketserver()->CreateAsyncSocket(addr.family(),
                                                         SOCK_DGRAM);
  MessageClient msg_client(&th1, socket);

  // Create the socket client on its own thread.
  Thread th2;
  AsyncSocket* asocket =
      th2.socketserver()->CreateAsyncSocket(addr.family(), SOCK_DGRAM);
  SocketClient sock_client(asocket, addr, &th1, &msg_client);

  socket->Connect(sock_client.address());

  th1.Start();
  th2.Start();

  // Get the messages started.
  th1.PostDelayed(100, &msg_client, 0, new TestMessage(1));

  // Give the clients a little while to run.
  // Messages will be processed at 100, 300, 500, 700, 900.
  Thread* th_main = Thread::Current();
  th_main->ProcessMessages(1000);

  // Stop the sending client. Give the receiver a bit longer to run, in case
  // it is running on a machine that is under load (e.g. the build machine).
  th1.Stop();
  th_main->ProcessMessages(200);
  th2.Stop();

  // Make sure the results were correct
  EXPECT_EQ(5, msg_client.count);
  EXPECT_EQ(34, msg_client.last);
  EXPECT_EQ(5, sock_client.count);
  EXPECT_EQ(55, sock_client.last);
}

// Test that setting thread names doesn't cause a malfunction.
// There's no easy way to verify the name was set properly at this time.
TEST(ThreadTest, DISABLED_ON_MAC(Names)) {
  // Default name
  Thread *thread;
  thread = new Thread();
  EXPECT_TRUE(thread->Start());
  thread->Stop();
  delete thread;
  thread = new Thread();
  // Name with no object parameter
  EXPECT_TRUE(thread->SetName("No object", NULL));
  EXPECT_TRUE(thread->Start());
  thread->Stop();
  delete thread;
  // Really long name
  thread = new Thread();
  EXPECT_TRUE(thread->SetName("Abcdefghijklmnopqrstuvwxyz1234567890", this));
  EXPECT_TRUE(thread->Start());
  thread->Stop();
  delete thread;
}

// Test that setting thread priorities doesn't cause a malfunction.
// There's no easy way to verify the priority was set properly at this time.
TEST(ThreadTest, DISABLED_ON_MAC(Priorities)) {
  Thread *thread;
  thread = new Thread();
  EXPECT_TRUE(thread->SetPriority(PRIORITY_HIGH));
  EXPECT_TRUE(thread->Start());
  thread->Stop();
  delete thread;
  thread = new Thread();
  EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
  EXPECT_TRUE(thread->Start());
  thread->Stop();
  delete thread;

  thread = new Thread();
  EXPECT_TRUE(thread->Start());
#if defined(WEBRTC_WIN)
  EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
#else
  EXPECT_FALSE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
#endif
  thread->Stop();
  delete thread;

}

TEST(ThreadTest, DISABLED_ON_MAC(Wrap)) {
  CustomThread* cthread = new CustomThread();
  EXPECT_TRUE(cthread->WrapCurrent());
  EXPECT_TRUE(cthread->RunningForTest());
  EXPECT_FALSE(cthread->IsOwned());
  cthread->UnwrapCurrent();
  EXPECT_FALSE(cthread->RunningForTest());
  delete cthread;
}

TEST(ThreadTest, DISABLED_ON_MAC(Invoke)) {
  // Create and start the thread.
  Thread thread;
  thread.Start();
  // Try calling functors.
  EXPECT_EQ(42, thread.Invoke<int>(FunctorA()));
  bool called = false;
  FunctorB f2(&called);
  thread.Invoke<void>(f2);
  EXPECT_TRUE(called);
  // Try calling bare functions.
  struct LocalFuncs {
    static int Func1() { return 999; }
    static void Func2() {}
  };
  EXPECT_EQ(999, thread.Invoke<int>(&LocalFuncs::Func1));
  thread.Invoke<void>(&LocalFuncs::Func2);
}

class AsyncInvokeTest : public testing::Test {
 public:
  void IntCallback(int value) {
    EXPECT_EQ(expected_thread_, Thread::Current());
    int_value_ = value;
  }
  void AsyncInvokeIntCallback(AsyncInvoker* invoker, Thread* thread) {
    expected_thread_ = thread;
    invoker->AsyncInvoke(thread, FunctorC(),
                         &AsyncInvokeTest::IntCallback,
                         static_cast<AsyncInvokeTest*>(this));
    invoke_started_.Set();
  }
  void SetExpectedThreadForIntCallback(Thread* thread) {
    expected_thread_ = thread;
  }

 protected:
  enum { kWaitTimeout = 1000 };
  AsyncInvokeTest()
      : int_value_(0),
        invoke_started_(true, false),
        expected_thread_(NULL) {}

  int int_value_;
  Event invoke_started_;
  Thread* expected_thread_;
};

TEST_F(AsyncInvokeTest, DISABLED_ON_MAC(FireAndForget)) {
  AsyncInvoker invoker;
  // Create and start the thread.
  Thread thread;
  thread.Start();
  // Try calling functor.
  bool called = false;
  invoker.AsyncInvoke<void>(&thread, FunctorB(&called));
  EXPECT_TRUE_WAIT(called, kWaitTimeout);
}

TEST_F(AsyncInvokeTest, DISABLED_ON_MAC(WithCallback)) {
  AsyncInvoker invoker;
  // Create and start the thread.
  Thread thread;
  thread.Start();
  // Try calling functor.
  SetExpectedThreadForIntCallback(Thread::Current());
  invoker.AsyncInvoke(&thread, FunctorA(),
                      &AsyncInvokeTest::IntCallback,
                      static_cast<AsyncInvokeTest*>(this));
  EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout);
}

TEST_F(AsyncInvokeTest, DISABLED_ON_MAC(CancelInvoker)) {
  // Create and start the thread.
  Thread thread;
  thread.Start();
  // Try destroying invoker during call.
  {
    AsyncInvoker invoker;
    invoker.AsyncInvoke(&thread, FunctorC(),
                        &AsyncInvokeTest::IntCallback,
                        static_cast<AsyncInvokeTest*>(this));
  }
  // With invoker gone, callback should be cancelled.
  Thread::Current()->ProcessMessages(kWaitTimeout);
  EXPECT_EQ(0, int_value_);
}

TEST_F(AsyncInvokeTest, DISABLED_ON_MAC(CancelCallingThread)) {
  AsyncInvoker invoker;
  { // Create and start the thread.
    Thread thread;
    thread.Start();
    // Try calling functor.
    thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
                             static_cast<AsyncInvokeTest*>(this),
                             &invoker, Thread::Current()));
    // Wait for the call to begin.
    ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
  }
  // Calling thread is gone. Return message shouldn't happen.
  Thread::Current()->ProcessMessages(kWaitTimeout);
  EXPECT_EQ(0, int_value_);
}

TEST_F(AsyncInvokeTest, DISABLED_ON_MAC(KillInvokerBeforeExecute)) {
  Thread thread;
  thread.Start();
  {
    AsyncInvoker invoker;
    // Try calling functor.
    thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
                             static_cast<AsyncInvokeTest*>(this),
                             &invoker, Thread::Current()));
    // Wait for the call to begin.
    ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
  }
  // Invoker is destroyed. Function should not execute.
  Thread::Current()->ProcessMessages(kWaitTimeout);
  EXPECT_EQ(0, int_value_);
}

TEST_F(AsyncInvokeTest, Flush) {
  AsyncInvoker invoker;
  bool flag1 = false;
  bool flag2 = false;
  // Queue two async calls to the current thread.
  invoker.AsyncInvoke<void>(Thread::Current(),
                            FunctorB(&flag1));
  invoker.AsyncInvoke<void>(Thread::Current(),
                            FunctorB(&flag2));
  // Because we haven't pumped messages, these should not have run yet.
  EXPECT_FALSE(flag1);
  EXPECT_FALSE(flag2);
  // Force them to run now.
  invoker.Flush(Thread::Current());
  EXPECT_TRUE(flag1);
  EXPECT_TRUE(flag2);
}

TEST_F(AsyncInvokeTest, FlushWithIds) {
  AsyncInvoker invoker;
  bool flag1 = false;
  bool flag2 = false;
  // Queue two async calls to the current thread, one with a message id.
  invoker.AsyncInvoke<void>(Thread::Current(),
                            FunctorB(&flag1),
                            5);
  invoker.AsyncInvoke<void>(Thread::Current(),
                            FunctorB(&flag2));
  // Because we haven't pumped messages, these should not have run yet.
  EXPECT_FALSE(flag1);
  EXPECT_FALSE(flag2);
  // Execute pending calls with id == 5.
  invoker.Flush(Thread::Current(), 5);
  EXPECT_TRUE(flag1);
  EXPECT_FALSE(flag2);
  flag1 = false;
  // Execute all pending calls. The id == 5 call should not execute again.
  invoker.Flush(Thread::Current());
  EXPECT_FALSE(flag1);
  EXPECT_TRUE(flag2);
}

#if defined(WEBRTC_WIN)
class ComThreadTest : public testing::Test, public MessageHandler {
 public:
  ComThreadTest() : done_(false) {}
 protected:
  virtual void OnMessage(Message* message) {
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    // S_FALSE means the thread was already inited for a multithread apartment.
    EXPECT_EQ(S_FALSE, hr);
    if (SUCCEEDED(hr)) {
      CoUninitialize();
    }
    done_ = true;
  }
  bool done_;
};

TEST_F(ComThreadTest, ComInited) {
  Thread* thread = new ComThread();
  EXPECT_TRUE(thread->Start());
  thread->Post(this, 0);
  EXPECT_TRUE_WAIT(done_, 1000);
  delete thread;
}
#endif
<commit_msg>Additional disabled tests in rtc_unittests.<commit_after>/*
 *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/base/asyncinvoker.h"
#include "webrtc/base/asyncudpsocket.h"
#include "webrtc/base/event.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/physicalsocketserver.h"
#include "webrtc/base/socketaddress.h"
#include "webrtc/base/thread.h"
#include "webrtc/test/testsupport/gtest_disable.h"

#if defined(WEBRTC_WIN)
#include <comdef.h>  // NOLINT
#endif

using namespace rtc;

// Generates a sequence of numbers (collaboratively).
class TestGenerator {
 public:
  TestGenerator() : last(0), count(0) {}

  int Next(int prev) {
    int result = prev + last;
    last = result;
    count += 1;
    return result;
  }

  int last;
  int count;
};

struct TestMessage : public MessageData {
  explicit TestMessage(int v) : value(v) {}
  virtual ~TestMessage() {}

  int value;
};

// Receives on a socket and sends by posting messages.
class SocketClient : public TestGenerator, public sigslot::has_slots<> {
 public:
  SocketClient(AsyncSocket* socket, const SocketAddress& addr,
               Thread* post_thread, MessageHandler* phandler)
      : socket_(AsyncUDPSocket::Create(socket, addr)),
        post_thread_(post_thread),
        post_handler_(phandler) {
    socket_->SignalReadPacket.connect(this, &SocketClient::OnPacket);
  }

  ~SocketClient() {
    delete socket_;
  }

  SocketAddress address() const { return socket_->GetLocalAddress(); }

  void OnPacket(AsyncPacketSocket* socket, const char* buf, size_t size,
                const SocketAddress& remote_addr,
                const PacketTime& packet_time) {
    EXPECT_EQ(size, sizeof(uint32));
    uint32 prev = reinterpret_cast<const uint32*>(buf)[0];
    uint32 result = Next(prev);

    post_thread_->PostDelayed(200, post_handler_, 0, new TestMessage(result));
  }

 private:
  AsyncUDPSocket* socket_;
  Thread* post_thread_;
  MessageHandler* post_handler_;
};

// Receives messages and sends on a socket.
class MessageClient : public MessageHandler, public TestGenerator {
 public:
  MessageClient(Thread* pth, Socket* socket)
      : socket_(socket) {
  }

  virtual ~MessageClient() {
    delete socket_;
  }

  virtual void OnMessage(Message *pmsg) {
    TestMessage* msg = static_cast<TestMessage*>(pmsg->pdata);
    int result = Next(msg->value);
    EXPECT_GE(socket_->Send(&result, sizeof(result)), 0);
    delete msg;
  }

 private:
  Socket* socket_;
};

class CustomThread : public rtc::Thread {
 public:
  CustomThread() {}
  virtual ~CustomThread() { Stop(); }
  bool Start() { return false; }

  bool WrapCurrent() {
    return Thread::WrapCurrent();
  }
  void UnwrapCurrent() {
    Thread::UnwrapCurrent();
  }
};

// A thread that does nothing when it runs and signals an event
// when it is destroyed.
class SignalWhenDestroyedThread : public Thread {
 public:
  SignalWhenDestroyedThread(Event* event)
      : event_(event) {
  }

  virtual ~SignalWhenDestroyedThread() {
    Stop();
    event_->Set();
  }

  virtual void Run() {
    // Do nothing.
  }

 private:
  Event* event_;
};

// Function objects to test Thread::Invoke.
struct FunctorA {
  int operator()() { return 42; }
};
class FunctorB {
 public:
  explicit FunctorB(bool* flag) : flag_(flag) {}
  void operator()() { if (flag_) *flag_ = true; }
 private:
  bool* flag_;
};
struct FunctorC {
  int operator()() {
    Thread::Current()->ProcessMessages(50);
    return 24;
  }
};

// See: https://code.google.com/p/webrtc/issues/detail?id=2409
TEST(ThreadTest, DISABLED_Main) {
  const SocketAddress addr("127.0.0.1", 0);

  // Create the messaging client on its own thread.
  Thread th1;
  Socket* socket = th1.socketserver()->CreateAsyncSocket(addr.family(),
                                                         SOCK_DGRAM);
  MessageClient msg_client(&th1, socket);

  // Create the socket client on its own thread.
  Thread th2;
  AsyncSocket* asocket =
      th2.socketserver()->CreateAsyncSocket(addr.family(), SOCK_DGRAM);
  SocketClient sock_client(asocket, addr, &th1, &msg_client);

  socket->Connect(sock_client.address());

  th1.Start();
  th2.Start();

  // Get the messages started.
  th1.PostDelayed(100, &msg_client, 0, new TestMessage(1));

  // Give the clients a little while to run.
  // Messages will be processed at 100, 300, 500, 700, 900.
  Thread* th_main = Thread::Current();
  th_main->ProcessMessages(1000);

  // Stop the sending client. Give the receiver a bit longer to run, in case
  // it is running on a machine that is under load (e.g. the build machine).
  th1.Stop();
  th_main->ProcessMessages(200);
  th2.Stop();

  // Make sure the results were correct
  EXPECT_EQ(5, msg_client.count);
  EXPECT_EQ(34, msg_client.last);
  EXPECT_EQ(5, sock_client.count);
  EXPECT_EQ(55, sock_client.last);
}

// Test that setting thread names doesn't cause a malfunction.
// There's no easy way to verify the name was set properly at this time.
TEST(ThreadTest, DISABLED_ON_MAC(Names)) {
  // Default name
  Thread *thread;
  thread = new Thread();
  EXPECT_TRUE(thread->Start());
  thread->Stop();
  delete thread;
  thread = new Thread();
  // Name with no object parameter
  EXPECT_TRUE(thread->SetName("No object", NULL));
  EXPECT_TRUE(thread->Start());
  thread->Stop();
  delete thread;
  // Really long name
  thread = new Thread();
  EXPECT_TRUE(thread->SetName("Abcdefghijklmnopqrstuvwxyz1234567890", this));
  EXPECT_TRUE(thread->Start());
  thread->Stop();
  delete thread;
}

// Test that setting thread priorities doesn't cause a malfunction.
// There's no easy way to verify the priority was set properly at this time.
TEST(ThreadTest, DISABLED_ON_MAC(Priorities)) {
  Thread *thread;
  thread = new Thread();
  EXPECT_TRUE(thread->SetPriority(PRIORITY_HIGH));
  EXPECT_TRUE(thread->Start());
  thread->Stop();
  delete thread;
  thread = new Thread();
  EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
  EXPECT_TRUE(thread->Start());
  thread->Stop();
  delete thread;

  thread = new Thread();
  EXPECT_TRUE(thread->Start());
#if defined(WEBRTC_WIN)
  EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
#else
  EXPECT_FALSE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
#endif
  thread->Stop();
  delete thread;

}

TEST(ThreadTest, DISABLED_ON_MAC(Wrap)) {
  CustomThread* cthread = new CustomThread();
  EXPECT_TRUE(cthread->WrapCurrent());
  EXPECT_TRUE(cthread->RunningForTest());
  EXPECT_FALSE(cthread->IsOwned());
  cthread->UnwrapCurrent();
  EXPECT_FALSE(cthread->RunningForTest());
  delete cthread;
}

TEST(ThreadTest, DISABLED_ON_MAC(Invoke)) {
  // Create and start the thread.
  Thread thread;
  thread.Start();
  // Try calling functors.
  EXPECT_EQ(42, thread.Invoke<int>(FunctorA()));
  bool called = false;
  FunctorB f2(&called);
  thread.Invoke<void>(f2);
  EXPECT_TRUE(called);
  // Try calling bare functions.
  struct LocalFuncs {
    static int Func1() { return 999; }
    static void Func2() {}
  };
  EXPECT_EQ(999, thread.Invoke<int>(&LocalFuncs::Func1));
  thread.Invoke<void>(&LocalFuncs::Func2);
}

class AsyncInvokeTest : public testing::Test {
 public:
  void IntCallback(int value) {
    EXPECT_EQ(expected_thread_, Thread::Current());
    int_value_ = value;
  }
  void AsyncInvokeIntCallback(AsyncInvoker* invoker, Thread* thread) {
    expected_thread_ = thread;
    invoker->AsyncInvoke(thread, FunctorC(),
                         &AsyncInvokeTest::IntCallback,
                         static_cast<AsyncInvokeTest*>(this));
    invoke_started_.Set();
  }
  void SetExpectedThreadForIntCallback(Thread* thread) {
    expected_thread_ = thread;
  }

 protected:
  enum { kWaitTimeout = 1000 };
  AsyncInvokeTest()
      : int_value_(0),
        invoke_started_(true, false),
        expected_thread_(NULL) {}

  int int_value_;
  Event invoke_started_;
  Thread* expected_thread_;
};

TEST_F(AsyncInvokeTest, DISABLED_FireAndForget) {
  AsyncInvoker invoker;
  // Create and start the thread.
  Thread thread;
  thread.Start();
  // Try calling functor.
  bool called = false;
  invoker.AsyncInvoke<void>(&thread, FunctorB(&called));
  EXPECT_TRUE_WAIT(called, kWaitTimeout);
}

TEST_F(AsyncInvokeTest, DISABLED_WithCallback) {
  AsyncInvoker invoker;
  // Create and start the thread.
  Thread thread;
  thread.Start();
  // Try calling functor.
  SetExpectedThreadForIntCallback(Thread::Current());
  invoker.AsyncInvoke(&thread, FunctorA(),
                      &AsyncInvokeTest::IntCallback,
                      static_cast<AsyncInvokeTest*>(this));
  EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout);
}

TEST_F(AsyncInvokeTest, DISABLED_CancelInvoker) {
  // Create and start the thread.
  Thread thread;
  thread.Start();
  // Try destroying invoker during call.
  {
    AsyncInvoker invoker;
    invoker.AsyncInvoke(&thread, FunctorC(),
                        &AsyncInvokeTest::IntCallback,
                        static_cast<AsyncInvokeTest*>(this));
  }
  // With invoker gone, callback should be cancelled.
  Thread::Current()->ProcessMessages(kWaitTimeout);
  EXPECT_EQ(0, int_value_);
}

TEST_F(AsyncInvokeTest, DISABLED_CancelCallingThread) {
  AsyncInvoker invoker;
  { // Create and start the thread.
    Thread thread;
    thread.Start();
    // Try calling functor.
    thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
                             static_cast<AsyncInvokeTest*>(this),
                             &invoker, Thread::Current()));
    // Wait for the call to begin.
    ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
  }
  // Calling thread is gone. Return message shouldn't happen.
  Thread::Current()->ProcessMessages(kWaitTimeout);
  EXPECT_EQ(0, int_value_);
}

TEST_F(AsyncInvokeTest, DISABLED_KillInvokerBeforeExecute) {
  Thread thread;
  thread.Start();
  {
    AsyncInvoker invoker;
    // Try calling functor.
    thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
                             static_cast<AsyncInvokeTest*>(this),
                             &invoker, Thread::Current()));
    // Wait for the call to begin.
    ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
  }
  // Invoker is destroyed. Function should not execute.
  Thread::Current()->ProcessMessages(kWaitTimeout);
  EXPECT_EQ(0, int_value_);
}

TEST_F(AsyncInvokeTest, DISABLED_Flush) {
  AsyncInvoker invoker;
  bool flag1 = false;
  bool flag2 = false;
  // Queue two async calls to the current thread.
  invoker.AsyncInvoke<void>(Thread::Current(),
                            FunctorB(&flag1));
  invoker.AsyncInvoke<void>(Thread::Current(),
                            FunctorB(&flag2));
  // Because we haven't pumped messages, these should not have run yet.
  EXPECT_FALSE(flag1);
  EXPECT_FALSE(flag2);
  // Force them to run now.
  invoker.Flush(Thread::Current());
  EXPECT_TRUE(flag1);
  EXPECT_TRUE(flag2);
}

TEST_F(AsyncInvokeTest, DISABLED_FlushWithIds) {
  AsyncInvoker invoker;
  bool flag1 = false;
  bool flag2 = false;
  // Queue two async calls to the current thread, one with a message id.
  invoker.AsyncInvoke<void>(Thread::Current(),
                            FunctorB(&flag1),
                            5);
  invoker.AsyncInvoke<void>(Thread::Current(),
                            FunctorB(&flag2));
  // Because we haven't pumped messages, these should not have run yet.
  EXPECT_FALSE(flag1);
  EXPECT_FALSE(flag2);
  // Execute pending calls with id == 5.
  invoker.Flush(Thread::Current(), 5);
  EXPECT_TRUE(flag1);
  EXPECT_FALSE(flag2);
  flag1 = false;
  // Execute all pending calls. The id == 5 call should not execute again.
  invoker.Flush(Thread::Current());
  EXPECT_FALSE(flag1);
  EXPECT_TRUE(flag2);
}

#if defined(WEBRTC_WIN)
class ComThreadTest : public testing::Test, public MessageHandler {
 public:
  ComThreadTest() : done_(false) {}
 protected:
  virtual void OnMessage(Message* message) {
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    // S_FALSE means the thread was already inited for a multithread apartment.
    EXPECT_EQ(S_FALSE, hr);
    if (SUCCEEDED(hr)) {
      CoUninitialize();
    }
    done_ = true;
  }
  bool done_;
};

TEST_F(ComThreadTest, ComInited) {
  Thread* thread = new ComThread();
  EXPECT_TRUE(thread->Start());
  thread->Post(this, 0);
  EXPECT_TRUE_WAIT(done_, 1000);
  delete thread;
}
#endif
<|endoftext|>


<commit_before>/*
 *
 * Copyright (C) 2019-2021 Intel Corporation
 *
 * SPDX-License-Identifier: MIT
 *
 * @file ze_lib.cpp
 *
 */
#include "ze_lib.h"
#ifndef DYNAMIC_LOAD_LOADER
#include "../loader/ze_loader_api.h"
#endif

namespace ze_lib
{
    ///////////////////////////////////////////////////////////////////////////////
    context_t *context;

    ///////////////////////////////////////////////////////////////////////////////
    context_t::context_t()
    {
    };

    ///////////////////////////////////////////////////////////////////////////////
    context_t::~context_t()
    {
#ifdef DYNAMIC_LOAD_LOADER
        FREE_DRIVER_LIBRARY( loader );
#endif
    };

    //////////////////////////////////////////////////////////////////////////
    __zedlllocal ze_result_t context_t::Init(ze_init_flags_t flags)
    {
        ze_result_t result;
#ifdef DYNAMIC_LOAD_LOADER
        std::string loaderLibraryPath;
#ifdef _WIN32
        loaderLibraryPath = readLevelZeroLoaderLibraryPath();
#endif
        std::string loaderFullLibraryPath = create_library_path(MAKE_LIBRARY_NAME( "ze_loader", L0_LOADER_VERSION), loaderLibraryPath.c_str());
        loader = LOAD_DRIVER_LIBRARY(loaderFullLibraryPath.c_str());

        if( NULL == loader )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        typedef ze_result_t (ZE_APICALL *loaderInit_t)();
        auto loaderInit = reinterpret_cast<loaderInit_t>(
                GET_FUNCTION_PTR(loader, "zeLoaderInit") );
        result = loaderInit();
        if( ZE_RESULT_SUCCESS == result ) {
            typedef HMODULE (ZE_APICALL *getTracing_t)();
            auto getTracing = reinterpret_cast<getTracing_t>(
                GET_FUNCTION_PTR(loader, "zeLoaderGetTracingHandle") );
            tracing_lib = getTracing();
        }
#else
        result = zeLoaderInit();
        if( ZE_RESULT_SUCCESS == result ) {
            tracing_lib = zeLoaderGetTracingHandle();
        }

#endif

        if( ZE_RESULT_SUCCESS == result )
        {
            result = zeInit();
        }

        if( ZE_RESULT_SUCCESS == result )
        {
            result = zetInit();
        }

        if( ZE_RESULT_SUCCESS == result )
        {
            result = zesInit();
        }

        if( ZE_RESULT_SUCCESS == result )
        {
            result = zelTracingInit();
        }

        result = zelLoaderDriverCheck(flags);

        return result;
    }

} // namespace ze_lib

extern "C" {

ze_result_t ZE_APICALL
zelLoaderGetVersions(
   size_t *num_elems,                     //Pointer to num versions to get.
   zel_component_version_t *versions)     //Pointer to array of versions. If set to NULL, num_elems is returned
{
#ifdef DYNAMIC_LOAD_LOADER
    if(nullptr == ze_lib::context->loader)
        return ZE_RESULT_ERROR;
    typedef ze_result_t (ZE_APICALL *zelLoaderGetVersions_t)(size_t *num_elems, zel_component_version_t *versions);
    auto getVersions = reinterpret_cast<zelLoaderGetVersions_t>(
            GET_FUNCTION_PTR(ze_lib::context->loader, "zelLoaderGetVersionsInternal") );
    return getVersions(num_elems, versions);
#else
    return zelLoaderGetVersionsInternal(num_elems, versions);
#endif
}

ze_result_t ZE_APICALL
zelLoaderTranslateHandle(
   zel_handle_type_t handleType,
   void *handleIn,
   void **handleOut)

{
    return zelLoaderTranslateHandleInternal(handleType, handleIn, handleOut);
}

} //extern "c"<commit_msg>Add success test guard around LoaderDriverCheck()<commit_after>/*
 *
 * Copyright (C) 2019-2021 Intel Corporation
 *
 * SPDX-License-Identifier: MIT
 *
 * @file ze_lib.cpp
 *
 */
#include "ze_lib.h"
#ifndef DYNAMIC_LOAD_LOADER
#include "../loader/ze_loader_api.h"
#endif

namespace ze_lib
{
    ///////////////////////////////////////////////////////////////////////////////
    context_t *context;

    ///////////////////////////////////////////////////////////////////////////////
    context_t::context_t()
    {
    };

    ///////////////////////////////////////////////////////////////////////////////
    context_t::~context_t()
    {
#ifdef DYNAMIC_LOAD_LOADER
        FREE_DRIVER_LIBRARY( loader );
#endif
    };

    //////////////////////////////////////////////////////////////////////////
    __zedlllocal ze_result_t context_t::Init(ze_init_flags_t flags)
    {
        ze_result_t result;
#ifdef DYNAMIC_LOAD_LOADER
        std::string loaderLibraryPath;
#ifdef _WIN32
        loaderLibraryPath = readLevelZeroLoaderLibraryPath();
#endif
        std::string loaderFullLibraryPath = create_library_path(MAKE_LIBRARY_NAME( "ze_loader", L0_LOADER_VERSION), loaderLibraryPath.c_str());
        loader = LOAD_DRIVER_LIBRARY(loaderFullLibraryPath.c_str());

        if( NULL == loader )
            return ZE_RESULT_ERROR_UNINITIALIZED;

        typedef ze_result_t (ZE_APICALL *loaderInit_t)();
        auto loaderInit = reinterpret_cast<loaderInit_t>(
                GET_FUNCTION_PTR(loader, "zeLoaderInit") );
        result = loaderInit();
        if( ZE_RESULT_SUCCESS == result ) {
            typedef HMODULE (ZE_APICALL *getTracing_t)();
            auto getTracing = reinterpret_cast<getTracing_t>(
                GET_FUNCTION_PTR(loader, "zeLoaderGetTracingHandle") );
            tracing_lib = getTracing();
        }
#else
        result = zeLoaderInit();
        if( ZE_RESULT_SUCCESS == result ) {
            tracing_lib = zeLoaderGetTracingHandle();
        }

#endif

        if( ZE_RESULT_SUCCESS == result )
        {
            result = zeInit();
        }

        if( ZE_RESULT_SUCCESS == result )
        {
            result = zetInit();
        }

        if( ZE_RESULT_SUCCESS == result )
        {
            result = zesInit();
        }

        if( ZE_RESULT_SUCCESS == result )
        {
            result = zelTracingInit();
        }

        if( ZE_RESULT_SUCCESS == result )
        {
            result = zelLoaderDriverCheck(flags);
        }

        return result;
    }

} // namespace ze_lib

extern "C" {

ze_result_t ZE_APICALL
zelLoaderGetVersions(
   size_t *num_elems,                     //Pointer to num versions to get.
   zel_component_version_t *versions)     //Pointer to array of versions. If set to NULL, num_elems is returned
{
#ifdef DYNAMIC_LOAD_LOADER
    if(nullptr == ze_lib::context->loader)
        return ZE_RESULT_ERROR;
    typedef ze_result_t (ZE_APICALL *zelLoaderGetVersions_t)(size_t *num_elems, zel_component_version_t *versions);
    auto getVersions = reinterpret_cast<zelLoaderGetVersions_t>(
            GET_FUNCTION_PTR(ze_lib::context->loader, "zelLoaderGetVersionsInternal") );
    return getVersions(num_elems, versions);
#else
    return zelLoaderGetVersionsInternal(num_elems, versions);
#endif
}

ze_result_t ZE_APICALL
zelLoaderTranslateHandle(
   zel_handle_type_t handleType,
   void *handleIn,
   void **handleOut)

{
    return zelLoaderTranslateHandleInternal(handleType, handleIn, handleOut);
}

} //extern "c"<|endoftext|>


<commit_before>/*  This file is part of the Vc library.

    Copyright (C) 2009 Matthias Kretz <kretz@kde.org>

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

    Vc 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 Vc.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <Vc/Vc>
#include "benchmark.h"
#include "random.h"
#include <limits>

using namespace Vc;

enum {
    MemorySize = 1024 * 1024 * 64 // 64 MiB
};

void *blackHolePtr = 0;

template<typename V>
static void doBlah()
{
    typedef typename V::EntryType T;
    typedef typename V::IndexType I;
    typedef typename V::Mask M;

    const T two = 2;
    const T divider = std::numeric_limits<T>::max() / 1500;
    const T bound = 1000;

    enum {
        ArraySize = MemorySize / sizeof(V)
    };
    union {
        V *v;
        T *t;
    } mem = { new V[ArraySize] };
    for (int i = 0; i < ArraySize; ++i) {
        mem.v[i] = PseudoRandom<V>::next();
    }
    V t = mem.v[0];
    mem.v[0].setZero();
    for (int i = 1; i < ArraySize; ++i) {
        t = (t * mem.v[i] + t) / divider;
        t(t >= bound || t < 0) = two;
        mem.v[i] = t;
        t(t == 0) += V(One);
    }
    M mask;
    T data[1000];
    for (I i(Vc::Zero); !(mask = i < 1000).isEmpty(); i += I::Size) {
        I i2 = static_cast<I>(V(mem.t, i, mask));
        V v(data, i2, mask);
        v = v * two + t;
        v.scatter(data, i2, mask);
    }
    asm volatile(""::"r"(&data[0]));
    blackHolePtr = mem.v;
}

template<typename V>
static double opsFactor()
{
    enum {
        ArraySize = MemorySize / sizeof(V)
    };
    return V::Size * (ArraySize * (5 + 10) + (1000 + V::Size - 1) / V::Size * 5);
}

int bmain()
{
    Benchmark timer("DhryRock", opsFactor<int_v>() + opsFactor<uint_v>() + opsFactor<short_v>() + opsFactor<ushort_v>(), "Op");
    while (timer.wantsMoreDataPoints()) {
        timer.Start();
        doBlah<int_v>();
        delete[] static_cast<int_v *>(blackHolePtr);
        doBlah<uint_v>();
        delete[] static_cast<uint_v *>(blackHolePtr);
        doBlah<short_v>();
        delete[] static_cast<short_v *>(blackHolePtr);
        doBlah<ushort_v>();
        delete[] static_cast<ushort_v *>(blackHolePtr);
        timer.Stop();
    }
    timer.Print();
    return 0;
}
<commit_msg>same as in whetrock, this DCE inhibition via inline asm does not work on non-GNU<commit_after>/*  This file is part of the Vc library.

    Copyright (C) 2009 Matthias Kretz <kretz@kde.org>

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

    Vc 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 Vc.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <Vc/Vc>
#include "benchmark.h"
#include "random.h"
#include <limits>

using namespace Vc;

enum {
    MemorySize = 1024 * 1024 * 64 // 64 MiB
};

void *blackHolePtr = 0;

template<typename V>
static void doBlah()
{
    typedef typename V::EntryType T;
    typedef typename V::IndexType I;
    typedef typename V::Mask M;

    const T two = 2;
    const T divider = std::numeric_limits<T>::max() / 1500;
    const T bound = 1000;

    enum {
        ArraySize = MemorySize / sizeof(V)
    };
    union {
        V *v;
        T *t;
    } mem = { new V[ArraySize] };
    for (int i = 0; i < ArraySize; ++i) {
        mem.v[i] = PseudoRandom<V>::next();
    }
    V t = mem.v[0];
    mem.v[0].setZero();
    for (int i = 1; i < ArraySize; ++i) {
        t = (t * mem.v[i] + t) / divider;
        t(t >= bound || t < 0) = two;
        mem.v[i] = t;
        t(t == 0) += V(One);
    }
    M mask;
    T data[1000];
    for (I i(Vc::Zero); !(mask = i < 1000).isEmpty(); i += I::Size) {
        I i2 = static_cast<I>(V(mem.t, i, mask));
        V v(data, i2, mask);
        v = v * two + t;
        v.scatter(data, i2, mask);
    }
#ifdef __GNUC__
    asm volatile(""::"r"(&data[0]));
#endif
    blackHolePtr = mem.v;
}

template<typename V>
static double opsFactor()
{
    enum {
        ArraySize = MemorySize / sizeof(V)
    };
    return V::Size * (ArraySize * (5 + 10) + (1000 + V::Size - 1) / V::Size * 5);
}

int bmain()
{
    Benchmark timer("DhryRock", opsFactor<int_v>() + opsFactor<uint_v>() + opsFactor<short_v>() + opsFactor<ushort_v>(), "Op");
    while (timer.wantsMoreDataPoints()) {
        timer.Start();
        doBlah<int_v>();
        delete[] static_cast<int_v *>(blackHolePtr);
        doBlah<uint_v>();
        delete[] static_cast<uint_v *>(blackHolePtr);
        doBlah<short_v>();
        delete[] static_cast<short_v *>(blackHolePtr);
        doBlah<ushort_v>();
        delete[] static_cast<ushort_v *>(blackHolePtr);
        timer.Stop();
    }
    timer.Print();
    return 0;
}
<|endoftext|>


<commit_before>// External Dependencies
#include <jni.h>

// Local Dependencies
#include "internal.h"

namespace jni
{
	// Forward Declarations
	JNIEnv* env();

	namespace internal
	{
		// Base Type Signatures
		template <> String valueSig(const void*)		{ return "V"; }
		template <> String valueSig(const bool*)		{ return "Z"; }
		template <> String valueSig(const wchar_t*)		{ return "C"; }
		template <> String valueSig(const short*)		{ return "S"; }
		template <> String valueSig(const int*)			{ return "I"; }
		template <> String valueSig(const long long*)	{ return "J"; }
		template <> String valueSig(const float*)		{ return "F"; }
		template <> String valueSig(const double*)		{ return "D"; }

		// Base Type Conversions
		template <> void valueArg(value_t* v, const bool& a)		{ ((jvalue*) v)->z = a; }
		template <> void valueArg(value_t* v, const wchar_t& a)		{ ((jvalue*) v)->c = a; }
		template <> void valueArg(value_t* v, const short& a)		{ ((jvalue*) v)->s = a; }
		template <> void valueArg(value_t* v, const int& a)			{ ((jvalue*) v)->i = a; }
		template <> void valueArg(value_t* v, const long long& a)	{ ((jvalue*) v)->j = a; }
		template <> void valueArg(value_t* v, const float& a)		{ ((jvalue*) v)->f = a; }
		template <> void valueArg(value_t* v, const double& a)		{ ((jvalue*) v)->d = a; }
		template <> void valueArg(value_t* v, const jobject& a)		{ ((jvalue*) v)->l = a; }

		/*
			String Implementations
		 */

		template <> String valueSig(const char* const*)
		{
			return "Ljava/lang/String;";
		}

		template <> String valueSig(const String*)
		{
			return "Ljava/lang/String;";
		}

		template <> void cleanupArg<String>(value_t* v)
		{
			env()->DeleteLocalRef(((jvalue*) v)->l);
		}

		template <> void valueArg(value_t* v, const String& a)
		{
			((jvalue*) v)->l = env()->NewStringUTF(a.c_str());
		}

		template <> void valueArg(value_t* v, const char* const& a)
		{
			((jvalue*) v)->l = env()->NewStringUTF(a);
		}

		template <> void cleanupArg<const char*>(value_t* v)
		{
			env()->DeleteLocalRef(((jvalue*) v)->l);
		}
	}
}

<commit_msg>String argument handling.<commit_after>// External Dependencies
#include <jni.h>

// Local Dependencies
#include "internal.h"

namespace jni
{
	// Forward Declarations
	JNIEnv* env();

	namespace internal
	{
		// Base Type Signatures
		template <> String valueSig(const void*)		{ return "V"; }
		template <> String valueSig(const bool*)		{ return "Z"; }
		template <> String valueSig(const wchar_t*)		{ return "C"; }
		template <> String valueSig(const short*)		{ return "S"; }
		template <> String valueSig(const int*)			{ return "I"; }
		template <> String valueSig(const long long*)	{ return "J"; }
		template <> String valueSig(const float*)		{ return "F"; }
		template <> String valueSig(const double*)		{ return "D"; }

		// Base Type Conversions
		template <> void valueArg(value_t* v, const bool& a)		{ ((jvalue*) v)->z = a; }
		template <> void valueArg(value_t* v, const wchar_t& a)		{ ((jvalue*) v)->c = a; }
		template <> void valueArg(value_t* v, const short& a)		{ ((jvalue*) v)->s = a; }
		template <> void valueArg(value_t* v, const int& a)			{ ((jvalue*) v)->i = a; }
		template <> void valueArg(value_t* v, const long long& a)	{ ((jvalue*) v)->j = a; }
		template <> void valueArg(value_t* v, const float& a)		{ ((jvalue*) v)->f = a; }
		template <> void valueArg(value_t* v, const double& a)		{ ((jvalue*) v)->d = a; }
		template <> void valueArg(value_t* v, const jobject& a)		{ ((jvalue*) v)->l = a; }

		/*
			String Implementations
		 */

		template <> String valueSig(const String*)
		{
			return "Ljava/lang/String;";
		}

		template <> void valueArg(value_t* v, const String& a)
		{
			((jvalue*) v)->l = env()->NewStringUTF(a.c_str());
		}

		template <> void cleanupArg<String>(value_t* v)
		{
			env()->DeleteLocalRef(((jvalue*)v)->l);
		}

		template <> String valueSig(const char* const*)
		{
			return "Ljava/lang/String;";
		}

		template <> void valueArg(value_t* v, const char* const& a)
		{
			((jvalue*) v)->l = env()->NewStringUTF(a);
		}

		template <> void cleanupArg<const char*>(value_t* v)
		{
			env()->DeleteLocalRef(((jvalue*) v)->l);
		}
	}
}

<|endoftext|>