Main Page   Class Hierarchy   Compound List   File List   Compound Members  

TValHashMapT.hh

00001 #ifndef _T_VAL_HASH_MAP_T_HH
00002 #define _T_VAL_HASH_MAP_T_HH
00003 
00004 #include <stdio.h>
00005 #include <stdlib.h>
00006 #include "TMemoryException.hh"
00007 
00008 
00009 // Template class used to hold one key, value pair in a TValHashMapT object.
00010 
00011 template <class K, class V>
00012 class TValHashMapEntryT
00013 {
00014 public:
00015   
00019   TValHashMapEntryT (const K& k, const V& v)
00020     : key (k),
00021       value (v)
00022   {
00023   }
00024   
00026   TValHashMapEntryT *next;
00027   
00029   unsigned int hash;
00030   
00032   K key;
00033   
00035   V value;
00036 };
00037 
00038 
00054 template <class K, class V, class U>
00055 class TValHashMapT
00056 {
00057 public:
00058   
00062   TValHashMapT ();
00063   
00067   inline TValHashMapT (const TValHashMapT<K,V,U> &map) { Copy (map); }
00068   
00072   ~TValHashMapT ();
00073   
00080   void Apply (void (*fn)(const K *, V *, void *), void *d);
00081   
00085   void Clear ();
00086   
00093   inline bool Contains (const K& k) { return Find (k); }
00094   
00100   inline int Entries () { return myNumEntries; }
00101 
00109   bool FindValue (const K& k, V& v);
00110   
00118   bool Insert (const K& k, const V& v);
00119   
00126   bool Remove (const K& k);
00127   
00134   inline void Shrink (bool flag) { myIsShrinkEnabled = flag; }
00135   
00141   V& operator[](const K& k);
00142   
00146   TValHashMapT<K,V,U>& operator=(const TValHashMapT<K,V,U> &map);
00147   
00148 private:
00149 
00154   void Copy (const TValHashMapT<K,V,U>& map);
00155   
00162   V* Find (const K& k);
00163   
00167   void Grow ();
00168   
00175   void ReHash (int new_num_buckets);
00176 
00180   void Shrink ();
00181   
00182   
00184   TValHashMapEntryT<K,V> **myBuckets;
00185   
00187   int myNumBuckets;
00188   
00190   int myBucketMask;
00191   
00194   int myShrinkSize;
00195   
00198   int myGrowSize;
00199   
00201   int myNumEntries;
00202   
00204   bool myIsShrinkEnabled;
00205   
00208   static const int BUCKET_MULTIPLIER;
00209   
00211   static const int NUM_BUCKETS;
00212 };
00213 
00214 
00215 template <class K, class V, class U>
00216 const int TValHashMapT<K,V,U>::BUCKET_MULTIPLIER = 3;
00217 
00218 template <class K, class V, class U>
00219 const int TValHashMapT<K,V,U>::NUM_BUCKETS = 4;
00220 
00221 
00222 template <class K, class V, class U>
00223 TValHashMapT<K,V,U>::TValHashMapT ()
00224   : myNumBuckets (NUM_BUCKETS),
00225     myBucketMask (NUM_BUCKETS - 1),
00226     myGrowSize (NUM_BUCKETS * BUCKET_MULTIPLIER),
00227     myNumEntries (0),
00228     myIsShrinkEnabled (true)
00229 {
00230   myBuckets = (TValHashMapEntryT<K,V> **)
00231     calloc (myNumBuckets, sizeof (myBuckets));
00232   
00233   if (! myBuckets)
00234     throw TMemoryException ();
00235 }
00236 
00237 
00238 template <class K, class V, class U>
00239 TValHashMapT<K,V,U>::~TValHashMapT ()
00240 {
00241   myIsShrinkEnabled = false;
00242   Clear ();
00243   free (myBuckets);
00244 }
00245 
00246 
00247 template <class K, class V, class U>
00248 void TValHashMapT<K,V,U>::Apply (void (*fn)(const K *, V *, void *), void *d)
00249 {
00250   TValHashMapEntryT<K,V> *entry;
00251   
00252   for (int i = 0; i < myNumBuckets; i++)
00253     {
00254       entry = myBuckets[i];
00255       while (entry)
00256         {
00257           fn (&entry->key, &entry->value, d);
00258           entry = entry->next;
00259         }
00260     }
00261 }
00262 
00263 
00264 template <class K, class V, class U>
00265 void TValHashMapT<K,V,U>::Clear ()
00266 {
00267   TValHashMapEntryT<K,V> *entry, *tmp_entry;
00268   
00269   if (myNumEntries)
00270     {
00271       for (int i = 0; i < myNumBuckets; i++)
00272         {
00273           entry = myBuckets[i];
00274           while (entry)
00275             {
00276               tmp_entry = entry;
00277               entry = entry->next;
00278               delete tmp_entry;
00279             }
00280           
00281           myBuckets[i] = 0;
00282         }
00283       
00284       myNumEntries = 0;
00285     }
00286   
00287   if (myIsShrinkEnabled)
00288     {
00289       myNumBuckets = NUM_BUCKETS;
00290       myBucketMask = NUM_BUCKETS - 1;
00291       myGrowSize = NUM_BUCKETS * BUCKET_MULTIPLIER;
00292       
00293       myBuckets = (TValHashMapEntryT<K,V> **)
00294         realloc (myBuckets, myNumBuckets * sizeof (myBuckets));
00295     }
00296 }
00297 
00298 
00299 template <class K, class V, class U>
00300 bool TValHashMapT<K,V,U>::FindValue (const K& k, V& v)
00301 {
00302   V *value = Find (k);
00303   if (value)
00304     {
00305       v = *value;
00306       return true;
00307     }
00308   
00309   return false;
00310 }
00311 
00312 
00313 template <class K, class V, class U>
00314 bool TValHashMapT<K,V,U>::Insert (const K& k, const V& v)
00315 {
00316   TValHashMapEntryT<K,V> *entry, *old_entry;
00317   unsigned int hash = U::Hash (k);
00318   int index = hash & myBucketMask;
00319   
00320   entry = old_entry = myBuckets[index];
00321   while (entry)
00322     {
00323       if (entry->hash == hash &&
00324           U::Equal (k, entry->key))
00325         return false;
00326       
00327       entry = entry->next;
00328     }
00329   
00330   entry = new TValHashMapEntryT<K,V> (k, v);
00331   myBuckets[index] = entry;
00332   entry->next = old_entry;
00333   entry->hash = hash;
00334   
00335   myNumEntries++;
00336   if (myNumEntries >= myGrowSize)
00337     Grow ();
00338   
00339   return true;
00340 }
00341 
00342 
00343 template <class K, class V, class U>
00344 bool TValHashMapT<K,V,U>::Remove (const K& k)
00345 {
00346   TValHashMapEntryT<K,V> *entry, *prev = 0;
00347   unsigned int hash = U::Hash (k);
00348   int index = hash & myBucketMask;
00349   
00350   entry = myBuckets[index];
00351   while (entry)
00352     {
00353       if (entry->hash == hash &&
00354           U::Equal (k, entry->key))
00355         {
00356           if (entry == myBuckets[index])
00357             myBuckets[index] = entry->next;
00358           else
00359             prev->next = entry->next;
00360           
00361           delete (entry);
00362           myNumEntries--;
00363           if (myIsShrinkEnabled && myNumBuckets > NUM_BUCKETS &&
00364               myNumEntries <= myShrinkSize)
00365             Shrink ();
00366           
00367           return true;
00368         }
00369       
00370       prev = entry;
00371       entry = entry->next;
00372     }
00373   
00374   return false;
00375 }
00376 
00377 
00378 template <class K, class V, class U>
00379 V& TValHashMapT<K,V,U>::operator[](const K& k)
00380 {
00381   V *v = Find (k);
00382   
00383   if (v)
00384     return *v;
00385   else
00386     {
00387       V some_value;
00388       Insert (k, some_value);
00389       return *(Find (k));
00390     }
00391 }
00392 
00393 
00394 template <class K, class V, class U>
00395 TValHashMapT<K,V,U>&
00396 TValHashMapT<K,V,U>::operator=(const TValHashMapT<K,V,U> &map)
00397 {
00398   /* Only copy if different objects. */
00399   if (&map != this)
00400     {
00401       bool shrink_enabled = myIsShrinkEnabled;
00402       
00403       myIsShrinkEnabled = false;
00404       Clear ();
00405       free (myBuckets);
00406       Copy (map);
00407       myIsShrinkEnabled = shrink_enabled;
00408     }
00409   
00410   return *this;
00411 }
00412 
00413 
00414 template <class K, class V, class U>
00415 void TValHashMapT<K,V,U>::Copy (const TValHashMapT<K,V,U>& map)
00416 {
00417   TValHashMapEntryT<K,V> *orig_entry, *new_entry, *old_entry;
00418   
00419   myNumBuckets = map.myNumBuckets;
00420   myBucketMask = map.myBucketMask;
00421   myShrinkSize = map.myShrinkSize;
00422   myGrowSize = map.myGrowSize;
00423   myNumEntries = map.myNumEntries;
00424   myIsShrinkEnabled = map.myIsShrinkEnabled;
00425   
00426   myBuckets = (TValHashMapEntryT<K,V> **)
00427     calloc (myNumBuckets, sizeof (myBuckets));
00428   
00429   if (! myBuckets)
00430     throw TMemoryException ();
00431   
00432   for (int i = 0; i < myNumBuckets; i++)
00433     {
00434       orig_entry = map.myBuckets[i];
00435       while (orig_entry)
00436         {
00437           old_entry = myBuckets[i];
00438           new_entry = new TValHashMapEntryT<K,V> (orig_entry->key,
00439                                                   orig_entry->value);
00440           new_entry->next = old_entry;
00441           new_entry->hash = orig_entry->hash;
00442           myBuckets[i] = new_entry;
00443           orig_entry = orig_entry->next;
00444         }
00445     }
00446 }
00447 
00448 
00449 template <class K, class V, class U>
00450 V* TValHashMapT<K,V,U>::Find (const K& k)
00451 {
00452   TValHashMapEntryT<K,V> *entry;
00453   unsigned int hash = U::Hash (k);
00454   
00455   entry = myBuckets[hash & myBucketMask];
00456   while (entry)
00457     {
00458       if (entry->hash == hash &&
00459           U::Equal (k, entry->key))
00460         return &entry->value;
00461       
00462       entry = entry->next;
00463     }
00464   
00465   return 0;
00466 }
00467 
00468 
00469 template <class K, class V, class U>
00470 void TValHashMapT<K,V,U>::Grow ()
00471 {
00472   ReHash (myNumBuckets << 2);
00473   myShrinkSize = (myNumBuckets * BUCKET_MULTIPLIER) >> 4;
00474   myGrowSize <<= 2;
00475 }
00476 
00477 
00478 template <class K, class V, class U>
00479 void TValHashMapT<K,V,U>::ReHash (int new_num_buckets)
00480 {
00481   TValHashMapEntryT<K,V> **orig_buckets = myBuckets;
00482   TValHashMapEntryT<K,V> *entry, *old_entry, *tmp_entry;
00483   int old_num_buckets = myNumBuckets, index;
00484   
00485   myBuckets = (TValHashMapEntryT<K,V> **)
00486     calloc (new_num_buckets, sizeof (myBuckets));
00487   
00488   if (! myBuckets)
00489     throw TMemoryException ();
00490   
00491   myNumBuckets = new_num_buckets;
00492   myBucketMask = new_num_buckets - 1;
00493   
00494   for (int i = 0; i < old_num_buckets; i++)
00495     {
00496       entry = orig_buckets[i];
00497       while (entry)
00498         {
00499           tmp_entry = entry;
00500           entry = entry->next;
00501           index = tmp_entry->hash & myBucketMask;
00502           old_entry = myBuckets[index];
00503           myBuckets[index] = tmp_entry;
00504           tmp_entry->next = old_entry;    
00505         }
00506     }
00507   
00508   free (orig_buckets);
00509 }
00510 
00511 
00512 template <class K, class V, class U>
00513 void TValHashMapT<K,V,U>::Shrink ()
00514 {
00515   ReHash (myNumBuckets >> 2);
00516   myShrinkSize >>= 2;
00517   myGrowSize >>= 2;
00518 }
00519 
00520 #endif // _T_VAL_HASH_MAP_T_HH

Generated on Sat Feb 15 18:37:16 2003 for Tools by doxygen1.3-rc2