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
00026
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
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
00073
00074
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
00084 bool Add( const KEY& key, const VALUE& value );
00085
00086
00087 bool Remove( const KEY& key );
00088
00089
00090
00091 bool Find( const KEY& key, VALUE* value );
00092
00093
00094 enum {
00095 EXPAND = 4
00096 };
00097
00098 struct Item
00099 {
00100 KEY key;
00101 VALUE value;
00102 Item* next;
00103 };
00104
00105
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
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
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
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
00183 delete [] buckets;
00184 buckets = 0;
00185
00186 #ifdef DEBUG
00187
00188 #endif
00189
00190 numBuckets = GlPrime( newsize, 1 );
00191 #ifdef DEBUG
00192
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
00221 if ( ( ( numItems + 1 ) * 100 / numBuckets ) > grow )
00222 {
00223 Grow( GlMax( numItems * EXPAND, numBuckets * EXPAND ) );
00224 }
00225
00226
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
00318 || ( item && bucket >=0 ))
00319 {
00320 return;
00321 }
00322 GLASSERT( item == 0 );
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