OpenTTD
hashtable.hpp
Go to the documentation of this file.
1 /* $Id: hashtable.hpp 23640 2011-12-20 17:57:56Z truebrain $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8  */
9 
12 #ifndef HASHTABLE_HPP
13 #define HASHTABLE_HPP
14 
15 #include "../core/math_func.hpp"
16 
17 template <class Titem_>
19 {
20  typedef typename Titem_::Key Key; // make Titem_::Key a property of HashTable
21 
22  Titem_ *m_pFirst;
23 
24  inline CHashTableSlotT() : m_pFirst(NULL) {}
25 
27  inline void Clear() {m_pFirst = NULL;}
28 
30  inline const Titem_ *Find(const Key& key) const
31  {
32  for (const Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) {
33  if (pItem->GetKey() == key) {
34  /* we have found the item, return it */
35  return pItem;
36  }
37  }
38  return NULL;
39  }
40 
42  inline Titem_ *Find(const Key& key)
43  {
44  for (Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) {
45  if (pItem->GetKey() == key) {
46  /* we have found the item, return it */
47  return pItem;
48  }
49  }
50  return NULL;
51  }
52 
54  inline void Attach(Titem_& new_item)
55  {
56  assert(new_item.GetHashNext() == NULL);
57  new_item.SetHashNext(m_pFirst);
58  m_pFirst = &new_item;
59  }
60 
62  inline bool Detach(Titem_& item_to_remove)
63  {
64  if (m_pFirst == &item_to_remove) {
65  m_pFirst = item_to_remove.GetHashNext();
66  item_to_remove.SetHashNext(NULL);
67  return true;
68  }
69  Titem_ *pItem = m_pFirst;
70  for (;;) {
71  if (pItem == NULL) {
72  return false;
73  }
74  Titem_ *pNextItem = pItem->GetHashNext();
75  if (pNextItem == &item_to_remove) break;
76  pItem = pNextItem;
77  }
78  pItem->SetHashNext(item_to_remove.GetHashNext());
79  item_to_remove.SetHashNext(NULL);
80  return true;
81  }
82 
84  inline Titem_ *Detach(const Key& key)
85  {
86  /* do we have any items? */
87  if (m_pFirst == NULL) {
88  return NULL;
89  }
90  /* is it our first item? */
91  if (m_pFirst->GetKey() == key) {
92  Titem_& ret_item = *m_pFirst;
93  m_pFirst = m_pFirst->GetHashNext();
94  ret_item.SetHashNext(NULL);
95  return &ret_item;
96  }
97  /* find it in the following items */
98  Titem_ *pPrev = m_pFirst;
99  for (Titem_ *pItem = m_pFirst->GetHashNext(); pItem != NULL; pPrev = pItem, pItem = pItem->GetHashNext()) {
100  if (pItem->GetKey() == key) {
101  /* we have found the item, unlink and return it */
102  pPrev->SetHashNext(pItem->GetHashNext());
103  pItem->SetHashNext(NULL);
104  return pItem;
105  }
106  }
107  return NULL;
108  }
109 };
110 
133 template <class Titem_, int Thash_bits_>
134 class CHashTableT {
135 public:
136  typedef Titem_ Titem; // make Titem_ visible from outside of class
137  typedef typename Titem_::Key Tkey; // make Titem_::Key a property of HashTable
138  static const int Thash_bits = Thash_bits_; // publish num of hash bits
139  static const int Tcapacity = 1 << Thash_bits; // and num of slots 2^bits
140 
141 protected:
147 
148  Slot m_slots[Tcapacity]; // here we store our data (array of blobs)
149  int m_num_items; // item counter
150 
151 public:
152  /* default constructor */
153  inline CHashTableT() : m_num_items(0)
154  {
155  }
156 
157 protected:
159  inline static int CalcHash(const Tkey& key)
160  {
161  int32 hash = key.CalcHash();
162  if ((8 * Thash_bits) < 32) hash ^= hash >> (min(8 * Thash_bits, 31));
163  if ((4 * Thash_bits) < 32) hash ^= hash >> (min(4 * Thash_bits, 31));
164  if ((2 * Thash_bits) < 32) hash ^= hash >> (min(2 * Thash_bits, 31));
165  if ((1 * Thash_bits) < 32) hash ^= hash >> (min(1 * Thash_bits, 31));
166  hash &= (1 << Thash_bits) - 1;
167  return hash;
168  }
169 
171  inline static int CalcHash(const Titem_& item) {return CalcHash(item.GetKey());}
172 
173 public:
175  inline int Count() const {return m_num_items;}
176 
178  inline void Clear() {for (int i = 0; i < Tcapacity; i++) m_slots[i].Clear();}
179 
181  const Titem_ *Find(const Tkey& key) const
182  {
183  int hash = CalcHash(key);
184  const Slot& slot = m_slots[hash];
185  const Titem_ *item = slot.Find(key);
186  return item;
187  }
188 
190  Titem_ *Find(const Tkey& key)
191  {
192  int hash = CalcHash(key);
193  Slot& slot = m_slots[hash];
194  Titem_ *item = slot.Find(key);
195  return item;
196  }
197 
199  Titem_ *TryPop(const Tkey& key)
200  {
201  int hash = CalcHash(key);
202  Slot& slot = m_slots[hash];
203  Titem_ *item = slot.Detach(key);
204  if (item != NULL) {
205  m_num_items--;
206  }
207  return item;
208  }
209 
211  Titem_& Pop(const Tkey& key)
212  {
213  Titem_ *item = TryPop(key);
214  assert(item != NULL);
215  return *item;
216  }
217 
219  bool TryPop(Titem_& item)
220  {
221  const Tkey& key = item.GetKey();
222  int hash = CalcHash(key);
223  Slot& slot = m_slots[hash];
224  bool ret = slot.Detach(item);
225  if (ret) {
226  m_num_items--;
227  }
228  return ret;
229  }
230 
232  void Pop(Titem_& item)
233  {
234  bool ret = TryPop(item);
235  assert(ret);
236  }
237 
239  void Push(Titem_& new_item)
240  {
241  int hash = CalcHash(new_item);
242  Slot& slot = m_slots[hash];
243  assert(slot.Find(new_item.GetKey()) == NULL);
244  slot.Attach(new_item);
245  m_num_items++;
246  }
247 };
248 
249 #endif /* HASHTABLE_HPP */