CrystalSpace

Public API Reference

csutil/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 #if (CS_LONG_SIZE < 8)    
00100 CS_SPECIALIZE_TEMPLATE
00101 class csHashComputer<longlong> : 
00102   public csHashComputerIntegral<longlong> {}; 
00103 CS_SPECIALIZE_TEMPLATE
00104 class csHashComputer<ulonglong> : 
00105   public csHashComputerIntegral<ulonglong> {}; 
00106 #endif
00107     
00108 CS_SPECIALIZE_TEMPLATE
00109 class csHashComputer<float>
00110 {
00111 public:
00113   static uint ComputeHash (float key)
00114   {
00115     union
00116     {
00117       float f;
00118       uint u;
00119     } float2uint;
00120     float2uint.f = key;
00121     return float2uint.u;
00122   }
00123 };
00124 CS_SPECIALIZE_TEMPLATE
00125 class csHashComputer<double>
00126 {
00127 public:
00129   static uint ComputeHash (double key)
00130   {
00131     union
00132     {
00133       double f;
00134       uint u;
00135     } double2uint;
00136     double2uint.f = key;
00137     return double2uint.u;
00138   }
00139 };
00141 
00145 template <typename T>
00146 class csPtrKey
00147 {
00148   T* ptr;
00149 public:
00150   csPtrKey () : ptr(0) {}
00151   csPtrKey (T* ptr) : ptr(ptr) {}
00152   csPtrKey (csPtrKey const& other) : ptr (other.ptr) {}
00153 
00154   uint GetHash () const { return (uintptr_t)ptr; }
00155   inline friend bool operator < (const csPtrKey& r1, const csPtrKey& r2)
00156   { return r1.ptr < r2.ptr; }
00157   operator T* () const
00158   { return ptr; }
00159   T* operator -> () const
00160   { return ptr; }
00161   csPtrKey& operator = (csPtrKey const& other)
00162   { ptr = other.ptr; return *this; }
00163 };
00164 
00174 template <class T>
00175 class csHashComputerString
00176 {
00177 public:
00178   static uint ComputeHash (const T& key)
00179   {
00180     return csHashCompute ((const char*)key);
00181   }
00182 };
00183 
00187 CS_SPECIALIZE_TEMPLATE
00188 class csHashComputer<const char*> : public csHashComputerString<const char*> {};
00189 
00199 template <class T>
00200 class csHashComputerStruct
00201 {
00202 public:
00203   static uint ComputeHash (const T& key)
00204   {
00205     return csHashCompute ((char*)&key, sizeof (T));
00206   }
00207 };
00208 
00214 class csStrKey
00215 {
00216 private:
00217   char* str;
00218 
00219 public:
00220   csStrKey () { str = 0; }
00221   csStrKey (const char* s) { str = csStrNew (s); }
00222   csStrKey (const csStrKey& c) { str = csStrNew (c.str); }
00223   ~csStrKey () { delete[] str; }
00224   csStrKey& operator=(const csStrKey& o)
00225   {
00226     delete[] str; str = csStrNew (o.str);
00227     return *this;
00228   }
00229   operator const char* () const { return str; }
00230   uint GetHash() const { return csHashCompute (str); }
00231 };
00232 
00236 CS_SPECIALIZE_TEMPLATE
00237 class csComparator<csStrKey, csStrKey> : public csComparatorString<csStrKey> {};
00238 
00248 template <class T, class K = unsigned int> 
00249 class csHash
00250 {
00251 protected:
00252   struct Element
00253   {
00254     const K key;
00255     T value;
00256 
00257     Element (const K& key0, const T &value0) : key (key0), value (value0) {}
00258     Element (const Element &other) : key (other.key), value (other.value) {}
00259   };
00260   csArray< csArray<Element> > Elements;
00261 
00262   size_t Modulo;
00263 
00264 private:
00265   size_t InitModulo;
00266   size_t GrowRate;
00267   size_t MaxSize;
00268   size_t Size;
00269 
00270   void Grow ()
00271   {
00272     static const size_t Primes[] =
00273     {
00274       53,         97,         193,       389,       769, 
00275       1543,       3079,       6151,      12289,     24593,
00276       49157,      98317,      196613,    393241,    786433,
00277       1572869,    3145739,    6291469,   12582917,  25165843,
00278       50331653,   100663319,  201326611, 402653189, 805306457,
00279       1610612741, 0
00280     };
00281 
00282     const size_t *p;
00283     size_t elen = Elements.Length ();
00284     for (p = Primes; *p && *p <= elen; p++) ;
00285     Modulo = *p;
00286     CS_ASSERT (Modulo);
00287 
00288     Elements.SetLength(Modulo, csArray<Element>(0, MIN(Modulo / GrowRate, 8)));
00289 
00290     for (size_t i = 0; i < elen; i++)
00291     {
00292       csArray<Element>& src = Elements[i];
00293       size_t slen = src.Length ();
00294       for (size_t j = slen; j > 0; j--)
00295       {
00296         const Element& srcElem = src[j - 1];
00297         csArray<Element>& dst = 
00298           Elements.Get (csHashComputer<K>::ComputeHash (srcElem.key) % Modulo);
00299         if (&src != &dst)
00300         {
00301           dst.Push (srcElem);
00302           src.DeleteIndex (j - 1);
00303         }
00304       }
00305     }
00306   }
00307 
00308 public:
00323   csHash (size_t size = 23, size_t grow_rate = 5, size_t max_size = 20000)
00324     : Elements (size), Modulo (size), InitModulo (size),
00325       GrowRate (MIN (grow_rate, size)), MaxSize (max_size), Size (0)
00326   {
00327     Elements.SetLength (size, csArray<Element> (0, MIN (size / GrowRate, 8)));
00328   }
00329 
00331   csHash (const csHash<T> &o) : Elements (o.Elements),
00332     Modulo (o.Modulo), InitModulo (o.InitModulo),
00333     GrowRate (o.GrowRate), MaxSize (o.MaxSize), Size (o.Size) {}
00334 
00342   void Put (const K& key, const T &value)
00343   {
00344     csArray<Element> &values = 
00345       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00346     values.Push (Element (key, value));
00347     Size++;
00348     if (values.Length () > Elements.Length () / GrowRate
00349      && Elements.Length () < MaxSize) Grow ();
00350   }
00351 
00353   csArray<T> GetAll (const K& key) const
00354   {
00355     const csArray<Element> &values = 
00356       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00357     csArray<T> ret (values.Length () / 2);
00358     const size_t len = values.Length ();
00359     for (size_t i = 0; i < len; ++i)
00360     {
00361       const Element& v = values[i];
00362       if (csComparator<K, K>::Compare (v.key, key) == 0) 
00363         ret.Push (v.value);
00364     }
00365     return ret;
00366   }
00367 
00369   void PutUnique (const K& key, const T &value)
00370   {
00371     csArray<Element> &values = 
00372       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00373     const size_t len = values.Length ();
00374     for (size_t i = 0; i < len; ++i)
00375     {
00376       Element& v = values[i];
00377       if (csComparator<K, K>::Compare (v.key, key) == 0)
00378       {
00379         v.value = value;
00380         return;
00381       }
00382     }
00383 
00384     values.Push (Element (key, value));
00385     Size++;
00386     if (values.Length () > Elements.Length () / GrowRate
00387      && Elements.Length () < MaxSize) Grow ();
00388   }
00389 
00394   CS_DEPRECATED_METHOD void PutFirst (const K& key, const T &value)
00395   {
00396     PutUnique(key, value);
00397   }
00398 
00400   bool Contains (const K& key) const
00401   {
00402     const csArray<Element> &values = 
00403       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00404     const size_t len = values.Length ();
00405     for (size_t i = 0; i < len; ++i)
00406       if (csComparator<K, K>::Compare (values[i].key, key) == 0) 
00407         return true;
00408     return false;
00409   }
00410 
00416   bool In (const K& key) const
00417   { return Contains(key); }
00418 
00423   const T* GetElementPointer (const K& key) const
00424   {
00425     const csArray<Element> &values = 
00426       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00427     const size_t len = values.Length ();
00428     for (size_t i = 0; i < len; ++i)
00429     {
00430       const Element& v = values[i];
00431       if (csComparator<K, K>::Compare (v.key, key) == 0)
00432         return &v.value;
00433     }
00434 
00435     return 0;
00436   }
00437 
00442   T* GetElementPointer (const K& key)
00443   {
00444     csArray<Element> &values = 
00445       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00446     const size_t len = values.Length ();
00447     for (size_t i = 0; i < len; ++i)
00448     {
00449       Element& v = values[i];
00450       if (csComparator<K, K>::Compare (v.key, key) == 0)
00451         return &v.value;
00452     }
00453 
00454     return 0;
00455   }
00456 
00461   const T& Get (const K& key, const T& fallback) const
00462   {
00463     const csArray<Element> &values = 
00464       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00465     const size_t len = values.Length ();
00466     for (size_t i = 0; i < len; ++i)
00467     {
00468       const Element& v = values[i];
00469       if (csComparator<K, K>::Compare (v.key, key) == 0)
00470         return v.value;
00471     }
00472 
00473     return fallback;
00474   }
00475 
00480   T& Get (const K& key, T& fallback)
00481   {
00482     csArray<Element> &values = 
00483       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00484     const size_t len = values.Length ();
00485     for (size_t i = 0; i < len; ++i)
00486     {
00487       Element& v = values[i];
00488       if (csComparator<K, K>::Compare (v.key, key) == 0)
00489         return v.value;
00490     }
00491 
00492     return fallback;
00493   }
00494 
00496   void DeleteAll ()
00497   {
00498     Elements.SetLength (Modulo = InitModulo);
00499     size_t elen = Elements.Length ();
00500     for (size_t i = 0; i < elen; i++)
00501       Elements[i].Empty ();
00502     Size = 0;
00503   }
00504 
00506   void Empty() { DeleteAll(); }
00507 
00509   bool DeleteAll (const K& key)
00510   {
00511     bool ret = false;
00512     csArray<Element> &values = 
00513       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00514     for (size_t i = values.Length (); i > 0; i--)
00515     {
00516       const size_t idx = i - 1;
00517       if (csComparator<K, K>::Compare (values[idx].key, key) == 0)
00518       {
00519         values.DeleteIndexFast (idx);
00520         ret = true;
00521         Size--;
00522       }
00523     }
00524     return ret;
00525   }
00526   
00528   bool Delete (const K& key, const T &value)
00529   {
00530     bool ret = false;
00531     csArray<Element> &values = 
00532       Elements[csHashComputer<K>::ComputeHash (key) % Modulo];
00533     for (size_t i = values.Length (); i > 0; i--)
00534     {
00535       const size_t idx = i - 1;
00536       if ((csComparator<K, K>::Compare (values[idx].key, key) == 0) && 
00537         (values[idx].value == value))
00538       {
00539         values.DeleteIndexFast (idx);
00540         ret = true;
00541         Size--;
00542       }
00543     }
00544     return ret;
00545   }
00546 
00548   size_t GetSize () const
00549   {
00550     return Size;
00551   }
00552 
00558   bool IsEmpty() const
00559   {
00560     return GetSize() == 0;
00561   }
00562 
00564   class Iterator
00565   {
00566   private:
00567     const csHash<T, K>* hash;
00568     const K key;
00569     size_t bucket, size, element;
00570 
00571     void Seek ()
00572     {
00573       while ((element < size) && 
00574         (csComparator<K, K>::Compare (hash->Elements[bucket][element].key, 
00575         key) != 0))
00576           element++;
00577     }
00578 
00579   protected:
00580     Iterator (const csHash<T, K>* hash0, const K& key0) :
00581       hash(hash0),
00582       key(key0), 
00583       bucket(csHashComputer<K>::ComputeHash (key) % hash->Modulo),
00584       size(hash->Elements[bucket].Length ())
00585       { Reset (); }
00586 
00587     friend class csHash<T, K>;
00588   public:
00590     Iterator (const Iterator &o) :
00591       hash (o.hash),
00592       key(o.key),
00593       bucket(o.bucket),
00594       size(o.size),
00595       element(o.element) {}
00596 
00598     Iterator& operator=(const Iterator& o)
00599     {
00600       hash = o.hash;
00601       key = o.key;
00602       bucket = o.bucket;
00603       size = o.size;
00604       element = o.element;
00605       return *this;
00606     }
00607 
00609     bool HasNext () const
00610     {
00611       return element < size;
00612     }
00613 
00615     const T& Next ()
00616     {
00617       const T &ret = hash->Elements[bucket][element].value;
00618       element++;
00619       Seek ();
00620       return ret;
00621     }
00622 
00624     void Reset () { element = 0; Seek (); }
00625   };
00626   friend class Iterator;
00627 
00629   class GlobalIterator
00630   {
00631   private:
00632     const csHash<T, K> *hash;
00633     size_t bucket, size, element;
00634 
00635     void Zero () { bucket = element = 0; }
00636     void Init () { size = hash->Elements[bucket].Length (); }
00637 
00638     void FindItem ()
00639     {
00640       if (element >= size)
00641       {
00642         while (++bucket < hash->Elements.Length ())
00643         {
00644           Init ();
00645           if (size != 0)
00646           {
00647             element = 0;
00648             break;
00649           }
00650         }
00651       }
00652     }
00653 
00654   protected:
00655     GlobalIterator (const csHash<T, K> *hash0) : hash (hash0) 
00656     { 
00657       Zero (); 
00658       Init (); 
00659       FindItem ();
00660     }
00661 
00662     friend class csHash<T, K>;
00663   public:
00665     GlobalIterator (const Iterator &o) :
00666       hash (o.hash),
00667       bucket (o.bucket),
00668       size (o.size),
00669       element (o.element) {}
00670 
00672     GlobalIterator& operator=(const GlobalIterator& o)
00673     {
00674       hash = o.hash;
00675       bucket = o.bucket;
00676       size = o.size;
00677       element = o.element;
00678       return *this;
00679     }
00680 
00682     bool HasNext () const
00683     {
00684       if (hash->Elements.Length () == 0) return false;
00685       return element < size || bucket < hash->Elements.Length ();
00686     }
00687 
00689     void Advance ()
00690     {
00691       element++;
00692       FindItem ();
00693     }
00694 
00696     const T& NextNoAdvance ()
00697     {
00698       return hash->Elements[bucket][element].value;
00699     }
00700 
00702     const T& Next ()
00703     {
00704       const T &ret = NextNoAdvance ();
00705       Advance ();
00706       return ret;
00707     }
00708 
00710     const T& NextNoAdvance (K &key)
00711     {
00712       key = hash->Elements[bucket][element].key;
00713       return NextNoAdvance ();
00714     }
00715 
00717     const T& Next (K &key)
00718     {
00719       key = hash->Elements[bucket][element].key;
00720       return Next ();
00721     }
00722 
00724     void Reset () { Zero (); Init (); FindItem (); }
00725   };
00726   friend class GlobalIterator;
00727 
00730   void DeleteElement (GlobalIterator& iterator)
00731   {
00732     Elements[iterator.bucket].DeleteIndex(iterator.element);
00733     Size--;
00734     iterator.size--;
00735     iterator.FindItem ();
00736   }
00737 
00744   Iterator GetIterator (const K& key) const
00745   {
00746     return Iterator (this, key);
00747   }
00748 
00754   GlobalIterator GetIterator () const
00755   {
00756     return GlobalIterator (this);
00757   }
00758 };
00759 
00762 #endif

Generated for Crystal Space by doxygen 1.4.6