00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef _SHARED_TABLE_H
00026 #define _SHARED_TABLE_H
00027
00028 #include <Basics.H>
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 template <class K, class V>
00049 class SharedTable {
00050 public:
00051
00052 class KVPair {
00053 public:
00054 KVPair(const K& k, const V& v) throw ()
00055 : key(k), val(v) { }
00056 K key;
00057 V val;
00058 };
00059
00060
00061 typedef KVPair *KVPairPtr;
00062
00063
00064 class Iterator;
00065
00066
00067 class T {
00068 public:
00069 T(Bit32 sizeHint = 0) throw ()
00070 : buckets(NULL) { Init(sizeHint); }
00071
00072
00073
00074 T(const T *tbl) throw ()
00075 : buckets(NULL) { Init(tbl->numEntries); Copy(tbl); }
00076
00077
00078 void Init(Bit32 sizeHint = 0U) throw ();
00079
00080
00081
00082
00083
00084 T& operator= (const T& tbl) throw ()
00085 { Init(tbl.numEntries); Copy(&tbl); return *this; }
00086
00087
00088 int Size() const throw () { return numEntries; }
00089
00090
00091 bool Get(const K& k, KVPairPtr& pr) const throw ();
00092
00093
00094
00095
00096 bool Put(KVPairPtr pr, bool resize = true) throw ();
00097
00098
00099
00100
00101 bool Put(const K& k, const V& v, KVPairPtr& pr,
00102 bool resize = true) throw ();
00103
00104
00105
00106
00107
00108
00109 void Copy(const T* tbl, bool resize = true) throw ();
00110
00111
00112
00113 bool Delete(const K& k, KVPairPtr& pr, bool resize = true)
00114 throw ();
00115
00116
00117
00118
00119
00120 void Resize() throw ();
00121
00122
00123
00124
00125 private:
00126 Bit32 numEntries;
00127 Bit32 minEntries;
00128 Bit32 maxEntries;
00129 Bit16 logBuckets;
00130 Bit16 minLogBuckets;
00131 KVPairPtr *buckets;
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 class MultiBucket {
00142 public:
00143 Bit32 num;
00144 Bit32 len;
00145 };
00146 typedef MultiBucket *MultiBucketPtr;
00147
00148 inline static unsigned int MultiBucketSlots() throw()
00149 {
00150 static unsigned int slots = 0;
00151
00152 if(slots == 0)
00153 {
00154 slots = sizeof(MultiBucket) / sizeof(KVPairPtr);
00155
00156
00157 while(sizeof(MultiBucket) > (slots * sizeof(KVPairPtr)))
00158 slots++;
00159 }
00160 return slots;
00161 }
00162
00163
00164
00165
00166 void NewBuckets(bool allocBuckets) throw ();
00167
00168
00169
00170
00171
00172 void AllocBuckets(Bit32 numBuckets) throw ();
00173
00174
00175
00176 void EmptyBuckets(Bit32 numBuckets) throw ();
00177
00178
00179 void Rehash(Bit16 logBuckets) throw ();
00180
00181
00182
00183 inline Bit32 BucketNum(const K &k) const throw ();
00184
00185
00186 KVPair *InitBucket(KVPair *elt0, KVPair *elt1) throw ();
00187
00188
00189
00190 KVPair *GrowBucket( MultiBucketPtr &mb,
00191 KVPairPtr* &elt) throw ();
00192
00193
00194
00195
00196
00197 bool PutPrivate(KVPairPtr pr) throw ();
00198
00199
00200
00201
00202
00203 friend class Iterator;
00204
00205
00206 T(const T&);
00207 };
00208
00209
00210 class Iterator {
00211 public:
00212 Iterator(const T* tbl) throw () : tbl(tbl) { Reset(); }
00213
00214
00215
00216
00217
00218
00219 void Reset() throw ();
00220
00221
00222
00223
00224 bool Next( KVPairPtr& pr) throw ();
00225
00226
00227
00228
00229
00230 private:
00231
00232 const T *tbl;
00233 Bit32 bucket;
00234 Bit16 next;
00235 bool done;
00236
00237
00238 Iterator(const Iterator&);
00239 };
00240 };
00241
00242
00243
00244 #include "TableUtils.H"
00245 #include "TableConsts.H"
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 template <class K, class V>
00269 void SharedTable<K,V>::T::Copy(const T *tbl, bool resize) throw ()
00270
00271
00272
00273 {
00274 Iterator iter(tbl);
00275 KVPairPtr pr;
00276 while (iter.Next( pr)) {
00277
00278 (void) this->Put(pr, resize);
00279 }
00280 if (!resize) Resize();
00281 }
00282
00283 template <class K, class V>
00284 void SharedTable<K,V>::T::Init(Bit32 sizeHint) throw ()
00285 {
00286 Bit32 idealBuckets;
00287 float idealF = (float)sizeHint / TableConsts::IdealDensity;
00288 idealBuckets = (idealF > (float)TableConsts::MaxBuckets) ? TableConsts::MaxBuckets : Ceiling(idealF);
00289 idealBuckets = max(TableConsts::MinBuckets, idealBuckets);
00290 this->numEntries = 0U;
00291 if (this->buckets != NULL && idealBuckets < (TableConsts::One32U << this->logBuckets)) {
00292
00293 this->EmptyBuckets(TableConsts::One32U << this->logBuckets);
00294 } else {
00295
00296 this->logBuckets = this->minLogBuckets = Log_2(idealBuckets);
00297 this->NewBuckets(sizeHint > 0);
00298 }
00299 }
00300
00301 template <class K, class V>
00302 void SharedTable<K,V>::T::NewBuckets(bool allocBuckets) throw ()
00303 {
00304
00305 Bit32 numBuckets = (TableConsts::One32U << this->logBuckets);
00306 this->minEntries = Round(TableConsts::MinDensity * (float)numBuckets);
00307 this->maxEntries = Round(TableConsts::MaxDensity * (float)numBuckets);
00308
00309
00310 if (allocBuckets) {
00311 this->AllocBuckets(numBuckets);
00312 } else {
00313 this->buckets = NULL;
00314 }
00315 }
00316
00317 template <class K, class V>
00318 void SharedTable<K,V>::T::AllocBuckets(Bit32 numBuckets) throw ()
00319 {
00320 this->buckets = NEW_ARRAY(KVPairPtr, numBuckets);
00321 assert(this->buckets != NULL);
00322 this->EmptyBuckets(numBuckets);
00323 }
00324
00325 template <class K, class V>
00326 void SharedTable<K,V>::T::EmptyBuckets(Bit32 numBuckets) throw ()
00327 {
00328 for (Bit32 i = 0U; i < numBuckets; i++) {
00329 this->buckets[i] = (KVPair *)NULL;
00330 }
00331 }
00332
00333 template <class K, class V>
00334 inline Bit32 SharedTable<K,V>::T::BucketNum(const K& k) const throw ()
00335 {
00336 return ((TableConsts::Multiplier * k.Hash()) >> (TableConsts::BitsPerWd - this->logBuckets));
00337 }
00338
00339 template <class K, class V>
00340 typename SharedTable<K,V>::KVPair*
00341 SharedTable<K,V>::T::InitBucket(KVPair *elt0, KVPair *elt1) throw ()
00342 {
00343 unsigned int mb_slots = MultiBucketSlots();
00344 KVPairPtr *elt =
00345 NEW_ARRAY(KVPairPtr, mb_slots + TableConsts::InitBucketSize);
00346 MultiBucket *mb = (MultiBucket *)(elt);
00347 elt += mb_slots;
00348
00349
00350 mb->num = 2U;
00351 mb->len = TableConsts::InitBucketSize;
00352 elt[0] = elt0, elt[1] = elt1;
00353
00354
00355 for (int i = 2; i < mb->len; i++) {
00356 elt[i] = (KVPair *)NULL;
00357 }
00358 return (KVPair *)((PointerInt)mb | TableConsts::LSBMask);
00359 }
00360
00361 template <class K, class V>
00362 typename SharedTable<K,V>::KVPair*
00363 SharedTable<K,V>::T::GrowBucket( MultiBucketPtr &mb, KVPairPtr* &elt) throw ()
00364 {
00365
00366 assert(mb->num == mb->len);
00367 mb->len = Ceiling((float)(mb->len) * TableConsts::BucketGrowFactor);
00368 unsigned int mb_slots = MultiBucketSlots();
00369 KVPairPtr *eltNew = NEW_ARRAY(KVPairPtr, mb_slots + mb->len);
00370 MultiBucket *mbNew = (MultiBucket *)(eltNew);
00371 eltNew += mb_slots;
00372 *mbNew = *mb;
00373 assert(mbNew->len > mbNew->num);
00374
00375
00376 int k;
00377 for (k = 0; k < mb->num; k++) {
00378 eltNew[k] = elt[k];
00379 elt[k] = (KVPair *)NULL;
00380 }
00381
00382
00383 for (; k < mbNew->len; k++) {
00384 eltNew[k] = (KVPair *)NULL;
00385 }
00386
00387
00388 mb = mbNew; elt = eltNew;
00389 return (KVPair *)((PointerInt)mbNew | TableConsts::LSBMask);
00390 }
00391
00392 template <class K, class V>
00393 void SharedTable<K,V>::T::Rehash(Bit16 logBuckets) throw ()
00394 {
00395 assert(logBuckets <= TableConsts::MaxLogBuckets);
00396 assert(logBuckets >= this->minLogBuckets);
00397
00398 KVPairPtr *ob = this->buckets;
00399 Bit16 oldLogBuckets = this->logBuckets;
00400 Bit32 oldNumBuckets = (TableConsts::One32U << oldLogBuckets);
00401
00402
00403 this->logBuckets = logBuckets;
00404 this->NewBuckets(ob != (KVPairPtr *)NULL);
00405
00406 if (ob != (KVPairPtr *)NULL) {
00407
00408 for (Bit32 i = 0U; i < oldNumBuckets; i++) {
00409 KVPair *b = ob[i];
00410 if (b != (KVPair *)NULL) {
00411
00412 if (!((PointerInt)b & TableConsts::LSBMask)) {
00413
00414 this->PutPrivate(b);
00415 ob[i] = (KVPair *)NULL;
00416 } else {
00417
00418 KVPairPtr *elt = (KVPairPtr *)((PointerInt)b & TableConsts::LSBMaskBar);
00419 unsigned int mb_slots = MultiBucketSlots();
00420 MultiBucket *mb = (MultiBucket *)(elt);
00421 elt += mb_slots;
00422 register Bit16 j;
00423 for (j = 0U; j < mb->num; j++) {
00424 if (elt[j] != (KVPair *)NULL) {
00425 this->PutPrivate(elt[j]);
00426 elt[j] = (KVPair *)NULL;
00427 }
00428 }
00429 }
00430 }
00431 }
00432 }
00433 }
00434
00435 template <class K, class V>
00436 void SharedTable<K,V>::T::Resize() throw ()
00437 {
00438 if (this->numEntries < this->minEntries
00439 && this->logBuckets > this->minLogBuckets) {
00440
00441 Rehash(this->logBuckets - 1);
00442 } else if (this->numEntries > this->maxEntries
00443 && this->logBuckets < TableConsts::MaxLogBuckets) {
00444
00445 Rehash(this->logBuckets + 1);
00446 }
00447 }
00448
00449 template <class K, class V>
00450 bool SharedTable<K,V>::T::Get(const K& k, KVPairPtr& pr) const throw ()
00451 {
00452 if (this->buckets == NULL) return false;
00453 KVPair *b = this->buckets[this->BucketNum(k)];
00454 if (b == (KVPair *)NULL) return false;
00455 if (!((PointerInt)b & TableConsts::LSBMask)) {
00456
00457 if (b->key == k) {
00458 pr = b;
00459 return true;
00460 }
00461 } else {
00462
00463 KVPairPtr *elt = (KVPairPtr *)((PointerInt)b & TableConsts::LSBMaskBar);
00464 unsigned int mb_slots = MultiBucketSlots();
00465 MultiBucket *mb = (MultiBucket *)(elt);
00466 elt += mb_slots;
00467 register Bit16 i;
00468 for (i = 0; i < mb->num; i++) {
00469 if (elt[i] != (KVPair *)NULL && elt[i]->key == k) break;
00470 }
00471 if (i < mb->num) {
00472 pr = elt[i];
00473 return true;
00474 }
00475 }
00476 return false;
00477 }
00478
00479 template <class K, class V>
00480 bool SharedTable<K,V>::T::PutPrivate(KVPairPtr pr) throw ()
00481 {
00482 Bit32 bucketNum = this->BucketNum(pr->key);
00483 if (this->buckets == NULL) AllocBuckets(TableConsts::One32U << this->logBuckets);
00484 KVPair *b = this->buckets[bucketNum];
00485
00486 if (b == (KVPair *)NULL) {
00487
00488 this->buckets[bucketNum] = pr;
00489 } else if (!((PointerInt)b & TableConsts::LSBMask)) {
00490
00491 if (b->key == pr->key) {
00492
00493 this->buckets[bucketNum] = pr;
00494
00495 return true;
00496 } else {
00497
00498 this->buckets[bucketNum] = (KVPair *)InitBucket(b, pr);
00499 }
00500 } else {
00501
00502 KVPairPtr *elt = (KVPairPtr *)((PointerInt)b & TableConsts::LSBMaskBar);
00503 unsigned int mb_slots = MultiBucketSlots();
00504 MultiBucket *mb = (MultiBucket *)(elt);
00505 elt += mb_slots;
00506 int emptySlot = -1;
00507 register Bit16 i;
00508 for (i = 0; i < mb->num; i++) {
00509 if (elt[i] == (KVPair *)NULL) {
00510 if (emptySlot < 0) emptySlot = i;
00511 } else if (elt[i]->key == pr->key) {
00512 break;
00513 }
00514 }
00515 if (i < mb->num) {
00516
00517 elt[i] = pr;
00518
00519 return true;
00520 } else {
00521
00522 if (emptySlot >= 0) {
00523
00524 elt[emptySlot] = pr;
00525 } else {
00526
00527 if (mb->num >= mb->len) {
00528 this->buckets[bucketNum] =
00529 (KVPair *)(this->GrowBucket(mb, elt));
00530 }
00531 elt[mb->num++] = pr;
00532 }
00533 }
00534 }
00535 return false;
00536 }
00537
00538 template <class K, class V>
00539 bool SharedTable<K,V>::T::Put(KVPairPtr pr, bool resize) throw ()
00540 {
00541 bool res = this->PutPrivate(pr);
00542 if (!res) {
00543
00544
00545 this->numEntries++;
00546 if (resize && this->numEntries > this->maxEntries
00547 && this->logBuckets < TableConsts::MaxLogBuckets) {
00548
00549 Rehash(this->logBuckets + 1);
00550 }
00551 }
00552 return res;
00553 }
00554
00555 template <class K, class V>
00556 bool SharedTable<K,V>::T::Put(const K& k, const V& v,
00557 KVPairPtr& pr, bool resize) throw ()
00558 {
00559 Bit32 bucketNum = this->BucketNum(k);
00560 if (this->buckets == NULL) AllocBuckets(TableConsts::One32U << this->logBuckets);
00561 KVPair *b = this->buckets[bucketNum];
00562
00563 if (b == (KVPair *)NULL) {
00564
00565 pr = NEW_CONSTR(KVPair, (k,v));
00566 this->buckets[bucketNum] = pr;
00567 } else if (!((PointerInt)b & TableConsts::LSBMask)) {
00568
00569 if (b->key == k) {
00570
00571 pr = this->buckets[bucketNum];
00572 return true;
00573 } else {
00574
00575 pr = NEW_CONSTR(KVPair, (k,v));
00576 this->buckets[bucketNum] = (KVPair *)InitBucket(b, pr);
00577 }
00578 } else {
00579
00580 KVPairPtr *elt = (KVPairPtr *)((PointerInt)b & TableConsts::LSBMaskBar);
00581 unsigned int mb_slots = MultiBucketSlots();
00582 MultiBucket *mb = (MultiBucket *)(elt);
00583 elt += mb_slots;
00584 int emptySlot = -1;
00585 register Bit16 i;
00586 for (i = 0; i < mb->num; i++) {
00587 if (elt[i] == (KVPair *)NULL) {
00588 if (emptySlot < 0) emptySlot = i;
00589 } else if (elt[i]->key == k) {
00590 break;
00591 }
00592 }
00593 if (i < mb->num) {
00594
00595 pr = elt[i];
00596 return true;
00597 } else {
00598
00599 pr = NEW_CONSTR(KVPair, (k,v));
00600 if (emptySlot >= 0) {
00601
00602 elt[emptySlot] = pr;
00603 } else {
00604
00605 if (mb->num >= mb->len) {
00606 this->buckets[bucketNum] =
00607 (KVPair *)(this->GrowBucket(mb, elt));
00608 }
00609 elt[mb->num++] = pr;
00610 }
00611 }
00612 }
00613
00614
00615 this->numEntries++;
00616 if (resize && this->numEntries > this->maxEntries
00617 && this->logBuckets < TableConsts::MaxLogBuckets) {
00618
00619 Rehash(this->logBuckets + 1);
00620 }
00621 return false;
00622 }
00623
00624 template <class K, class V>
00625 bool SharedTable<K,V>::T::Delete(const K& k, KVPairPtr& pr,
00626 bool resize) throw ()
00627 {
00628 if (this->buckets == NULL) return false;
00629 Bit32 bucketNum = this->BucketNum(k);
00630 KVPair *b = this->buckets[bucketNum];
00631
00632 if (b == (KVPair *)NULL) {
00633
00634 return false;
00635 } else if (!((PointerInt)b & TableConsts::LSBMask)) {
00636
00637 if (b->key == k) {
00638
00639 pr = b;
00640 this->buckets[bucketNum] = (KVPair *)NULL;
00641 } else {
00642 return false;
00643 }
00644 } else {
00645
00646 KVPairPtr *elt = (KVPairPtr *)((PointerInt)b & TableConsts::LSBMaskBar);
00647 unsigned int mb_slots = MultiBucketSlots();
00648 MultiBucket *mb = (MultiBucket *)(elt);
00649 elt += mb_slots;
00650 register Bit16 i;
00651 for (i = 0; i < mb->num; i++) {
00652 if (elt[i] != (KVPair *)NULL && elt[i]->key == k) break;
00653 }
00654 if (i < mb->num) {
00655 pr = elt[i];
00656 elt[i] = (KVPair *)NULL;
00657 } else {
00658 return false;
00659 }
00660 }
00661
00662
00663
00664 this->numEntries--;
00665 if (resize && this->numEntries < this->minEntries
00666 && this->logBuckets > this->minLogBuckets) {
00667
00668 Rehash(this->logBuckets - 1);
00669 }
00670 return true;
00671 }
00672
00673
00674
00675 template <class K, class V>
00676 void SharedTable<K,V>::Iterator::Reset() throw ()
00677 {
00678 this->bucket = 0U;
00679 this->next = 0U;
00680 this->done = false;
00681 }
00682
00683 template <class K, class V>
00684 bool SharedTable<K,V>::Iterator::Next( KVPairPtr& pr) throw ()
00685 {
00686 const T *t = this->tbl;
00687 if (t->buckets != NULL) {
00688 while (this->bucket < (TableConsts::One32U << t->logBuckets)) {
00689 KVPair *b = t->buckets[this->bucket];
00690 if (b != (KVPair *)NULL) {
00691 if (!((PointerInt)b & TableConsts::LSBMask)) {
00692
00693 pr = b;
00694 this->bucket++;
00695 return true;
00696 } else {
00697
00698 KVPairPtr *elt = (KVPairPtr *)((PointerInt)b & TableConsts::LSBMaskBar);
00699 unsigned int mb_slots = T::MultiBucketSlots();
00700 typename T::MultiBucket *mb =
00701 (typename T::MultiBucket *)(elt);
00702 elt += mb_slots;
00703
00704
00705 while (this->next < mb->num &&
00706 elt[this->next] == (KVPair *)NULL) {
00707 this->next++;
00708 }
00709 if (this->next < mb->num) {
00710
00711 pr = elt[this->next++];
00712 return true;
00713 }
00714
00715
00716 this->next = 0;
00717 }
00718 }
00719 this->bucket++;
00720 }
00721 }
00722 assert(!(this->done));
00723 this->done = true;
00724 return false;
00725 }
00726
00727 #endif // _SHARED_TABLE_H