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

tables.h

Go to the documentation of this file.
00001 // -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*-
00002 ////////////////////////////////////////////////////////////////////
00003 //
00004 // Filename : tables.h
00005 //
00006 // AbstractTable  : abstract template
00007 //  |
00008 //  +-TableSingle : template for single linked bucket hash table
00009 //  |
00010 //  +-TableDouble : template for double linked bucket hash table
00011 //
00012 // This file is a part of the UPPAAL toolkit.
00013 // Copyright (c) 1995 - 2003, Uppsala University and Aalborg University.
00014 // All right reserved.
00015 //
00016 // $Id: tables.h,v 1.11 2005/04/25 16:38:27 behrmann Exp $
00017 //
00018 ///////////////////////////////////////////////////////////////////
00019 
00020 #ifndef INCLUDE_BASE_TABLES_H
00021 #define INCLUDE_BASE_TABLES_H
00022 
00023 #include "base/intutils.h"
00024 #include "base/Enumerator.h"
00025 
00026 /**
00027  * @file
00028  * Basis for hash tables. To get a working hash table one has
00029  * to implement the insert/delete that is dependant on the data
00030  * type, in particular to test for equality.
00031  */
00032 
00033 namespace hash
00034 {
00035     /** Single linked buckets
00036      * info contains the hash value and possible other data:
00037      * (info & mask) free for data, (info & ~mask) reserved.
00038      * We need a concrete type for the generic rehash functions
00039      * that do not depend on any customized data, and a template
00040      * type to avoid tons of casts.
00041      */
00042     struct SingleBucket_t : /* concrete type */
00043         public base::SingleLinkable<SingleBucket_t>
00044     {
00045         uint32_t info;
00046     };
00047 
00048     template<class BucketType>
00049     struct SingleBucket :   /* template */
00050         public base::SingleLinkable<BucketType>
00051     {
00052         uint32_t info;
00053     };
00054 
00055 
00056     /** Double linked buckets, as for single buckets.
00057      */
00058     struct DoubleBucket_t : /* concrete type */
00059         public base::DoubleLinkable<DoubleBucket_t>
00060     {
00061         uint32_t info;
00062     };
00063 
00064     template<class BucketType>
00065     struct DoubleBucket :   /* template */
00066         public base::DoubleLinkable<BucketType>
00067     {
00068         uint32_t info;
00069         /**< Default use of info lower bits:
00070          * reference counter.
00071          */
00072 
00073         /** Increment reference counter
00074          * with a given mask being the maximal
00075          * possible value.
00076          * @param mask: mask (also max)
00077          * @pre mask = ((1 << n) - 1) for some n
00078          * such that size of hash table <= 2^n.
00079          */
00080         void incRef(uint32_t mask)
00081         {
00082             if ((info & mask) != mask) info++;
00083         }
00084 
00085         /** Decrement reference counter.
00086          * May skip decrement if counter == mask.
00087          * @return true if counter is == 0
00088          * @param mask: mask (also max)
00089          */
00090         bool decRef(uint32_t mask)
00091         {
00092             if ((info & mask) == mask) return false;
00093             assert(info & mask); // must be referenced
00094             return (--info & mask) == 0;
00095         }
00096     };
00097 
00098 
00099     /** Rehashing for single/double linked
00100      * buckets. In practice, the hash value is
00101      * not recomputed since it is stored in the
00102      * 'info' field of the buckets.
00103      * @param tablePtr: where the table of bucket* to
00104      * rehash is. The table will be reallocated.
00105      * @param maskPtr: the mask used to access the indices
00106      * it will be read and written.
00107      * @pre the size of the table is a power of
00108      * 2 and size = mask + 1
00109      * @post *tablePtr is deallocated (delete) and
00110      * the new table is newly allocated (new).
00111      */
00112     void rehash(SingleBucket_t*** tablePtr, uint32_t *maskPtr);
00113     void rehash(DoubleBucket_t*** tablePtr, uint32_t *maskPtr);
00114 
00115 
00116     /** Abstract general hash table. DO NOT USE DIRECTLY.
00117      * @param BucketType: customized buckets (with customized
00118      * data) to use.
00119      * @param BucketParentType: SingleBucket_t or DoubleBucket_t
00120      * @param BucketParentTemplate: SingleBucket or DoubleBucket
00121      */
00122     template<class BucketType,
00123              class BucketParentType,
00124              class BucketParentTemplate>
00125     class AbstractTable
00126     {
00127     public:
00128 
00129         /** Control rehashing: by default
00130          * hash tables rehash themselves
00131          * automatically. You can disable this
00132          * feature.
00133          */
00134         void disableRehash() { mayRehash = false; }
00135         void enableRehash()  { mayRehash = mask < MAX_TABLE_SIZE-1; }
00136 
00137         /** Return the hash mask to get access
00138          * to the table: index = hashValue & mask.
00139          * @return a binary mask.
00140          */
00141         uint32_t getHashMask()  const { return mask; }
00142 
00143 
00144         /** @return the number of used buckets
00145          * so far.
00146          */
00147         size_t getNbBuckets() const { return nbBuckets; }
00148         
00149 
00150         /** @return the size of the table. As the size
00151          * is a power of 2, mask = size - 1. We keep
00152          * mask because it is more useful.
00153          */
00154         size_t getTableSize() const { return mask + 1; }
00155 
00156         
00157         /** Reset the table without deleting the buckets
00158          */
00159         void reset()
00160         {
00161             nbBuckets = 0;
00162             base_resetLarge(buckets, getTableSize());
00163         }
00164 
00165 
00166         /** Reset the table and delete the buckets.
00167          * Note: as the bucket type is custom, the delete call
00168          * may call destructors of the sub-types.
00169          */
00170         void resetDelete()
00171         {
00172             size_t n = getTableSize(); // mask + 1 > 0
00173             BucketType **table = getBuckets();
00174             do {
00175                 if (*table) {
00176                     BucketType *bucket = *table;
00177                     do {
00178                         BucketType *next = bucket->getNext();
00179                         delete bucket;
00180                         bucket = next;
00181                     } while(bucket);
00182                     *table = NULL;
00183                 }
00184                 ++table;
00185             } while(--n);
00186             nbBuckets = 0;  
00187         }
00188 
00189 
00190         /** Simple adapter to tie together the hash table and
00191          * bucket types.
00192          */
00193         struct Bucket_t : public BucketParentTemplate
00194         {};
00195 
00196         
00197         /** Enumerator
00198          */
00199         base::Enumerator<BucketType> getEnumerator() const
00200         {
00201             return base::Enumerator<BucketType>(getTableSize(), getBuckets());
00202         }
00203 
00204 
00205         /** Increase the counter of the buckets. This
00206          * automatically calls rehash if needed. Call
00207          * this whenever you add a new bucket in the
00208          * hash table, BUT ALWAYS AFTER adding a bucket
00209          * (bucket->link(somewhere) because of the rehashing.
00210          */
00211         void incBuckets()
00212         {
00213             ++nbBuckets;
00214             if (needsRehash() && mayRehash)
00215             {
00216                 rehash(reinterpret_cast<BucketParentType***>(&buckets), &mask);
00217                 mayRehash = mask < MAX_TABLE_SIZE-1;
00218             }
00219         }
00220         
00221         
00222         /** Decrease the counter of the buckets.
00223          * Call this whenever you remove a bucket from
00224          * the hash table.
00225          */
00226         void decBuckets()
00227         {
00228             assert(nbBuckets);
00229             --nbBuckets;
00230         }
00231         
00232         
00233         /** Access to a particular table
00234          * entry with a hash value.
00235          * @param hashValue: the hash to compute the index.
00236          */
00237         BucketType** getAtBucket(uint32_t hashValue) const
00238         {
00239             return &buckets[hashValue & mask];
00240         }
00241         
00242         
00243         /** Access to the first bucket in the
00244          * table with a given hash value.
00245          * @param hashValue: the hash to compute the index.
00246          */
00247         BucketType* getBucket(uint32_t hashValue) const
00248         {
00249             return buckets[hashValue & mask];
00250         }
00251 
00252 
00253     protected:
00254 
00255         /** Access to the bucket table.
00256          */
00257         BucketType** getBuckets() const
00258         {
00259             return buckets;
00260         }
00261 
00262 
00263         /** Protected constructor: this is an abstract
00264          * class only.
00265          * @param sizePower2: size in power of 2, ie, real
00266          * size will be 2**sizePower2.
00267          * @param aggressive: aggressive rehashing or not,
00268          * which decides the threshold for rehashing.
00269          */
00270         AbstractTable(uint32_t sizePower2, bool aggressive)
00271             : nbBuckets(0),
00272               mask((1 << sizePower2) - 1),
00273               shiftThreshold(aggressive ? 1 : 0),
00274               mayRehash(true)
00275         {
00276             buckets = new BucketType*[getTableSize()];
00277             base_resetLarge(buckets, getTableSize());
00278 
00279 #ifndef NDEBUG
00280             for (size_t i = 0; i < getTableSize(); ++i) {
00281                 assert(buckets[i] == 0);
00282             }
00283 #endif /* not NDEBUG */
00284         }
00285 
00286         
00287         /** Destructor: not virtual. There is no polymorphism
00288          * involved here.
00289          */
00290         ~AbstractTable() { delete [] buckets; }
00291 
00292 
00293         /** We give a limit to the size of the tables
00294          * to stop rehashing after a certain point.
00295          */
00296         enum { MAX_TABLE_SIZE = (1 << 26) };
00297 
00298         size_t nbBuckets;   /**< number of buckets */
00299 
00300     private:
00301 
00302         /** @return true if the threshold for rehashing is reached
00303          */
00304         bool needsRehash() const
00305         {
00306             return nbBuckets > (mask >> shiftThreshold);
00307         }
00308         
00309         
00310         uint32_t mask;           /**< mask to apply to hash value
00311                                     to get indices = size - 1 since
00312                                     the size of the table is a power of 2     */
00313         uint32_t shiftThreshold; /**< mask >> shiftThreshold is the threshold */
00314         bool mayRehash;          /**< used to disable rehashing               */
00315         BucketType **buckets;    /**< the table of buckets                    */
00316     };
00317 
00318 
00319     /**************************************************************
00320      * Adapters to implement easily hash tables using single or
00321      * double linked buckets.
00322      *
00323      * - How to use:
00324      *
00325      * struct MyBucket_t
00326      *       : public TableSingle<MyBucket_t>::Bucket_t { ... };
00327      * class MyHashTable
00328      *       : public TableSingle<MyBucket_t> { ... };
00329      *
00330      * - Better way to make it more readable:
00331      *
00332      * struct MyBucket_t;
00333      * typedef TableSingle<MyBucket_t> ParentTable;
00334      *
00335      * struct MyBucket_t : public ParentTable::Bucket_t { ... };
00336      * class MyHashtable : public ParentTable { ... };
00337      *
00338      ***************************************************************/
00339 
00340     template<class BucketType>
00341     class TableSingle :
00342         public AbstractTable<BucketType,
00343                              SingleBucket_t,
00344                              SingleBucket<BucketType> >
00345     {
00346     public:
00347         TableSingle(uint32_t sizePower2 = 8, bool aggressive = false)
00348             : AbstractTable<BucketType,
00349                             SingleBucket_t,
00350                             SingleBucket<BucketType> >
00351                            (sizePower2, aggressive)
00352             {}
00353 
00354 
00355         /** Remove a bucket from the hash table. This
00356          * is useful for singly linked buckets only
00357          * where the info field stores the hash value
00358          * ON ALL ITS BITS.
00359          * @param bucket: bucket to remove from the hash table.
00360          * @pre
00361          * - bucket->info = hash value
00362          * - bucket is stored in this hash table (otherwise segfault)
00363          * @post bucket is removed but not deallocated
00364          */
00365         void remove(BucketType *bucket)
00366         {
00367             remove(bucket, bucket->info);
00368         }
00369 
00370         /** Real implementation of remove, using explicitely the
00371          * hash value that was used to entering this bucket in the
00372          * table. THIS IS VITAL.
00373          * @param bucket: bucket belonging to this table to remove
00374          * @param hashValue: hash that was used to enter this table
00375          */
00376         void remove(BucketType *bucket, uint32_t hashValue)
00377         {
00378             BucketType **entry = 
00379                 AbstractTable<BucketType,
00380                 SingleBucket_t,
00381                 SingleBucket<BucketType> >::getAtBucket(hashValue);
00382             while(*entry != bucket)
00383             {
00384                 assert(*entry); // MUST find it
00385                 entry = (*entry)->getAtNext();
00386             }
00387             *entry = bucket->getNext(); // unlink
00388             AbstractTable<BucketType,
00389                              SingleBucket_t,
00390                              SingleBucket<BucketType> >::decBuckets();
00391         }
00392 
00393     };
00394 
00395     template<class BucketType>
00396     class TableDouble :
00397         public AbstractTable<BucketType,
00398                              DoubleBucket_t,
00399                              DoubleBucket<BucketType> >
00400     {
00401     public:
00402         TableDouble(uint32_t sizePower2 = 8, bool aggressive = false)
00403             : AbstractTable<BucketType,
00404                             DoubleBucket_t,
00405                             DoubleBucket<BucketType> >
00406                            (sizePower2, aggressive)
00407             {}
00408 
00409         /** Remove a bucket from this hash table.
00410          * @param bucket: bucket in this hash table to remove
00411          */
00412         void remove(BucketType *bucket)
00413         {
00414             assert(bucket);
00415             bucket->unlink();
00416             AbstractTable<BucketType,
00417                 DoubleBucket_t,
00418                 DoubleBucket<BucketType> >::decBuckets();
00419         }
00420     };
00421 
00422 } // namespace hash
00423 
00424 #endif // INCLUDE_BASE_TABLES_H
00425 

Generated on Fri Jun 30 00:03:00 2006 for Module hash by  doxygen 1.4.2