#include "TRefTable.h"
#include "TObjArray.h"
#include "TProcessID.h"
#include <algorithm>
TRefTable *TRefTable::fgRefTable = 0;
ClassImp(TRefTable)
TRefTable::TRefTable() : fNumPIDs(0), fAllocSize(0), fN(0), fParentIDs(0), fParentID(-1),
fDefaultSize(10), fUID(0), fUIDContext(0), fSize(0), fParents(0), fOwner(0)
{
fgRefTable = this;
}
TRefTable::TRefTable(TObject *owner, Int_t size) :
fNumPIDs(0), fAllocSize(0), fN(0), fParentIDs(0), fParentID(-1),
fDefaultSize(size<10 ? 10 : size), fUID(0), fUIDContext(0), fSize(0), fParents(new TObjArray(1)), fOwner(owner)
{
fgRefTable = this;
}
TRefTable::~TRefTable()
{
delete [] fAllocSize;
delete [] fN;
for (Int_t pid = 0; pid < fNumPIDs; ++pid) {
delete [] fParentIDs[pid];
}
delete [] fParentIDs;
delete fParents;
if (fgRefTable == this) fgRefTable = 0;
}
Int_t TRefTable::Add(Int_t uid, TProcessID *context)
{
if (!context)
context = TProcessID::GetSessionProcessID();
Int_t iid = GetInternalIdxForPID(context);
Int_t newsize = 0;
uid = uid & 0xffffff;
if (uid >= fAllocSize[iid]) {
newsize = uid + uid / 2;
if (newsize < fDefaultSize)
newsize = fDefaultSize;
newsize = ExpandForIID(iid, newsize);
}
if (newsize < 0) {
Error("Add", "Cannot allocate space to store uid=%d", uid);
return -1;
}
if (fParentID < 0) {
Error("Add", "SetParent must be called before adding uid=%d", uid);
return -1;
}
fParentIDs[iid][uid] = fParentID + 1;
if (uid >= fN[iid]) fN[iid] = uid + 1;
return uid;
}
Int_t TRefTable::AddInternalIdxForPID(TProcessID *procid)
{
if (!procid)
procid = TProcessID::GetSessionProcessID();
Int_t pid = procid->GetUniqueID();
if (fMapPIDtoInternal.size() <= (size_t) pid)
fMapPIDtoInternal.resize(TProcessID::GetNProcessIDs(), -1);
Int_t iid = fMapPIDtoInternal[pid];
if (iid == -1) {
iid = FindPIDGUID(procid->GetTitle());
if (iid == -1) {
fProcessGUIDs.push_back(procid->GetTitle());
iid = fProcessGUIDs.size() - 1;
}
fMapPIDtoInternal[pid] = iid;
}
ExpandPIDs(iid + 1);
return iid;
}
void TRefTable::Clear(Option_t * )
{
for (Int_t iid = 0; iid < fNumPIDs; ++iid) {
memset(fParentIDs[iid], 0, sizeof(Int_t) * fN[iid]);
}
memset(fN, 0, sizeof(Int_t) * fNumPIDs);
fParentID = -1;
}
Int_t TRefTable::Expand(Int_t pid, Int_t newsize)
{
Int_t iid = GetInternalIdxForPID(pid);
if (iid < 0) return -1;
return ExpandForIID(iid, newsize);
}
Int_t TRefTable::ExpandForIID(Int_t iid, Int_t newsize)
{
if (newsize < 0) return newsize;
if (newsize != fAllocSize[iid]) {
Int_t *temp = fParentIDs[iid];
if (newsize != 0) {
fParentIDs[iid] = new Int_t[newsize];
if (newsize < fAllocSize[iid])
memcpy(fParentIDs[iid], temp, newsize * sizeof(Int_t));
else {
memcpy(fParentIDs[iid], temp, fAllocSize[iid] * sizeof(Int_t));
memset(&fParentIDs[iid][fAllocSize[iid]], 0,
(newsize - fAllocSize[iid]) * sizeof(Int_t));
}
} else {
fParentIDs[iid] = 0;
}
if (fAllocSize[iid]) delete [] temp;
fAllocSize[iid] = newsize;
}
return newsize;
}
void TRefTable::ExpandPIDs(Int_t numpids)
{
if (numpids <= fNumPIDs) return;
Int_t oldNumPIDs = fNumPIDs;
fNumPIDs = numpids;
Int_t *temp = fAllocSize;
fAllocSize = new Int_t[fNumPIDs];
if (temp) memcpy(fAllocSize, temp, oldNumPIDs * sizeof(Int_t));
memset(&fAllocSize[oldNumPIDs], 0,
(fNumPIDs - oldNumPIDs) * sizeof(Int_t));
delete [] temp;
temp = fN;
fN = new Int_t[fNumPIDs];
if (temp) memcpy(fN, temp, oldNumPIDs * sizeof(Int_t));
memset(&fN[oldNumPIDs], 0, (fNumPIDs - oldNumPIDs) * sizeof(Int_t));
delete [] temp;
Int_t **temp2 = fParentIDs;
fParentIDs = new Int_t *[fNumPIDs];
if (temp2) memcpy(fParentIDs, temp2, oldNumPIDs * sizeof(Int_t *));
memset(&fParentIDs[oldNumPIDs], 0,
(fNumPIDs - oldNumPIDs) * sizeof(Int_t*));
}
void TRefTable::FillBuffer(TBuffer & b)
{
b << -fNumPIDs;
for (Int_t iid = 0; iid < fNumPIDs; ++iid) {
b << fN[iid];
b.WriteFastArray(fParentIDs[iid], fN[iid]);
}
}
Int_t TRefTable::FindPIDGUID(const char *guid) const
{
std::vector<std::string>::const_iterator posPID
= std::find(fProcessGUIDs.begin(), fProcessGUIDs.end(), guid);
if (posPID == fProcessGUIDs.end()) return -1;
return posPID - fProcessGUIDs.begin();
}
TObject *TRefTable::GetParent(Int_t uid, TProcessID *context ) const
{
if (!fParents) return 0;
Int_t iid = -1;
if (!context) context = TProcessID::GetSessionProcessID();
iid = GetInternalIdxForPID(context);
uid = uid & 0xFFFFFF;
if (uid < 0 || uid >= fN[iid]) return 0;
Int_t pnumber = fParentIDs[iid][uid] - 1;
Int_t nparents = fParents->GetEntriesFast();
if (pnumber < 0 || pnumber >= nparents) return 0;
return fParents->UncheckedAt(pnumber);
}
Int_t TRefTable::GetInternalIdxForPID(TProcessID *procid) const
{
return const_cast <TRefTable*>(this)->AddInternalIdxForPID(procid);
}
Int_t TRefTable::GetInternalIdxForPID(Int_t pid) const
{
return GetInternalIdxForPID(TProcessID::GetProcessID(pid));
}
TRefTable *TRefTable::GetRefTable()
{
return fgRefTable;
}
Bool_t TRefTable::Notify()
{
return fOwner->Notify();
}
void TRefTable::ReadBuffer(TBuffer &b)
{
Int_t firstInt = 0;
b >> firstInt;
Int_t numIids = -1;
Int_t startIid = 0;
if (firstInt < 0) numIids = -firstInt;
else {
numIids = 1;
TProcessID *fileProcessID = b.GetLastProcessID(this);
startIid = GetInternalIdxForPID(fileProcessID);
if (startIid == -1) {
fProcessGUIDs.push_back(fileProcessID->GetTitle());
startIid = fProcessGUIDs.size() - 1;
}
numIids += startIid;
}
ExpandPIDs(numIids);
for (Int_t iid = startIid; iid < numIids; ++iid) {
Int_t newN = 0;
if (firstInt < 0) b >> newN;
else newN = firstInt;
if (newN > fAllocSize[iid])
ExpandForIID(iid, newN + newN / 2);
fN[iid] = newN;
b.ReadFastArray(fParentIDs[iid], fN[iid]);
}
}
void TRefTable::Reset(Option_t * )
{
Clear();
if (fParents) fParents->Clear();
}
Int_t TRefTable::SetParent(const TObject* parent, Int_t branchID)
{
if (!fParents) {
return -1;
}
Int_t nparents = fParents->GetEntriesFast();
if (branchID != -1) {
fParentID = branchID;
}
else {
fParentID = fParents->IndexOf(parent);
if (fParentID < 0) {
fParents->AddAtAndExpand(const_cast<TObject*>(parent), nparents);
fParentID = nparents;
}
}
return fParentID;
}
void TRefTable::SetRefTable(TRefTable *table)
{
fgRefTable = table;
}
void TRefTable::Streamer(TBuffer &R__b)
{
if (R__b.IsReading()) {
R__b.ReadClassBuffer(TRefTable::Class(),this);
} else {
R__b.WriteClassBuffer(TRefTable::Class(),this);
#if 0
TObjArray *pids = TProcessID::GetPIDs();
Int_t npids = pids->GetEntries();
Int_t npid2 = fProcessGUIDs.size();
for (Int_t i = 0; i < npid2; i++) {
TProcessID *pid;
for (Int_t ipid = 0;ipid<npids;ipid++) {
pid = (TProcessID*)pids->At(ipid);
if (!pid) continue;
if (!strcmp(pid->GetTitle(),fProcessGUIDs[i].c_str()))
R__b.WriteProcessID(pid);
}
}
#endif
}
}