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
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
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