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

OpenTTD Source 15.0-RC2

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
10#ifndef HASHTABLE_HPP
11#define HASHTABLE_HPP
12
13template <class TItem>
14 struct HashTableSlot
15{
16 typedef typename TItem::Key Key; // make Titem::Key a property of HashTable
17
18 TItem *first_item = nullptr;
19
21 inline void Clear()
22 {
23 this->first_item = nullptr;
24 }
25
27 inline const TItem *Find(const Key &key) const
28 {
29 for (const TItem *item = this->first_item; item != nullptr; item = item->GetHashNext()) {
30 if (item->GetKey() == key) {
31 /* we have found the item, return it */
32 return item;
33 }
34 }
35 return nullptr;
36 }
37
39 inline TItem *Find(const Key &key)
40 {
41 for (TItem *item = this->first_item; item != nullptr; item = item->GetHashNext()) {
42 if (item->GetKey() == key) {
43 /* we have found the item, return it */
44 return item;
45 }
46 }
47 return nullptr;
48 }
49
51 inline void Attach(TItem &new_item)
52 {
53 assert(new_item.GetHashNext() == nullptr);
54 new_item.SetHashNext(this->first_item);
55 this->first_item = &new_item;
56 }
57
59 inline bool Detach(TItem &item_to_remove)
60 {
61 if (this->first_item == &item_to_remove) {
62 this->first_item = item_to_remove.GetHashNext();
63 item_to_remove.SetHashNext(nullptr);
64 return true;
65 }
66 TItem *item = this->first_item;
67 for (;;) {
68 if (item == nullptr) {
69 return false;
70 }
71 TItem *next_item = item->GetHashNext();
72 if (next_item == &item_to_remove) break;
73 item = next_item;
74 }
75 item->SetHashNext(item_to_remove.GetHashNext());
76 item_to_remove.SetHashNext(nullptr);
77 return true;
78 }
79
81 inline TItem *Detach(const Key &key)
82 {
83 /* do we have any items? */
84 if (this->first_item == nullptr) {
85 return nullptr;
86 }
87 /* is it our first item? */
88 if (this->first_item->GetKey() == key) {
89 TItem &ret_item = *this->first_item;
90 this->first_item = this->first_item->GetHashNext();
91 ret_item.SetHashNext(nullptr);
92 return &ret_item;
93 }
94 /* find it in the following items */
95 TItem *previous_item = this->first_item;
96 for (TItem *item = this->first_item->GetHashNext(); item != nullptr; previous_item = item, item = item->GetHashNext()) {
97 if (item->GetKey() == key) {
98 /* we have found the item, unlink and return it */
99 previous_item->SetHashNext(item->GetHashNext());
100 item->SetHashNext(nullptr);
101 return item;
102 }
103 }
104 return nullptr;
105 }
106};
107
130template <class Titem, int Thash_bits_>
131 class HashTable {
132public:
133 typedef typename Titem::Key Tkey; // make Titem::Key a property of HashTable
134 static constexpr int HASH_BITS = Thash_bits_; // publish num of hash bits
135 static constexpr int CAPACITY = 1 << HASH_BITS; // and num of slots 2^bits
136
137protected:
142 typedef HashTableSlot<Titem> Slot;
143
144 Slot slots[CAPACITY]; // here we store our data (array of blobs)
145 int number_of_items = 0; // item counter
146
148 static inline int CalcHash(const Tkey &key)
149 {
150 uint32_t hash = key.CalcHash();
151 hash -= (hash >> 17); // hash * 131071 / 131072
152 hash -= (hash >> 5); // * 31 / 32
153 hash &= (1 << HASH_BITS) - 1; // modulo slots
154 return hash;
155 }
156
158 static inline int CalcHash(const Titem &item)
159 {
160 return CalcHash(item.GetKey());
161 }
162
163public:
165 inline int Count() const
166 {
167 return this->number_of_items;
168 }
169
171 inline void Clear()
172 {
173 for (int i = 0; i < CAPACITY; i++) this->slots[i].Clear();
174 this->number_of_items = 0;
175 }
176
178 const Titem *Find(const Tkey &key) const
179 {
180 int hash = CalcHash(key);
181 const Slot &slot = this->slots[hash];
182 const Titem *item = slot.Find(key);
183 return item;
184 }
185
187 Titem *Find(const Tkey &key)
188 {
189 int hash = CalcHash(key);
190 Slot &slot = this->slots[hash];
191 Titem *item = slot.Find(key);
192 return item;
193 }
194
196 Titem *TryPop(const Tkey &key)
197 {
198 int hash = CalcHash(key);
199 Slot &slot = this->slots[hash];
200 Titem *item = slot.Detach(key);
201 if (item != nullptr) {
202 this->number_of_items--;
203 }
204 return item;
205 }
206
208 Titem &Pop(const Tkey &key)
209 {
210 Titem *item = TryPop(key);
211 assert(item != nullptr);
212 return *item;
213 }
214
216 bool TryPop(Titem &item)
217 {
218 const Tkey &key = item.GetKey();
219 int hash = CalcHash(key);
220 Slot &slot = this->slots[hash];
221 bool ret = slot.Detach(item);
222 if (ret) {
223 this->number_of_items--;
224 }
225 return ret;
226 }
227
229 void Pop(Titem &item)
230 {
231 [[maybe_unused]] bool ret = TryPop(item);
232 assert(ret);
233 }
234
236 void Push(Titem &new_item)
237 {
238 int hash = CalcHash(new_item);
239 Slot &slot = this->slots[hash];
240 assert(slot.Find(new_item.GetKey()) == nullptr);
241 slot.Attach(new_item);
242 this->number_of_items++;
243 }
244};
245
246#endif /* HASHTABLE_HPP */
HashTable
class HashTable<Titem, HASH_BITS> - simple hash table of pointers allocated elsewhere.
Definition hashtable.hpp:131
HashTable::TryPop
Titem * TryPop(const Tkey &key)
non-const item search & optional removal (if found)
Definition hashtable.hpp:196
HashTable::Push
void Push(Titem &new_item)
add one item - copy it from the given item
Definition hashtable.hpp:236
HashTable::Find
const Titem * Find(const Tkey &key) const
const item search
Definition hashtable.hpp:178
HashTable::Find
Titem * Find(const Tkey &key)
non-const item search
Definition hashtable.hpp:187
HashTable::Count
int Count() const
item count
Definition hashtable.hpp:165
HashTable::Clear
void Clear()
simple clear - forget all items - used by CSegmentCostCacheT.Flush()
Definition hashtable.hpp:171
HashTable::Pop
Titem & Pop(const Tkey &key)
non-const item search & removal
Definition hashtable.hpp:208
HashTable::CalcHash
static int CalcHash(const Titem &item)
static helper - return hash for the given item modulo number of slots
Definition hashtable.hpp:158
HashTable::Slot
HashTableSlot< Titem > Slot
each slot contains pointer to the first item in the list, Titem contains pointer to the next item - G...
Definition hashtable.hpp:142
HashTable::TryPop
bool TryPop(Titem &item)
non-const item search & optional removal (if found)
Definition hashtable.hpp:216
HashTable::CalcHash
static int CalcHash(const Tkey &key)
static helper - return hash for the given key modulo number of slots
Definition hashtable.hpp:148
HashTable::Pop
void Pop(Titem &item)
non-const item search & removal
Definition hashtable.hpp:229
HashTableSlot
Definition hashtable.hpp:15
HashTableSlot::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:39
HashTableSlot::Detach
bool Detach(TItem &item_to_remove)
hash table slot helper - remove item from a slot
Definition hashtable.hpp:59
HashTableSlot::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:27
HashTableSlot::Attach
void Attach(TItem &new_item)
hash table slot helper - add new item to the slot
Definition hashtable.hpp:51
HashTableSlot::Detach
TItem * Detach(const Key &key)
hash table slot helper - remove and return item from a slot
Definition hashtable.hpp:81
HashTableSlot::Clear
void Clear()
hash table slot helper - clears the slot by simple forgetting its items
Definition hashtable.hpp:21