Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

SharedTable.H

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 
00003 // This file is part of Vesta.
00004 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Created on Fri May  2 15:58:40 PDT 1997 by heydon
00020 
00021 // Last modified on Thu Apr 21 09:28:51 EDT 2005 by irina.furman@intel.com
00022 //      modified on Tue Sep 21 13:55:51 EDT 2004 by ken@xorian.net
00023 //      modified on Mon May  3 16:04:44 PDT 1999 by heydon
00024 
00025 #ifndef _SHARED_TABLE_H
00026 #define _SHARED_TABLE_H
00027 
00028 #include <Basics.H>
00029 
00030 /* This interface defines a template for a generic variant of the "Table"
00031    class that allows key-value pairs to be shared between tables so as to
00032    minimize heap allocations.
00033 
00034    The class "SharedTable<K,V>" maps keys of type "K" to values of type "V".
00035    Unlike the "Table<K,V>" class, however, the methods for looking up,
00036    inserting, deleting, and iterating over table elements treat key-value
00037    pairs as a single value. Hence, a key-value pair from one table can be
00038    copied to another table without an extra allocation.
00039 
00040    The requirements on the "K" and "V" parameters of this interface are the
00041    same as those for the "Table" interface. Since key-value pairs can be
00042    shared between tables, you should not modify either field of a key-value
00043    pair once it has been installed in a table.
00044 
00045    This implementation assumes the use of a garbage collector; it does not
00046    free any memory explicitly. */
00047 
00048 template <class K, class V>
00049 class SharedTable {
00050   public:
00051     // the class of key-value pairs
00052     class KVPair {
00053       public:
00054         KVPair(const K& k, const V& v) throw ()
00055             : key(k), val(v) { /*SKIP*/ }
00056         K key;
00057         V val;
00058     };
00059 
00060     // a pointer to a KVPair
00061     typedef KVPair *KVPairPtr;
00062 
00063     // Iterator class defined below
00064     class Iterator;
00065 
00066     // the table class itself
00067     class T {
00068       public:
00069         T(Bit32 sizeHint = 0) throw ()
00070           : buckets(NULL) { Init(sizeHint); }
00071         /* Return a new, empty table. See the "Init" method below for a
00072             description of the "sizeHint" argument. */
00073 
00074         T(const T *tbl) throw ()
00075           : buckets(NULL) { Init(tbl->numEntries); Copy(tbl); }
00076         /* Initialize this table to be a copy of "*tbl". */
00077 
00078         void Init(Bit32 sizeHint = 0U) throw ();
00079         /* Reset the table to be empty. If "sizeHint" is greater than zero,
00080            the table is initialized with the expectation that "sizeHint"
00081            different pairs will eventually be "Put" into the table. These
00082            calls may execute somewhat faster than if "sizeHint" was 0. */
00083 
00084         T& operator= (const T& tbl) throw ()
00085           { Init(tbl.numEntries); Copy(&tbl); return *this; }
00086         /* Make this table a copy of "tbl". */
00087 
00088         int Size() const throw () { return numEntries; }
00089         /* Return the number of <k,v> pairs in the table. */
00090 
00091         bool Get(const K& k, /*OUT*/ KVPairPtr& pr) const throw ();
00092         /* If the key "k" exists in the table, then set "pr" to a pointer
00093            to the associated key-value pair and return "true". Otherwise,
00094            leave "pr" unchanged and return "false". */
00095 
00096         bool Put(KVPairPtr pr, bool resize = true) throw ();
00097         /* Install the key-value pair pointed to by "pr" in the table.
00098            Return "true" iff there was already a value associated with
00099            "pr->key" in the table before the method was invoked. */
00100 
00101         bool Put(const K& k, const V& v, /*OUT*/ KVPairPtr& pr,
00102           bool resize = true) throw ();
00103         /* If there is no entry in the table with key "k", install a new
00104             pair "(k,v)" in the table, set "pr" to that new pair, and return
00105             "false". Otherwise, a pair already exists in the table with key
00106             "k". In that case, "v" is ignored, "pr" is set to the existing
00107             pair, and the method returns "true". */
00108 
00109         void Copy(const T* tbl, bool resize = true) throw ();
00110         /* Add the key-value pairs in "tbl" to this table. That is, execute
00111            "this->Put(pr, resize)" for each key-value pair "pr" in "tbl". */
00112 
00113         bool Delete(const K& k, /*OUT*/ KVPairPtr& pr, bool resize = true)
00114           throw ();
00115         /* If the key "k" exists in the table, set "pr" to the pointer to the
00116            associated key-value pair, remove the association from the table,
00117            and return "true". Otherwise, leave "pr" unchanged and return
00118            "false". */
00119 
00120         void Resize() throw ();
00121         /* Grow or shrink the table as necessary after performing a sequence
00122            of "Put" or "Delete" operations all of which were passed "resize =
00123            false". */
00124 
00125       private:
00126         Bit32 numEntries;      // current number of entries in table
00127         Bit32 minEntries;      // minimum number of entries
00128         Bit32 maxEntries;      // maximum number of entries
00129         Bit16 logBuckets;      // Log_2(numBuckets)
00130         Bit16 minLogBuckets;   // minimum value for Log_2(initial size)
00131         KVPairPtr *buckets;    // buckets array
00132 
00133         /* Invariants of an initialized table:
00134              I1. buckets != NULL => NUMBER(*buckets) = 2^logBuckets
00135              I2. minEntries < maxEntries
00136            Note: it is possible for "numEntries < minEntries" or for
00137            "maxEntries < numEntries". This can happen when "resize = false"
00138            is used, or when the minimum or maximum bucket size is reached. */
00139 
00140         // see "SharedTable.C" for details about this structure
00141         class MultiBucket {
00142           public:
00143             Bit32 num;  // number of elements in bucket
00144             Bit32 len;  // total size of the bucket
00145         };
00146         typedef MultiBucket *MultiBucketPtr;
00147 
00148         inline static unsigned int MultiBucketSlots() throw()
00149         {
00150           static unsigned int slots = 0;
00151           // If we haven't computed the number of slots yet...
00152           if(slots == 0)
00153             {
00154               slots = sizeof(MultiBucket) / sizeof(KVPairPtr);
00155               // In case it's not an even multiple, make sure we
00156               // reserve enough slots.
00157               while(sizeof(MultiBucket) > (slots * sizeof(KVPairPtr)))
00158                 slots++;
00159             }
00160           return slots;
00161         }
00162         /* Return the number of slots in an array of KVPairPtr's that
00163            a MultiBucket struct will consume.  (The value depends on
00164            the size of pointers on the target architecture). */
00165 
00166         void NewBuckets(bool allocBuckets) throw ();
00167         /* Initialize the "minEntries" and "maxEntries" fields from the
00168            "this->logBuckets" field. If "allocBuckets" is true, allocate
00169            and initialize the "buckets" field to point to an array of
00170            "2^(logBuckets)" buckets. */
00171 
00172         void AllocBuckets(Bit32 numBuckets) throw ();
00173         /* Allocate and initialize the "buckets" field to point to an array
00174            array of "2^(logBuckets)" buckets. */
00175 
00176         void EmptyBuckets(Bit32 numBuckets) throw ();
00177         /* Forall "0 <= i < numBuckets", set "buckets[i]" to "NULL". */
00178 
00179         void Rehash(Bit16 logBuckets) throw ();
00180         /* Reallocate "2^logBuckets" buckets, and rehash the entries into
00181            the new table. */
00182 
00183         inline Bit32 BucketNum(const K &k) const throw ();
00184         // Return the bucket index for key "k".
00185 
00186         KVPair *InitBucket(KVPair *elt0, KVPair *elt1) throw ();
00187         /* Return a new multi-bucket containing the two elements "elt0" and
00188            "elt1". */
00189 
00190         KVPair *GrowBucket(/*INOUT*/ MultiBucketPtr &mb,
00191           /*INOUT*/ KVPairPtr* &elt) throw ();
00192         /* Grow the multi-bucket pointed to by "mb" and "elt" so it can hold
00193            more elements. This requires that the bucket is full, i.e., that
00194            "mb->num == mb->len". Return a pointer to the new multi-bucket,
00195            and set "mb" and "elt" to point to the new parts of it. */
00196 
00197         bool PutPrivate(KVPairPtr pr) throw ();
00198         /* Like "Put", but in the event that an entry did not already exist in
00199            the current table with key "pr->key", this neither increments the
00200            number of entries in the table nor attempts to resize the table. */
00201 
00202         // friends
00203         friend class Iterator;
00204 
00205         // hide copy constructor
00206         T(const T&);
00207     };
00208 
00209     // table iterators
00210     class Iterator {
00211       public:
00212         Iterator(const T* tbl) throw () : tbl(tbl) { Reset(); }
00213         /* Return a new iterator on the "T" table "tbl". While the iterator
00214            is in use, the client is only allowed to modify the table by
00215            invoking the "Put" and "Delete" methods with "resize = false".
00216            Once the iteration is complete, it is recommended that the "Resize"
00217            method be called to adjust the size of the table if necessary. */
00218 
00219         void Reset() throw ();
00220         /* Resets the iterator so that it will iterate over all the elements
00221            in its associated table. This can be used to iterate over the
00222            elements of the same table multiple times. */
00223 
00224         bool Next(/*OUT*/ KVPairPtr& pr) throw ();
00225         /* If there is a key-value pair in this iterator's table that has
00226            not already been enumerated, select one, set "pr" to point to it,
00227            and return "true". Otherwise, leave "pr" unchanged, and return
00228            "false". */
00229 
00230       private:
00231         // fields
00232         const T *tbl;             // this iterator's corresponding table
00233         Bit32 bucket;             // next bucket if < "tbl->numBuckets"
00234         Bit16 next;               // index of next entry in current bucket
00235         bool done;                // true if next() has returned "FALSE"
00236 
00237         // hide copy constructor
00238         Iterator(const Iterator&);
00239     };
00240 };
00241 
00242 // ========== template member definitions ==========
00243 
00244 #include "TableUtils.H"
00245 #include "TableConsts.H"
00246 
00247 /* Implementation
00248 
00249    Within a table, the pointers in the "buckets" array are overloaded.
00250    There are three cases:
00251 
00252    1) If the pointer is NULL, the bucket is empty.
00253 
00254    2) If the least significant bit of the pointer is unset, the bucket
00255       contains a single KVPair pointed to by the pointer.
00256 
00257    3) If the least significant bit of the pointer is set, the bucket
00258       contains more than one entry. The pointer (with its LSB reset)
00259       points to an array of KVPairPtr's. The first element of the array
00260       is actually not a pointer, but a "MultiBucket" structure containing
00261       a pair of 32-bit integers representing the number of significant
00262       pointers in the succeeding elements of the array and the total number
00263       of slots in the array (not counting the first entry).
00264 */
00265 
00266 // ----------------------------------------------- Default table methods -----
00267 
00268 template <class K, class V>
00269 void SharedTable<K,V>::T::Copy(const T *tbl, bool resize) throw ()
00270 /* Iterate over the elements of "tbl", and put each (key,value) pair
00271    in this table. This could probably be done more efficiently without
00272    using an iterator. */
00273 {
00274     Iterator iter(tbl);
00275     KVPairPtr pr;
00276     while (iter.Next(/*OUT*/ pr)) {
00277         // add the pair to this table
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         // enough buckets already exist; just empty them
00293         this->EmptyBuckets(TableConsts::One32U << this->logBuckets);
00294     } else {
00295         // allocate new buckets
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     // calculate "minEntries" and "maxEntries"
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     // allocate buckets array if necessary
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     // set multi bucket fields
00350     mb->num = 2U;
00351     mb->len = TableConsts::InitBucketSize;
00352     elt[0] = elt0, elt[1] = elt1;
00353 
00354     // NULL out all but first two bucket entries (for GC safety)
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(/*INOUT*/ MultiBucketPtr &mb, /*INOUT*/ KVPairPtr* &elt) throw ()
00364 {
00365     // grow bucket
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     // copy existing entries
00376     int k;
00377     for (k = 0; k < mb->num; k++) {
00378         eltNew[k] = elt[k];
00379         elt[k] = (KVPair *)NULL; // drop on floor
00380     }
00381 
00382     // NULL out remaining entries (for GC safety)
00383     for (/*SKIP*/; k < mbNew->len; k++) {
00384         eltNew[k] = (KVPair *)NULL;
00385     }
00386 
00387     // update INOUT args
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;                   // old buckets
00399     Bit16 oldLogBuckets = this->logBuckets;          // log of their old size
00400     Bit32 oldNumBuckets = (TableConsts::One32U << oldLogBuckets); // their old size
00401 
00402     // allocate new buckets
00403     this->logBuckets = logBuckets;
00404     this->NewBuckets(ob != (KVPairPtr *)NULL);
00405 
00406     if (ob != (KVPairPtr *)NULL) {
00407         // rehash entries from old table into new table
00408         for (Bit32 i = 0U; i < oldNumBuckets; i++) {
00409             KVPair *b = ob[i];
00410             if (b != (KVPair *)NULL) {
00411                 // bucket is non-empty
00412                 if (!((PointerInt)b & TableConsts::LSBMask)) {
00413                     // single-entry bucket
00414                     this->PutPrivate(b);
00415                     ob[i] = (KVPair *)NULL; // drop on floor
00416                 } else {
00417                     // multi-entry bucket
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; // drop on floor
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         // too sparse
00441         Rehash(this->logBuckets - 1);
00442     } else if (this->numEntries > this->maxEntries
00443                && this->logBuckets < TableConsts::MaxLogBuckets) {
00444         // too crowded
00445         Rehash(this->logBuckets + 1);
00446     }
00447 }
00448 
00449 template <class K, class V>
00450 bool SharedTable<K,V>::T::Get(const K& k, /*OUT*/ 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         // singleton case
00457         if (b->key == k) {
00458             pr = b;
00459             return true;
00460         }
00461     } else {
00462         // multibucket case
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         // bucket currently empty
00488         this->buckets[bucketNum] = pr;
00489     } else if (!((PointerInt)b & TableConsts::LSBMask)) {
00490         // single-entry bucket
00491         if (b->key == pr->key) {
00492             // replace existing entry
00493             this->buckets[bucketNum] = pr;
00494             // assert(b->val == pr->val);
00495             return true;
00496         } else {
00497             // create a new multibucket
00498             this->buckets[bucketNum] = (KVPair *)InitBucket(b, pr);
00499         }
00500     } else {
00501         // multi-entry bucket
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             // match found -- replace existing value
00517             elt[i] = pr;
00518             // assert(elt[i]->val == pr->val);
00519             return true;
00520         } else {
00521             // insert new entry in table
00522             if (emptySlot >= 0) {
00523                 // use empty slot without growing bucket
00524                 elt[emptySlot] = pr;
00525             } else {
00526                 // add to end of bucket
00527                 if (mb->num >= mb->len) {
00528                     this->buckets[bucketNum] = 
00529                       (KVPair *)(this->GrowBucket(/*INOUT*/mb, /*INOUT*/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         /* If PutPrivate returned "false", the number of entries in the
00544            table has increased. See if the table needs to be resized. */
00545         this->numEntries++;
00546         if (resize && this->numEntries > this->maxEntries
00547             && this->logBuckets < TableConsts::MaxLogBuckets) {
00548             // too crowded
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   /*OUT*/ 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         // bucket currently empty
00565         pr = NEW_CONSTR(KVPair, (k,v));
00566         this->buckets[bucketNum] = pr;
00567     } else if (!((PointerInt)b & TableConsts::LSBMask)) {
00568         // single-entry bucket
00569         if (b->key == k) {
00570             // match found -- remember pair
00571             pr = this->buckets[bucketNum];
00572             return true;
00573         } else {
00574             // create a new multibucket
00575             pr = NEW_CONSTR(KVPair, (k,v));
00576             this->buckets[bucketNum] = (KVPair *)InitBucket(b, pr);
00577         }
00578     } else {
00579         // multi-entry bucket
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             // match found -- remember pair
00595             pr = elt[i];
00596             return true;
00597         } else {
00598             // insert new entry in table
00599             pr = NEW_CONSTR(KVPair, (k,v));
00600             if (emptySlot >= 0) {
00601                 // use empty slot without growing bucket
00602                 elt[emptySlot] = pr;
00603             } else {
00604                 // add to end of bucket
00605                 if (mb->num >= mb->len) {
00606                     this->buckets[bucketNum] = 
00607                       (KVPair *)(this->GrowBucket(/*INOUT*/mb, /*INOUT*/elt));
00608                 }
00609                 elt[mb->num++] = pr;
00610             }
00611         }
00612     }
00613     /* If we have not yet returned "true", the number of entries in the
00614        table has increased. See if the table needs to be resized. */
00615     this->numEntries++;
00616     if (resize && this->numEntries > this->maxEntries
00617         && this->logBuckets < TableConsts::MaxLogBuckets) {
00618         // too crowded
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, /*OUT*/ 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         // empty bucket
00634         return false;
00635     } else if (!((PointerInt)b & TableConsts::LSBMask)) {
00636         // single-entry bucket
00637         if (b->key == k) {
00638             // match; make bucket empty
00639             pr = b;
00640             this->buckets[bucketNum] = (KVPair *)NULL;
00641         } else {
00642             return false;
00643         }
00644     } else {
00645         // multi-entry bucket
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     /* If we have not returned by now, the number of entries in the table
00663        has decreased. See if the table needs to be resized; return true. */
00664     this->numEntries--;
00665     if (resize && this->numEntries < this->minEntries
00666         && this->logBuckets > this->minLogBuckets) {
00667         // too sparse
00668         Rehash(this->logBuckets - 1);
00669     }
00670     return true;
00671 }
00672 
00673 // ---------------------------------------------------- Iterator methods -----
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(/*OUT*/ 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                     // single-entry bucket
00693                     pr = b;
00694                     this->bucket++;
00695                     return true;
00696                 } else {
00697                     // multi-entry bucket
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                     // skip NULL entries in the bucket
00705                     while (this->next < mb->num &&
00706                            elt[this->next] == (KVPair *)NULL) {
00707                         this->next++;
00708                     }
00709                     if (this->next < mb->num) {
00710                         // non-NULL entry found; return "true"
00711                         pr = elt[this->next++];
00712                         return true;
00713                     }
00714 
00715                     // end of bucket reached; reset and try again
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

Generated on Mon May 8 00:48:29 2006 for Vesta by  doxygen 1.4.2