Main Page   Class Hierarchy   Compound List   File List   Compound Members  

glmap.h

00001 /*--License:
00002         Kyra Sprite Engine
00003         Copyright Lee Thomason (Grinning Lizard Software) 2001-2002
00004         www.grinninglizard.com/kyra
00005         www.sourceforge.net/projects/kyra
00006 
00007         Kyra is provided under 2 licenses:
00008 
00009         - The GPL, with no additional restrictions.
00010         - The LGPL, provided you display the Kyra splash screen, described below.
00011 
00012 
00013 --- GPL License --
00014         This program is free software; you can redistribute it and/or
00015         modify it under the terms of the GNU General Public License
00016         as published by the Free Software Foundation; either version 2
00017         of the License, or (at your option) any later version.
00018 
00019         This program is distributed in the hope that it will be useful,
00020         but WITHOUT ANY WARRANTY; without even the implied warranty of
00021         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022         GNU General Public License for more details.
00023 
00024         You should have received a copy of the GNU General Public License
00025         along with this program; if not, write to the Free Software
00026         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00027 
00028         The full text of the license can be found in license.txt
00029 
00030 
00031 --- LGPL License --
00032   **Provided you kindly display the Kyra splash screen (details below), 
00033         you     may use the LGPL license:**
00034 
00035     This library is free software; you can redistribute it and/or
00036     modify it under the terms of the GNU Lesser General Public
00037     License as published by the Free Software Foundation; either
00038     version 2.1 of the License, or (at your option) any later version.
00039 
00040     This library is distributed in the hope that it will be useful,
00041     but WITHOUT ANY WARRANTY; without even the implied warranty of
00042     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00043     Lesser General Public License for more details.
00044 
00045     You should have received a copy of the GNU Lesser General Public
00046     License along with this library; if not, write to the Free Software
00047     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00048 
00049         The full text of the license can be found in lgpl.txt
00050 
00051 
00052 --- Kyra Splash Screen.
00053 
00054         It would be appreciate if you display the Kyra splash screen when using
00055         either license, however it is only required for the LGPL. All the
00056         resources for the splash are compiled into the library, and it can be
00057         accessed through the following API:
00058 
00059                 KrEngine::StartSplash
00060                 KrEngine::UpdateSplash
00061                 KrEngine::EndSplash
00062 
00063         Full documentation is provided with the KrEngine class. The splash screen
00064         should be displayed for 2 seconds.
00065 
00066         Thank you.
00067 */
00068 
00069 #ifndef GLMAP_INCLUDED
00070 #define GLMAP_INCLUDED
00071 
00072 #pragma warning( disable : 4530 )
00073 #pragma warning( disable : 4786 )
00074 #include <string>
00075 #include <ctype.h>
00076 #include "glutil.h"
00077 #include "gldebug.h"
00078 #include "glprime.h"
00079 #include "gltypes.h"
00080 
00081 // Standard Hash classes.
00082 class GlHash
00083 {
00084   public:
00085         U32 HashValue() { return val; }
00086   protected:
00087         U32 val;        
00088 };
00089 
00090 class GlStringHash : public GlHash
00091 {
00092   public:
00093         GlStringHash( const std::string& str )
00094         {       
00095                 val = 0;
00096                 for ( unsigned i=0; i<str.length() && i < 32; ++i )
00097                 {
00098                         val <<= 1;
00099                         val |= str[i];
00100                 }
00101         }
00102 };
00103 
00104 template < class T >
00105 class GlNumberHash : public GlHash
00106 {
00107   public:
00108         GlNumberHash( T num )   { val = (T) num; }
00109 };
00110 
00111 
00112 // A map template class. It associates a KEY with a VALUE.
00113 // It uses a HASH class to get a hash value from the KEY. 2 Hash classes are
00114 // provided: GlStringHash and GlNumberHash.
00115 
00116 template < class KEY, class VALUE, class HASH >
00117 class GlMap
00118 {
00119   public:
00120         GlMap( U32 startSize = 64, U32 grow = 60 );
00121         ~GlMap();
00122 
00123         // Adds a key value pair. Will fail if the key is not unique.
00124         bool Add( const KEY& key, const VALUE& value );
00125         
00126         // Remove a key value pair. Will fail if the key is not found.
00127         bool Remove( const KEY& key );
00128         
00129         // Returns true if the key is found, and writes the result to value.
00130         // Value will not be set if the key is not found.
00131         bool Find( const KEY& key, VALUE* value );
00132 
00133         // PRIVATE! But silly template friends too hard.
00134         enum {
00135                 EXPAND = 4
00136         };
00137 
00138         struct Item
00139         {
00140                 KEY             key;
00141                 VALUE   value;
00142                 Item*   next;
00143         };
00144 
00145         // Grow the hash table. Dicey work, and slow.
00146         void Grow( unsigned newsize );
00147 
00148         U32 numBuckets;
00149         Item** buckets;
00150         U32 grow;
00151         U32 numItems;
00152 };
00153 
00154 
00155 
00156 
00157 template < class KEY, class VALUE, class HASH >
00158 inline GlMap< KEY, VALUE, HASH>::GlMap( U32 startSize, U32 _grow )
00159 {
00160         numBuckets = GlPrime( startSize, 1 );
00161         buckets = new Item*[ numBuckets ];
00162         memset( buckets, 0, sizeof( Item* ) * numBuckets );
00163         grow = _grow;
00164         numItems = 0;
00165 
00166         #ifdef DEBUG
00167                 //GLOUTPUT( "Created Map: %d buckets\n", numBuckets );
00168         #endif
00169 };
00170 
00171 
00172 template < class KEY, class VALUE, class HASH >
00173 inline GlMap< KEY, VALUE, HASH>::~GlMap()
00174 {
00175         for( U32 i=0; i<numBuckets; ++i )
00176         {       
00177                 while ( buckets[i] )
00178                 {
00179                         Item* next = buckets[i]->next;
00180                         delete buckets[i];
00181                         buckets[i] = next;
00182                 }
00183         }
00184                 
00185         // Everything is in the new list, create new buckets and put it back in.
00186         delete [] buckets;
00187 };
00188 
00189 
00190 template < class KEY, class VALUE, class HASH >
00191 inline void GlMap< KEY, VALUE, HASH>::Grow( unsigned newsize )
00192 {
00193         #ifdef DEBUG
00194         int itemcount = 0;
00195         #endif
00196 
00197         // Yep. Unlink everything, put in a linked list, and re-insert.
00198         Item *root = 0;
00199         for( U32 i=0; i<numBuckets; ++i )
00200         {       
00201                 while ( buckets[i] )
00202                 {
00203                         Item* next = buckets[i]->next;
00204 
00205                         buckets[i]->next = root;
00206                         root = buckets[i];
00207 
00208                         buckets[i] = next;
00209 
00210                         #ifdef DEBUG
00211                         ++itemcount;
00212                         #endif
00213                 }
00214         }
00215         #ifdef DEBUG
00216         int comparecount = 0;
00217         for( Item* it = root; it; it = it->next )
00218                 ++comparecount;
00219         GLASSERT( comparecount == itemcount );
00220         #endif
00221                 
00222         // Everything is in the new list, create new buckets and put it back in.
00223         delete [] buckets;
00224         buckets = 0;
00225 
00226         #ifdef DEBUG
00227                 //GLOUTPUT( "Rebuilding map (from %d)...", numBuckets );
00228         #endif
00229 
00230         numBuckets = GlPrime( newsize, 1 );
00231         #ifdef DEBUG
00232                 //GLOUTPUT( "%d buckets\n", numBuckets );
00233         #endif
00234 
00235         buckets = new Item*[ numBuckets ];
00236         memset( buckets, 0, sizeof( Item* ) * numBuckets );
00237 
00238         while ( root )
00239         {
00240                 Item* next = root->next;
00241 
00242                 HASH hash( root->key );
00243                 U32 which = hash.HashValue() % numBuckets;
00244 
00245                 root->next = buckets[ which ];
00246                 buckets[ which ] = root;
00247 
00248                 root = next;
00249         }
00250 }
00251 
00252 
00253 template < class KEY, class VALUE, class HASH >
00254 inline bool GlMap< KEY, VALUE, HASH>::Add( const KEY& key, const VALUE& value )
00255 {
00256         VALUE dummy;
00257         if ( Find( key, &dummy ) ) 
00258                 return false;
00259 
00260         // Do we need to get bigger?
00261         if ( ( ( numItems + 1 ) * 100 / numBuckets ) > grow )
00262         {
00263                 Grow( GlMax( numItems * EXPAND, numBuckets * EXPAND ) );
00264         }
00265 
00266         // Add the key in, if it is unique.
00267         HASH hash( key );
00268         U32 which = hash.HashValue() % numBuckets;
00269 
00270         Item* item      = new Item;
00271         item->key       = key;
00272         item->value = value;
00273         item->next      = buckets[ which ];
00274 
00275         buckets[ which ] = item;
00276         ++numItems;
00277         return true;
00278 }
00279 
00280 
00281 template < class KEY, class VALUE, class HASH >
00282 inline bool GlMap< KEY, VALUE, HASH>::Find( const KEY& key, VALUE* value )
00283 {
00284         HASH hash( key );
00285         U32 which = hash.HashValue() % numBuckets;
00286 
00287         Item* item = buckets[which];
00288         
00289         while( item )
00290         {
00291                 if ( item->key == key )
00292                 {
00293                         *value = item->value;
00294                         return true;
00295                 }
00296                 item = item->next;
00297         }
00298         return false;   
00299 }
00300 
00301 
00302 template < class KEY, class VALUE, class HASH >
00303 inline bool GlMap< KEY, VALUE, HASH>::Remove( const KEY& key )
00304 {
00305         HASH hash( key );
00306         U32 which = hash.HashValue() % numBuckets;
00307 
00308         Item* item = buckets[which];
00309         Item* prev = 0;
00310         
00311         while( item )
00312         {
00313                 if ( item->key == key )
00314                 {
00315                         if ( prev )
00316                                 prev->next = item->next;
00317                         else
00318                                 buckets[ which ] = item->next;
00319 
00320                         delete item;
00321                         --numItems;
00322                         return true;
00323                 }
00324                 prev = item;
00325                 item = item->next;
00326         }
00327         return false;   
00328 }
00329 
00330 
00331 template < class KEY, class VALUE, class HASH >
00332 class GlMapIterator
00333 {
00334   public:
00335         GlMapIterator( GlMap< KEY, VALUE, HASH >& _map )        { map = &_map; bucket=0; item=0; }
00336 
00337         void Begin()            { bucket=0; item=map->buckets[0]; FindValid(); }
00338         void Next()                     { item=item->next; FindValid(); }
00339         bool Done()                     { return ( bucket < 0 ); }
00340 
00341         void Current( KEY* key, VALUE* value )
00342         {
00343                 if ( item )
00344                 {
00345                         *key = item->key;
00346                         *value = item->value;
00347                 }
00348         }
00349 
00350   private:
00351         GlMap< KEY, VALUE, HASH >* map;
00352         int bucket;
00353         typename GlMap< KEY, VALUE, HASH >::Item* item;
00354 
00355         void FindValid()
00356         {
00357                 if (    bucket < 0                              // we are done
00358                          || ( item && bucket >=0 ))     // we have a current value
00359                 {
00360                         return;
00361                 }
00362                 GLASSERT( item == 0 );                  // else we should have current value
00363                 for ( ++bucket; bucket < map->numBuckets; ++bucket )
00364                 {
00365                         if ( map->buckets[bucket] )
00366                         {
00367                                 item = map->buckets[ bucket ];
00368                                 return;
00369                         }
00370                 }
00371                 bucket = -1;
00372                 item = 0;
00373         }
00374 };
00375 
00376 
00377 #endif
00378 

Generated on Fri Feb 7 20:44:20 2003 for Kyra by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001