TClassTable.cxx

Go to the documentation of this file.
00001 // @(#)root/cont:$Id: TClassTable.cxx 37531 2010-12-10 20:38:06Z pcanal $
00002 // Author: Fons Rademakers   11/08/95
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // This class registers for all classes their name, id and dictionary   //
00015 // function in a hash table. Classes are automatically added by the     //
00016 // ctor of a special init class when a global of this init class is     //
00017 // initialized when the program starts (see the ClassImp macro).        //
00018 //                                                                      //
00019 //////////////////////////////////////////////////////////////////////////
00020 
00021 #include "RConfig.h"
00022 #include <stdlib.h>
00023 #include <string>
00024 #include <map>
00025 #include <typeinfo>
00026 #include "Riostream.h"
00027 
00028 #include "TClassTable.h"
00029 #include "TClass.h"
00030 #include "TClassEdit.h"
00031 #include "TROOT.h"
00032 #include "TString.h"
00033 #include "TError.h"
00034 #include "TRegexp.h"
00035 
00036 #include "TObjString.h"
00037 #include "TMap.h"
00038 
00039 TClassTable *gClassTable;
00040 
00041 TClassRec  **TClassTable::fgTable;
00042 TClassRec  **TClassTable::fgSortedTable;
00043 int          TClassTable::fgSize;
00044 int          TClassTable::fgTally;
00045 Bool_t       TClassTable::fgSorted;
00046 int          TClassTable::fgCursor;
00047 TClassTable::IdMap_t *TClassTable::fgIdMap;
00048 
00049 ClassImp(TClassTable)
00050 
00051 //______________________________________________________________________________
00052 namespace ROOT {
00053 
00054    class TMapTypeToClassRec {
00055 #if defined R__USE_STD_MAP
00056      // This wrapper class allow to avoid putting #include <map> in the
00057      // TROOT.h header file.
00058    public:
00059 #ifdef R__GLOBALSTL
00060       typedef map<string, TClassRec*>           IdMap_t;
00061 #else
00062       typedef std::map<std::string, TClassRec*> IdMap_t;
00063 #endif
00064       typedef IdMap_t::key_type                 key_type;
00065       typedef IdMap_t::const_iterator           const_iterator;
00066       typedef IdMap_t::size_type                size_type;
00067 #ifdef R__WIN32
00068       // Window's std::map does NOT defined mapped_type
00069       typedef TClassRec*                        mapped_type;
00070 #else
00071       typedef IdMap_t::mapped_type              mapped_type;
00072 #endif
00073 
00074    private:
00075       IdMap_t fMap;
00076 
00077    public:
00078       void Add(const key_type &key, mapped_type &obj) {
00079          fMap[key] = obj;
00080       }
00081 
00082       mapped_type Find(const key_type &key) const {
00083 
00084          IdMap_t::const_iterator iter = fMap.find(key);
00085          mapped_type cl = 0;
00086          if (iter != fMap.end()) cl = iter->second;
00087          return cl;
00088       }
00089 
00090       void Remove(const key_type &key) { fMap.erase(key); }
00091 
00092       void Print() {
00093          Info("TMapTypeToClassRec::Print", "printing the typeinfo map in TClassTable");
00094          for (const_iterator iter = fMap.begin(); iter != fMap.end(); iter++) {
00095             printf("Key: %40s 0x%lx\n", iter->first.c_str(), iter->second);
00096          }
00097       }
00098 #else
00099    private:
00100       TMap fMap;
00101    public:
00102 #ifdef R__COMPLETE_MEM_TERMINATION
00103       ~TMapTypeToClassRec() {
00104          TIter next(&fMap);
00105          TObjString *key;
00106          while((key = (TObjString*)next())) {
00107             delete key;
00108          }         
00109       }
00110 #endif
00111 
00112       void Add(const char *key, TClassRec *&obj) {
00113          TObjString *realkey = new TObjString(key);
00114          fMap.Add(realkey, (TObject*)obj);
00115       }
00116 
00117       TClassRec *Find(const char *key) const {
00118          const TPair *a = (const TPair *)fMap.FindObject(key);
00119          if (a) return (TClassRec*) a->Value();
00120          return 0;
00121       }
00122 
00123       void Remove(const char *key) {
00124          TObjString realkey(key);
00125          TObject *actual = fMap.Remove(&realkey);
00126          delete actual;
00127       }
00128 
00129       void Print() {
00130          Info("TMapTypeToClassRec::Print", "printing the typeinfo map in TClassTable");
00131          TIter next(&fMap);
00132          TObjString *key;
00133          while((key = (TObjString*)next())) {
00134             printf("Key: %s\n",key->String().Data());
00135             TClassRec *data = (TClassRec*)fMap.GetValue(key);
00136             if (data) {
00137                printf("  class: %s %d\n",data->fName,data->fId);
00138             } else {
00139                printf("  no class: \n");
00140             }
00141          }
00142       }
00143 #endif
00144    };
00145 }
00146 
00147 //______________________________________________________________________________
00148 TClassTable::TClassTable()
00149 {
00150    // TClassTable is a singleton (i.e. only one can exist per application).
00151 
00152    if (gClassTable) return;
00153 
00154    fgSize  = 1009;  //this is thge result of (int)TMath::NextPrime(1000);
00155    fgTable = new TClassRec* [fgSize];
00156    fgIdMap = new IdMap_t;
00157    memset(fgTable, 0, fgSize*sizeof(TClassRec*));
00158    gClassTable = this;
00159 }
00160 
00161 //______________________________________________________________________________
00162 TClassTable::~TClassTable()
00163 {
00164    // TClassTable singleton is deleted in Terminate().
00165 
00166    // Try to avoid spurrious warning from memory leak checkers.
00167    if (gClassTable != this) return;
00168 
00169    for (Int_t i = 0; i < fgSize; i++) {
00170       TClassRec *r = fgTable[i];
00171       while (r) {
00172          delete [] r->fName;
00173          TClassRec *next = r->fNext;
00174          delete r;
00175          r = next;
00176       }
00177    }
00178    delete [] fgTable; fgTable = 0;
00179    delete [] fgSortedTable; fgSortedTable = 0;
00180    delete fgIdMap; fgIdMap = 0;
00181 }
00182 
00183 //______________________________________________________________________________
00184 void TClassTable::Print(Option_t *option) const
00185 {
00186    // Print the class table. Before printing the table is sorted
00187    // alphabetically. Only classes specified in option are listed.
00188    // The default is to list all classes.
00189    // Standard wilcarding notation supported.
00190 
00191    if (fgTally == 0 || !fgTable)
00192       return;
00193 
00194    SortTable();
00195 
00196    int n = 0, ninit = 0, nl = 0;
00197 
00198    int nch = strlen(option);
00199    TRegexp re(option, kTRUE);
00200 
00201    Printf("\nDefined classes");
00202    Printf("class                                 version  bits  initialized");
00203    Printf("================================================================");
00204    for (int i = 0; i < fgTally; i++) {
00205       if (!fgTable[i]) continue;
00206       TClassRec *r = fgSortedTable[i];
00207       if (!r) break;
00208       n++;
00209       TString s = r->fName;
00210       if (nch && strcmp(option,r->fName) && s.Index(re) == kNPOS) continue;
00211       nl++;
00212       if (TClass::GetClass(r->fName, kFALSE)) {
00213          ninit++;
00214          Printf("%-35s %6d %7d       Yes", r->fName, r->fId, r->fBits);
00215       } else
00216          Printf("%-35s %6d %7d       No",  r->fName, r->fId, r->fBits);
00217    }
00218    Printf("----------------------------------------------------------------");
00219    Printf("Listed Classes: %4d  Total classes: %4d   initialized: %4d",nl, n, ninit);
00220    Printf("================================================================\n");
00221 }
00222 
00223 //---- static members --------------------------------------------------------
00224 
00225 //______________________________________________________________________________
00226 char *TClassTable::At(int index)
00227 {
00228     // Returns class at index from sorted class table. Don't use this iterator
00229     // while modifying the class table. The class table can be modified
00230     // when making calls like TClass::GetClass(), etc.
00231     // Returns 0 if index points beyond last class name.
00232 
00233    SortTable();
00234    if (index >= 0 && index < fgTally) {
00235       TClassRec *r = fgSortedTable[index];
00236       if (r) return r->fName;
00237    }
00238    return 0;
00239 }
00240 
00241 //______________________________________________________________________________
00242 int   TClassTable::Classes() { return fgTally; }
00243 //______________________________________________________________________________
00244 void  TClassTable::Init() { fgCursor = 0; SortTable(); }
00245 
00246 namespace ROOT { class TForNamespace {}; } // Dummy class to give a typeid to namespace (see also TGenericClassInfo)
00247 
00248 //______________________________________________________________________________
00249 void TClassTable::Add(const char *cname, Version_t id,  const type_info &info,
00250                       VoidFuncPtr_t dict, Int_t pragmabits)
00251 {
00252    // Add a class to the class table (this is a static function).
00253 
00254    if (!gClassTable)
00255       new TClassTable;
00256 
00257    // Only register the name without the default STL template arguments ...
00258    TClassEdit::TSplitType splitname( cname, TClassEdit::kLong64 );
00259    std::string shortName;
00260    splitname.ShortType(shortName, TClassEdit::kDropStlDefault);
00261 
00262    // check if already in table, if so return
00263    TClassRec *r = FindElementImpl(shortName.c_str(), kTRUE);
00264    if (r->fName) {
00265       if ( strcmp(r->fInfo->name(),typeid(ROOT::TForNamespace).name())==0
00266            && strcmp(info.name(),typeid(ROOT::TForNamespace).name())==0 ) {
00267          // We have a namespace being reloaded.
00268          // This okay we just keep the old one.
00269          return;
00270       }
00271       if (splitname.IsSTLCont()==0) {
00272          // Warn only for class that are not STL containers.
00273          ::Warning("TClassTable::Add", "class %s already in TClassTable", cname);
00274       }
00275       return;
00276    }
00277 
00278    r->fName = StrDup(shortName.c_str());
00279    r->fId   = id;
00280    r->fBits = pragmabits;
00281    r->fDict = dict;
00282    r->fInfo = &info;
00283 
00284    fgIdMap->Add(info.name(),r);
00285 
00286    fgTally++;
00287    fgSorted = kFALSE;
00288 }
00289 
00290 //______________________________________________________________________________
00291 void TClassTable::Remove(const char *cname)
00292 {
00293    // Remove a class from the class table. This happens when a shared library
00294    // is unloaded (i.e. the dtor's of the global init objects are called).
00295 
00296    if (!gClassTable || !fgTable) return;
00297 
00298    int slot = 0;
00299    const char *p = cname;
00300 
00301    while (*p) slot = slot<<1 ^ *p++;
00302    if (slot < 0) slot = -slot;
00303    slot %= fgSize;
00304 
00305    TClassRec *r;
00306    TClassRec *prev = 0;
00307    for (r = fgTable[slot]; r; r = r->fNext) {
00308       if (!strcmp(r->fName, cname)) {
00309          if (prev)
00310             prev->fNext = r->fNext;
00311          else
00312             fgTable[slot] = r->fNext;
00313          fgIdMap->Remove(r->fInfo->name());
00314          delete [] r->fName;
00315          delete r;
00316          fgTally--;
00317          fgSorted = kFALSE;
00318          break;
00319       }
00320       prev = r;
00321    }
00322 }
00323 
00324 //______________________________________________________________________________
00325 TClassRec *TClassTable::FindElementImpl(const char *cname, Bool_t insert)
00326 {
00327    // Find a class by name in the class table (using hash of name). Returns
00328    // 0 if the class is not in the table. Unless arguments insert is true in
00329    // which case a new entry is created and returned.
00330 
00331    int slot = 0;
00332    const char *p = cname;
00333 
00334    while (*p) slot = slot<<1 ^ *p++;
00335    if (slot < 0) slot = -slot;
00336    slot %= fgSize;
00337 
00338    TClassRec *r;
00339 
00340    for (r = fgTable[slot]; r; r = r->fNext)
00341       if (strcmp(cname,r->fName)==0) return r;
00342 
00343    if (!insert) return 0;
00344 
00345    r = new TClassRec;
00346    r->fName = 0;
00347    r->fId   = 0;
00348    r->fDict = 0;
00349    r->fInfo = 0;
00350    r->fNext = fgTable[slot];
00351    fgTable[slot] = r;
00352 
00353    return r;
00354 }
00355 
00356 //______________________________________________________________________________
00357 TClassRec *TClassTable::FindElement(const char *cname, Bool_t insert)
00358 {
00359    // Find a class by name in the class table (using hash of name). Returns
00360    // 0 if the class is not in the table. Unless arguments insert is true in
00361    // which case a new entry is created and returned.
00362 
00363    if (!fgTable) return 0;
00364 
00365    // Only register the name without the default STL template arguments ...
00366    TClassEdit::TSplitType splitname( cname, TClassEdit::kLong64 );
00367    std::string shortName;
00368    splitname.ShortType(shortName, TClassEdit::kDropStlDefault);
00369 
00370    return FindElementImpl(shortName.c_str(), insert);
00371 }
00372 
00373 //______________________________________________________________________________
00374 Version_t TClassTable::GetID(const char *cname)
00375 {
00376    // Returns the ID of a class.
00377 
00378    TClassRec *r = FindElement(cname);
00379    if (r) return r->fId;
00380    return -1;
00381 }
00382 
00383 //______________________________________________________________________________
00384 Int_t TClassTable::GetPragmaBits(const char *cname)
00385 {
00386    // Returns the pragma bits as specified in the LinkDef.h file.
00387 
00388    TClassRec *r = FindElement(cname);
00389    if (r) return r->fBits;
00390    return 0;
00391 }
00392 
00393 //______________________________________________________________________________
00394 VoidFuncPtr_t TClassTable::GetDict(const char *cname)
00395 {
00396    // Given the class name returns the Dictionary() function of a class
00397    // (uses hash of name).
00398 
00399    if (gDebug > 9) {
00400       ::Info("GetDict", "searches for %s", cname);
00401       fgIdMap->Print();
00402    }
00403 
00404    TClassRec *r = FindElement(cname);
00405    if (r) return r->fDict;
00406    return 0;
00407 }
00408 
00409 //______________________________________________________________________________
00410 VoidFuncPtr_t TClassTable::GetDict(const type_info& info)
00411 {
00412    // Given the type_info returns the Dictionary() function of a class
00413    // (uses hash of type_info::name()).
00414 
00415    if (gDebug > 9) {
00416       ::Info("GetDict", "searches for %s at 0x%lx", info.name(), (Long_t)&info);
00417       fgIdMap->Print();
00418    }
00419 
00420    TClassRec *r = fgIdMap->Find(info.name());
00421    if (r) return r->fDict;
00422    return 0;
00423 }
00424 
00425 
00426 //______________________________________________________________________________
00427 extern "C" {
00428    static int ClassComp(const void *a, const void *b)
00429    {
00430       // Function used for sorting classes alphabetically.
00431 
00432       return strcmp((*(TClassRec **)a)->fName, (*(TClassRec **)b)->fName);
00433    }
00434 }
00435 
00436 //______________________________________________________________________________
00437 char *TClassTable::Next()
00438 {
00439     // Returns next class from sorted class table. Don't use this iterator
00440     // while modifying the class table. The class table can be modified
00441     // when making calls like TClass::GetClass(), etc.
00442 
00443    if (fgCursor < fgTally) {
00444       TClassRec *r = fgSortedTable[fgCursor++];
00445       return r->fName;
00446    } else
00447       return 0;
00448 }
00449 
00450 //______________________________________________________________________________
00451 void TClassTable::PrintTable()
00452 {
00453    // Print the class table. Before printing the table is sorted
00454    // alphabetically.
00455 
00456    if (fgTally == 0 || !fgTable)
00457       return;
00458 
00459    SortTable();
00460 
00461    int n = 0, ninit = 0;
00462 
00463    Printf("\nDefined classes");
00464    Printf("class                                 version  bits  initialized");
00465    Printf("================================================================");
00466    for (int i = 0; i < fgTally; i++) {
00467       if (!fgTable[i]) continue;
00468       TClassRec *r = fgSortedTable[i];
00469       if (!r) break;
00470       n++;
00471       if (TClass::GetClass(r->fName, kFALSE)) {
00472          ninit++;
00473          Printf("%-35s %6d %7d       Yes", r->fName, r->fId, r->fBits);
00474       } else
00475          Printf("%-35s %6d %7d       No",  r->fName, r->fId, r->fBits);
00476    }
00477    Printf("----------------------------------------------------------------");
00478    Printf("Total classes: %4d   initialized: %4d", n, ninit);
00479    Printf("================================================================\n");
00480 }
00481 
00482 //______________________________________________________________________________
00483 void TClassTable::SortTable()
00484 {
00485    // Sort the class table by ascending class ID's.
00486 
00487    if (!fgSorted) {
00488       delete [] fgSortedTable;
00489       fgSortedTable = new TClassRec* [fgTally];
00490 
00491       int j = 0;
00492       for (int i = 0; i < fgSize; i++)
00493          for (TClassRec *r = fgTable[i]; r; r = r->fNext)
00494             fgSortedTable[j++] = r;
00495 
00496       ::qsort(fgSortedTable, fgTally, sizeof(TClassRec *), ::ClassComp);
00497       fgSorted = kTRUE;
00498    }
00499 }
00500 
00501 //______________________________________________________________________________
00502 void TClassTable::Terminate()
00503 {
00504    // Deletes the class table (this static class function calls the dtor).
00505 
00506    if (gClassTable) {
00507       for (int i = 0; i < fgSize; i++)
00508          for (TClassRec *r = fgTable[i]; r; ) {
00509             TClassRec *t = r;
00510             r = r->fNext;
00511             fgIdMap->Remove(r->fInfo->name());
00512             delete [] t->fName;
00513             delete t;
00514          }
00515       delete [] fgTable; fgTable = 0;
00516       delete [] fgSortedTable; fgSortedTable = 0;
00517       delete fgIdMap; fgIdMap = 0;
00518       fgSize = 0;
00519       SafeDelete(gClassTable);
00520    }
00521 }
00522 
00523 //______________________________________________________________________________
00524 void ROOT::AddClass(const char *cname, Version_t id,
00525                     const type_info& info,
00526                     VoidFuncPtr_t dict,
00527                     Int_t pragmabits)
00528 {
00529    // Global function called by the ctor of a class's init class
00530    // (see the ClassImp macro).
00531 
00532    TClassTable::Add(cname, id, info, dict, pragmabits);
00533 }
00534 
00535 //______________________________________________________________________________
00536 void ROOT::ResetClassVersion(TClass *cl, const char *cname, Short_t newid)
00537 {
00538    // Global function to update the version number.
00539    // This is called via the RootClassVersion macro.
00540    //
00541    // if cl!=0 and cname==-1, set the new class version if and only is
00542    // greater than the existing one and greater or equal to 2;
00543    // and also ignore the request if fVersionUsed is true.
00544    //
00545    // Note on class version number:
00546    //   If no class has been specified, TClass::GetVersion will return -1
00547    //   The Class Version 0 request the whole object to be transient
00548    //   The Class Version 1, unless specify via ClassDef indicates that the
00549    //      I/O should use the TClass checksum to distinguish the layout of the class
00550 
00551    if (cname && cname!=(void*)-1) {
00552       TClassRec *r = TClassTable::FindElement(cname,kFALSE);
00553       if (r) r->fId = newid;
00554    }
00555    if (cl) {
00556       if (cl->fVersionUsed) {
00557          // Problem, the reset is called after the first usage!
00558          if (cname!=(void*)-1)
00559             Error("ResetClassVersion","Version number of %s can not be changed after first usage!",
00560                   cl->GetName());
00561       } else {
00562          if (newid < 0) {
00563             Error("SetClassVersion","The class version (for %s) must be positive (value %d is ignored)",cl->GetName(),newid);
00564          }
00565          if (cname==(void*)-1) {
00566             if (cl->fClassVersion<newid && 2<=newid) {
00567                cl->SetClassVersion(newid);
00568             }
00569          } else {
00570             cl->SetClassVersion(newid);
00571          }
00572       }
00573    }
00574 }
00575 
00576 
00577 //______________________________________________________________________________
00578 void ROOT::RemoveClass(const char *cname)
00579 {
00580    // Global function called by the dtor of a class's init class
00581    // (see the ClassImp macro).
00582 
00583    // don't delete class information since it is needed by the I/O system
00584    // to write the StreamerInfo to file
00585    if (cname) {
00586       // Let's still remove this information to allow reloading later.
00587       // Anyway since the shared library has been unloaded, the dictionary
00588       // pointer is now invalid ....
00589       // We still keep the TClass object around because TFile needs to
00590       // get to the TStreamerInfo.
00591       if (gROOT && gROOT->GetListOfClasses()) {
00592          TObject *pcname;
00593          if ((pcname=gROOT->GetListOfClasses()->FindObject(cname))) {
00594             TClass *cl = dynamic_cast<TClass*>(pcname);
00595             if (cl) cl->SetUnloaded();
00596          }
00597       }
00598       TClassTable::Remove(cname);
00599    }
00600 }
00601 
00602 //______________________________________________________________________________
00603 TNamed *ROOT::RegisterClassTemplate(const char *name, const char *file,
00604                                     Int_t line)
00605 {
00606    // Global function to register the implementation file and line of
00607    // a class template (i.e. NOT a concrete class).
00608 
00609    static TList table;
00610    static Bool_t isInit = kFALSE;
00611    if (!isInit) {
00612       table.SetOwner(kTRUE);
00613       isInit = kTRUE;
00614    }
00615 
00616    TString classname(name);
00617    Ssiz_t loc = classname.Index("<");
00618    if (loc >= 1) classname.Remove(loc);
00619    if (file) {
00620       TNamed *obj = new TNamed((const char*)classname, file);
00621       obj->SetUniqueID(line);
00622       table.Add(obj);
00623       return obj;
00624    } else {
00625       return (TNamed*)table.FindObject(classname);
00626    }
00627 }

Generated on Tue Jul 5 14:11:37 2011 for ROOT_528-00b_version by  doxygen 1.5.1