OpenTTD
hashtable.hpp
Go to the documentation of this file.
1 /* $Id: hashtable.hpp 27363 2015-08-08 13:19:38Z alberth $ */
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()
28  {
29  m_pFirst = NULL;
30  }
31 
33  inline const Titem_ *Find(const Key &key) const
34  {
35  for (const Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) {
36  if (pItem->GetKey() == key) {
37  /* we have found the item, return it */
38  return pItem;
39  }
40  }
41  return NULL;
42  }
43 
45  inline Titem_ *Find(const Key &key)
46  {
47  for (Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) {
48  if (pItem->GetKey() == key) {
49  /* we have found the item, return it */
50  return pItem;
51  }
52  }
53  return NULL;
54  }
55 
57  inline void Attach(Titem_ &new_item)
58  {
59  assert(new_item.GetHashNext() == NULL);
60  new_item.SetHashNext(m_pFirst);
61  m_pFirst = &new_item;
62  }
63 
65  inline bool Detach(Titem_ &item_to_remove)
66  {
67  if (m_pFirst == &item_to_remove) {
68  m_pFirst = item_to_remove.GetHashNext();
69  item_to_remove.SetHashNext(NULL);
70  return true;
71  }
72  Titem_ *pItem = m_pFirst;
73  for (;;) {
74  if (pItem == NULL) {
75  return false;
76  }
77  Titem_ *pNextItem = pItem->GetHashNext();
78  if (pNextItem == &item_to_remove) break;
79  pItem = pNextItem;
80  }
81  pItem->SetHashNext(item_to_remove.GetHashNext());
82  item_to_remove.SetHashNext(NULL);
83  return true;
84  }
85 
87  inline Titem_ *Detach(const Key &key)
88  {
89  /* do we have any items? */
90  if (m_pFirst == NULL) {
91  return NULL;
92  }
93  /* is it our first item? */
94  if (m_pFirst->GetKey() == key) {
95  Titem_ &ret_item = *m_pFirst;
96  m_pFirst = m_pFirst->GetHashNext();
97  ret_item.SetHashNext(NULL);
98  return &ret_item;
99  }
100  /* find it in the following items */
101  Titem_ *pPrev = m_pFirst;
102  for (Titem_ *pItem = m_pFirst->GetHashNext(); pItem != NULL; pPrev = pItem, pItem = pItem->GetHashNext()) {
103  if (pItem->GetKey() == key) {
104  /* we have found the item, unlink and return it */
105  pPrev->SetHashNext(pItem->GetHashNext());
106  pItem->SetHashNext(NULL);
107  return pItem;
108  }
109  }
110  return NULL;
111  }
112 };
113 
136 template <class Titem_, int Thash_bits_>
137 class CHashTableT {
138 public:
139  typedef Titem_ Titem; // make Titem_ visible from outside of class
140  typedef typename Titem_::Key Tkey; // make Titem_::Key a property of HashTable
141  static const int Thash_bits = Thash_bits_; // publish num of hash bits
142  static const int Tcapacity = 1 << Thash_bits; // and num of slots 2^bits
143 
144 protected:
150 
151  Slot m_slots[Tcapacity]; // here we store our data (array of blobs)
152  int m_num_items; // item counter
153 
154 public:
155  /* default constructor */
156  inline CHashTableT() : m_num_items(0)
157  {
158  }
159 
160 protected:
162  inline static int CalcHash(const Tkey &key)
163  {
164  int32 hash = key.CalcHash();
165  if ((8 * Thash_bits) < 32) hash ^= hash >> (min(8 * Thash_bits, 31));
166  if ((4 * Thash_bits) < 32) hash ^= hash >> (min(4 * Thash_bits, 31));
167  if ((2 * Thash_bits) < 32) hash ^= hash >> (min(2 * Thash_bits, 31));
168  if ((1 * Thash_bits) < 32) hash ^= hash >> (min(1 * Thash_bits, 31));
169  hash &= (1 << Thash_bits) - 1;
170  return hash;
171  }
172 
174  inline static int CalcHash(const Titem_ &item)
175  {
176  return CalcHash(item.GetKey());
177  }
178 
179 public:
181  inline int Count() const
182  {
183  return m_num_items;
184  }
185 
187  inline void Clear()
188  {
189  for (int i = 0; i < Tcapacity; i++) m_slots[i].Clear();
190  }
191 
193  const Titem_ *Find(const Tkey &key) const
194  {
195  int hash = CalcHash(key);
196  const Slot &slot = m_slots[hash];
197  const Titem_ *item = slot.Find(key);
198  return item;
199  }
200 
202  Titem_ *Find(const Tkey &key)
203  {
204  int hash = CalcHash(key);
205  Slot &slot = m_slots[hash];
206  Titem_ *item = slot.Find(key);
207  return item;
208  }
209 
211  Titem_ *TryPop(const Tkey &key)
212  {
213  int hash = CalcHash(key);
214  Slot &slot = m_slots[hash];
215  Titem_ *item = slot.Detach(key);
216  if (item != NULL) {
217  m_num_items--;
218  }
219  return item;
220  }
221 
223  Titem_& Pop(const Tkey &key)
224  {
225  Titem_ *item = TryPop(key);
226  assert(item != NULL);
227  return *item;
228  }
229 
231  bool TryPop(Titem_ &item)
232  {
233  const Tkey &key = item.GetKey();
234  int hash = CalcHash(key);
235  Slot &slot = m_slots[hash];
236  bool ret = slot.Detach(item);
237  if (ret) {
238  m_num_items--;
239  }
240  return ret;
241  }
242 
244  void Pop(Titem_ &item)
245  {
246  bool ret = TryPop(item);
247  assert(ret);
248  }
249 
251  void Push(Titem_ &new_item)
252  {
253  int hash = CalcHash(new_item);
254  Slot &slot = m_slots[hash];
255  assert(slot.Find(new_item.GetKey()) == NULL);
256  slot.Attach(new_item);
257  m_num_items++;
258  }
259 };
260 
261 #endif /* HASHTABLE_HPP */