# hashtable.hpp

Go to the documentation of this file.

    00001 /* $Id: hashtable.hpp 15718 2009-03-15 00:32:18Z rubidium $ */
    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 */