<commit_before>// @(#)root/cont:$Name:  $:$Id: TProcessID.cxx,v 1.16 2002/07/13 16:19:26 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"

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

ClassImp(TProcessID)

//______________________________________________________________________________
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;
}

//______________________________________________________________________________
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)
{
// static function returning a pointer to TProcessID with its pid
// encoded in the highest byte of uid

   Int_t pid = (uid>>24)&0xff;
   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);
}

//______________________________________________________________________________
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);
}

//______________________________________________________________________________
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) return 0;
   TObjArray *pids = file->GetListOfProcessIDs();
   TProcessID *pid = 0;
   if (pidf < pids->GetSize()) pid = (TProcessID *)pids->UncheckedAt(pidf);
   if (pid) 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 (!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->Add(pid);
   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: Add a missing IncrementCount when the processID object is being reused.<commit_after>// @(#)root/cont:$Name:  $:$Id: TProcessID.cxx,v 1.17 2002/08/12 06:20:13 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"

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

ClassImp(TProcessID)

//______________________________________________________________________________
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;
}

//______________________________________________________________________________
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)
{
// static function returning a pointer to TProcessID with its pid
// encoded in the highest byte of uid

   Int_t pid = (uid>>24)&0xff;
   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);
}

//______________________________________________________________________________
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);
}

//______________________________________________________________________________
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) return 0;
   TObjArray *pids = file->GetListOfProcessIDs();
   TProcessID *pid = 0;
   if (pidf < pids->GetSize()) pid = (TProcessID *)pids->UncheckedAt(pidf);
   if (pid) 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 (!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->Add(pid);
   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>// @(#)root/base:$Name:  $:$Id: TVirtualIO.cxx,v 1.17 2006/07/09 05:27:53 brun Exp $
// Author: Rene Brun   24/01/2007
/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//
// TVirtualIO
//
// TVirtualIO is an interface class for File I/O operations.
// The class is used to decouple the base classes from the I/O packages.
// The concrete I/O sub-system is dynamically linked by the PluginManager.
// The default implementation TFileIO can be changed in system.rootrc.
//
//////////////////////////////////////////////////////////////////////////

#include "TVirtualIO.h"
#include "TROOT.h"
#include "TPluginManager.h"
#include "TEnv.h"

TVirtualIO *TVirtualIO::fgIO      = 0;
TString     TVirtualIO::fgDefault = "FileIO";

ClassImp(TVirtualIO)

//______________________________________________________________________________
TVirtualIO::TVirtualIO()
{
   // Default constructor.
}

//______________________________________________________________________________
TVirtualIO::TVirtualIO(const TVirtualIO& io) : TObject(io)
{
   //copy constructor
}

//______________________________________________________________________________
TVirtualIO& TVirtualIO::operator=(const TVirtualIO& io)
{
   //assignment operator
   if(this!=&io) {
      TObject::operator=(io);
   }
   return *this;
}

//______________________________________________________________________________
TVirtualIO::~TVirtualIO()
{
   // destructor

   delete fgIO;
   fgIO = 0;
}

//______________________________________________________________________________
TVirtualIO *TVirtualIO::GetIO()
{
   // Static function returning a pointer to the current I/O class.
   // If the class does not exist, the default TFileIO is created.

   if (!fgIO) {
      TPluginHandler *h;
      if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualIO",fgDefault))) {
         if (h->LoadPlugin() == -1)
            return 0;
         fgIO = (TVirtualIO*) h->ExecPlugin(0);
      }
   }

   return fgIO;
}

//______________________________________________________________________________
const char *TVirtualIO::GetDefaultIO()
{
   // static: return the name of the default I/O class

   return fgDefault.Data();
}

//______________________________________________________________________________
void TVirtualIO::SetDefaultIO(const char *name)
{
   // static: set name of default I/O system

   if (fgDefault == name) return;
   delete fgIO;
   fgIO = 0;
   fgDefault = name;
}
<commit_msg>Do not delete statics in the destructor.<commit_after>// @(#)root/base:$Name:  $:$Id: TVirtualIO.cxx,v 1.1 2007/01/25 11:46:20 brun Exp $
// Author: Rene Brun   24/01/2007
/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//
// TVirtualIO
//
// TVirtualIO is an interface class for File I/O operations.
// The class is used to decouple the base classes from the I/O packages.
// The concrete I/O sub-system is dynamically linked by the PluginManager.
// The default implementation TFileIO can be changed in system.rootrc.
//
//////////////////////////////////////////////////////////////////////////

#include "TVirtualIO.h"
#include "TROOT.h"
#include "TPluginManager.h"
#include "TEnv.h"

TVirtualIO *TVirtualIO::fgIO      = 0;
TString     TVirtualIO::fgDefault = "FileIO";

ClassImp(TVirtualIO)

//______________________________________________________________________________
TVirtualIO::TVirtualIO()
{
   // Default constructor.
}

//______________________________________________________________________________
TVirtualIO::TVirtualIO(const TVirtualIO& io) : TObject(io)
{
   //copy constructor
}

//______________________________________________________________________________
TVirtualIO& TVirtualIO::operator=(const TVirtualIO& io)
{
   //assignment operator
   if(this!=&io) {
      TObject::operator=(io);
   }
   return *this;
}

//______________________________________________________________________________
TVirtualIO::~TVirtualIO()
{
   // destructor

   //delete fgIO;  do not delete these statics
   //fgIO = 0;
}

//______________________________________________________________________________
TVirtualIO *TVirtualIO::GetIO()
{
   // Static function returning a pointer to the current I/O class.
   // If the class does not exist, the default TFileIO is created.

   if (!fgIO) {
      TPluginHandler *h;
      if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualIO",fgDefault))) {
         if (h->LoadPlugin() == -1)
            return 0;
         fgIO = (TVirtualIO*) h->ExecPlugin(0);
      }
   }

   return fgIO;
}

//______________________________________________________________________________
const char *TVirtualIO::GetDefaultIO()
{
   // static: return the name of the default I/O class

   return fgDefault.Data();
}

//______________________________________________________________________________
void TVirtualIO::SetDefaultIO(const char *name)
{
   // static: set name of default I/O system

   if (fgDefault == name) return;
   delete fgIO;
   fgIO = 0;
   fgDefault = name;
}
<|endoftext|>


<commit_before>// @(#)root/base:$Name:  $:$Id: TVirtualPS.cxx,v 1.8 2004/03/17 17:35:31 brun Exp $
// Author: Rene Brun   05/09/99

/*************************************************************************
 * 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.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TVirtualPS is an abstract interface to a Postscript and SVG drivers  //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "Riostream.h"
#include "TVirtualPS.h"

TVirtualPS *gVirtualPS = 0;

const Int_t  kMaxBuffer = 250;

ClassImp(TVirtualPS)

//______________________________________________________________________________
//
//  TVirtualPS is an abstract interface to a Postscript driver
//

//______________________________________________________________________________
TVirtualPS::TVirtualPS()
{
   // VirtualPS default constructor
   fStream    = 0;
   fNByte     = 0;
   fSizBuffer = kMaxBuffer;
   fBuffer    = new char[fSizBuffer+1];
}

//______________________________________________________________________________
TVirtualPS::TVirtualPS(const char *name, Int_t)
          : TNamed(name,"Postscript interface")
{
   // VirtualPS constructor
   fStream    = 0;
   fNByte     = 0;
   fSizBuffer = kMaxBuffer;
   fBuffer    = new char[fSizBuffer];
}

//______________________________________________________________________________
TVirtualPS::~TVirtualPS()
{
   // VirtualPS destructor

   if (fBuffer) delete [] fBuffer;
}

//______________________________________________________________________________
void TVirtualPS::PrintStr(const char *str)
{
   // Output the string str in the output buffer

   Int_t len = strlen(str);
   if (len == 0) return;
   if( str[0] == '@') {
      if( fLenBuffer ) {
         fStream->write(fBuffer, fLenBuffer);
         fStream->write("\n",1); fNByte++;
      }
      if ( len < 2)  {
         fBuffer[0] = ' ';
      } else {
         strcpy(fBuffer, str+1);
      }
      fLenBuffer = len-1;
      fPrinted = kTRUE;
      fNByte += len-1;
      return;
   }

   if( str[len-1] == '@') {
      if( fLenBuffer ) {
         fStream->write(fBuffer, fLenBuffer);
         fStream->write("\n",1); fNByte++;
      }
      fStream->write(str, len-1);
      fStream->write("\n",1);
      fLenBuffer = 0;
      fNByte += len;
      fPrinted = kTRUE;
      return;
   }

   if( (len + fLenBuffer ) > kMaxBuffer) {
      fStream->write(fBuffer, fLenBuffer);
      fStream->write("\n",1); fNByte++;
      strcpy(fBuffer, str);
      fLenBuffer = len;
      fNByte += len;
   } else {
      strcpy(fBuffer + fLenBuffer, str);
      fLenBuffer += len;
      fNByte += len;
   }
   fPrinted = kTRUE;
}

//______________________________________________________________________________
void TVirtualPS::PrintFast(Int_t len, const char *str)
{
   // Fast version of Print

   if( (len + fLenBuffer ) > kMaxBuffer) {
      fStream->write(fBuffer, fLenBuffer);
      fStream->write("\n",1); fNByte++;
      strcpy(fBuffer, str);
      fLenBuffer = len;
   } else {
      strcpy(fBuffer + fLenBuffer, str);
      fLenBuffer += len;
   }
   fNByte += len;
   fPrinted = kTRUE;
}

//______________________________________________________________________________
void TVirtualPS::WriteInteger(Int_t n, Bool_t space )
{
   // Write one Integer to the file
   //
   // n: Integer to be written in the file.
   // space: If TRUE, a space in written before the integer.

   char str[15];
   if (space) {
      sprintf(str," %d", n);
   } else {
      sprintf(str,"%d", n);
   }
   PrintStr(str);
}

//______________________________________________________________________________
void TVirtualPS::WriteReal(Float_t z)
{
   // Write a Real number to the file

   char str[15];
   sprintf(str," %g", z);
   PrintStr(str);
}
<commit_msg>From Olivier: - The previous change must be done in all contructors (obviously !)<commit_after>// @(#)root/base:$Name:  $:$Id: TVirtualPS.cxx,v 1.9 2004/05/10 09:55:40 brun Exp $
// Author: Rene Brun   05/09/99

/*************************************************************************
 * 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.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TVirtualPS is an abstract interface to a Postscript and SVG drivers  //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "Riostream.h"
#include "TVirtualPS.h"

TVirtualPS *gVirtualPS = 0;

const Int_t  kMaxBuffer = 250;

ClassImp(TVirtualPS)

//______________________________________________________________________________
//
//  TVirtualPS is an abstract interface to a Postscript driver
//

//______________________________________________________________________________
TVirtualPS::TVirtualPS()
{
   // VirtualPS default constructor
   fStream    = 0;
   fNByte     = 0;
   fSizBuffer = kMaxBuffer;
   fBuffer    = new char[fSizBuffer+1];
}

//______________________________________________________________________________
TVirtualPS::TVirtualPS(const char *name, Int_t)
          : TNamed(name,"Postscript interface")
{
   // VirtualPS constructor
   fStream    = 0;
   fNByte     = 0;
   fSizBuffer = kMaxBuffer;
   fBuffer    = new char[fSizBuffer+1];
}

//______________________________________________________________________________
TVirtualPS::~TVirtualPS()
{
   // VirtualPS destructor

   if (fBuffer) delete [] fBuffer;
}

//______________________________________________________________________________
void TVirtualPS::PrintStr(const char *str)
{
   // Output the string str in the output buffer

   Int_t len = strlen(str);
   if (len == 0) return;
   if( str[0] == '@') {
      if( fLenBuffer ) {
         fStream->write(fBuffer, fLenBuffer);
         fStream->write("\n",1); fNByte++;
      }
      if ( len < 2)  {
         fBuffer[0] = ' ';
      } else {
         strcpy(fBuffer, str+1);
      }
      fLenBuffer = len-1;
      fPrinted = kTRUE;
      fNByte += len-1;
      return;
   }

   if( str[len-1] == '@') {
      if( fLenBuffer ) {
         fStream->write(fBuffer, fLenBuffer);
         fStream->write("\n",1); fNByte++;
      }
      fStream->write(str, len-1);
      fStream->write("\n",1);
      fLenBuffer = 0;
      fNByte += len;
      fPrinted = kTRUE;
      return;
   }

   if( (len + fLenBuffer ) > kMaxBuffer) {
      fStream->write(fBuffer, fLenBuffer);
      fStream->write("\n",1); fNByte++;
      strcpy(fBuffer, str);
      fLenBuffer = len;
      fNByte += len;
   } else {
      strcpy(fBuffer + fLenBuffer, str);
      fLenBuffer += len;
      fNByte += len;
   }
   fPrinted = kTRUE;
}

//______________________________________________________________________________
void TVirtualPS::PrintFast(Int_t len, const char *str)
{
   // Fast version of Print

   if( (len + fLenBuffer ) > kMaxBuffer) {
      fStream->write(fBuffer, fLenBuffer);
      fStream->write("\n",1); fNByte++;
      strcpy(fBuffer, str);
      fLenBuffer = len;
   } else {
      strcpy(fBuffer + fLenBuffer, str);
      fLenBuffer += len;
   }
   fNByte += len;
   fPrinted = kTRUE;
}

//______________________________________________________________________________
void TVirtualPS::WriteInteger(Int_t n, Bool_t space )
{
   // Write one Integer to the file
   //
   // n: Integer to be written in the file.
   // space: If TRUE, a space in written before the integer.

   char str[15];
   if (space) {
      sprintf(str," %d", n);
   } else {
      sprintf(str,"%d", n);
   }
   PrintStr(str);
}

//______________________________________________________________________________
void TVirtualPS::WriteReal(Float_t z)
{
   // Write a Real number to the file

   char str[15];
   sprintf(str," %g", z);
   PrintStr(str);
}
<|endoftext|>


<commit_before>/* **** **** **** **** **** **** **** **** *
 *
 *         _/        _/        _/
 *        _/_/_/    _/_/_/    _/_/_/
 *       _/    _/  _/    _/  _/    _/
 *      _/    _/  _/    _/  _/    _/
 *     _/_/_/    _/_/_/    _/_/_/
 *
 * bit by bit
 * bbb/tmp/alias.hpp
 *
 * author: ISHII 2bit
 * mail:   2bit@backspace.tokyo
 *
 * **** **** **** **** **** **** **** **** */

#pragma once

#include <bbb/core/type/utility.hpp>

namespace bbb {
    namespace aliases {
        template <typename> struct alias;

        namespace detail {
            template<typename type_, std::size_t depth>
            struct deep_alias {
                using type = alias<deep_alias<type_, depth - 1L>>;
            };

            template <typename type_>
            struct deep_alias<type_, 0L> {
                using type = type_;
            };
        };

        template<typename type, std::size_t depth>
        using deep_alias = get_type<detail::deep_alias<type, depth>>;

        namespace detail {
            template <typename raw_type>
            struct remove_alias { using type = raw_type; };
            template <typename raw_type>
            struct remove_alias<alias<raw_type>> { using type = raw_type; };
            template <typename raw_type>
            struct remove_aliases { using type = raw_type; };
            template <typename raw_type>
            struct remove_aliases<alias<raw_type>> { using type = get_type<remove_aliases<raw_type>>; };
        };

        template <typename type>
        using remove_alias = get_type<detail::remove_alias<type>>;
        template <typename type>
        using remove_aliases = get_type<detail::remove_aliases<type>>;

        template <typename lhs, typename rhs>
        constexpr bool is_same_alias() {
            return is_same<remove_aliases<lhs>, remove_aliases<rhs>>();
        };
    };
};<commit_msg>publish to bbb<commit_after>/* **** **** **** **** **** **** **** **** *
 *
 *         _/        _/        _/
 *        _/_/_/    _/_/_/    _/_/_/
 *       _/    _/  _/    _/  _/    _/
 *      _/    _/  _/    _/  _/    _/
 *     _/_/_/    _/_/_/    _/_/_/
 *
 * bit by bit
 * bbb/tmp/alias.hpp
 *
 * author: ISHII 2bit
 * mail:   2bit@backspace.tokyo
 *
 * **** **** **** **** **** **** **** **** */

#pragma once

#include <bbb/core/type/utility.hpp>

namespace bbb {
    namespace aliases {
        template <typename> struct alias;

        namespace detail {
            template<typename type_, std::size_t depth>
            struct deep_alias {
                using type = alias<deep_alias<type_, depth - 1L>>;
            };

            template <typename type_>
            struct deep_alias<type_, 0L> {
                using type = type_;
            };
        };

        template<typename type, std::size_t depth>
        using deep_alias = get_type<detail::deep_alias<type, depth>>;

        namespace detail {
            template <typename raw_type>
            struct remove_alias { using type = raw_type; };
            template <typename raw_type>
            struct remove_alias<alias<raw_type>> { using type = raw_type; };
            template <typename raw_type>
            struct remove_aliases { using type = raw_type; };
            template <typename raw_type>
            struct remove_aliases<alias<raw_type>> { using type = get_type<remove_aliases<raw_type>>; };
        };

        template <typename type>
        using remove_alias = get_type<detail::remove_alias<type>>;
        template <typename type>
        using remove_aliases = get_type<detail::remove_aliases<type>>;

        template <typename lhs, typename rhs>
        constexpr bool is_same_alias() {
            return is_same<remove_aliases<lhs>, remove_aliases<rhs>>();
        };
    };

    using namespace aliases;
};<|endoftext|>


<commit_before>/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#include <eosio/chain/block.hpp>
#include <eosio/chain/merkle.hpp>
#include <fc/io/raw.hpp>
#include <fc/bitutil.hpp>
#include <algorithm>

namespace eosio { namespace chain {
   digest_type block_header::digest()const
   {
      return digest_type::hash(*this);
   }

   uint32_t block_header::num_from_id(const block_id_type& id)
   {
      return fc::endian_reverse_u32(id._hash[0]);
   }

   block_id_type signed_block_header::id()const
   {
      block_id_type result = fc::sha256::hash(*this);
      result._hash[0] &= 0xffffffff00000000;
      result._hash[0] += fc::endian_reverse_u32(block_num()); // store the block num in the ID, 160 bits is plenty for the hash
      return result;
   }

   public_key_type signed_block_header::signee()const
   {
      return fc::crypto::public_key(producer_signature, digest(), true/*enforce canonical*/);
   }

   void signed_block_header::sign(const private_key_type& signer)
   {
      producer_signature = signer.sign(digest());
   }

   bool signed_block_header::validate_signee(const public_key_type& expected_signee)const
   {
      return signee() == expected_signee;
   }

   checksum256_type signed_block_summary::calculate_transaction_mroot()const {
      vector<digest_type> merkle_of_each_shard;
      for(const region_summary& rs : regions) {
         for(const cycle& cs : rs.cycles_summary) {
            for(const shard_summary& ss: cs) {
               vector<digest_type> merkle_list_for_txns_in_shard;
               for(const transaction_receipt& tr : ss.transactions) {
                  merkle_list_for_txns_in_shard.emplace_back(tr.id);
               }
               merkle_of_each_shard.emplace_back( merkle(std::move(merkle_list_for_txns_in_shard)) );
            }
         }
      }
      return merkle( std::move(merkle_of_each_shard) );
    }

} }
<commit_msg>Exclude producer_signature from block id<commit_after>/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#include <eosio/chain/block.hpp>
#include <eosio/chain/merkle.hpp>
#include <fc/io/raw.hpp>
#include <fc/bitutil.hpp>
#include <algorithm>

namespace eosio { namespace chain {
   digest_type block_header::digest()const
   {
      return digest_type::hash(*this);
   }

   uint32_t block_header::num_from_id(const block_id_type& id)
   {
      return fc::endian_reverse_u32(id._hash[0]);
   }

   block_id_type signed_block_header::id()const
   {
      // Do not include signed_block_header attributes in id, specifically exclude producer_signature.
      block_id_type result = fc::sha256::hash(*static_cast<const block_header*>(this));
      result._hash[0] &= 0xffffffff00000000;
      result._hash[0] += fc::endian_reverse_u32(block_num()); // store the block num in the ID, 160 bits is plenty for the hash
      return result;
   }

   public_key_type signed_block_header::signee()const
   {
      return fc::crypto::public_key(producer_signature, digest(), true/*enforce canonical*/);
   }

   void signed_block_header::sign(const private_key_type& signer)
   {
      producer_signature = signer.sign(digest());
   }

   bool signed_block_header::validate_signee(const public_key_type& expected_signee)const
   {
      return signee() == expected_signee;
   }

   checksum256_type signed_block_summary::calculate_transaction_mroot()const {
      vector<digest_type> merkle_of_each_shard;
      for(const region_summary& rs : regions) {
         for(const cycle& cs : rs.cycles_summary) {
            for(const shard_summary& ss: cs) {
               vector<digest_type> merkle_list_for_txns_in_shard;
               for(const transaction_receipt& tr : ss.transactions) {
                  merkle_list_for_txns_in_shard.emplace_back(tr.id);
               }
               merkle_of_each_shard.emplace_back( merkle(std::move(merkle_list_for_txns_in_shard)) );
            }
         }
      }
      return merkle( std::move(merkle_of_each_shard) );
    }

} }
<|endoftext|>


<commit_before>//
// Created by Vadim N. on 18/03/2015.
//

#ifndef _BENCHMARK_H_
#define _BENCHMARK_H_

#define YMIR_BENCHMARK(expr) {}

#include <chrono>
#include <ctime>

#include "Inference"

using namespace ymir;

int main(int argc, char* argv[]) {
    std::chrono::system_clock::time_point tp1, tp2;

    time_t vj_single_parse, vdj_single_parse,
            vj_single_prob, vj_single_meta,
            vj_single_infer, vdj_single_prob,
            vdj_single_meta, vdj_single_infer;

    time_t vj_good_parse, vdj_good_parse,
            vj_good_prob, vj_good_meta,
            vj_good_infer, vdj_good_prob,
            vdj_good_meta, vdj_good_infer;

    std::string BENCH_DATA_FOLDER = argv[1];

    RepertoireParser parser;

    //
    // TCR alpha chain repertoire - VJ recombination
    //
    VDJRecombinationGenes vj_single_genes("Vgene",
                                   BENCH_DATA_FOLDER + "trav.txt",
                                   "Jgene",
                                   BENCH_DATA_FOLDER + "traj.txt");

    tp1 = std::chrono::system_clock::now();
    Cloneset cloneset_vj;
    parser.parse(BENCH_DATA_FOLDER + "alpha.500k.txt",
                 &cloneset_vj,
                 vj_single_genes,
                 RepertoireParser::AlignmentColumnOptions()
                         .setV(RepertoireParser::MAKE_IF_NOT_FOUND)
                         .setJ(RepertoireParser::MAKE_IF_NOT_FOUND)
                         .setD(RepertoireParser::SKIP));
    tp2 = std::chrono::system_clock::now();
    vj_single_parse = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    //
    // TCR beta chain repertoire - VDJ recombination
    //
    VDJRecombinationGenes vdj_single_genes("Vgene",
                                    BENCH_DATA_FOLDER + "trbv.txt",
                                    "Jgene",
                                    BENCH_DATA_FOLDER + "trbj.txt",
                                    "Dgene",
                                    BENCH_DATA_FOLDER + "trbd.txt");

    tp1 = std::chrono::system_clock::now();
    Cloneset cloneset_vdj;
    parser.parse(BENCH_DATA_FOLDER + "beta.500k.txt",
                 &cloneset_vdj,
                 vdj_single_genes,
                 RepertoireParser::AlignmentColumnOptions()
                         .setV(RepertoireParser::MAKE_IF_NOT_FOUND)
                         .setJ(RepertoireParser::MAKE_IF_NOT_FOUND)
                         .setD(RepertoireParser::OVERWRITE));
    tp2 = std::chrono::system_clock::now();
    vdj_single_parse = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    //
    // VJ MAAG
    //
    ProbabilisticAssemblingModel vj_single_model(BENCH_DATA_FOLDER + "../../models/hTRA"); //, EMPTY);
//    ProbabilisticAssemblingModel vj_single_model2(BENCH_DATA_FOLDER + "../../models/hTRA");
//    cout << "empty:" << vj_single_model.event_probabilities().size() << endl;
//    cout << "default:" << vj_single_model2.event_probabilities().size() << endl;
//    cout << "empty:" << vj_single_model.event_probabilities().families() << endl;
//    cout << "default:" << vj_single_model2.event_probabilities().families() << endl;
//    for (auto i = 0; i < std::min(vj_single_model.event_probabilities().families(), vj_single_model2.event_probabilities().families()) - 1; ++i) {
//        cout << vj_single_model.event_probabilities().eventClassSize(i) << ":" << vj_single_model2.event_probabilities().eventClassSize(i) << endl;
//    }
//    return 0;

    tp1 = std::chrono::system_clock::now();
    vj_single_model.buildGraphs(cloneset_vj, SAVE_METADATA);
    tp2 = std::chrono::system_clock::now();
    vj_single_meta = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    tp1 = std::chrono::system_clock::now();
    vj_single_model.computeFullProbabilities(cloneset_vj, NO_METADATA);
    tp2 = std::chrono::system_clock::now();
    vj_single_prob = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    //
    // VDJ MAAG
    //
    ProbabilisticAssemblingModel vdj_single_model(BENCH_DATA_FOLDER + "../../models/hTRB", EMPTY);
//    ProbabilisticAssemblingModel vdj_single_model2(BENCH_DATA_FOLDER + "../../models/hTRB");
//    cout << "empty:" << vdj_single_model.event_probabilities().size() << endl;
//    cout << "default:" << vdj_single_model2.event_probabilities().size() << endl;
//    cout << "empty:" << vdj_single_model.event_probabilities().families() << endl;
//    cout << "default:" << vdj_single_model2.event_probabilities().families() << endl;
//    for (auto i = 0; i < std::min(vdj_single_model.event_probabilities().families(), vdj_single_model2.event_probabilities().families()) - 1; ++i) {
//        cout << vdj_single_model.event_probabilities().eventClassSize(i) << ":" << vdj_single_model2.event_probabilities().eventClassSize(i) << endl;
//    }
//    return 0;

    tp1 = std::chrono::system_clock::now();
    MAAGRepertoire(vdj_single_model.buildGraphs(cloneset_vdj, SAVE_METADATA));
    tp2 = std::chrono::system_clock::now();
    vdj_single_meta = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    tp1 = std::chrono::system_clock::now();
    vdj_single_model.computeFullProbabilities(cloneset_vdj, NO_METADATA);
    tp2 = std::chrono::system_clock::now();
    vdj_single_prob = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    //
    // VJ inference
    //
    tp1 = std::chrono::system_clock::now();
    EMAlgorithm().statisticalInference(cloneset_vj, vj_single_model, EMAlgorithm::AlgorithmParameters().set("niter", 10));
    tp2 = std::chrono::system_clock::now();
    vj_single_infer = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    //
    // VDJ inference
    //
    tp1 = std::chrono::system_clock::now();
    EMAlgorithm().statisticalInference(cloneset_vdj, vdj_single_model, EMAlgorithm::AlgorithmParameters().set("niter", 10));
    tp2 = std::chrono::system_clock::now();
    vdj_single_infer = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    //
    // Results
    //
    cout << "========================" << endl << "Results:" << endl;

    cout << endl;
    cout << "TCR alpha repertoire:\tsingle V-J alignment" << endl;
    cout << "TCR beta repertoire:\tsingle V-J alignment, all D alignments" << endl;

    cout << "Parsing VJ, seconds:\t" << vj_single_parse << endl;
    cout << "Parsing VDJ, seconds:\t" << vdj_single_parse << endl;

    cout << "VJ MAAG computing, seconds:\t" << vj_single_prob << endl;
    cout << "VJ MAAG metadata, seconds:\t" << vj_single_meta << endl;
    cout << "VJ inference 10 iter, seconds:\t" << vj_single_infer << endl;

    cout << "VDJ MAAG computing, seconds:\t" << vdj_single_prob << endl;
    cout << "VDJ MAAG metadata, seconds:\t" << vdj_single_meta << endl;
    cout << "VDJ inference 10 iter, seconds:\t" << vdj_single_infer << endl;

    cout << endl;
    cout << "TCR alpha repertoire:\tall good V-J alignments" << endl;
    cout << "TCR beta repertoire:\tall good V-J alignments, all D alignments" << endl;

    cout << "Parsing VJ, seconds:\t" << vj_good_parse << endl;
    cout << "Parsing VDJ, seconds:\t" << vdj_good_parse << endl;

    cout << "VJ MAAG computing, seconds:\t" << vj_good_prob << endl;
    cout << "VJ MAAG metadata, seconds:\t" << vj_good_meta << endl;
    cout << "VJ inference 10 iter, seconds:\t" << vj_good_infer << endl;

    cout << "VDJ MAAG computing, seconds:\t" << vdj_good_prob << endl;
    cout << "VDJ MAAG metadata, seconds:\t" << vdj_good_meta << endl;
    cout << "VDJ inference 10 iter, seconds:\t" << vdj_good_infer << endl;

    return 0;
}

#endif //_BENCHMARK_H_
<commit_msg>trying to fix the nastiest bug ever<commit_after>//
// Created by Vadim N. on 18/03/2015.
//

#ifndef _BENCHMARK_H_
#define _BENCHMARK_H_

#define YMIR_BENCHMARK(expr) {}

#include <chrono>
#include <ctime>

#include "Inference"

using namespace ymir;

int main(int argc, char* argv[]) {
    std::chrono::system_clock::time_point tp1, tp2;

    time_t vj_single_parse, vdj_single_parse,
            vj_single_prob, vj_single_meta,
            vj_single_infer, vdj_single_prob,
            vdj_single_meta, vdj_single_infer;

    time_t vj_good_parse, vdj_good_parse,
            vj_good_prob, vj_good_meta,
            vj_good_infer, vdj_good_prob,
            vdj_good_meta, vdj_good_infer;

    std::string BENCH_DATA_FOLDER = argv[1];

    RepertoireParser parser;

    //
    // TCR alpha chain repertoire - VJ recombination
    //
//    VDJRecombinationGenes vj_single_genes("Vgene",
//                                   BENCH_DATA_FOLDER + "trav.txt",
//                                   "Jgene",
//                                   BENCH_DATA_FOLDER + "traj.txt");
//
//    tp1 = std::chrono::system_clock::now();
//    Cloneset cloneset_vj;
//    parser.parse(BENCH_DATA_FOLDER + "alpha.500k.new.txt",
//                 &cloneset_vj,
//                 vj_single_genes,
//                 NUCLEOTIDE,
//                 VJ_RECOMB,
//                 RepertoireParser::AlignmentColumnOptions()
//                         .setV(RepertoireParser::USE_PROVIDED)
//                         .setJ(RepertoireParser::USE_PROVIDED));
//    tp2 = std::chrono::system_clock::now();
//    vj_single_parse = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    //
    // TCR beta chain repertoire - VDJ recombination
    //
    VDJRecombinationGenes vdj_single_genes("Vgene",
                                    BENCH_DATA_FOLDER + "trbv.txt",
                                    "Jgene",
                                    BENCH_DATA_FOLDER + "trbj.txt",
                                    "Dgene",
                                    BENCH_DATA_FOLDER + "trbd.txt");

    tp1 = std::chrono::system_clock::now();
    Cloneset cloneset_vdj;
    parser.parse(BENCH_DATA_FOLDER + "beta.500k.new.txt",
                 &cloneset_vdj,
                 vdj_single_genes,
                 NUCLEOTIDE,
                 VDJ_RECOMB,
                 RepertoireParser::AlignmentColumnOptions()
                         .setV(RepertoireParser::USE_PROVIDED)
                         .setJ(RepertoireParser::USE_PROVIDED)
                         .setD(RepertoireParser::OVERWRITE));
    tp2 = std::chrono::system_clock::now();
    vdj_single_parse = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    //
    // VJ MAAG
    //
//    ProbabilisticAssemblingModel vj_single_model(BENCH_DATA_FOLDER + "../../models/hTRA"); //, EMPTY);
//
//    tp1 = std::chrono::system_clock::now();
//    vj_single_model.buildGraphs(cloneset_vj, SAVE_METADATA);
//    tp2 = std::chrono::system_clock::now();
//    vj_single_meta = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);
//
//    tp1 = std::chrono::system_clock::now();
//    vj_single_model.computeFullProbabilities(cloneset_vj, NO_METADATA);
//    tp2 = std::chrono::system_clock::now();
//    vj_single_prob = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    //
    // VDJ MAAG
    //
    ProbabilisticAssemblingModel vdj_single_model(BENCH_DATA_FOLDER + "../../models/hTRB", EMPTY);

    tp1 = std::chrono::system_clock::now();
//    MAAGRepertoire(vdj_single_model.buildGraphs(cloneset_vdj, SAVE_METADATA));
    vdj_single_model.buildGraphs(cloneset_vdj, SAVE_METADATA);
    tp2 = std::chrono::system_clock::now();
    vdj_single_meta = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    tp1 = std::chrono::system_clock::now();
    vdj_single_model.computeFullProbabilities(cloneset_vdj, NO_METADATA);
    tp2 = std::chrono::system_clock::now();
    vdj_single_prob = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    //
    // VJ inference
    //
//    tp1 = std::chrono::system_clock::now();
//    EMAlgorithm().statisticalInference(cloneset_vj, vj_single_model, EMAlgorithm::AlgorithmParameters().set("niter", 10));
//    tp2 = std::chrono::system_clock::now();
//    vj_single_infer = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    //
    // VDJ inference
    //
    tp1 = std::chrono::system_clock::now();
    EMAlgorithm().statisticalInference(cloneset_vdj, vdj_single_model, EMAlgorithm::AlgorithmParameters().set("niter", 10));
    tp2 = std::chrono::system_clock::now();
    vdj_single_infer = std::chrono::system_clock::to_time_t(tp2)- std::chrono::system_clock::to_time_t(tp1);

    //
    // Results
    //
    cout << "========================" << endl << "Results:" << endl;

    cout << endl;
    cout << "TCR alpha repertoire:\tsingle V-J alignment" << endl;
    cout << "TCR beta repertoire:\tsingle V-J alignment, all D alignments" << endl;

    cout << "Parsing VJ, seconds:\t" << vj_single_parse << endl;
    cout << "Parsing VDJ, seconds:\t" << vdj_single_parse << endl;

    cout << "VJ MAAG computing, seconds:\t" << vj_single_prob << endl;
    cout << "VJ MAAG metadata, seconds:\t" << vj_single_meta << endl;
    cout << "VJ inference 10 iter, seconds:\t" << vj_single_infer << endl;

    cout << "VDJ MAAG computing, seconds:\t" << vdj_single_prob << endl;
    cout << "VDJ MAAG metadata, seconds:\t" << vdj_single_meta << endl;
    cout << "VDJ inference 10 iter, seconds:\t" << vdj_single_infer << endl;

    cout << endl;
    cout << "TCR alpha repertoire:\tall good V-J alignments" << endl;
    cout << "TCR beta repertoire:\tall good V-J alignments, all D alignments" << endl;

    cout << "Parsing VJ, seconds:\t" << vj_good_parse << endl;
    cout << "Parsing VDJ, seconds:\t" << vdj_good_parse << endl;

    cout << "VJ MAAG computing, seconds:\t" << vj_good_prob << endl;
    cout << "VJ MAAG metadata, seconds:\t" << vj_good_meta << endl;
    cout << "VJ inference 10 iter, seconds:\t" << vj_good_infer << endl;

    cout << "VDJ MAAG computing, seconds:\t" << vdj_good_prob << endl;
    cout << "VDJ MAAG metadata, seconds:\t" << vdj_good_meta << endl;
    cout << "VDJ inference 10 iter, seconds:\t" << vdj_good_infer << endl;

    return 0;
}

#endif //_BENCHMARK_H_
<|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;
    typedef typename I::Mask IM;

    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].makeZero();
    for (int i = 1; i < ArraySize; ++i) {
        t = Vc::abs(t * mem.v[i] + t) / divider;
        t(t >= bound) = two;
        mem.v[i] = t;
        t(t == 0) += V(One);
    }
    IM mask;
    T data[1000];
    for (I i(Vc::Zero); !(mask = i < 1000).isEmpty(); i += V::Size) {
        M mask2(mask);
        I i2 = static_cast<I>(V(mem.t, i, mask2));
        V v(data, i2, mask2, Vc::Zero);
        v = v * two + t;
        v.scatter(data, i2, mask2);
    }
    asm volatile(""::"r"(&data[0]));
    blackHolePtr = mem.v;
}

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

int bmain()
{
    Benchmark timer("WhetRock", opsFactor<float_v>() + opsFactor<double_v>(), "Op");
    while (timer.wantsMoreDataPoints()) {
        timer.Start();
        doBlah<float_v>();
        delete[] (float_v *)blackHolePtr;
        doBlah<double_v>();
        delete[] (double_v *)blackHolePtr;
        timer.Stop();
    }
    timer.Print();
    return 0;
}
<commit_msg>two more unnecessary C-style casts<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;
    typedef typename I::Mask IM;

    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].makeZero();
    for (int i = 1; i < ArraySize; ++i) {
        t = Vc::abs(t * mem.v[i] + t) / divider;
        t(t >= bound) = two;
        mem.v[i] = t;
        t(t == 0) += V(One);
    }
    IM mask;
    T data[1000];
    for (I i(Vc::Zero); !(mask = i < 1000).isEmpty(); i += V::Size) {
        M mask2(mask);
        I i2 = static_cast<I>(V(mem.t, i, mask2));
        V v(data, i2, mask2, Vc::Zero);
        v = v * two + t;
        v.scatter(data, i2, mask2);
    }
    asm volatile(""::"r"(&data[0]));
    blackHolePtr = mem.v;
}

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

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


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "RedexContext.h"

#include <exception>
#include <mutex>
#include <regex>
#include <unordered_set>

#include "Debug.h"
#include "DexClass.h"

RedexContext* g_redex;

RedexContext::RedexContext() {}

RedexContext::~RedexContext() {
  // Delete DexStrings.
  for (auto const& p : s_string_map) {
    delete p.second;
  }
  // Delete DexTypes.  NB: This table intentionally contains aliases (multiple
  // DexStrings map to the same DexType), so we have to dedup the set of types
  // before deleting to avoid double-frees.
  std::unordered_set<DexType*> delete_types;
  for (auto const& p : s_type_map) {
    delete_types.emplace(p.second);
  }
  for (auto const& t : delete_types) {
    delete t;
  }
  // Delete DexFields.
  for (auto const& it : s_field_map) {
    delete static_cast<DexField*>(it.second);
  }
  // Delete DexTypeLists.
  for (auto const& p : s_typelist_map) {
    delete p.second;
  }
  // Delete DexProtos.
  for (auto const& p : s_proto_map) {
    delete p.second;
  }
  // Delete DexMethods.
  for (auto const& it : s_method_map) {
    delete it.second;
  }

  for (const auto& p : s_keep_reasons) {
    delete p.second;
  }
}

/*
 * Try and insert (:key, :value) into :container. This insertion may fail if
 * another thread has already inserted that key. In that case, return the
 * existing value and discard the one we were trying to insert.
 *
 * We distinguish between the types of the inserted and stored values to handle
 * DexFields and DexMethods, where we upcast the inserted value into a
 * DexFieldRef / DexMethodRef respectively when storing it.
 */
template <class InsertValue,
          class StoredValue = InsertValue,
          class Deleter = std::default_delete<InsertValue>,
          class Key,
          class Container>
static StoredValue* try_insert(Key key,
                               InsertValue* value,
                               Container* container) {
  std::unique_ptr<InsertValue, Deleter> to_insert(value);
  if (container->emplace(key, to_insert.get())) {
    return to_insert.release();
  }
  return container->at(key);
}

DexString* RedexContext::make_string(const char* nstr, uint32_t utfsize) {
  always_assert(nstr != nullptr);
  auto rv = s_string_map.get(nstr, nullptr);
  if (rv != nullptr) {
    return rv;
  }
  // Note that DexStrings are keyed by the c_str() of the underlying
  // std::string. The c_str is valid until a the string is destroyed, or until a
  // non-const function is called on the string (but note the std::string itself
  // is const)
  auto dexstring = new DexString(nstr, utfsize);
  return try_insert(dexstring->c_str(), dexstring, &s_string_map);
}

DexString* RedexContext::get_string(const char* nstr, uint32_t utfsize) {
  if (nstr == nullptr) {
    return nullptr;
  }
  return s_string_map.get(nstr, nullptr);
}

DexType* RedexContext::make_type(DexString* dstring) {
  always_assert(dstring != nullptr);
  auto rv = s_type_map.get(dstring, nullptr);
  if (rv != nullptr) {
    return rv;
  }
  return try_insert(dstring, new DexType(dstring), &s_type_map);
}

DexType* RedexContext::get_type(DexString* dstring) {
  if (dstring == nullptr) {
    return nullptr;
  }
  return s_type_map.get(dstring, nullptr);
}

void RedexContext::alias_type_name(DexType* type, DexString* new_name) {
  always_assert_log(
      !s_type_map.count(new_name),
      "Bailing, attempting to alias a symbol that already exists! '%s'\n",
      new_name->c_str());
  type->m_name = new_name;
  s_type_map.emplace(new_name, type);
}

DexFieldRef* RedexContext::make_field(const DexType* container,
                                      const DexString* name,
                                      const DexType* type) {
  always_assert(container != nullptr && name != nullptr && type != nullptr);
  DexFieldSpec r(const_cast<DexType*>(container),
                 const_cast<DexString*>(name),
                 const_cast<DexType*>(type));
  auto rv = s_field_map.get(r, nullptr);
  if (rv != nullptr) {
    return rv;
  }
  auto field = new DexField(const_cast<DexType*>(container),
                            const_cast<DexString*>(name),
                            const_cast<DexType*>(type));
  return try_insert<DexField, DexFieldRef>(r, field, &s_field_map);
}

DexFieldRef* RedexContext::get_field(const DexType* container,
                                     const DexString* name,
                                     const DexType* type) {
  if (container == nullptr || name == nullptr || type == nullptr) {
    return nullptr;
  }
  DexFieldSpec r(const_cast<DexType*>(container),
                 const_cast<DexString*>(name),
                 const_cast<DexType*>(type));
  return s_field_map.get(r, nullptr);
}

void RedexContext::erase_field(DexFieldRef* field) {
  s_field_map.erase(field->m_spec);
}

void RedexContext::mutate_field(DexFieldRef* field,
                                const DexFieldSpec& ref,
                                bool rename_on_collision,
                                bool update_deobfuscated_name) {
  std::lock_guard<std::mutex> lock(s_field_lock);
  DexFieldSpec& r = field->m_spec;
  s_field_map.erase(r);
  r.cls = ref.cls != nullptr ? ref.cls : field->m_spec.cls;
  r.name = ref.name != nullptr ? ref.name : field->m_spec.name;
  r.type = ref.type != nullptr ? ref.type : field->m_spec.type;
  field->m_spec = r;

  if (rename_on_collision && s_field_map.find(r) != s_field_map.end()) {
    uint32_t i = 0;
    while (true) {
      r.name = DexString::make_string(("f$" + std::to_string(i++)).c_str());
      if (s_field_map.find(r) == s_field_map.end()) {
        break;
      }
    }
  }
  always_assert_log(s_field_map.find(r) == s_field_map.end(),
                    "Another field with the same signature already exists %s",
                    SHOW(s_field_map.at(r)));
  s_field_map.emplace(r, field);

  if (field->is_def() && update_deobfuscated_name) {
    static_cast<DexField*>(field)->set_deobfuscated_name(show(field));
  }
}

DexTypeList* RedexContext::make_type_list(std::deque<DexType*>&& p) {
  auto rv = s_typelist_map.get(p, nullptr);
  if (rv != nullptr) {
    return rv;
  }
  auto typelist = new DexTypeList(std::move(p));
  return try_insert(typelist->m_list, typelist, &s_typelist_map);
}

DexTypeList* RedexContext::get_type_list(std::deque<DexType*>&& p) {
  return s_typelist_map.get(p, nullptr);
}

DexProto* RedexContext::make_proto(DexType* rtype,
                                   DexTypeList* args,
                                   DexString* shorty) {
  always_assert(rtype != nullptr && args != nullptr && shorty != nullptr);
  ProtoKey key(rtype, args);
  auto rv = s_proto_map.get(key, nullptr);
  if (rv != nullptr) {
    return rv;
  }
  return try_insert(key, new DexProto(rtype, args, shorty), &s_proto_map);
}

DexProto* RedexContext::get_proto(DexType* rtype, DexTypeList* args) {
  if (rtype == nullptr || args == nullptr) {
    return nullptr;
  }
  return s_proto_map.get(ProtoKey(rtype, args), nullptr);
}

DexMethodRef* RedexContext::make_method(DexType* type,
                                        DexString* name,
                                        DexProto* proto) {
  always_assert(type != nullptr && name != nullptr && proto != nullptr);
  DexMethodSpec r(type, name, proto);
  auto rv = s_method_map.get(r, nullptr);
  if (rv != nullptr) {
    return rv;
  }
  return try_insert<DexMethod, DexMethodRef, DexMethod::Deleter>(
      r, new DexMethod(type, name, proto), &s_method_map);
}

DexMethodRef* RedexContext::get_method(DexType* type,
                                       DexString* name,
                                       DexProto* proto) {
  if (type == nullptr || name == nullptr || proto == nullptr) {
    return nullptr;
  }
  DexMethodSpec r(type, name, proto);
  return s_method_map.get(r, nullptr);
}

void RedexContext::erase_method(DexMethodRef* method) {
  s_method_map.erase(method->m_spec);
}

void RedexContext::mutate_method(DexMethodRef* method,
                                 const DexMethodSpec& new_spec,
                                 bool rename_on_collision,
                                 bool update_deobfuscated_name) {
  std::lock_guard<std::mutex> lock(s_method_lock);
  DexMethodSpec old_spec = method->m_spec;
  s_method_map.erase(method->m_spec);

  DexMethodSpec& r = method->m_spec;
  r.cls = new_spec.cls != nullptr ? new_spec.cls : method->m_spec.cls;
  r.name = new_spec.name != nullptr ? new_spec.name : method->m_spec.name;
  r.proto = new_spec.proto != nullptr ? new_spec.proto : method->m_spec.proto;

  if (s_method_map.count(r) && rename_on_collision) {
    // Never rename constructors, which causes runtime verification error:
    // "Method 42(Foo;.$init$$0) is marked constructor, but doesn't match name"
    always_assert_log(show(r.name) != "<init>",
                      "you should not rename constructor on a collision");
    if (new_spec.cls == nullptr) {
      // Either method prototype or name is going to be changed, and we hit a
      // collision. Make an unique name: "name$[0-9]+". But in case of <clinit>,
      // libdex rejects a name like "<clinit>$1". See:
      // http://androidxref.com/9.0.0_r3/xref/dalvik/libdex/DexUtf.cpp#115
      // Valid characters can be found here: [_a-zA-Z0-9$\-]
      // http://androidxref.com/9.0.0_r3/xref/dalvik/libdex/DexUtf.cpp#50
      // If a method name begins with "<", it must end with ">". We generate a
      // name like "$clinit$$42" by replacing <, > with $.
      uint32_t i = 0;
      std::string prefix;
      if (r.name->str().front() == '<') {
        assert(r.name->str().back() == '>');
        prefix =
            "$" + r.name->str().substr(1, r.name->str().length() - 2) + "$$";
      } else {
        prefix = r.name->str() + "$";
      }
      do {
        r.name = DexString::make_string((prefix + std::to_string(i++)).c_str());
      } while (s_method_map.count(r));
    } else {
      // We are about to change its class. Use a better name to remeber its
      // original source class on a collision. Tokenize the class name into
      // parts, and use them until no more collison.
      //
      // "com/facebook/foo/Bar;" => {"com", "facebook", "foo", "Bar"}
      std::string cls_name = show_deobfuscated(old_spec.cls);
      std::regex separator{"[/;]"};
      std::vector<std::string> parts;
      std::copy(std::sregex_token_iterator(cls_name.begin(), cls_name.end(),
                                           separator, -1),
                std::sregex_token_iterator(),
                std::back_inserter(parts));

      // Make a name like "name$Bar$foo", or "$clinit$$Bar$foo".
      std::stringstream ss;
      if (old_spec.name->str().front() == '<') {
        ss << "$"
           << old_spec.name->str().substr(1, old_spec.name->str().length() - 2)
           << "$";
      } else {
        ss << *old_spec.name;
      }
      for (auto part = parts.rbegin(); part != parts.rend(); ++part) {
        ss << "$" << *part;
        r.name = DexString::make_string(ss.str());
        if (!s_method_map.count(r)) {
          break;
        }
      }
      // By this time, it should be no collision anymore.
    }
  }

  always_assert_log(!s_method_map.count(r),
                    "Another method of the same signature already exists");
  s_method_map.emplace(r, method);

  // We just updated DexMethodSpec, which will update this method's name.
  // But we also need to update deobfuscated names properly, except for the
  // cases of ObfuscatePass. Otherwise, there won't be no 1:1 mapping between
  // obfuscated and deobfuscated names. See D13025081 for more detailed example.
  if (method->is_def() && update_deobfuscated_name) {
    // 'show(method)' correctly populates the name as 'show' dynamically builds
    // the name from its DexMethodSpec. We can safely use here.
    static_cast<DexMethod*>(method)->set_deobfuscated_name(show(method));
  }
}

void RedexContext::publish_class(DexClass* cls) {
  std::lock_guard<std::mutex> l(m_type_system_mutex);
  const DexType* type = cls->get_type();
  if (m_type_to_class.find(type) != end(m_type_to_class)) {
    const auto& prev_loc = m_type_to_class[type]->get_location();
    const auto& cur_loc = cls->get_location();
    if (prev_loc == cur_loc) {
      TRACE(MAIN, 1, "Warning: found a duplicate class: %s\n", SHOW(cls));
    } else {
      std::string class_name = show(cls);
      std::string dex_1 = m_type_to_class[type]->get_location();
      std::string dex_2 = cls->get_location();

      TRACE(MAIN,
            1,
            "ABORT! Found a duplicate class: %s in two dexes:\ndex 1: %s\ndex "
            "2: %s\n",
            class_name.c_str(),
            dex_1.c_str(),
            dex_2.c_str());

      throw duplicate_class(class_name, dex_1, dex_2);
    }
  }
  m_type_to_class.emplace(type, cls);
}

DexClass* RedexContext::type_class(const DexType* t) {
  auto it = m_type_to_class.find(t);
  return it != m_type_to_class.end() ? it->second : nullptr;
}
<commit_msg>Enforce no renaming on <clinit>, too<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "RedexContext.h"

#include <exception>
#include <mutex>
#include <regex>
#include <unordered_set>

#include "Debug.h"
#include "DexClass.h"

RedexContext* g_redex;

RedexContext::RedexContext() {}

RedexContext::~RedexContext() {
  // Delete DexStrings.
  for (auto const& p : s_string_map) {
    delete p.second;
  }
  // Delete DexTypes.  NB: This table intentionally contains aliases (multiple
  // DexStrings map to the same DexType), so we have to dedup the set of types
  // before deleting to avoid double-frees.
  std::unordered_set<DexType*> delete_types;
  for (auto const& p : s_type_map) {
    delete_types.emplace(p.second);
  }
  for (auto const& t : delete_types) {
    delete t;
  }
  // Delete DexFields.
  for (auto const& it : s_field_map) {
    delete static_cast<DexField*>(it.second);
  }
  // Delete DexTypeLists.
  for (auto const& p : s_typelist_map) {
    delete p.second;
  }
  // Delete DexProtos.
  for (auto const& p : s_proto_map) {
    delete p.second;
  }
  // Delete DexMethods.
  for (auto const& it : s_method_map) {
    delete it.second;
  }

  for (const auto& p : s_keep_reasons) {
    delete p.second;
  }
}

/*
 * Try and insert (:key, :value) into :container. This insertion may fail if
 * another thread has already inserted that key. In that case, return the
 * existing value and discard the one we were trying to insert.
 *
 * We distinguish between the types of the inserted and stored values to handle
 * DexFields and DexMethods, where we upcast the inserted value into a
 * DexFieldRef / DexMethodRef respectively when storing it.
 */
template <class InsertValue,
          class StoredValue = InsertValue,
          class Deleter = std::default_delete<InsertValue>,
          class Key,
          class Container>
static StoredValue* try_insert(Key key,
                               InsertValue* value,
                               Container* container) {
  std::unique_ptr<InsertValue, Deleter> to_insert(value);
  if (container->emplace(key, to_insert.get())) {
    return to_insert.release();
  }
  return container->at(key);
}

DexString* RedexContext::make_string(const char* nstr, uint32_t utfsize) {
  always_assert(nstr != nullptr);
  auto rv = s_string_map.get(nstr, nullptr);
  if (rv != nullptr) {
    return rv;
  }
  // Note that DexStrings are keyed by the c_str() of the underlying
  // std::string. The c_str is valid until a the string is destroyed, or until a
  // non-const function is called on the string (but note the std::string itself
  // is const)
  auto dexstring = new DexString(nstr, utfsize);
  return try_insert(dexstring->c_str(), dexstring, &s_string_map);
}

DexString* RedexContext::get_string(const char* nstr, uint32_t utfsize) {
  if (nstr == nullptr) {
    return nullptr;
  }
  return s_string_map.get(nstr, nullptr);
}

DexType* RedexContext::make_type(DexString* dstring) {
  always_assert(dstring != nullptr);
  auto rv = s_type_map.get(dstring, nullptr);
  if (rv != nullptr) {
    return rv;
  }
  return try_insert(dstring, new DexType(dstring), &s_type_map);
}

DexType* RedexContext::get_type(DexString* dstring) {
  if (dstring == nullptr) {
    return nullptr;
  }
  return s_type_map.get(dstring, nullptr);
}

void RedexContext::alias_type_name(DexType* type, DexString* new_name) {
  always_assert_log(
      !s_type_map.count(new_name),
      "Bailing, attempting to alias a symbol that already exists! '%s'\n",
      new_name->c_str());
  type->m_name = new_name;
  s_type_map.emplace(new_name, type);
}

DexFieldRef* RedexContext::make_field(const DexType* container,
                                      const DexString* name,
                                      const DexType* type) {
  always_assert(container != nullptr && name != nullptr && type != nullptr);
  DexFieldSpec r(const_cast<DexType*>(container),
                 const_cast<DexString*>(name),
                 const_cast<DexType*>(type));
  auto rv = s_field_map.get(r, nullptr);
  if (rv != nullptr) {
    return rv;
  }
  auto field = new DexField(const_cast<DexType*>(container),
                            const_cast<DexString*>(name),
                            const_cast<DexType*>(type));
  return try_insert<DexField, DexFieldRef>(r, field, &s_field_map);
}

DexFieldRef* RedexContext::get_field(const DexType* container,
                                     const DexString* name,
                                     const DexType* type) {
  if (container == nullptr || name == nullptr || type == nullptr) {
    return nullptr;
  }
  DexFieldSpec r(const_cast<DexType*>(container),
                 const_cast<DexString*>(name),
                 const_cast<DexType*>(type));
  return s_field_map.get(r, nullptr);
}

void RedexContext::erase_field(DexFieldRef* field) {
  s_field_map.erase(field->m_spec);
}

void RedexContext::mutate_field(DexFieldRef* field,
                                const DexFieldSpec& ref,
                                bool rename_on_collision,
                                bool update_deobfuscated_name) {
  std::lock_guard<std::mutex> lock(s_field_lock);
  DexFieldSpec& r = field->m_spec;
  s_field_map.erase(r);
  r.cls = ref.cls != nullptr ? ref.cls : field->m_spec.cls;
  r.name = ref.name != nullptr ? ref.name : field->m_spec.name;
  r.type = ref.type != nullptr ? ref.type : field->m_spec.type;
  field->m_spec = r;

  if (rename_on_collision && s_field_map.find(r) != s_field_map.end()) {
    uint32_t i = 0;
    while (true) {
      r.name = DexString::make_string(("f$" + std::to_string(i++)).c_str());
      if (s_field_map.find(r) == s_field_map.end()) {
        break;
      }
    }
  }
  always_assert_log(s_field_map.find(r) == s_field_map.end(),
                    "Another field with the same signature already exists %s",
                    SHOW(s_field_map.at(r)));
  s_field_map.emplace(r, field);

  if (field->is_def() && update_deobfuscated_name) {
    static_cast<DexField*>(field)->set_deobfuscated_name(show(field));
  }
}

DexTypeList* RedexContext::make_type_list(std::deque<DexType*>&& p) {
  auto rv = s_typelist_map.get(p, nullptr);
  if (rv != nullptr) {
    return rv;
  }
  auto typelist = new DexTypeList(std::move(p));
  return try_insert(typelist->m_list, typelist, &s_typelist_map);
}

DexTypeList* RedexContext::get_type_list(std::deque<DexType*>&& p) {
  return s_typelist_map.get(p, nullptr);
}

DexProto* RedexContext::make_proto(DexType* rtype,
                                   DexTypeList* args,
                                   DexString* shorty) {
  always_assert(rtype != nullptr && args != nullptr && shorty != nullptr);
  ProtoKey key(rtype, args);
  auto rv = s_proto_map.get(key, nullptr);
  if (rv != nullptr) {
    return rv;
  }
  return try_insert(key, new DexProto(rtype, args, shorty), &s_proto_map);
}

DexProto* RedexContext::get_proto(DexType* rtype, DexTypeList* args) {
  if (rtype == nullptr || args == nullptr) {
    return nullptr;
  }
  return s_proto_map.get(ProtoKey(rtype, args), nullptr);
}

DexMethodRef* RedexContext::make_method(DexType* type,
                                        DexString* name,
                                        DexProto* proto) {
  always_assert(type != nullptr && name != nullptr && proto != nullptr);
  DexMethodSpec r(type, name, proto);
  auto rv = s_method_map.get(r, nullptr);
  if (rv != nullptr) {
    return rv;
  }
  return try_insert<DexMethod, DexMethodRef, DexMethod::Deleter>(
      r, new DexMethod(type, name, proto), &s_method_map);
}

DexMethodRef* RedexContext::get_method(DexType* type,
                                       DexString* name,
                                       DexProto* proto) {
  if (type == nullptr || name == nullptr || proto == nullptr) {
    return nullptr;
  }
  DexMethodSpec r(type, name, proto);
  return s_method_map.get(r, nullptr);
}

void RedexContext::erase_method(DexMethodRef* method) {
  s_method_map.erase(method->m_spec);
}

void RedexContext::mutate_method(DexMethodRef* method,
                                 const DexMethodSpec& new_spec,
                                 bool rename_on_collision,
                                 bool update_deobfuscated_name) {
  std::lock_guard<std::mutex> lock(s_method_lock);
  DexMethodSpec old_spec = method->m_spec;
  s_method_map.erase(method->m_spec);

  DexMethodSpec& r = method->m_spec;
  r.cls = new_spec.cls != nullptr ? new_spec.cls : method->m_spec.cls;
  r.name = new_spec.name != nullptr ? new_spec.name : method->m_spec.name;
  r.proto = new_spec.proto != nullptr ? new_spec.proto : method->m_spec.proto;

  if (s_method_map.count(r) && rename_on_collision) {
    // Never rename constructors, which causes runtime verification error:
    // "Method 42(Foo;.$init$$0) is marked constructor, but doesn't match name"
    always_assert_log(show(r.name) != "<init>" && show(r.name) != "<clinit>",
                      "you should not rename constructor on a collision");
    if (new_spec.cls == nullptr) {
      // Either method prototype or name is going to be changed, and we hit a
      // collision. Make an unique name: "name$[0-9]+". But in case of <clinit>,
      // libdex rejects a name like "<clinit>$1". See:
      // http://androidxref.com/9.0.0_r3/xref/dalvik/libdex/DexUtf.cpp#115
      // Valid characters can be found here: [_a-zA-Z0-9$\-]
      // http://androidxref.com/9.0.0_r3/xref/dalvik/libdex/DexUtf.cpp#50
      // If a method name begins with "<", it must end with ">". We generate a
      // name like "$clinit$$42" by replacing <, > with $.
      uint32_t i = 0;
      std::string prefix;
      if (r.name->str().front() == '<') {
        assert(r.name->str().back() == '>');
        prefix =
            "$" + r.name->str().substr(1, r.name->str().length() - 2) + "$$";
      } else {
        prefix = r.name->str() + "$";
      }
      do {
        r.name = DexString::make_string((prefix + std::to_string(i++)).c_str());
      } while (s_method_map.count(r));
    } else {
      // We are about to change its class. Use a better name to remeber its
      // original source class on a collision. Tokenize the class name into
      // parts, and use them until no more collison.
      //
      // "com/facebook/foo/Bar;" => {"com", "facebook", "foo", "Bar"}
      std::string cls_name = show_deobfuscated(old_spec.cls);
      std::regex separator{"[/;]"};
      std::vector<std::string> parts;
      std::copy(std::sregex_token_iterator(cls_name.begin(), cls_name.end(),
                                           separator, -1),
                std::sregex_token_iterator(),
                std::back_inserter(parts));

      // Make a name like "name$Bar$foo", or "$clinit$$Bar$foo".
      std::stringstream ss;
      if (old_spec.name->str().front() == '<') {
        ss << "$"
           << old_spec.name->str().substr(1, old_spec.name->str().length() - 2)
           << "$";
      } else {
        ss << *old_spec.name;
      }
      for (auto part = parts.rbegin(); part != parts.rend(); ++part) {
        ss << "$" << *part;
        r.name = DexString::make_string(ss.str());
        if (!s_method_map.count(r)) {
          break;
        }
      }
      // By this time, it should be no collision anymore.
    }
  }

  always_assert_log(!s_method_map.count(r),
                    "Another method of the same signature already exists");
  s_method_map.emplace(r, method);

  // We just updated DexMethodSpec, which will update this method's name.
  // But we also need to update deobfuscated names properly, except for the
  // cases of ObfuscatePass. Otherwise, there won't be no 1:1 mapping between
  // obfuscated and deobfuscated names. See D13025081 for more detailed example.
  if (method->is_def() && update_deobfuscated_name) {
    // 'show(method)' correctly populates the name as 'show' dynamically builds
    // the name from its DexMethodSpec. We can safely use here.
    static_cast<DexMethod*>(method)->set_deobfuscated_name(show(method));
  }
}

void RedexContext::publish_class(DexClass* cls) {
  std::lock_guard<std::mutex> l(m_type_system_mutex);
  const DexType* type = cls->get_type();
  if (m_type_to_class.find(type) != end(m_type_to_class)) {
    const auto& prev_loc = m_type_to_class[type]->get_location();
    const auto& cur_loc = cls->get_location();
    if (prev_loc == cur_loc) {
      TRACE(MAIN, 1, "Warning: found a duplicate class: %s\n", SHOW(cls));
    } else {
      std::string class_name = show(cls);
      std::string dex_1 = m_type_to_class[type]->get_location();
      std::string dex_2 = cls->get_location();

      TRACE(MAIN,
            1,
            "ABORT! Found a duplicate class: %s in two dexes:\ndex 1: %s\ndex "
            "2: %s\n",
            class_name.c_str(),
            dex_1.c_str(),
            dex_2.c_str());

      throw duplicate_class(class_name, dex_1, dex_2);
    }
  }
  m_type_to_class.emplace(type, cls);
}

DexClass* RedexContext::type_class(const DexType* t) {
  auto it = m_type_to_class.find(t);
  return it != m_type_to_class.end() ? it->second : nullptr;
}
<|endoftext|>