OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

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_>
18 struct CHashTableSlotT
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:
146 typedef CHashTableSlotT<Titem_> Slot;
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 */