00001 // @(#)root/cont:$Id: THashList.cxx 27904 2009-03-20 19:44:39Z pcanal $ 00002 // Author: Fons Rademakers 10/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 // THashList // 00015 // // 00016 // THashList implements a hybrid collection class consisting of a // 00017 // hash table and a list to store TObject's. The hash table is used for // 00018 // quick access and lookup of objects while the list allows the objects // 00019 // to be ordered. The hash value is calculated using the value returned // 00020 // by the TObject's Hash() function. Each class inheriting from TObject // 00021 // can override Hash() as it sees fit. // 00022 //Begin_Html 00023 /* 00024 <img src=gif/thashlist.gif> 00025 */ 00026 //End_Html 00027 // // 00028 ////////////////////////////////////////////////////////////////////////// 00029 00030 #include "THashList.h" 00031 #include "THashTable.h" 00032 00033 00034 ClassImp(THashList) 00035 00036 //______________________________________________________________________________ 00037 THashList::THashList(Int_t capacity, Int_t rehash) 00038 { 00039 // Create a THashList object. Capacity is the initial hashtable capacity 00040 // (i.e. number of slots), by default kInitHashTableCapacity = 17, and 00041 // rehash is the value at which a rehash will be triggered. I.e. when the 00042 // average size of the linked lists at a slot becomes longer than rehash 00043 // then the hashtable will be resized and refilled to reduce the collision 00044 // rate to about 1. The higher the collision rate, i.e. the longer the 00045 // linked lists, the longer lookup will take. If rehash=0 the table will 00046 // NOT automatically be rehashed. Use Rehash() for manual rehashing. 00047 // WARNING !!! 00048 // If the name of an object in the HashList is modified, The hashlist 00049 // must be Rehashed 00050 00051 fTable = new THashTable(capacity, rehash); 00052 } 00053 00054 //______________________________________________________________________________ 00055 THashList::THashList(TObject *, Int_t capacity, Int_t rehash) 00056 { 00057 // For backward compatibility only. Use other ctor. 00058 00059 fTable = new THashTable(capacity, rehash); 00060 } 00061 00062 //______________________________________________________________________________ 00063 THashList::~THashList() 00064 { 00065 // Delete a hashlist. Objects are not deleted unless the THashList is the 00066 // owner (set via SetOwner()). 00067 00068 Clear(); 00069 SafeDelete(fTable); 00070 } 00071 00072 //______________________________________________________________________________ 00073 void THashList::AddFirst(TObject *obj) 00074 { 00075 // Add object at the beginning of the list. 00076 00077 TList::AddFirst(obj); 00078 fTable->Add(obj); 00079 } 00080 00081 //______________________________________________________________________________ 00082 void THashList::AddFirst(TObject *obj, Option_t *opt) 00083 { 00084 // Add object at the beginning of the list and also store option. 00085 // Storing an option is useful when one wants to change the behaviour 00086 // of an object a little without having to create a complete new 00087 // copy of the object. This feature is used, for example, by the Draw() 00088 // method. It allows the same object to be drawn in different ways. 00089 00090 TList::AddFirst(obj, opt); 00091 fTable->Add(obj); 00092 } 00093 00094 //______________________________________________________________________________ 00095 void THashList::AddLast(TObject *obj) 00096 { 00097 // Add object at the end of the list. 00098 00099 TList::AddLast(obj); 00100 fTable->Add(obj); 00101 } 00102 00103 //______________________________________________________________________________ 00104 void THashList::AddLast(TObject *obj, Option_t *opt) 00105 { 00106 // Add object at the end of the list and also store option. 00107 // Storing an option is useful when one wants to change the behaviour 00108 // of an object a little without having to create a complete new 00109 // copy of the object. This feature is used, for example, by the Draw() 00110 // method. It allows the same object to be drawn in different ways. 00111 00112 TList::AddLast(obj, opt); 00113 fTable->Add(obj); 00114 } 00115 00116 //______________________________________________________________________________ 00117 void THashList::AddBefore(const TObject *before, TObject *obj) 00118 { 00119 // Insert object before object before in the list. 00120 00121 TList::AddBefore(before, obj); 00122 fTable->Add(obj); 00123 } 00124 00125 //______________________________________________________________________________ 00126 void THashList::AddBefore(TObjLink *before, TObject *obj) 00127 { 00128 // Insert object before object before in the list. 00129 00130 TList::AddBefore(before, obj); 00131 fTable->Add(obj); 00132 } 00133 00134 //______________________________________________________________________________ 00135 void THashList::AddAfter(const TObject *after, TObject *obj) 00136 { 00137 // Insert object after object after in the list. 00138 00139 TList::AddAfter(after, obj); 00140 fTable->Add(obj); 00141 } 00142 00143 //______________________________________________________________________________ 00144 void THashList::AddAfter(TObjLink *after, TObject *obj) 00145 { 00146 // Insert object after object after in the list. 00147 00148 TList::AddAfter(after, obj); 00149 fTable->Add(obj); 00150 } 00151 00152 //______________________________________________________________________________ 00153 void THashList::AddAt(TObject *obj, Int_t idx) 00154 { 00155 // Insert object at location idx in the list. 00156 00157 TList::AddAt(obj, idx); 00158 fTable->Add(obj); 00159 } 00160 00161 //______________________________________________________________________________ 00162 Float_t THashList::AverageCollisions() const 00163 { 00164 // Return the average collision rate. The higher the number the longer 00165 // the linked lists in the hashtable, the slower the lookup. If the number 00166 // is high, or lookup noticeably too slow, perfrom a Rehash(). 00167 00168 return fTable->AverageCollisions(); 00169 } 00170 00171 //______________________________________________________________________________ 00172 void THashList::Clear(Option_t *option) 00173 { 00174 // Remove all objects from the list. Does not delete the objects unless 00175 // the THashList is the owner (set via SetOwner()). 00176 00177 fTable->Clear("nodelete"); // clear table so not more lookups 00178 if (IsOwner()) 00179 TList::Delete(option); 00180 else 00181 TList::Clear(option); 00182 } 00183 00184 //______________________________________________________________________________ 00185 void THashList::Delete(Option_t *option) 00186 { 00187 // Remove all objects from the list AND delete all heap based objects. 00188 // If option="slow" then keep list consistent during delete. This allows 00189 // recursive list operations during the delete (e.g. during the dtor 00190 // of an object in this list one can still access the list to search for 00191 // other not yet deleted objects). 00192 00193 Bool_t slow = option ? (!strcmp(option, "slow") ? kTRUE : kFALSE) : kFALSE; 00194 00195 if (!slow) { 00196 fTable->Clear("nodelete"); // clear table so no more lookups 00197 TList::Delete(option); // this deletes the objects 00198 } else { 00199 while (fFirst) { 00200 TObjLink *tlk = fFirst; 00201 fFirst = fFirst->Next(); 00202 fSize--; 00203 // remove object from table 00204 fTable->Remove(tlk->GetObject()); 00205 // delete only heap objects 00206 if (tlk->GetObject() && tlk->GetObject()->IsOnHeap()) 00207 TCollection::GarbageCollect(tlk->GetObject()); 00208 00209 delete tlk; 00210 } 00211 fFirst = fLast = fCache = 0; 00212 fSize = 0; 00213 } 00214 } 00215 00216 //______________________________________________________________________________ 00217 TObject *THashList::FindObject(const char *name) const 00218 { 00219 // Find object using its name. Uses the hash value returned by the 00220 // TString::Hash() after converting name to a TString. 00221 00222 return fTable->FindObject(name); 00223 } 00224 00225 //______________________________________________________________________________ 00226 TObject *THashList::FindObject(const TObject *obj) const 00227 { 00228 // Find object using its hash value (returned by its Hash() member). 00229 00230 return fTable->FindObject(obj); 00231 } 00232 00233 //______________________________________________________________________________ 00234 TList *THashList::GetListForObject(const char *name) const 00235 { 00236 // Return the THashTable's list (bucket) in which obj can be found based on 00237 // its hash; see THashTable::GetListForObject(). 00238 00239 return fTable->GetListForObject(name); 00240 } 00241 00242 //______________________________________________________________________________ 00243 TList *THashList::GetListForObject(const TObject *obj) const 00244 { 00245 // Return the THashTable's list (bucket) in which obj can be found based on 00246 // its hash; see THashTable::GetListForObject(). 00247 00248 return fTable->GetListForObject(obj); 00249 } 00250 00251 //______________________________________________________________________________ 00252 void THashList::RecursiveRemove(TObject *obj) 00253 { 00254 // Remove object from this collection and recursively remove the object 00255 // from all other objects (and collections). 00256 // This function overrides TCollection::RecursiveRemove that calls 00257 // the Remove function. THashList::Remove cannot be called because 00258 // it uses the hash value of the hash table. This hash value 00259 // is not available anymore when RecursiveRemove is called from 00260 // the TObject destructor. 00261 00262 if (!obj) return; 00263 00264 // Remove obj in the list itself 00265 TObject *object = TList::Remove(obj); 00266 if (object) fTable->RemoveSlow(object); 00267 00268 // Scan again the list and invoke RecursiveRemove for all objects 00269 TIter next(this); 00270 00271 while ((object = next())) { 00272 if (object->TestBit(kNotDeleted)) object->RecursiveRemove(obj); 00273 } 00274 } 00275 00276 //______________________________________________________________________________ 00277 void THashList::Rehash(Int_t newCapacity) 00278 { 00279 // Rehash the hashlist. If the collision rate becomes too high (i.e. 00280 // the average size of the linked lists become too long) then lookup 00281 // efficiency decreases since relatively long lists have to be searched 00282 // every time. To improve performance rehash the hashtable. This resizes 00283 // the table to newCapacity slots and refills the table. Use 00284 // AverageCollisions() to check if you need to rehash. 00285 00286 fTable->Rehash(newCapacity); 00287 } 00288 00289 //______________________________________________________________________________ 00290 TObject *THashList::Remove(TObject *obj) 00291 { 00292 // Remove object from the list. 00293 00294 if (!obj || !fTable->FindObject(obj)) return 0; 00295 00296 TList::Remove(obj); 00297 return fTable->Remove(obj); 00298 } 00299 00300 //______________________________________________________________________________ 00301 TObject *THashList::Remove(TObjLink *lnk) 00302 { 00303 // Remove object via its objlink from the list. 00304 00305 if (!lnk) return 0; 00306 00307 TObject *obj = lnk->GetObject(); 00308 00309 TList::Remove(lnk); 00310 return fTable->Remove(obj); 00311 }