#include "RConfig.h"
#include <stdlib.h>
#include <string>
#include <map>
#include <typeinfo>
#include "Riostream.h"
#include "TClassTable.h"
#include "TClass.h"
#include "TClassEdit.h"
#include "TROOT.h"
#include "TString.h"
#include "TError.h"
#include "TRegexp.h"
#include "TObjString.h"
#include "TMap.h"
TClassTable *gClassTable;
TClassRec **TClassTable::fgTable;
TClassRec **TClassTable::fgSortedTable;
int TClassTable::fgSize;
int TClassTable::fgTally;
Bool_t TClassTable::fgSorted;
int TClassTable::fgCursor;
TClassTable::IdMap_t *TClassTable::fgIdMap;
ClassImp(TClassTable)
namespace ROOT {
class TMapTypeToClassRec {
#if defined R__USE_STD_MAP
public:
#ifdef R__GLOBALSTL
typedef 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
};
}
TClassTable::TClassTable()
{
if (gClassTable) return;
fgSize = 1009;
fgTable = new TClassRec* [fgSize];
fgIdMap = new IdMap_t;
memset(fgTable, 0, fgSize*sizeof(TClassRec*));
gClassTable = this;
}
TClassTable::~TClassTable()
{
if (gClassTable != this) return;
for (Int_t i = 0; i < fgSize; i++) {
TClassRec *r = fgTable[i];
while (r) {
delete [] r->fName;
TClassRec *next = r->fNext;
delete r;
r = next;
}
}
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 (int i = 0; i < fgTally; i++) {
if (!fgTable[i]) continue;
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(int index)
{
SortTable();
if (index >= 0 && 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,
VoidFuncPtr_t dict, Int_t pragmabits)
{
if (!gClassTable)
new TClassTable;
TClassEdit::TSplitType splitname( cname, TClassEdit::kLong64 );
std::string shortName;
splitname.ShortType(shortName, TClassEdit::kDropStlDefault);
TClassRec *r = FindElementImpl(shortName.c_str(), kTRUE);
if (r->fName) {
if ( strcmp(r->fInfo->name(),typeid(ROOT::TForNamespace).name())==0
&& strcmp(info.name(),typeid(ROOT::TForNamespace).name())==0 ) {
return;
}
if (splitname.IsSTLCont()==0) {
::Warning("TClassTable::Add", "class %s already in TClassTable", cname);
}
return;
}
r->fName = StrDup(shortName.c_str());
r->fId = id;
r->fBits = pragmabits;
r->fDict = dict;
r->fInfo = &info;
fgIdMap->Add(info.name(),r);
fgTally++;
fgSorted = kFALSE;
}
void TClassTable::Remove(const char *cname)
{
if (!gClassTable || !fgTable) return;
unsigned int slot = 0;
const char *p = cname;
while (*p) slot = slot<<1 ^ *p++;
slot %= 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());
delete [] r->fName;
delete r;
fgTally--;
fgSorted = kFALSE;
break;
}
prev = r;
}
}
TClassRec *TClassTable::FindElementImpl(const char *cname, Bool_t insert)
{
unsigned int slot = 0;
const char *p = cname;
while (*p) slot = slot<<1 ^ *p++;
slot %= fgSize;
TClassRec *r;
for (r = fgTable[slot]; r; r = r->fNext)
if (strcmp(cname,r->fName)==0) return r;
if (!insert) return 0;
r = new TClassRec;
r->fName = 0;
r->fId = 0;
r->fDict = 0;
r->fInfo = 0;
r->fNext = fgTable[slot];
fgTable[slot] = r;
return r;
}
TClassRec *TClassTable::FindElement(const char *cname, Bool_t insert)
{
if (!fgTable) return 0;
TClassEdit::TSplitType splitname( cname, TClassEdit::kLong64 );
std::string shortName;
splitname.ShortType(shortName, TClassEdit::kDropStlDefault);
return FindElementImpl(shortName.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;
}
VoidFuncPtr_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;
}
VoidFuncPtr_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;
}
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("================================================================");
for (int i = 0; i < fgTally; i++) {
if (!fgTable[i]) continue;
TClassRec *r = fgSortedTable[i];
if (!r) break;
n++;
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("Total classes: %4d initialized: %4d", n, ninit);
Printf("================================================================\n");
}
void TClassTable::SortTable()
{
if (!fgSorted) {
delete [] fgSortedTable;
fgSortedTable = new TClassRec* [fgTally];
int j = 0;
for (int 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 (int i = 0; i < fgSize; i++)
for (TClassRec *r = fgTable[i]; r; ) {
TClassRec *t = r;
r = r->fNext;
fgIdMap->Remove(r->fInfo->name());
delete [] t->fName;
delete t;
}
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,
VoidFuncPtr_t dict,
Int_t pragmabits)
{
TClassTable::Add(cname, id, info, dict, pragmabits);
}
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);
}
}