OpenTTD Source 20260218-master-g2123fca5ea
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#ifndef HASHTABLE_HPP
11#define HASHTABLE_HPP
12
13template <class TItem>
15 typedef typename TItem::Key Key; // make Titem::Key a property of HashTable
16
17 TItem *first_item = nullptr;
18
20 inline void Clear()
21 {
22 this->first_item = nullptr;
23 }
24
30 inline const TItem *Find(const Key &key) const
31 {
32 for (const TItem *item = this->first_item; item != nullptr; item = item->GetHashNext()) {
33 if (item->GetKey() == key) {
34 /* we have found the item, return it */
35 return item;
36 }
37 }
38 return nullptr;
39 }
40
46 inline TItem *Find(const Key &key)
47 {
48 for (TItem *item = this->first_item; item != nullptr; item = item->GetHashNext()) {
49 if (item->GetKey() == key) {
50 /* we have found the item, return it */
51 return item;
52 }
53 }
54 return nullptr;
55 }
56
61 inline void Attach(TItem &new_item)
62 {
63 assert(new_item.GetHashNext() == nullptr);
64 new_item.SetHashNext(this->first_item);
65 this->first_item = &new_item;
66 }
67
73 inline bool Detach(TItem &item_to_remove)
74 {
75 if (this->first_item == &item_to_remove) {
76 this->first_item = item_to_remove.GetHashNext();
77 item_to_remove.SetHashNext(nullptr);
78 return true;
79 }
80 TItem *item = this->first_item;
81 for (;;) {
82 if (item == nullptr) {
83 return false;
84 }
85 TItem *next_item = item->GetHashNext();
86 if (next_item == &item_to_remove) break;
87 item = next_item;
88 }
89 item->SetHashNext(item_to_remove.GetHashNext());
90 item_to_remove.SetHashNext(nullptr);
91 return true;
92 }
93
99 inline TItem *Detach(const Key &key)
100 {
101 /* do we have any items? */
102 if (this->first_item == nullptr) {
103 return nullptr;
104 }
105 /* is it our first item? */
106 if (this->first_item->GetKey() == key) {
107 TItem &ret_item = *this->first_item;
108 this->first_item = this->first_item->GetHashNext();
109 ret_item.SetHashNext(nullptr);
110 return &ret_item;
111 }
112 /* find it in the following items */
113 TItem *previous_item = this->first_item;
114 for (TItem *item = this->first_item->GetHashNext(); item != nullptr; previous_item = item, item = item->GetHashNext()) {
115 if (item->GetKey() == key) {
116 /* we have found the item, unlink and return it */
117 previous_item->SetHashNext(item->GetHashNext());
118 item->SetHashNext(nullptr);
119 return item;
120 }
121 }
122 return nullptr;
123 }
124};
125
148template <class Titem, int Thash_bits_>
150public:
151 typedef typename Titem::Key Tkey; // make Titem::Key a property of HashTable
152 static constexpr int HASH_BITS = Thash_bits_; // publish num of hash bits
153 static constexpr int CAPACITY = 1 << HASH_BITS; // and num of slots 2^bits
154
155protected:
161
162 Slot slots[CAPACITY];
164
170 static inline int CalcHash(const Tkey &key)
171 {
172 uint32_t hash = key.CalcHash();
173 hash -= (hash >> 17); // hash * 131071 / 131072
174 hash -= (hash >> 5); // * 31 / 32
175 hash &= (1 << HASH_BITS) - 1; // modulo slots
176 return hash;
177 }
178
184 static inline int CalcHash(const Titem &item)
185 {
186 return CalcHash(item.GetKey());
187 }
188
189public:
194 inline int Count() const
195 {
196 return this->number_of_items;
197 }
198
200 inline void Clear()
201 {
202 for (int i = 0; i < CAPACITY; i++) this->slots[i].Clear();
203 this->number_of_items = 0;
204 }
205
211 const Titem *Find(const Tkey &key) const
212 {
213 int hash = CalcHash(key);
214 const Slot &slot = this->slots[hash];
215 const Titem *item = slot.Find(key);
216 return item;
217 }
218
224 Titem *Find(const Tkey &key)
225 {
226 int hash = CalcHash(key);
227 Slot &slot = this->slots[hash];
228 Titem *item = slot.Find(key);
229 return item;
230 }
231
237 Titem *TryPop(const Tkey &key)
238 {
239 int hash = CalcHash(key);
240 Slot &slot = this->slots[hash];
241 Titem *item = slot.Detach(key);
242 if (item != nullptr) {
243 this->number_of_items--;
244 }
245 return item;
246 }
247
253 Titem &Pop(const Tkey &key)
254 {
255 Titem *item = TryPop(key);
256 assert(item != nullptr);
257 return *item;
258 }
259
265 bool TryPop(Titem &item)
266 {
267 const Tkey &key = item.GetKey();
268 int hash = CalcHash(key);
269 Slot &slot = this->slots[hash];
270 bool ret = slot.Detach(item);
271 if (ret) {
272 this->number_of_items--;
273 }
274 return ret;
275 }
276
281 void Pop(Titem &item)
282 {
283 [[maybe_unused]] bool ret = TryPop(item);
284 assert(ret);
285 }
286
291 void Push(Titem &new_item)
292 {
293 int hash = CalcHash(new_item);
294 Slot &slot = this->slots[hash];
295 assert(slot.Find(new_item.GetKey()) == nullptr);
296 slot.Attach(new_item);
297 this->number_of_items++;
298 }
299};
300
301#endif /* HASHTABLE_HPP */
class HashTable<Titem, HASH_BITS> - simple hash table of pointers allocated elsewhere.
Titem * TryPop(const Tkey &key)
Remove an item by key if found.
void Push(Titem &new_item)
Add an item that may not exist.
const Titem * Find(const Tkey &key) const
Try to find an item by key.
Titem * Find(const Tkey &key)
Try to find an item by key.
int Count() const
Get the number of elements.
void Clear()
Clear all items.
Titem & Pop(const Tkey &key)
Remove an item by key that must exist.
Slot slots[CAPACITY]
Data storage (array of blobs).
static int CalcHash(const Titem &item)
Return hash for the given item modulo number of slots.
bool TryPop(Titem &item)
Remove an item if found.
int number_of_items
Item counter.
HashTableSlot< Titem > Slot
each slot contains pointer to the first item in the list, Titem contains pointer to the next item - G...
static int CalcHash(const Tkey &key)
Return hash for the given key modulo number of slots.
void Pop(Titem &item)
Remove an item that must exist.
TItem * Find(const Key &key)
Linear search for item with given key through the given blob.
Definition hashtable.hpp:46
bool Detach(TItem &item_to_remove)
Remove item from a slot.
Definition hashtable.hpp:73
const TItem * Find(const Key &key) const
Linear search for item with given key through the given blob.
Definition hashtable.hpp:30
void Attach(TItem &new_item)
Add new item to the slot.
Definition hashtable.hpp:61
TItem * Detach(const Key &key)
Remove and return item from a slot.
Definition hashtable.hpp:99
void Clear()
Clears the slot by simple forgetting its items.
Definition hashtable.hpp:20