00001 #ifndef _T_VAL_HASH_SET_T_HH
00002 #define _T_VAL_HASH_SET_T_HH
00003
00004 #include <stdio.h>
00005 #include <stdlib.h>
00006 #include "TMemoryException.hh"
00007
00008
00009
00010
00011 template <class K>
00012 class TValHashSetEntryT
00013 {
00014 public:
00015
00019 TValHashSetEntryT (const K& k)
00020 : key (k)
00021 {
00022 }
00023
00025 TValHashSetEntryT *next;
00026
00028 unsigned int hash;
00029
00031 K key;
00032 };
00033
00034
00050 template <class K, class U>
00051 class TValHashSetT
00052 {
00053 public:
00054
00058 TValHashSetT ();
00059
00063 TValHashSetT (const TValHashSetT<K,U> &set) { Copy (set); }
00064
00068 ~TValHashSetT ();
00069
00076 void Apply (void (*fn)(const K *, void *), void *d);
00077
00081 void Clear ();
00082
00089 bool Contains (const K& k);
00090
00096 int Entries () { return myNumEntries; }
00097
00104 bool Insert (const K& k);
00105
00112 bool Remove (const K& k);
00113
00120 void Shrink (bool flag) { myIsShrinkEnabled = flag; }
00121
00125 TValHashSetT<K,U>& operator=(const TValHashSetT<K,U> &set);
00126
00127 private:
00128
00133 void Copy (const TValHashSetT<K,U>& set);
00134
00138 void Grow ();
00139
00146 void ReHash (int new_num_buckets);
00147
00151 void Shrink ();
00152
00153
00155 TValHashSetEntryT<K> **myBuckets;
00156
00158 int myNumBuckets;
00159
00161 int myBucketMask;
00162
00165 int myShrinkSize;
00166
00169 int myGrowSize;
00170
00172 int myNumEntries;
00173
00175 bool myIsShrinkEnabled;
00176
00179 static const int BUCKET_MULTIPLIER;
00180
00182 static const int NUM_BUCKETS;
00183 };
00184
00185
00186 template <class K, class U>
00187 const int TValHashSetT<K,U>::BUCKET_MULTIPLIER = 3;
00188
00189 template <class K, class U>
00190 const int TValHashSetT<K,U>::NUM_BUCKETS = 4;
00191
00192
00193 template <class K, class U>
00194 TValHashSetT<K,U>::TValHashSetT ()
00195 : myNumBuckets (NUM_BUCKETS),
00196 myBucketMask (NUM_BUCKETS - 1),
00197 myGrowSize (NUM_BUCKETS * BUCKET_MULTIPLIER),
00198 myNumEntries (0),
00199 myIsShrinkEnabled (true)
00200 {
00201 myBuckets = (TValHashSetEntryT<K> **)
00202 calloc (myNumBuckets, sizeof (myBuckets));
00203
00204 if (! myBuckets)
00205 throw TMemoryException ();
00206 }
00207
00208
00209 template <class K, class U>
00210 TValHashSetT<K,U>::~TValHashSetT ()
00211 {
00212 myIsShrinkEnabled = false;
00213 Clear ();
00214 free (myBuckets);
00215 }
00216
00217
00218 template <class K, class U>
00219 void TValHashSetT<K,U>::Apply (void (*fn)(const K *, void *), void *d)
00220 {
00221 TValHashSetEntryT<K> *entry;
00222
00223 for (int i = 0; i < myNumBuckets; i++)
00224 {
00225 entry = myBuckets[i];
00226 while (entry)
00227 {
00228 fn (&entry->key, d);
00229 entry = entry->next;
00230 }
00231 }
00232 }
00233
00234
00235 template <class K, class U>
00236 void TValHashSetT<K,U>::Clear ()
00237 {
00238 TValHashSetEntryT<K> *entry, *tmp_entry;
00239
00240 if (myNumEntries)
00241 {
00242 for (int i = 0; i < myNumBuckets; i++)
00243 {
00244 entry = myBuckets[i];
00245 while (entry)
00246 {
00247 tmp_entry = entry;
00248 entry = entry->next;
00249 delete tmp_entry;
00250 }
00251
00252 myBuckets[i] = 0;
00253 }
00254
00255 myNumEntries = 0;
00256 }
00257
00258 if (myIsShrinkEnabled)
00259 {
00260 myNumBuckets = NUM_BUCKETS;
00261 myBucketMask = NUM_BUCKETS - 1;
00262 myGrowSize = NUM_BUCKETS * BUCKET_MULTIPLIER;
00263
00264 myBuckets = (TValHashSetEntryT<K> **)
00265 realloc (myBuckets, myNumBuckets * sizeof (myBuckets));
00266 }
00267 }
00268
00269
00270 template <class K, class U>
00271 bool TValHashSetT<K,U>::Contains (const K& k)
00272 {
00273 TValHashSetEntryT<K> *entry;
00274 unsigned int hash = U::Hash (k);
00275
00276 entry = myBuckets[hash & myBucketMask];
00277 while (entry)
00278 {
00279 if (entry->hash == hash &&
00280 U::Equal (k, entry->key))
00281 return true;
00282
00283 entry = entry->next;
00284 }
00285
00286 return false;
00287 }
00288
00289
00290 template <class K, class U>
00291 bool TValHashSetT<K,U>::Insert (const K& k)
00292 {
00293 TValHashSetEntryT<K> *entry, *old_entry;
00294 unsigned int hash = U::Hash (k);
00295 int index = hash & myBucketMask;
00296
00297 entry = old_entry = myBuckets[index];
00298 while (entry)
00299 {
00300 if (entry->hash == hash &&
00301 U::Equal (k, entry->key))
00302 return false;
00303
00304 entry = entry->next;
00305 }
00306
00307 entry = new TValHashSetEntryT<K> (k);
00308 myBuckets[index] = entry;
00309 entry->next = old_entry;
00310 entry->hash = hash;
00311
00312 myNumEntries++;
00313 if (myNumEntries >= myGrowSize)
00314 Grow ();
00315
00316 return true;
00317 }
00318
00319
00320 template <class K, class U>
00321 bool TValHashSetT<K,U>::Remove (const K& k)
00322 {
00323 TValHashSetEntryT<K> *entry, *prev = 0;
00324 unsigned int hash = U::Hash (k);
00325 int index = hash & myBucketMask;
00326
00327 entry = myBuckets[index];
00328 while (entry)
00329 {
00330 if (entry->hash == hash &&
00331 U::Equal (k, entry->key))
00332 {
00333 if (entry == myBuckets[index])
00334 myBuckets[index] = entry->next;
00335 else
00336 prev->next = entry->next;
00337
00338 delete (entry);
00339 myNumEntries--;
00340 if (myIsShrinkEnabled && myNumBuckets > NUM_BUCKETS &&
00341 myNumEntries <= myShrinkSize)
00342 Shrink ();
00343
00344 return true;
00345 }
00346
00347 prev = entry;
00348 entry = entry->next;
00349 }
00350
00351 return false;
00352 }
00353
00354
00355 template <class K, class U>
00356 TValHashSetT<K,U>& TValHashSetT<K,U>::operator=(const TValHashSetT<K,U> &set)
00357 {
00358
00359 if (&set != this)
00360 {
00361 bool shrink_enabled = myIsShrinkEnabled;
00362
00363 myIsShrinkEnabled = false;
00364 Clear ();
00365 free (myBuckets);
00366 Copy (set);
00367 myIsShrinkEnabled = shrink_enabled;
00368 }
00369
00370 return *this;
00371 }
00372
00373
00374 template <class K, class U>
00375 void TValHashSetT<K,U>::Copy (const TValHashSetT<K,U>& set)
00376 {
00377 TValHashSetEntryT<K> *orig_entry, *new_entry, *old_entry;
00378
00379 myNumBuckets = set.myNumBuckets;
00380 myBucketMask = set.myBucketMask;
00381 myShrinkSize = set.myShrinkSize;
00382 myGrowSize = set.myGrowSize;
00383 myNumEntries = set.myNumEntries;
00384 myIsShrinkEnabled = set.myIsShrinkEnabled;
00385
00386 myBuckets = (TValHashSetEntryT<K> **)
00387 calloc (myNumBuckets, sizeof (myBuckets));
00388
00389 if (! myBuckets)
00390 throw TMemoryException ();
00391
00392 for (int i = 0; i < myNumBuckets; i++)
00393 {
00394 orig_entry = set.myBuckets[i];
00395 while (orig_entry)
00396 {
00397 old_entry = myBuckets[i];
00398 new_entry = new TValHashSetEntryT<K> (orig_entry->key);
00399 new_entry->next = old_entry;
00400 new_entry->hash = orig_entry->hash;
00401 myBuckets[i] = new_entry;
00402 orig_entry = orig_entry->next;
00403 }
00404 }
00405 }
00406
00407
00408 template <class K, class U>
00409 void TValHashSetT<K,U>::Grow ()
00410 {
00411 ReHash (myNumBuckets << 2);
00412 myShrinkSize = (myNumBuckets * BUCKET_MULTIPLIER) >> 4;
00413 myGrowSize <<= 2;
00414 }
00415
00416
00417 template <class K, class U>
00418 void TValHashSetT<K,U>::ReHash (int new_num_buckets)
00419 {
00420 TValHashSetEntryT<K> **orig_buckets = myBuckets;
00421 TValHashSetEntryT<K> *entry, *old_entry, *tmp_entry;
00422 int old_num_buckets = myNumBuckets, index;
00423
00424 myBuckets = (TValHashSetEntryT<K> **)
00425 calloc (new_num_buckets, sizeof (myBuckets));
00426
00427 if (! myBuckets)
00428 throw TMemoryException ();
00429
00430 myNumBuckets = new_num_buckets;
00431 myBucketMask = new_num_buckets - 1;
00432
00433 for (int i = 0; i < old_num_buckets; i++)
00434 {
00435 entry = orig_buckets[i];
00436 while (entry)
00437 {
00438 tmp_entry = entry;
00439 entry = entry->next;
00440 index = tmp_entry->hash & myBucketMask;
00441 old_entry = myBuckets[index];
00442 myBuckets[index] = tmp_entry;
00443 tmp_entry->next = old_entry;
00444 }
00445 }
00446
00447 free (orig_buckets);
00448 }
00449
00450
00451 template <class K, class U>
00452 void TValHashSetT<K,U>::Shrink ()
00453 {
00454 ReHash (myNumBuckets >> 2);
00455 myShrinkSize >>= 2;
00456 myGrowSize >>= 2;
00457 }
00458
00459 #endif // _T_VAL_HASH_SET_T_HH