hashtable.hpp

Go to the documentation of this file.
00001 /* $Id: hashtable.hpp 9662 2007-04-17 20:23:13Z belugas $ */
00002 
00005 #ifndef  HASHTABLE_HPP
00006 #define  HASHTABLE_HPP
00007 
00008 template <class Titem_>
00009 struct CHashTableSlotT
00010 {
00011   typedef typename Titem_::Key Key;          // make Titem_::Key a property of HashTable
00012 
00013   Titem_*    m_pFirst;
00014 
00015   CHashTableSlotT() : m_pFirst(NULL) {}
00016 
00018   FORCEINLINE void Clear() {m_pFirst = NULL;}
00019 
00021   FORCEINLINE const Titem_* Find(const Key& key) const
00022   {
00023     for (const Titem_* pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) {
00024       if (pItem->GetKey() == key) {
00025         // we have found the item, return it
00026         return pItem;
00027       }
00028     }
00029     return NULL;
00030   }
00031 
00033   FORCEINLINE Titem_* Find(const Key& key)
00034   {
00035     for (Titem_* pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) {
00036       if (pItem->GetKey() == key) {
00037         // we have found the item, return it
00038         return pItem;
00039       }
00040     }
00041     return NULL;
00042   }
00043 
00045   FORCEINLINE void Attach(Titem_& new_item)
00046   {
00047     assert(new_item.GetHashNext() == NULL);
00048     new_item.SetHashNext(m_pFirst);
00049     m_pFirst = &new_item;
00050   }
00051 
00053   FORCEINLINE bool Detach(Titem_& item_to_remove)
00054   {
00055     if (m_pFirst == &item_to_remove) {
00056       m_pFirst = item_to_remove.GetHashNext();
00057       item_to_remove.SetHashNext(NULL);
00058       return true;
00059     }
00060     Titem_* pItem = m_pFirst;
00061     while (true) {
00062       if (pItem == NULL) {
00063         return false;
00064       }
00065       Titem_* pNextItem = pItem->GetHashNext();
00066       if (pNextItem == &item_to_remove) break;
00067       pItem = pNextItem;
00068     }
00069     pItem->SetHashNext(item_to_remove.GetHashNext());
00070     item_to_remove.SetHashNext(NULL);
00071     return true;
00072   }
00073 
00075   FORCEINLINE Titem_* Detach(const Key& key)
00076   {
00077     // do we have any items?
00078     if (m_pFirst == NULL) {
00079       return NULL;
00080     }
00081     // is it our first item?
00082     if (m_pFirst->GetKey() == key) {
00083       Titem_& ret_item = *m_pFirst;
00084       m_pFirst = m_pFirst->GetHashNext();
00085       ret_item.SetHashNext(NULL);
00086       return &ret_item;
00087     }
00088     // find it in the following items
00089     Titem_* pPrev = m_pFirst;
00090     for (Titem_* pItem = m_pFirst->GetHashNext(); pItem != NULL; pPrev = pItem, pItem = pItem->GetHashNext()) {
00091       if (pItem->GetKey() == key) {
00092         // we have found the item, unlink and return it
00093         pPrev->SetHashNext(pItem->GetHashNext());
00094         pItem->SetHashNext(NULL);
00095         return pItem;
00096       }
00097     }
00098     return NULL;
00099   }
00100 };
00101 
00123 template <class Titem_, int Thash_bits_>
00124 class CHashTableT {
00125 public:
00126   typedef Titem_ Titem;                         // make Titem_ visible from outside of class
00127   typedef typename Titem_::Key Tkey;            // make Titem_::Key a property of HashTable
00128   static const int Thash_bits = Thash_bits_;    // publish num of hash bits
00129   static const int Tcapacity = 1 << Thash_bits; // and num of slots 2^bits
00130 
00131 protected:
00134   typedef CHashTableSlotT<Titem_> Slot;
00135 
00136   Slot*  m_slots;     // here we store our data (array of blobs)
00137   int    m_num_items; // item counter
00138 
00139 public:
00140   // default constructor
00141   FORCEINLINE CHashTableT()
00142   {
00143     // construct all slots
00144     m_slots = new Slot[Tcapacity];
00145     m_num_items = 0;
00146   }
00147 
00148   ~CHashTableT() {delete [] m_slots; m_num_items = 0; m_slots = NULL;}
00149 
00150 protected:
00152   FORCEINLINE static int CalcHash(const Tkey& key)
00153   {
00154     int32 hash = key.CalcHash();
00155     if ((8 * Thash_bits) < 32) hash ^= hash >> (min(8 * Thash_bits, 31));
00156     if ((4 * Thash_bits) < 32) hash ^= hash >> (min(4 * Thash_bits, 31));
00157     if ((2 * Thash_bits) < 32) hash ^= hash >> (min(2 * Thash_bits, 31));
00158     if ((1 * Thash_bits) < 32) hash ^= hash >> (min(1 * Thash_bits, 31));
00159     hash &= (1 << Thash_bits) - 1;
00160     return hash;
00161   }
00162 
00164   FORCEINLINE static int CalcHash(const Titem_& item) {return CalcHash(item.GetKey());}
00165 
00166 public:
00168   FORCEINLINE int Count() const {return m_num_items;}
00169 
00171   FORCEINLINE void Clear() const {for (int i = 0; i < Tcapacity; i++) m_slots[i].Clear();}
00172 
00174   const Titem_* Find(const Tkey& key) const
00175   {
00176     int hash = CalcHash(key);
00177     const Slot& slot = m_slots[hash];
00178     const Titem_* item = slot.Find(key);
00179     return item;
00180   }
00181 
00183   Titem_* Find(const Tkey& key)
00184   {
00185     int hash = CalcHash(key);
00186     Slot& slot = m_slots[hash];
00187     Titem_* item = slot.Find(key);
00188     return item;
00189   }
00190 
00192   Titem_* TryPop(const Tkey& key)
00193   {
00194     int hash = CalcHash(key);
00195     Slot& slot = m_slots[hash];
00196     Titem_* item = slot.Detach(key);
00197     if (item != NULL) {
00198       m_num_items--;
00199     }
00200     return item;
00201   }
00202 
00204   Titem_& Pop(const Tkey& key)
00205   {
00206     Titem_* item = TryPop(key);
00207     assert(item != NULL);
00208     return *item;
00209   }
00210 
00212   bool TryPop(Titem_& item)
00213   {
00214     const Tkey& key = item.GetKey();
00215     int hash = CalcHash(key);
00216     Slot& slot = m_slots[hash];
00217     bool ret = slot.Detach(item);
00218     if (ret) {
00219       m_num_items--;
00220     }
00221     return ret;
00222   }
00223 
00225   void Pop(Titem_& item)
00226   {
00227     bool ret = TryPop(item);
00228     assert(ret);
00229   }
00230 
00232   void Push(Titem_& new_item)
00233   {
00234     int hash = CalcHash(new_item);
00235     Slot& slot = m_slots[hash];
00236     assert(slot.Find(new_item.GetKey()) == NULL);
00237     slot.Attach(new_item);
00238     m_num_items++;
00239   }
00240 };
00241 
00242 #endif /* HASHTABLE_HPP */

Generated on Mon Sep 22 20:34:16 2008 for openttd by  doxygen 1.5.6