Main Page   Class Hierarchy   Compound List   File List   Compound Members  

glmap.h

00001 /*
00002 Copyright (c) 2000-2003 Lee Thomason (www.grinninglizard.com)
00003 
00004 Grinning Lizard Utilities. Note that software that uses the 
00005 utility package (including Lilith3D and Kyra) have more restrictive
00006 licences which applies to code outside of the utility package.
00007 
00008 
00009 This software is provided 'as-is', without any express or implied 
00010 warranty. In no event will the authors be held liable for any 
00011 damages arising from the use of this software.
00012 
00013 Permission is granted to anyone to use this software for any 
00014 purpose, including commercial applications, and to alter it and 
00015 redistribute it freely, subject to the following restrictions:
00016 
00017 1. The origin of this software must not be misrepresented; you must 
00018 not claim that you wrote the original software. If you use this 
00019 software in a product, an acknowledgment in the product documentation 
00020 would be appreciated but is not required.
00021 
00022 2. Altered source versions must be plainly marked as such, and 
00023 must not be misrepresented as being the original software.
00024 
00025 3. This notice may not be removed or altered from any source 
00026 distribution.
00027 */
00028 
00029 #ifndef GLMAP_INCLUDED
00030 #define GLMAP_INCLUDED
00031 
00032 #pragma warning( disable : 4530 )
00033 #pragma warning( disable : 4786 )
00034 #include <string>
00035 #include <ctype.h>
00036 #include "glutil.h"
00037 #include "gldebug.h"
00038 #include "glprime.h"
00039 #include "gltypes.h"
00040 
00041 // Standard Hash classes.
00042 class GlHash
00043 {
00044   public:
00045         U32 HashValue() { return val; }
00046   protected:
00047         U32 val;        
00048 };
00049 
00050 class GlStringHash : public GlHash
00051 {
00052   public:
00053         GlStringHash( const std::string& str )
00054         {       
00055                 val = 0;
00056                 for ( unsigned i=0; i<str.length() && i < 32; ++i )
00057                 {
00058                         val <<= 1;
00059                         val |= str[i];
00060                 }
00061         }
00062 };
00063 
00064 template < class T >
00065 class GlNumberHash : public GlHash
00066 {
00067   public:
00068         GlNumberHash( T num )   { val = (T) num; }
00069 };
00070 
00071 
00072 // A map template class. It associates a KEY with a VALUE.
00073 // It uses a HASH class to get a hash value from the KEY. 2 Hash classes are
00074 // provided: GlStringHash and GlNumberHash.
00075 
00076 template < class KEY, class VALUE, class HASH >
00077 class GlMap
00078 {
00079   public:
00080         GlMap( U32 startSize = 64, U32 grow = 60 );
00081         ~GlMap();
00082 
00083         // Adds a key value pair. Will fail if the key is not unique.
00084         bool Add( const KEY& key, const VALUE& value );
00085         
00086         // Remove a key value pair. Will fail if the key is not found.
00087         bool Remove( const KEY& key );
00088         
00089         // Returns true if the key is found, and writes the result to value.
00090         // Value will not be set if the key is not found.
00091         bool Find( const KEY& key, VALUE* value );
00092 
00093         // PRIVATE! But silly template friends too hard.
00094         enum {
00095                 EXPAND = 4
00096         };
00097 
00098         struct Item
00099         {
00100                 KEY             key;
00101                 VALUE   value;
00102                 Item*   next;
00103         };
00104 
00105         // Grow the hash table. Dicey work, and slow.
00106         void Grow( unsigned newsize );
00107 
00108         U32 numBuckets;
00109         Item** buckets;
00110         U32 grow;
00111         U32 numItems;
00112 };
00113 
00114 
00115 
00116 
00117 template < class KEY, class VALUE, class HASH >
00118 inline GlMap< KEY, VALUE, HASH>::GlMap( U32 startSize, U32 _grow )
00119 {
00120         numBuckets = GlPrime( startSize, 1 );
00121         buckets = new Item*[ numBuckets ];
00122         memset( buckets, 0, sizeof( Item* ) * numBuckets );
00123         grow = _grow;
00124         numItems = 0;
00125 
00126         #ifdef DEBUG
00127                 //GLOUTPUT( "Created Map: %d buckets\n", numBuckets );
00128         #endif
00129 };
00130 
00131 
00132 template < class KEY, class VALUE, class HASH >
00133 inline GlMap< KEY, VALUE, HASH>::~GlMap()
00134 {
00135         for( U32 i=0; i<numBuckets; ++i )
00136         {       
00137                 while ( buckets[i] )
00138                 {
00139                         Item* next = buckets[i]->next;
00140                         delete buckets[i];
00141                         buckets[i] = next;
00142                 }
00143         }
00144                 
00145         // Everything is in the new list, create new buckets and put it back in.
00146         delete [] buckets;
00147 };
00148 
00149 
00150 template < class KEY, class VALUE, class HASH >
00151 inline void GlMap< KEY, VALUE, HASH>::Grow( unsigned newsize )
00152 {
00153         #ifdef DEBUG
00154         int itemcount = 0;
00155         #endif
00156 
00157         // Yep. Unlink everything, put in a linked list, and re-insert.
00158         Item *root = 0;
00159         for( U32 i=0; i<numBuckets; ++i )
00160         {       
00161                 while ( buckets[i] )
00162                 {
00163                         Item* next = buckets[i]->next;
00164 
00165                         buckets[i]->next = root;
00166                         root = buckets[i];
00167 
00168                         buckets[i] = next;
00169 
00170                         #ifdef DEBUG
00171                         ++itemcount;
00172                         #endif
00173                 }
00174         }
00175         #ifdef DEBUG
00176         int comparecount = 0;
00177         for( Item* it = root; it; it = it->next )
00178                 ++comparecount;
00179         GLASSERT( comparecount == itemcount );
00180         #endif
00181                 
00182         // Everything is in the new list, create new buckets and put it back in.
00183         delete [] buckets;
00184         buckets = 0;
00185 
00186         #ifdef DEBUG
00187                 //GLOUTPUT( "Rebuilding map (from %d)...", numBuckets );
00188         #endif
00189 
00190         numBuckets = GlPrime( newsize, 1 );
00191         #ifdef DEBUG
00192                 //GLOUTPUT( "%d buckets\n", numBuckets );
00193         #endif
00194 
00195         buckets = new Item*[ numBuckets ];
00196         memset( buckets, 0, sizeof( Item* ) * numBuckets );
00197 
00198         while ( root )
00199         {
00200                 Item* next = root->next;
00201 
00202                 HASH hash( root->key );
00203                 U32 which = hash.HashValue() % numBuckets;
00204 
00205                 root->next = buckets[ which ];
00206                 buckets[ which ] = root;
00207 
00208                 root = next;
00209         }
00210 }
00211 
00212 
00213 template < class KEY, class VALUE, class HASH >
00214 inline bool GlMap< KEY, VALUE, HASH>::Add( const KEY& key, const VALUE& value )
00215 {
00216         VALUE dummy;
00217         if ( Find( key, &dummy ) ) 
00218                 return false;
00219 
00220         // Do we need to get bigger?
00221         if ( ( ( numItems + 1 ) * 100 / numBuckets ) > grow )
00222         {
00223                 Grow( GlMax( numItems * EXPAND, numBuckets * EXPAND ) );
00224         }
00225 
00226         // Add the key in, if it is unique.
00227         HASH hash( key );
00228         U32 which = hash.HashValue() % numBuckets;
00229 
00230         Item* item      = new Item;
00231         item->key       = key;
00232         item->value = value;
00233         item->next      = buckets[ which ];
00234 
00235         buckets[ which ] = item;
00236         ++numItems;
00237         return true;
00238 }
00239 
00240 
00241 template < class KEY, class VALUE, class HASH >
00242 inline bool GlMap< KEY, VALUE, HASH>::Find( const KEY& key, VALUE* value )
00243 {
00244         HASH hash( key );
00245         U32 which = hash.HashValue() % numBuckets;
00246 
00247         Item* item = buckets[which];
00248         
00249         while( item )
00250         {
00251                 if ( item->key == key )
00252                 {
00253                         *value = item->value;
00254                         return true;
00255                 }
00256                 item = item->next;
00257         }
00258         return false;   
00259 }
00260 
00261 
00262 template < class KEY, class VALUE, class HASH >
00263 inline bool GlMap< KEY, VALUE, HASH>::Remove( const KEY& key )
00264 {
00265         HASH hash( key );
00266         U32 which = hash.HashValue() % numBuckets;
00267 
00268         Item* item = buckets[which];
00269         Item* prev = 0;
00270         
00271         while( item )
00272         {
00273                 if ( item->key == key )
00274                 {
00275                         if ( prev )
00276                                 prev->next = item->next;
00277                         else
00278                                 buckets[ which ] = item->next;
00279 
00280                         delete item;
00281                         --numItems;
00282                         return true;
00283                 }
00284                 prev = item;
00285                 item = item->next;
00286         }
00287         return false;   
00288 }
00289 
00290 
00291 template < class KEY, class VALUE, class HASH >
00292 class GlMapIterator
00293 {
00294   public:
00295         GlMapIterator( GlMap< KEY, VALUE, HASH >& _map )        { map = &_map; bucket=0; item=0; }
00296 
00297         void Begin()            { bucket=0; item=map->buckets[0]; FindValid(); }
00298         void Next()                     { item=item->next; FindValid(); }
00299         bool Done()                     { return ( bucket < 0 ); }
00300 
00301         void Current( KEY* key, VALUE* value )
00302         {
00303                 if ( item )
00304                 {
00305                         *key = item->key;
00306                         *value = item->value;
00307                 }
00308         }
00309 
00310   private:
00311         GlMap< KEY, VALUE, HASH >* map;
00312         int bucket;
00313         typename GlMap< KEY, VALUE, HASH >::Item* item;
00314 
00315         void FindValid()
00316         {
00317                 if (    bucket < 0                              // we are done
00318                          || ( item && bucket >=0 ))     // we have a current value
00319                 {
00320                         return;
00321                 }
00322                 GLASSERT( item == 0 );                  // else we should have current value
00323                 for ( ++bucket; bucket < map->numBuckets; ++bucket )
00324                 {
00325                         if ( map->buckets[bucket] )
00326                         {
00327                                 item = map->buckets[ bucket ];
00328                                 return;
00329                         }
00330                 }
00331                 bucket = -1;
00332                 item = 0;
00333         }
00334 };
00335 
00336 
00337 #endif
00338 

Generated on Mon Sep 15 12:01:10 2003 for Kyra by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001