CrystalSpace

Public API Reference

Main Page   Modules   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

csutil/hash.h

00001 /*
00002     Copyright (C) 2003 by Mat Sutcliffe <oktal@gmx.co.uk>
00003 
00004     This library is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU Lesser General Public
00006     License as published by the Free Software Foundation; either
00007     version 2 of the License, or (at your option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012     Library General Public License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public
00015     License along with this library; if not, write to the Free
00016     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 */
00018 
00019 #ifndef __CS_UTIL_HASH_H__
00020 #define __CS_UTIL_HASH_H__
00021 
00022 #include "csextern.h"
00023 #include "array.h"
00024 
00031 CS_CSUTIL_EXPORT unsigned int csHashCompute (char const*);
00032 
00039 CS_CSUTIL_EXPORT unsigned int csHashCompute (char const*, size_t length);
00040 
00044 template <class T>
00045 class csIntegralHashKeyHandler
00046 {
00047 public:
00048   static unsigned int ComputeHash (const T& key)
00049   {
00050 #if (_MSC_VER >= 1300)
00051     /*
00052       VC7 with 64bit warnings complains about a pointer truncation when T is
00053       a pointer. This isn't serious (as csHash<> does not rely on the hash of
00054       a key alone to retrieve a value). The __w64 causes VC7 to not emit that
00055       warning (on 32bit compilers at least).
00056      */
00057     return (unsigned int __w64)key;  
00058 #else
00059     return (unsigned int)key;  
00060 #endif
00061   }
00062 
00063   static bool CompareKeys (const T& key1, const T& key2)
00064   {
00065     return (key1 == key2);
00066   }
00067 };
00068 
00073 template <class T, class K = unsigned int, 
00074   class KeyHandler = csIntegralHashKeyHandler<K> > 
00075 class csHash
00076 {
00077 protected:
00078   struct Element
00079   {
00080     const K key;
00081     T value;
00082 
00083     Element (const K& key0, const T &value0) : key (key0), value (value0) {}
00084     Element (const Element &other) : key (other.key), value (other.value) {}
00085   };
00086   csArray< csArray<Element> > Elements;
00087 
00088   int Modulo;
00089 
00090 private:
00091   int InitModulo;
00092   int GrowRate;
00093   int MaxSize;
00094   int Size;
00095 
00096   void Grow ()
00097   {
00098     static const int Primes[] =
00099     {
00100       53,         97,         193,       389,       769, 
00101       1543,       3079,       6151,      12289,     24593,
00102       49157,      98317,      196613,    393241,    786433,
00103       1572869,    3145739,    6291469,   12582917,  25165843,
00104       50331653,   100663319,  201326611, 402653189, 805306457,
00105       1610612741, 0
00106     };
00107 
00108     const int *p;
00109     int elen = Elements.Length ();
00110     for (p = Primes; *p && *p <= elen; p++) ;
00111     Modulo = *p;
00112     CS_ASSERT (Modulo);
00113 
00114     Elements.SetLength (Modulo);
00115 
00116     for (int i = 0; i < elen; i++)
00117     {
00118       csArray<Element>& src = Elements[i];
00119       int slen = src.Length ();
00120       for (int j = slen - 1; j >= 0; j--)
00121       {
00122         const Element& srcElem = src[j];
00123         csArray<Element>& dst = 
00124           Elements.Get (KeyHandler::ComputeHash (srcElem.key) % Modulo);
00125         if (&src != &dst)
00126         {
00127           dst.Push (srcElem);
00128           src.DeleteIndex (j);
00129         }
00130       }
00131     }
00132   }
00133 
00134 public:
00148   csHash (int size = 257, int grow_rate = 64, int max_size = 20000)
00149     : Elements (size), Modulo (size), InitModulo (size),
00150       GrowRate (grow_rate), MaxSize (max_size), Size (0)
00151   {
00152     Elements.SetLength (size, csArray<Element> (0, 8));
00153   }
00154 
00156   csHash (const csHash<T> &o) : Elements (o.Elements),
00157     Modulo (o.Modulo), InitModulo (o.InitModulo),
00158     GrowRate (o.GrowRate), MaxSize (o.MaxSize), Size (o.Size) {}
00159 
00161   void Put (const K& key, const T &value)
00162   {
00163     csArray<Element> &values = 
00164       Elements[KeyHandler::ComputeHash (key) % Modulo];
00165     values.Push (Element (key, value));
00166     Size++;
00167     if (values.Length () > Elements.Length () / GrowRate
00168      && Elements.Length () < MaxSize) Grow ();
00169   }
00170 
00172   csArray<T> GetAll (const K& key) const
00173   {
00174     const csArray<Element> &values = 
00175       Elements[KeyHandler::ComputeHash (key) % Modulo];
00176     csArray<T> ret (values.Length () / 2);
00177     const int len = values.Length ();
00178     for (int i = 0; i < len; ++i)
00179     {
00180       const Element& v = values[i];
00181       if (KeyHandler::CompareKeys (v.key, key)) 
00182         ret.Push (v.value);
00183     }
00184     return ret;
00185   }
00186 
00188   void PutFirst (const K& key, const T &value)
00189   {
00190     csArray<Element> &values = 
00191       Elements[KeyHandler::ComputeHash (key) % Modulo];
00192     const int len = values.Length ();
00193     for (int i = 0; i < len; ++i)
00194     {
00195       Element& v = values[i];
00196       if (KeyHandler::CompareKeys (v.key, key))
00197       {
00198         v.value = value;
00199         return;
00200       }
00201     }
00202 
00203     values.Push (Element (key, value));
00204     Size++;
00205     if (values.Length () > Elements.Length () / GrowRate
00206      && Elements.Length () < MaxSize) Grow ();
00207   }
00208 
00210   bool In (const K& key) const
00211   {
00212     const csArray<Element> &values = 
00213       Elements[KeyHandler::ComputeHash (key) % Modulo];
00214     const int len = values.Length ();
00215     for (int i = 0; i < len; ++i)
00216       if (KeyHandler::CompareKeys (values[i].key, key)) 
00217         return true;
00218 
00219     return false;
00220   }
00221 
00226   const T* GetElementPointer (const K& key) const
00227   {
00228     const csArray<Element> &values = 
00229       Elements[KeyHandler::ComputeHash (key) % Modulo];
00230     const int len = values.Length ();
00231     for (int i = 0; i < len; ++i)
00232     {
00233       const Element& v = values[i];
00234       if (KeyHandler::CompareKeys (v.key, key))
00235         return &v.value;
00236     }
00237 
00238     return 0;
00239   }
00240 
00245   T* GetElementPointer (const K& key)
00246   {
00247     csArray<Element> &values = 
00248       Elements[KeyHandler::ComputeHash (key) % Modulo];
00249     const int len = values.Length ();
00250     for (int i = 0; i < len; ++i)
00251     {
00252       Element& v = values[i];
00253       if (KeyHandler::CompareKeys (v.key, key))
00254         return &v.value;
00255     }
00256 
00257     return 0;
00258   }
00259 
00264   const T& Get (const K& key, const T& fallback) const
00265   {
00266     const csArray<Element> &values = 
00267       Elements[KeyHandler::ComputeHash (key) % Modulo];
00268     const int len = values.Length ();
00269     for (int i = 0; i < len; ++i)
00270     {
00271       const Element& v = values[i];
00272       if (KeyHandler::CompareKeys (v.key, key))
00273         return v.value;
00274     }
00275 
00276     return fallback;
00277   }
00278 
00283   T& Get (const K& key, T& fallback)
00284   {
00285     csArray<Element> &values = 
00286       Elements[KeyHandler::ComputeHash (key) % Modulo];
00287     const int len = values.Length ();
00288     for (int i = 0; i < len; ++i)
00289     {
00290       Element& v = values[i];
00291       if (KeyHandler::CompareKeys (v.key, key))
00292         return v.value;
00293     }
00294 
00295     return fallback;
00296   }
00297 
00299   void DeleteAll ()
00300   {
00301     Elements.SetLength (Modulo = InitModulo);
00302     int elen = Elements.Length ();
00303     for (int i = 0; i < elen; i++)
00304       Elements[i].Empty ();
00305     Size = 0;
00306   }
00307 
00309   bool DeleteAll (const K& key)
00310   {
00311     bool ret = false;
00312     csArray<Element> &values = 
00313       Elements[KeyHandler::ComputeHash (key) % Modulo];
00314     for (int i = values.Length () - 1; i >= 0; i--)
00315       if (KeyHandler::CompareKeys (values[i].key, key))
00316       {
00317         values.DeleteIndex (i);
00318         ret = true;
00319         Size--;
00320       }
00321     return ret;
00322   }
00323   
00325   bool Delete (const K& key, const T &value)
00326   {
00327     bool ret = false;
00328     csArray<Element> &values = 
00329       Elements[KeyHandler::ComputeHash (key) % Modulo];
00330     for (int i = values.Length () - 1; i >= 0; i--)
00331       if (KeyHandler::CompareKeys (values[i].key, key) && 
00332         (values[i].value == value))
00333       {
00334         values.DeleteIndex (i);
00335         ret = true;
00336         Size--;
00337       }
00338     return ret;
00339   }
00340 
00342   int GetSize () const
00343   {
00344     return Size;
00345   }
00346 
00348   class Iterator
00349   {
00350   private:
00351     const csHash<T, K, KeyHandler>* hash;
00352     const K key;
00353     int bucket, size, element;
00354 
00355     void Seek ()
00356     {
00357       while ((element < size) && 
00358         ! KeyHandler::CompareKeys (hash->Elements[bucket][element].key, key))
00359           element++;
00360     }
00361 
00362   protected:
00363     Iterator (const csHash<T, K, KeyHandler>* hash0, const K& key0) :
00364       hash(hash0),
00365       key(key0), 
00366       bucket(KeyHandler::ComputeHash(key) % hash->Modulo),
00367       size(hash->Elements[bucket].Length ())
00368       { Reset (); }
00369 
00370     friend class csHash;
00371   public:
00373     Iterator (const Iterator &o) :
00374       hash (o.hash),
00375       key(o.key),
00376       bucket(o.bucket),
00377       size(o.size),
00378       element(o.element) {}
00379 
00381     Iterator& operator=(const Iterator& o)
00382     {
00383       hash = o.hash;
00384       key = o.key;
00385       bucket = o.bucket;
00386       size = o.size;
00387       element = o.element;
00388       return *this;
00389     }
00390 
00392     bool HasNext () const
00393     {
00394       return element < size;
00395     }
00396 
00398     const T& Next ()
00399     {
00400       const T &ret = hash->Elements[bucket][element].value;
00401       element++;
00402       Seek ();
00403       return ret;
00404     }
00405 
00407     void Reset () { element = 0; Seek (); }
00408   };
00409   friend class Iterator;
00410 
00412   class GlobalIterator
00413   {
00414   private:
00415     const csHash<T, K, KeyHandler> *hash;
00416     int bucket, size, element;
00417 
00418     void Zero () { bucket = element = 0; }
00419     void Init () { size = hash->Elements[bucket].Length (); }
00420 
00421     void FindItem ()
00422     {
00423       if (element >= size)
00424       {
00425         while (++bucket < hash->Elements.Length ())
00426         {
00427           Init ();
00428           if (size != 0)
00429           {
00430             element = 0;
00431             break;
00432           }
00433         }
00434       }
00435     }
00436 
00437   protected:
00438     GlobalIterator (const csHash<T, K, KeyHandler> *hash0) : hash (hash0) 
00439     { 
00440       Zero (); 
00441       Init (); 
00442       FindItem ();
00443     }
00444 
00445     friend class csHash;
00446   public:
00448     GlobalIterator (const Iterator &o) :
00449       hash (o.hash),
00450       bucket (o.bucket),
00451       size (o.size),
00452       element (o.element) {}
00453 
00455     GlobalIterator& operator=(const GlobalIterator& o)
00456     {
00457       hash = o.hash;
00458       bucket = o.bucket;
00459       size = o.size;
00460       element = o.element;
00461       return *this;
00462     }
00463 
00465     bool HasNext () const
00466     {
00467       if (hash->Elements.Length () == 0) return false;
00468       return element < size || bucket < hash->Elements.Length ();
00469     }
00470 
00472     void Advance ()
00473     {
00474       element++;
00475       FindItem ();
00476     }
00477 
00479     const T& NextNoAdvance ()
00480     {
00481       return hash->Elements[bucket][element].value;
00482     }
00483 
00485     const T& Next ()
00486     {
00487       const T &ret = NextNoAdvance ();
00488       Advance ();
00489       return ret;
00490     }
00491 
00492     const T& NextNoAdvance (K &key)
00493     {
00494       key = hash->Elements[bucket][element].key;
00495       return NextNoAdvance ();
00496     }
00497 
00499     const T& Next (K &key)
00500     {
00501       key = hash->Elements[bucket][element].key;
00502       return Next ();
00503     }
00504 
00506     void Reset () { Zero (); Init (); FindItem (); }
00507   };
00508   friend class GlobalIterator;
00509 
00512   void DeleteElement (GlobalIterator& iterator)
00513   {
00514     Elements[iterator.bucket].DeleteIndex(iterator.element);
00515     Size--;
00516     iterator.size--;
00517     iterator.FindItem ();
00518   }
00519 
00526   Iterator GetIterator (const K& key) const
00527   {
00528     return Iterator (this, key);
00529   }
00530 
00536   GlobalIterator GetIterator () const
00537   {
00538     return GlobalIterator (this);
00539   }
00540 };
00541 
00547 template <class T, class KeyHandler = csIntegralHashKeyHandler<T> > 
00548 class csSet
00549 {
00550 private:
00551   csHash<T, T, KeyHandler> map;
00552 
00553 public:
00555   class Iterator : public csHash<T, T, KeyHandler>::Iterator
00556   {
00557   protected:
00558     Iterator () {}
00559   public:
00560   };
00562   class GlobalIterator : public csHash<T, T, KeyHandler>::GlobalIterator
00563   {
00564   protected:
00565     GlobalIterator () {}
00566     GlobalIterator (const csSet<T, KeyHandler> *set0) : 
00567       csHash<T, T, KeyHandler>::GlobalIterator(&set0->map)
00568     { }
00569 
00570   public:
00571     friend class csSet;
00572   };
00573   friend class GlobalIterator;
00574 
00579   csSet (int size = 257, int grow_rate = 64, int max_size = 20000)
00580         : map (size, grow_rate, max_size)
00581   {
00582   }
00583 
00588   void Add (const T& object)
00589   {
00590     if (In (object)) return;
00591     AddNoTest (object);
00592   }
00593 
00600   void AddNoTest (const T& object)
00601   {
00602     map.Put (object, object);
00603   }
00604 
00608   bool In (const T& object) const
00609   {
00610     return map.In (object);
00611   }
00612 
00616   void DeleteAll ()
00617   {
00618     map.DeleteAll ();
00619   }
00620 
00626   bool Delete (const T& object)
00627   {
00628     return map.Delete (object, object);
00629   }
00630 
00632   int GetSize () const
00633   {
00634     return map.GetSize ();
00635   }
00636 
00638   csHash<T, T, KeyHandler>* GetHash () { return &map; }
00639 
00645   GlobalIterator GetIterator () const
00646   {
00647     return GlobalIterator(this);
00648   }
00649 };
00650 
00651 
00652 #endif

Generated for Crystal Space by doxygen 1.2.18