CrystalSpace

Public API Reference

Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

hash.h

Go to the documentation of this file.
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 
00026 #include "csextern.h"
00027 #include "csutil/array.h"
00028 #include "csutil/comparator.h"
00029 
00030 
00040 CS_CRYSTALSPACE_EXPORT unsigned int csHashCompute (char const*);
00041 
00048 CS_CRYSTALSPACE_EXPORT unsigned int csHashCompute (char const*, size_t length);
00049 
00054 template <class T>
00055 class csHashComputer
00056 {
00057 public:
00059   static uint ComputeHash (const T& key)
00060   {
00061     return key.GetHash();
00062   }
00063 };
00064 
00069 template <class T>
00070 class csHashComputerIntegral
00071 {
00072 public:
00074   static uint ComputeHash (const T& key)
00075   {
00076     return (uintptr_t)key;
00077   }
00078 };
00079 
00081 
00084 CS_SPECIALIZE_TEMPLATE
00085 class csHashComputer<void*> : public csHashComputerIntegral<void*> {};
00086   
00087 CS_SPECIALIZE_TEMPLATE
00088 class csHashComputer<int> : public csHashComputerIntegral<int> {}; 
00089 CS_SPECIALIZE_TEMPLATE
00090 class csHashComputer<unsigned int> : 
00091   public csHashComputerIntegral<unsigned int> {}; 
00092     
00093 CS_SPECIALIZE_TEMPLATE
00094 class csHashComputer<long> : public csHashComputerIntegral<long> {}; 
00095 CS_SPECIALIZE_TEMPLATE
00096 class csHashComputer<unsigned long> : 
00097   public csHashComputerIntegral<unsigned long> {}; 
00098     
00099 CS_SPECIALIZE_TEMPLATE
00100 class csHashComputer<longlong> : 
00101   public csHashComputerIntegral<longlong> {}; 
00102 CS_SPECIALIZE_TEMPLATE
00103 class csHashComputer<ulonglong> : 
00104   public csHashComputerIntegral<ulonglong> {}; 
00105     
00106 CS_SPECIALIZE_TEMPLATE
00107 class csHashComputer<float>
00108 {
00109 public:
00111   static uint ComputeHash (float key)
00112   {
00113     union
00114     {
00115       float f;
00116       uint u;
00117     } float2uint;
00118     float2uint.f = key;
00119     return float2uint.u;
00120   }
00121 };
00122 CS_SPECIALIZE_TEMPLATE
00123 class csHashComputer<double>
00124 {
00125 public:
00127   static uint ComputeHash (double key)
00128   {
00129     union
00130     {
00131       double f;
00132       uint u;
00133     } double2uint;
00134     double2uint.f = key;
00135     return double2uint.u;
00136   }
00137 };
00139 
00143 template <typename T>
00144 class csPtrKey
00145 {
00146   T* ptr;
00147 public:
00148   csPtrKey () : ptr(0) {}
00149   csPtrKey (T* ptr) : ptr(ptr) {}
00150   csPtrKey (csPtrKey const& other) : ptr (other.ptr) {}
00151 
00152   uint GetHash () const { return (uintptr_t)ptr; }
00153   inline friend bool operator < (const csPtrKey& r1, const csPtrKey& r2)
00154   { return r1.ptr < r2.ptr; }
00155   operator T* () const
00156   { return ptr; }
00157   T* operator -> () const
00158   { return ptr; }
00159   csPtrKey& operator = (csPtrKey const& other)
00160   { ptr = other.ptr; return *this; }
00161 };
00162 
00172 template <class T>
00173 class csHashComputerString
00174 {
00175 public:
00176   static uint ComputeHash (const T& key)
00177   {
00178     return csHashCompute ((const char*)key);
00179   }
00180 };
00181 
00185 CS_SPECIALIZE_TEMPLATE
00186 class csHashComputer<const char*> : public csHashComputerString<const char*> {};
00187 
00197 template <class T>
00198 class csHashComputerStruct
00199 {
00200 public:
00201   static uint ComputeHash (const T& key)
00202   {
00203     return csHashCompute ((char*)&key, sizeof (T));
00204   }
00205 };
00206 
00212 class csStrKey
00213 {
00214 private:
00215   char* str;
00216 
00217 public:
00218   csStrKey () { str = 0; }
00219   csStrKey (const char* s) { str = csStrNew (s); }
00220   csStrKey (const csStrKey& c) { str = csStrNew (c.str); }
00221   ~csStrKey () { delete[] str; }
00222   csStrKey& operator=(const csStrKey& o)
00223   {
00224     delete[] str; str = csStrNew (o.str);
00225     return *this;
00226   }
00227   operator const char* () const { return str; }
00228   uint GetHash() const { return csHashCompute (str); }
00229 };
00230 
00234 CS_SPECIALIZE_TEMPLATE
00235 class csComparator<csStrKey, csStrKey> : public csComparatorString<csStrKey> {};
00236 
00246 template <class T, class K = unsigned int> 
00247 class csHash
00248 {
00249 protected:
00250   struct Element
00251   {
00252     const K key;
00253     T value;
00254 
00255     Element (const K& key0, const T &value0) : key (key0), value (value0) {}
00256     Element (const Element &other) : key (other.key), value (other.value) {}
00257   };
00258   csArray< csArray<Element> > Elements;
00259 
00260   size_t Modulo;
00261 
00262 private:
00263   size_t InitModulo;
00264   size_t GrowRate;
00265   size_t MaxSize;
00266   size_t Size;
00267 
00268   void Grow ()
00269   {
00270     static const size_t Primes[] =
00271     {
00272       53,         97,         193,       389,       769, 
00273       1543,       3079,       6151,      12289,     24593,
00274       49157,      98317,      196613,    393241,    786433,
00275       1572869,    3145739,    6291469,   12582917,  25165843,
00276       50331653,   100663319,  201326611, 402653189, 805306457,
00277       1610612741, 0
00278     };
00279 
00280     const size_t *p;
00281     size_t elen = Elements.Length ();
00282     for (p = Primes; *p && *p <= elen; p++) ;
00283     Modulo = *p;
00284     CS_ASSERT (Modulo);
00285 
00286     Elements.SetLength(Modulo, csArray<Element>(0, MIN(Modulo / GrowRate, 8)));
00287 
00288     for (size_t i = 0; i < elen; i++)
00289     {
00290       csArray<Element>& src = Elements[i];
00291       size_t slen = src.Length ();
00292       for (size_t j = slen; j > 0; j--)
00293       {
00294         const Element& srcElem = src[j - 1];
00295         csArray<Element>& dst = 
00296           Elements.Get (csHashComputer<K>::ComputeHash (srcElem.key) % Modulo);
00297         if (&src != &dst)
00298         {
00299           dst.Push (srcElem);
00300           src.DeleteIndex (j - 1);
00301         }
00302       }
00303     }
00304   }
00305 
00306 public:
00321   csHash (size_t size = 23, size_t grow_rate = 5, size_t max_size = 20000)
00322     : Elements (size), Modulo (size), InitModulo (size),
00323       GrowRate (MIN (grow_rate, size)), MaxSize (max_size), Size (0)
00324   {
00325     Elements.SetLength (size, csArray<Element> (0, MIN (size / GrowRate, 8)));
00326   }
00327 
00329   csHash (const csHash<T> &o) : Elements (o.Elements),
00330     Modulo (o.Modulo), InitModulo (o.InitModulo),
00331     GrowRate (o.GrowRate), MaxSize (o.MaxSize), Size (o.Size) {}
00332 
00340   void Put (const K& key, const T &value)
00341   {
00342     csArray<Element> &values = 
00343       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00344     values.Push (Element (key, value));
00345     Size++;
00346     if (values.Length () > Elements.Length () / GrowRate
00347      && Elements.Length () < MaxSize) Grow ();
00348   }
00349 
00351   csArray<T> GetAll (const K& key) const
00352   {
00353     const csArray<Element> &values = 
00354       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00355     csArray<T> ret (values.Length () / 2);
00356     const size_t len = values.Length ();
00357     for (size_t i = 0; i < len; ++i)
00358     {
00359       const Element& v = values[i];
00360       if (csComparator<K, K>::Compare (v.key, key) == 0) 
00361         ret.Push (v.value);
00362     }
00363     return ret;
00364   }
00365 
00367   void PutUnique (const K& key, const T &value)
00368   {
00369     csArray<Element> &values = 
00370       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00371     const size_t len = values.Length ();
00372     for (size_t i = 0; i < len; ++i)
00373     {
00374       Element& v = values[i];
00375       if (csComparator<K, K>::Compare (v.key, key) == 0)
00376       {
00377         v.value = value;
00378         return;
00379       }
00380     }
00381 
00382     values.Push (Element (key, value));
00383     Size++;
00384     if (values.Length () > Elements.Length () / GrowRate
00385      && Elements.Length () < MaxSize) Grow ();
00386   }
00387 
00392   CS_DEPRECATED_METHOD void PutFirst (const K& key, const T &value)
00393   {
00394     PutUnique(key, value);
00395   }
00396 
00398   bool Contains (const K& key) const
00399   {
00400     const csArray<Element> &values = 
00401       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00402     const size_t len = values.Length ();
00403     for (size_t i = 0; i < len; ++i)
00404       if (csComparator<K, K>::Compare (values[i].key, key) == 0) 
00405         return true;
00406     return false;
00407   }
00408 
00414   bool In (const K& key) const
00415   { return Contains(key); }
00416 
00421   const T* GetElementPointer (const K& key) const
00422   {
00423     const csArray<Element> &values = 
00424       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00425     const size_t len = values.Length ();
00426     for (size_t i = 0; i < len; ++i)
00427     {
00428       const Element& v = values[i];
00429       if (csComparator<K, K>::Compare (v.key, key) == 0)
00430         return &v.value;
00431     }
00432 
00433     return 0;
00434   }
00435 
00440   T* GetElementPointer (const K& key)
00441   {
00442     csArray<Element> &values = 
00443       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00444     const size_t len = values.Length ();
00445     for (size_t i = 0; i < len; ++i)
00446     {
00447       Element& v = values[i];
00448       if (csComparator<K, K>::Compare (v.key, key) == 0)
00449         return &v.value;
00450     }
00451 
00452     return 0;
00453   }
00454 
00459   const T& Get (const K& key, const T& fallback) const
00460   {
00461     const csArray<Element> &values = 
00462       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00463     const size_t len = values.Length ();
00464     for (size_t i = 0; i < len; ++i)
00465     {
00466       const Element& v = values[i];
00467       if (csComparator<K, K>::Compare (v.key, key) == 0)
00468         return v.value;
00469     }
00470 
00471     return fallback;
00472   }
00473 
00478   T& Get (const K& key, T& fallback)
00479   {
00480     csArray<Element> &values = 
00481       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00482     const size_t len = values.Length ();
00483     for (size_t i = 0; i < len; ++i)
00484     {
00485       Element& v = values[i];
00486       if (csComparator<K, K>::Compare (v.key, key) == 0)
00487         return v.value;
00488     }
00489 
00490     return fallback;
00491   }
00492 
00494   void DeleteAll ()
00495   {
00496     Elements.SetLength (Modulo = InitModulo);
00497     size_t elen = Elements.Length ();
00498     for (size_t i = 0; i < elen; i++)
00499       Elements[i].Empty ();
00500     Size = 0;
00501   }
00502 
00504   void Empty() { DeleteAll(); }
00505 
00507   bool DeleteAll (const K& key)
00508   {
00509     bool ret = false;
00510     csArray<Element> &values = 
00511       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00512     for (size_t i = values.Length (); i > 0; i--)
00513     {
00514       const size_t idx = i - 1;
00515       if (csComparator<K, K>::Compare (values[idx].key, key) == 0)
00516       {
00517         values.DeleteIndexFast (idx);
00518         ret = true;
00519         Size--;
00520       }
00521     }
00522     return ret;
00523   }
00524   
00526   bool Delete (const K& key, const T &value)
00527   {
00528     bool ret = false;
00529     csArray<Element> &values = 
00530       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00531     for (size_t i = values.Length (); i > 0; i--)
00532     {
00533       const size_t idx = i - 1;
00534       if ((csComparator<K, K>::Compare (values[idx].key, key) == 0) && 
00535         (values[idx].value == value))
00536       {
00537         values.DeleteIndexFast (idx);
00538         ret = true;
00539         Size--;
00540       }
00541     }
00542     return ret;
00543   }
00544 
00546   size_t GetSize () const
00547   {
00548     return Size;
00549   }
00550 
00556   bool IsEmpty() const
00557   {
00558     return GetSize() == 0;
00559   }
00560 
00562   class Iterator
00563   {
00564   private:
00565     const csHash<T, K>* hash;
00566     const K key;
00567     size_t bucket, size, element;
00568 
00569     void Seek ()
00570     {
00571       while ((element < size) && 
00572         (csComparator<K, K>::Compare (hash->Elements[bucket][element].key, 
00573         key) != 0))
00574           element++;
00575     }
00576 
00577   protected:
00578     Iterator (const csHash<T, K>* hash0, const K& key0) :
00579       hash(hash0),
00580       key(key0), 
00581       bucket(csHashComputer<K>::ComputeHash (key) % hash->Modulo),
00582       size(hash->Elements[bucket].Length ())
00583       { Reset (); }
00584 
00585     friend class csHash<T, K>;
00586   public:
00588     Iterator (const Iterator &o) :
00589       hash (o.hash),
00590       key(o.key),
00591       bucket(o.bucket),
00592       size(o.size),
00593       element(o.element) {}
00594 
00596     Iterator& operator=(const Iterator& o)
00597     {
00598       hash = o.hash;
00599       key = o.key;
00600       bucket = o.bucket;
00601       size = o.size;
00602       element = o.element;
00603       return *this;
00604     }
00605 
00607     bool HasNext () const
00608     {
00609       return element < size;
00610     }
00611 
00613     const T& Next ()
00614     {
00615       const T &ret = hash->Elements[bucket][element].value;
00616       element++;
00617       Seek ();
00618       return ret;
00619     }
00620 
00622     void Reset () { element = 0; Seek (); }
00623   };
00624   friend class Iterator;
00625 
00627   class GlobalIterator
00628   {
00629   private:
00630     const csHash<T, K> *hash;
00631     size_t bucket, size, element;
00632 
00633     void Zero () { bucket = element = 0; }
00634     void Init () { size = hash->Elements[bucket].Length (); }
00635 
00636     void FindItem ()
00637     {
00638       if (element >= size)
00639       {
00640         while (++bucket < hash->Elements.Length ())
00641         {
00642           Init ();
00643           if (size != 0)
00644           {
00645             element = 0;
00646             break;
00647           }
00648         }
00649       }
00650     }
00651 
00652   protected:
00653     GlobalIterator (const csHash<T, K> *hash0) : hash (hash0) 
00654     { 
00655       Zero (); 
00656       Init (); 
00657       FindItem ();
00658     }
00659 
00660     friend class csHash<T, K>;
00661   public:
00663     GlobalIterator (const Iterator &o) :
00664       hash (o.hash),
00665       bucket (o.bucket),
00666       size (o.size),
00667       element (o.element) {}
00668 
00670     GlobalIterator& operator=(const GlobalIterator& o)
00671     {
00672       hash = o.hash;
00673       bucket = o.bucket;
00674       size = o.size;
00675       element = o.element;
00676       return *this;
00677     }
00678 
00680     bool HasNext () const
00681     {
00682       if (hash->Elements.Length () == 0) return false;
00683       return element < size || bucket < hash->Elements.Length ();
00684     }
00685 
00687     void Advance ()
00688     {
00689       element++;
00690       FindItem ();
00691     }
00692 
00694     const T& NextNoAdvance ()
00695     {
00696       return hash->Elements[bucket][element].value;
00697     }
00698 
00700     const T& Next ()
00701     {
00702       const T &ret = NextNoAdvance ();
00703       Advance ();
00704       return ret;
00705     }
00706 
00708     const T& NextNoAdvance (K &key)
00709     {
00710       key = hash->Elements[bucket][element].key;
00711       return NextNoAdvance ();
00712     }
00713 
00715     const T& Next (K &key)
00716     {
00717       key = hash->Elements[bucket][element].key;
00718       return Next ();
00719     }
00720 
00722     void Reset () { Zero (); Init (); FindItem (); }
00723   };
00724   friend class GlobalIterator;
00725 
00728   void DeleteElement (GlobalIterator& iterator)
00729   {
00730     Elements[iterator.bucket].DeleteIndex(iterator.element);
00731     Size--;
00732     iterator.size--;
00733     iterator.FindItem ();
00734   }
00735 
00742   Iterator GetIterator (const K& key) const
00743   {
00744     return Iterator (this, key);
00745   }
00746 
00752   GlobalIterator GetIterator () const
00753   {
00754     return GlobalIterator (this);
00755   }
00756 };
00757 
00760 #endif

Generated for Crystal Space by doxygen 1.4.4