OpenTTD Source: src/misc/hashtable.hpp Source File

OpenTTD Source 13.1

hashtable.hpp
Go to the documentation of this file.
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
7
10 #ifndef HASHTABLE_HPP
11 #define HASHTABLE_HPP
12
13 #include "../core/math_func.hpp"
14
15 template <class Titem_>
16 struct CHashTableSlotT
17 {
18 typedef typename Titem_::Key Key; // make Titem_::Key a property of HashTable
19
20 Titem_ *m_pFirst;
21
22 inline CHashTableSlotT() : m_pFirst(nullptr) {}
23
25 inline void Clear()
26 {
27 m_pFirst = nullptr;
28 }
29
31 inline const Titem_ *Find(const Key &key) const
32 {
33 for (const Titem_ *pItem = m_pFirst; pItem != nullptr; pItem = pItem->GetHashNext()) {
34 if (pItem->GetKey() == key) {
35 /* we have found the item, return it */
36 return pItem;
37 }
38 }
39 return nullptr;
40 }
41
43 inline Titem_ *Find(const Key &key)
44 {
45 for (Titem_ *pItem = m_pFirst; pItem != nullptr; pItem = pItem->GetHashNext()) {
46 if (pItem->GetKey() == key) {
47 /* we have found the item, return it */
48 return pItem;
49 }
50 }
51 return nullptr;
52 }
53
55 inline void Attach(Titem_ &new_item)
56 {
57 assert(new_item.GetHashNext() == nullptr);
58 new_item.SetHashNext(m_pFirst);
59 m_pFirst = &new_item;
60 }
61
63 inline bool Detach(Titem_ &item_to_remove)
64 {
65 if (m_pFirst == &item_to_remove) {
66 m_pFirst = item_to_remove.GetHashNext();
67 item_to_remove.SetHashNext(nullptr);
68 return true;
69 }
70 Titem_ *pItem = m_pFirst;
71 for (;;) {
72 if (pItem == nullptr) {
73 return false;
74 }
75 Titem_ *pNextItem = pItem->GetHashNext();
76 if (pNextItem == &item_to_remove) break;
77 pItem = pNextItem;
78 }
79 pItem->SetHashNext(item_to_remove.GetHashNext());
80 item_to_remove.SetHashNext(nullptr);
81 return true;
82 }
83
85 inline Titem_ *Detach(const Key &key)
86 {
87 /* do we have any items? */
88 if (m_pFirst == nullptr) {
89 return nullptr;
90 }
91 /* is it our first item? */
92 if (m_pFirst->GetKey() == key) {
93 Titem_ &ret_item = *m_pFirst;
94 m_pFirst = m_pFirst->GetHashNext();
95 ret_item.SetHashNext(nullptr);
96 return &ret_item;
97 }
98 /* find it in the following items */
99 Titem_ *pPrev = m_pFirst;
100 for (Titem_ *pItem = m_pFirst->GetHashNext(); pItem != nullptr; pPrev = pItem, pItem = pItem->GetHashNext()) {
101 if (pItem->GetKey() == key) {
102 /* we have found the item, unlink and return it */
103 pPrev->SetHashNext(pItem->GetHashNext());
104 pItem->SetHashNext(nullptr);
105 return pItem;
106 }
107 }
108 return nullptr;
109 }
110 };
111
134 template <class Titem_, int Thash_bits_>
135 class CHashTableT {
136 public:
137 typedef Titem_ Titem; // make Titem_ visible from outside of class
138 typedef typename Titem_::Key Tkey; // make Titem_::Key a property of HashTable
139 static const int Thash_bits = Thash_bits_; // publish num of hash bits
140 static const int Tcapacity = 1 << Thash_bits; // and num of slots 2^bits
141
142 protected:
147 typedef CHashTableSlotT<Titem_> Slot;
148
149 Slot m_slots[Tcapacity]; // here we store our data (array of blobs)
150 int m_num_items; // item counter
151
152 public:
153 /* default constructor */
154 inline CHashTableT() : m_num_items(0)
155 {
156 }
157
158 protected:
160 inline static int CalcHash(const Tkey &key)
161 {
162 uint32 hash = key.CalcHash();
163 hash -= (hash >> 17); // hash * 131071 / 131072
164 hash -= (hash >> 5); // * 31 / 32
165 hash &= (1 << Thash_bits) - 1; // modulo slots
166 return hash;
167 }
168
170 inline static int CalcHash(const Titem_ &item)
171 {
172 return CalcHash(item.GetKey());
173 }
174
175 public:
177 inline int Count() const
178 {
179 return m_num_items;
180 }
181
183 inline void Clear()
184 {
185 for (int i = 0; i < Tcapacity; i++) m_slots[i].Clear();
186 }
187
189 const Titem_ *Find(const Tkey &key) const
190 {
191 int hash = CalcHash(key);
192 const Slot &slot = m_slots[hash];
193 const Titem_ *item = slot.Find(key);
194 return item;
195 }
196
198 Titem_ *Find(const Tkey &key)
199 {
200 int hash = CalcHash(key);
201 Slot &slot = m_slots[hash];
202 Titem_ *item = slot.Find(key);
203 return item;
204 }
205
207 Titem_ *TryPop(const Tkey &key)
208 {
209 int hash = CalcHash(key);
210 Slot &slot = m_slots[hash];
211 Titem_ *item = slot.Detach(key);
212 if (item != nullptr) {
213 m_num_items--;
214 }
215 return item;
216 }
217
219 Titem_& Pop(const Tkey &key)
220 {
221 Titem_ *item = TryPop(key);
222 assert(item != nullptr);
223 return *item;
224 }
225
227 bool TryPop(Titem_ &item)
228 {
229 const Tkey &key = item.GetKey();
230 int hash = CalcHash(key);
231 Slot &slot = m_slots[hash];
232 bool ret = slot.Detach(item);
233 if (ret) {
234 m_num_items--;
235 }
236 return ret;
237 }
238
240 void Pop(Titem_ &item)
241 {
242 [[maybe_unused]] bool ret = TryPop(item);
243 assert(ret);
244 }
245
247 void Push(Titem_ &new_item)
248 {
249 int hash = CalcHash(new_item);
250 Slot &slot = m_slots[hash];
251 assert(slot.Find(new_item.GetKey()) == nullptr);
252 slot.Attach(new_item);
253 m_num_items++;
254 }
255 };
256
257 #endif /* HASHTABLE_HPP */
CHashTableSlotT::Detach
bool Detach(Titem_ &item_to_remove)
hash table slot helper - remove item from a slot
Definition: hashtable.hpp:63
CHashTableSlotT::Clear
void Clear()
hash table slot helper - clears the slot by simple forgetting its items
Definition: hashtable.hpp:25
CHashTableT::Slot
CHashTableSlotT< Titem_ > Slot
each slot contains pointer to the first item in the list, Titem contains pointer to the next item - G...
Definition: hashtable.hpp:147
CHashTableT::Pop
Titem_ & Pop(const Tkey &key)
non-const item search & removal
Definition: hashtable.hpp:219
CHashTableSlotT
Definition: hashtable.hpp:16
CHashTableT::CalcHash
static int CalcHash(const Tkey &key)
static helper - return hash for the given key modulo number of slots
Definition: hashtable.hpp:160
CHashTableSlotT::Attach
void Attach(Titem_ &new_item)
hash table slot helper - add new item to the slot
Definition: hashtable.hpp:55
CHashTableT::Find
const Titem_ * Find(const Tkey &key) const
const item search
Definition: hashtable.hpp:189
CHashTableT::TryPop
bool TryPop(Titem_ &item)
non-const item search & optional removal (if found)
Definition: hashtable.hpp:227
CHashTableT::Pop
void Pop(Titem_ &item)
non-const item search & removal
Definition: hashtable.hpp:240
CHashTableT::Count
int Count() const
item count
Definition: hashtable.hpp:177
CHashTableT::Clear
void Clear()
simple clear - forget all items - used by CSegmentCostCacheT.Flush()
Definition: hashtable.hpp:183
CHashTableT::TryPop
Titem_ * TryPop(const Tkey &key)
non-const item search & optional removal (if found)
Definition: hashtable.hpp:207
CHashTableT::CalcHash
static int CalcHash(const Titem_ &item)
static helper - return hash for the given item modulo number of slots
Definition: hashtable.hpp:170
CHashTableSlotT::Find
const Titem_ * Find(const Key &key) const
hash table slot helper - linear search for item with given key through the given blob - const version
Definition: hashtable.hpp:31
CHashTableSlotT::Find
Titem_ * Find(const Key &key)
hash table slot helper - linear search for item with given key through the given blob - non-const ver...
Definition: hashtable.hpp:43
CHashTableT::Find
Titem_ * Find(const Tkey &key)
non-const item search
Definition: hashtable.hpp:198
CHashTableT::Push
void Push(Titem_ &new_item)
add one item - copy it from the given item
Definition: hashtable.hpp:247
CHashTableT
class CHashTableT<Titem, Thash_bits> - simple hash table of pointers allocated elsewhere.
Definition: hashtable.hpp:135
CHashTableSlotT::Detach
Titem_ * Detach(const Key &key)
hash table slot helper - remove and return item from a slot
Definition: hashtable.hpp:85