hashtable.hpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifndef HASHTABLE_HPP
00013 #define HASHTABLE_HPP
00014
00015 #include "../core/math_func.hpp"
00016
00017 template <class Titem_>
00018 struct CHashTableSlotT
00019 {
00020 typedef typename Titem_::Key Key;
00021
00022 Titem_ *m_pFirst;
00023
00024 FORCEINLINE CHashTableSlotT() : m_pFirst(NULL) {}
00025
00027 FORCEINLINE void Clear() {m_pFirst = NULL;}
00028
00030 FORCEINLINE const Titem_ *Find(const Key& key) const
00031 {
00032 for (const Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) {
00033 if (pItem->GetKey() == key) {
00034
00035 return pItem;
00036 }
00037 }
00038 return NULL;
00039 }
00040
00042 FORCEINLINE Titem_ *Find(const Key& key)
00043 {
00044 for (Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) {
00045 if (pItem->GetKey() == key) {
00046
00047 return pItem;
00048 }
00049 }
00050 return NULL;
00051 }
00052
00054 FORCEINLINE void Attach(Titem_& new_item)
00055 {
00056 assert(new_item.GetHashNext() == NULL);
00057 new_item.SetHashNext(m_pFirst);
00058 m_pFirst = &new_item;
00059 }
00060
00062 FORCEINLINE bool Detach(Titem_& item_to_remove)
00063 {
00064 if (m_pFirst == &item_to_remove) {
00065 m_pFirst = item_to_remove.GetHashNext();
00066 item_to_remove.SetHashNext(NULL);
00067 return true;
00068 }
00069 Titem_ *pItem = m_pFirst;
00070 while (true) {
00071 if (pItem == NULL) {
00072 return false;
00073 }
00074 Titem_ *pNextItem = pItem->GetHashNext();
00075 if (pNextItem == &item_to_remove) break;
00076 pItem = pNextItem;
00077 }
00078 pItem->SetHashNext(item_to_remove.GetHashNext());
00079 item_to_remove.SetHashNext(NULL);
00080 return true;
00081 }
00082
00084 FORCEINLINE Titem_ *Detach(const Key& key)
00085 {
00086
00087 if (m_pFirst == NULL) {
00088 return NULL;
00089 }
00090
00091 if (m_pFirst->GetKey() == key) {
00092 Titem_& ret_item = *m_pFirst;
00093 m_pFirst = m_pFirst->GetHashNext();
00094 ret_item.SetHashNext(NULL);
00095 return &ret_item;
00096 }
00097
00098 Titem_ *pPrev = m_pFirst;
00099 for (Titem_ *pItem = m_pFirst->GetHashNext(); pItem != NULL; pPrev = pItem, pItem = pItem->GetHashNext()) {
00100 if (pItem->GetKey() == key) {
00101
00102 pPrev->SetHashNext(pItem->GetHashNext());
00103 pItem->SetHashNext(NULL);
00104 return pItem;
00105 }
00106 }
00107 return NULL;
00108 }
00109 };
00110
00133 template <class Titem_, int Thash_bits_>
00134 class CHashTableT {
00135 public:
00136 typedef Titem_ Titem;
00137 typedef typename Titem_::Key Tkey;
00138 static const int Thash_bits = Thash_bits_;
00139 static const int Tcapacity = 1 << Thash_bits;
00140
00141 protected:
00146 typedef CHashTableSlotT<Titem_> Slot;
00147
00148 Slot *m_slots;
00149 int m_num_items;
00150
00151 public:
00152
00153 FORCEINLINE CHashTableT()
00154 {
00155
00156 m_slots = new Slot[Tcapacity];
00157 m_num_items = 0;
00158 }
00159
00160 ~CHashTableT() {delete [] m_slots; m_num_items = 0; m_slots = NULL;}
00161
00162 protected:
00164 FORCEINLINE static int CalcHash(const Tkey& key)
00165 {
00166 int32 hash = key.CalcHash();
00167 if ((8 * Thash_bits) < 32) hash ^= hash >> (min(8 * Thash_bits, 31));
00168 if ((4 * Thash_bits) < 32) hash ^= hash >> (min(4 * Thash_bits, 31));
00169 if ((2 * Thash_bits) < 32) hash ^= hash >> (min(2 * Thash_bits, 31));
00170 if ((1 * Thash_bits) < 32) hash ^= hash >> (min(1 * Thash_bits, 31));
00171 hash &= (1 << Thash_bits) - 1;
00172 return hash;
00173 }
00174
00176 FORCEINLINE static int CalcHash(const Titem_& item) {return CalcHash(item.GetKey());}
00177
00178 public:
00180 FORCEINLINE int Count() const {return m_num_items;}
00181
00183 FORCEINLINE void Clear() const {for (int i = 0; i < Tcapacity; i++) m_slots[i].Clear();}
00184
00186 const Titem_ *Find(const Tkey& key) const
00187 {
00188 int hash = CalcHash(key);
00189 const Slot& slot = m_slots[hash];
00190 const Titem_ *item = slot.Find(key);
00191 return item;
00192 }
00193
00195 Titem_ *Find(const Tkey& key)
00196 {
00197 int hash = CalcHash(key);
00198 Slot& slot = m_slots[hash];
00199 Titem_ *item = slot.Find(key);
00200 return item;
00201 }
00202
00204 Titem_ *TryPop(const Tkey& key)
00205 {
00206 int hash = CalcHash(key);
00207 Slot& slot = m_slots[hash];
00208 Titem_ *item = slot.Detach(key);
00209 if (item != NULL) {
00210 m_num_items--;
00211 }
00212 return item;
00213 }
00214
00216 Titem_& Pop(const Tkey& key)
00217 {
00218 Titem_ *item = TryPop(key);
00219 assert(item != NULL);
00220 return *item;
00221 }
00222
00224 bool TryPop(Titem_& item)
00225 {
00226 const Tkey& key = item.GetKey();
00227 int hash = CalcHash(key);
00228 Slot& slot = m_slots[hash];
00229 bool ret = slot.Detach(item);
00230 if (ret) {
00231 m_num_items--;
00232 }
00233 return ret;
00234 }
00235
00237 void Pop(Titem_& item)
00238 {
00239 bool ret = TryPop(item);
00240 assert(ret);
00241 }
00242
00244 void Push(Titem_& new_item)
00245 {
00246 int hash = CalcHash(new_item);
00247 Slot& slot = m_slots[hash];
00248 assert(slot.Find(new_item.GetKey()) == NULL);
00249 slot.Attach(new_item);
00250 m_num_items++;
00251 }
00252 };
00253
00254 #endif