#include "RConfig.h"
#include <stdlib.h>
#include <string>
#include <map>
#include <typeinfo>
#include "Riostream.h"
#include <memory>
#include "TClassTable.h"
#include "TClass.h"
#include "TClassEdit.h"
#include "TProtoClass.h"
#include "TROOT.h"
#include "TString.h"
#include "TError.h"
#include "TRegexp.h"
#include "TObjString.h"
#include "TMap.h"
#include "TInterpreter.h"
using namespace ROOT;
TClassTable *gClassTable;
TClassAlt **TClassTable::fgAlternate;
TClassRec **TClassTable::fgTable;
TClassRec **TClassTable::fgSortedTable;
UInt_t TClassTable::fgSize;
UInt_t TClassTable::fgTally;
Bool_t TClassTable::fgSorted;
UInt_t TClassTable::fgCursor;
TClassTable::IdMap_t *TClassTable::fgIdMap;
ClassImp(TClassTable)
namespace ROOT {
class TClassRec {
public:
TClassRec(TClassRec *next) :
fName(0), fId(0), fDict(0), fInfo(0), fProto(0), fNext(next)
{}
~TClassRec() {
delete [] fName;
delete fProto;
delete fNext;
}
char *fName;
Version_t fId;
Int_t fBits;
DictFuncPtr_t fDict;
const type_info *fInfo;
TProtoClass *fProto;
TClassRec *fNext;
};
class TClassAlt {
public:
TClassAlt(const char*alternate, const char *normName, TClassAlt *next) :
fName(alternate), fNormName(normName), fNext(next)
{}
~TClassAlt() {
}
const char *fName;
const char *fNormName;
std::unique_ptr<TClassAlt> fNext;
};
class TMapTypeToClassRec {
#if defined R__USE_STD_MAP
public:
#ifdef R__GLOBALSTL
typedef std::map<string, TClassRec*> IdMap_t;
#else
typedef std::map<std::string, TClassRec*> IdMap_t;
#endif
typedef IdMap_t::key_type key_type;
typedef IdMap_t::const_iterator const_iterator;
typedef IdMap_t::size_type size_type;
#ifdef R__WIN32
typedef TClassRec* mapped_type;
#else
typedef IdMap_t::mapped_type mapped_type;
#endif
private:
IdMap_t fMap;
public:
void Add(const key_type &key, mapped_type &obj) {
fMap[key] = obj;
}
mapped_type Find(const key_type &key) const {
IdMap_t::const_iterator iter = fMap.find(key);
mapped_type cl = 0;
if (iter != fMap.end()) cl = iter->second;
return cl;
}
void Remove(const key_type &key) { fMap.erase(key); }
void Print() {
Info("TMapTypeToClassRec::Print", "printing the typeinfo map in TClassTable");
for (const_iterator iter = fMap.begin(); iter != fMap.end(); iter++) {
printf("Key: %40s 0x%lx\n", iter->first.c_str(), iter->second);
}
}
#else
private:
TMap fMap;
public:
#ifdef R__COMPLETE_MEM_TERMINATION
~TMapTypeToClassRec() {
TIter next(&fMap);
TObjString *key;
while((key = (TObjString*)next())) {
delete key;
}
}
#endif
void Add(const char *key, TClassRec *&obj)
{
TObjString *realkey = new TObjString(key);
fMap.Add(realkey, (TObject*)obj);
}
TClassRec *Find(const char *key) const {
const TPair *a = (const TPair *)fMap.FindObject(key);
if (a) return (TClassRec*) a->Value();
return 0;
}
void Remove(const char *key) {
TObjString realkey(key);
TObject *actual = fMap.Remove(&realkey);
delete actual;
}
void Print() {
Info("TMapTypeToClassRec::Print", "printing the typeinfo map in TClassTable");
TIter next(&fMap);
TObjString *key;
while((key = (TObjString*)next())) {
printf("Key: %s\n",key->String().Data());
TClassRec *data = (TClassRec*)fMap.GetValue(key);
if (data) {
printf(" class: %s %d\n",data->fName,data->fId);
} else {
printf(" no class: \n");
}
}
}
#endif
};
static UInt_t ClassTableHash(const char *name, UInt_t size)
{
const char *p = name;
Int_t slot = 0;
while (*p) slot = slot<<1 ^ *p++;
if (slot < 0) slot = -slot;
slot %= size;
return slot;
}
}
TClassTable::TClassTable()
{
if (gClassTable) return;
fgSize = 1009;
fgTable = new TClassRec* [fgSize];
fgAlternate = new TClassAlt* [fgSize];
fgIdMap = new IdMap_t;
memset(fgTable, 0, fgSize*sizeof(TClassRec*));
memset(fgAlternate, 0, fgSize*sizeof(TClassAlt*));
gClassTable = this;
}
TClassTable::~TClassTable()
{
if (gClassTable != this) return;
for (UInt_t i = 0; i < fgSize; i++) {
delete fgTable[i];
}
delete [] fgTable; fgTable = 0;
delete [] fgSortedTable; fgSortedTable = 0;
delete fgIdMap; fgIdMap = 0;
}
void TClassTable::Print(Option_t *option) const
{
if (fgTally == 0 || !fgTable)
return;
SortTable();
int n = 0, ninit = 0, nl = 0;
int nch = strlen(option);
TRegexp re(option, kTRUE);
Printf("\nDefined classes");
Printf("class version bits initialized");
Printf("================================================================");
for (UInt_t i = 0; i < fgTally; i++) {
TClassRec *r = fgSortedTable[i];
if (!r) break;
n++;
TString s = r->fName;
if (nch && strcmp(option,r->fName) && s.Index(re) == kNPOS) continue;
nl++;
if (TClass::GetClass(r->fName, kFALSE)) {
ninit++;
Printf("%-35s %6d %7d Yes", r->fName, r->fId, r->fBits);
} else
Printf("%-35s %6d %7d No", r->fName, r->fId, r->fBits);
}
Printf("----------------------------------------------------------------");
Printf("Listed Classes: %4d Total classes: %4d initialized: %4d",nl, n, ninit);
Printf("================================================================\n");
}
char *TClassTable::At(UInt_t index)
{
SortTable();
if (index < fgTally) {
TClassRec *r = fgSortedTable[index];
if (r) return r->fName;
}
return 0;
}
int TClassTable::Classes() { return fgTally; }
void TClassTable::Init() { fgCursor = 0; SortTable(); }
namespace ROOT { class TForNamespace {}; }
void TClassTable::Add(const char *cname, Version_t id, const type_info &info,
DictFuncPtr_t dict, Int_t pragmabits)
{
if (!gClassTable)
new TClassTable;
TClassRec *r = FindElementImpl(cname, kTRUE);
if (r->fName && r->fInfo) {
if ( strcmp(r->fInfo->name(),typeid(ROOT::TForNamespace).name())==0
&& strcmp(info.name(),typeid(ROOT::TForNamespace).name())==0 ) {
return;
}
if (!TClassEdit::IsStdClass(cname)) {
::Warning("TClassTable::Add", "class %s already in TClassTable", cname);
}
return;
} else if (ROOT::gROOTLocal && gCling) {
TClass *oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(cname);
if (oldcl) {
gCling->RegisterTClassUpdate(oldcl,dict);
}
}
if (!r->fName) r->fName = StrDup(cname);
r->fId = id;
r->fBits = pragmabits;
r->fDict = dict;
r->fInfo = &info;
fgIdMap->Add(info.name(),r);
fgSorted = kFALSE;
}
void TClassTable::Add(TProtoClass *proto)
{
if (!gClassTable)
new TClassTable;
const char *cname = proto->GetName();
TClassRec *r = FindElementImpl(cname, kTRUE);
if (r->fName) {
r->fProto = proto;
return;
} else if (ROOT::gROOTLocal && gCling) {
TClass *oldcl = (TClass*)gROOT->GetListOfClasses()->FindObject(cname);
if (oldcl) {
::Warning("TClassTable::Add(TProtoClass*)","Called for existing class without a prior call add the dictionary function.");
}
}
r->fName = StrDup(cname);
r->fId = 0;
r->fBits = 0;
r->fDict = 0;
r->fInfo = 0;
r->fProto= proto;
fgSorted = kFALSE;
}
void TClassTable::AddAlternate(const char *normName, const char *alternate)
{
if (!gClassTable)
new TClassTable;
UInt_t slot = ROOT::ClassTableHash(alternate, fgSize);
for (const TClassAlt *a = fgAlternate[slot]; a; a = a->fNext.get()) {
if (strcmp(alternate,a->fName)==0) {
if (strcmp(normName,a->fNormName) != 0) {
fprintf(stderr,"Error in TClassTable::AddAlternate: "
"Second registration of %s with a different normalized name (old: '%s', new: '%s')\n",
alternate, a->fNormName, normName);
return;
}
}
}
fgAlternate[slot] = new TClassAlt(alternate,normName,fgAlternate[slot]);
}
Bool_t TClassTable::Check(const char *cname, std::string &normname)
{
if (!gClassTable || !fgTable) return kFALSE;
UInt_t slot = ROOT::ClassTableHash(cname, fgSize);
for (TClassRec *r = fgTable[slot]; r; r = r->fNext)
if (strcmp(cname,r->fName)==0) return kTRUE;
for (const TClassAlt *a = fgAlternate[slot]; a; a = a->fNext.get()) {
if (strcmp(cname,a->fName)==0) {
normname = a->fNormName;
return kTRUE;
}
}
return kFALSE;
}
void TClassTable::Remove(const char *cname)
{
if (!gClassTable || !fgTable) return;
UInt_t slot = ROOT::ClassTableHash(cname,fgSize);
TClassRec *r;
TClassRec *prev = 0;
for (r = fgTable[slot]; r; r = r->fNext) {
if (!strcmp(r->fName, cname)) {
if (prev)
prev->fNext = r->fNext;
else
fgTable[slot] = r->fNext;
fgIdMap->Remove(r->fInfo->name());
r->fNext = 0;
delete r;
fgTally--;
fgSorted = kFALSE;
break;
}
prev = r;
}
}
TClassRec *TClassTable::FindElementImpl(const char *cname, Bool_t insert)
{
UInt_t slot = ROOT::ClassTableHash(cname,fgSize);
for (TClassRec *r = fgTable[slot]; r; r = r->fNext)
if (strcmp(cname,r->fName)==0) return r;
if (!insert) return 0;
fgTable[slot] = new TClassRec(fgTable[slot]);
fgTally++;
return fgTable[slot];
}
TClassRec *TClassTable::FindElement(const char *cname, Bool_t insert)
{
if (!fgTable) return 0;
std::string normalized;
TClassEdit::GetNormalizedName(normalized,cname);
return FindElementImpl(normalized.c_str(), insert);
}
Version_t TClassTable::GetID(const char *cname)
{
TClassRec *r = FindElement(cname);
if (r) return r->fId;
return -1;
}
Int_t TClassTable::GetPragmaBits(const char *cname)
{
TClassRec *r = FindElement(cname);
if (r) return r->fBits;
return 0;
}
DictFuncPtr_t TClassTable::GetDict(const char *cname)
{
if (gDebug > 9) {
::Info("GetDict", "searches for %s", cname);
fgIdMap->Print();
}
TClassRec *r = FindElement(cname);
if (r) return r->fDict;
return 0;
}
DictFuncPtr_t TClassTable::GetDict(const type_info& info)
{
if (gDebug > 9) {
::Info("GetDict", "searches for %s at 0x%lx", info.name(), (Long_t)&info);
fgIdMap->Print();
}
TClassRec *r = fgIdMap->Find(info.name());
if (r) return r->fDict;
return 0;
}
DictFuncPtr_t TClassTable::GetDictNorm(const char *cname)
{
if (gDebug > 9) {
::Info("GetDict", "searches for %s", cname);
fgIdMap->Print();
}
TClassRec *r = FindElementImpl(cname,kFALSE);
if (r) return r->fDict;
return 0;
}
TProtoClass *TClassTable::GetProto(const char *cname)
{
if (gDebug > 9) {
::Info("GetDict", "searches for %s", cname);
fgIdMap->Print();
}
TClassRec *r = FindElement(cname);
if (r) return r->fProto;
return 0;
}
TProtoClass *TClassTable::GetProtoNorm(const char *cname)
{
if (gDebug > 9) {
::Info("GetDict", "searches for %s", cname);
fgIdMap->Print();
}
TClassRec *r = FindElementImpl(cname,kFALSE);
if (r) return r->fProto;
return 0;
}
extern "C" {
static int ClassComp(const void *a, const void *b)
{
return strcmp((*(TClassRec **)a)->fName, (*(TClassRec **)b)->fName);
}
}
char *TClassTable::Next()
{
if (fgCursor < fgTally) {
TClassRec *r = fgSortedTable[fgCursor++];
return r->fName;
} else
return 0;
}
void TClassTable::PrintTable()
{
if (fgTally == 0 || !fgTable)
return;
SortTable();
int n = 0, ninit = 0;
Printf("\nDefined classes");
Printf("class version bits initialized");
Printf("================================================================");
UInt_t last = fgTally;
for (UInt_t i = 0; i < last; i++) {
TClassRec *r = fgSortedTable[i];
if (!r) break;
n++;
if (gROOT->GetListOfClasses()->FindObject(r->fName)) {
ninit++;
Printf("%-35s %6d %7d Yes", r->fName, r->fId, r->fBits);
} else
Printf("%-35s %6d %7d No", r->fName, r->fId, r->fBits);
}
Printf("----------------------------------------------------------------");
Printf("Total classes: %4d initialized: %4d", n, ninit);
Printf("================================================================\n");
}
void TClassTable::SortTable()
{
if (!fgSorted) {
delete [] fgSortedTable;
fgSortedTable = new TClassRec* [fgTally];
int j = 0;
for (UInt_t i = 0; i < fgSize; i++)
for (TClassRec *r = fgTable[i]; r; r = r->fNext)
fgSortedTable[j++] = r;
::qsort(fgSortedTable, fgTally, sizeof(TClassRec *), ::ClassComp);
fgSorted = kTRUE;
}
}
void TClassTable::Terminate()
{
if (gClassTable) {
for (UInt_t i = 0; i < fgSize; i++)
delete fgTable[i];
delete [] fgTable; fgTable = 0;
delete [] fgSortedTable; fgSortedTable = 0;
delete fgIdMap; fgIdMap = 0;
fgSize = 0;
SafeDelete(gClassTable);
}
}
void ROOT::AddClass(const char *cname, Version_t id,
const type_info& info,
DictFuncPtr_t dict,
Int_t pragmabits)
{
TClassTable::Add(cname, id, info, dict, pragmabits);
}
void ROOT::AddClassAlternate(const char *normName, const char *alternate)
{
TClassTable::AddAlternate(normName,alternate);
}
void ROOT::ResetClassVersion(TClass *cl, const char *cname, Short_t newid)
{
if (cname && cname!=(void*)-1) {
TClassRec *r = TClassTable::FindElement(cname,kFALSE);
if (r) r->fId = newid;
}
if (cl) {
if (cl->fVersionUsed) {
if (cname!=(void*)-1)
Error("ResetClassVersion","Version number of %s can not be changed after first usage!",
cl->GetName());
} else {
if (newid < 0) {
Error("SetClassVersion","The class version (for %s) must be positive (value %d is ignored)",cl->GetName(),newid);
}
if (cname==(void*)-1) {
if (cl->fClassVersion<newid && 2<=newid) {
cl->SetClassVersion(newid);
}
} else {
cl->SetClassVersion(newid);
}
}
}
}
void ROOT::RemoveClass(const char *cname)
{
if (cname) {
if (gROOT && gROOT->GetListOfClasses()) {
TObject *pcname;
if ((pcname=gROOT->GetListOfClasses()->FindObject(cname))) {
TClass *cl = dynamic_cast<TClass*>(pcname);
if (cl) cl->SetUnloaded();
}
}
TClassTable::Remove(cname);
}
}
TNamed *ROOT::RegisterClassTemplate(const char *name, const char *file,
Int_t line)
{
static TList table;
static Bool_t isInit = kFALSE;
if (!isInit) {
table.SetOwner(kTRUE);
isInit = kTRUE;
}
TString classname(name);
Ssiz_t loc = classname.Index("<");
if (loc >= 1) classname.Remove(loc);
if (file) {
TNamed *obj = new TNamed((const char*)classname, file);
obj->SetUniqueID(line);
table.Add(obj);
return obj;
} else {
return (TNamed*)table.FindObject(classname);
}
}