CommonLibSSE NG
Loading...
Searching...
No Matches
GHashSetBase.h
Go to the documentation of this file.
1#pragma once
2
3#include "RE/G/GAllocator.h"
6#include "RE/G/GMath.h"
7#include "RE/G/GMemory.h"
8
9namespace RE
10{
11 template <
12 class C,
13 class HashF = GFixedSizeHash<C>,
14 class AltHashF = HashF,
15 class Allocator = GAllocatorGH<C>,
16 class Entry = GHashsetCachedEntry<C, HashF>>
18 {
19 public:
21
23 {
24 public:
26 hash(nullptr),
27 index(0)
28 {}
29
30 const C& operator*() const
31 {
32 assert(index >= 0 && index <= (SPInt)hash->table->sizeMask);
33 return hash->E(index).value;
34 }
35
36 const C* operator->() const
37 {
38 assert(index >= 0 && index <= (SPInt)hash->table->sizeMask);
39 return &hash->E(index).value;
40 }
41
43 {
44 if (index <= (SPInt)hash->table->sizeMask) {
45 ++index;
46 while ((UPInt)index <= hash->table->sizeMask && hash->E(index).IsEmpty()) {
47 ++index;
48 }
49 }
50 }
51
52 bool operator==(const const_iterator& a_it) const
53 {
54 if (IsEnd() && a_it.IsEnd()) {
55 return true;
56 } else {
57 return (hash == a_it.hash) && (index == a_it.index);
58 }
59 }
60
61 bool operator!=(const const_iterator& a_it) const
62 {
63 return !(*this == a_it);
64 }
65
66 [[nodiscard]] bool IsEnd() const
67 {
68 return (!hash) || (!hash->table) || (index > (SPInt)hash->table->sizeMask);
69 }
70
71 protected:
72 friend class GHashSetBase<C, HashF, AltHashF, Allocator, Entry>;
73
74 const_iterator(const SelfType* a_hash, SPInt a_index) :
75 hash(a_hash),
76 index(a_index)
77 {}
78
79 const SelfType* hash; // 00
80 SPInt index; // 08
81 };
82 static_assert(sizeof(const_iterator) == 0x10);
83
84 friend struct const_iterator;
85
86 struct iterator : public const_iterator
87 {
88 public:
90 const_iterator(nullptr, 0)
91 {}
92
93 C& operator*() const
94 {
95 assert(const_iterator::index >= 0 && const_iterator::index <= (SPInt)const_iterator::hash->table->sizeMask);
96 return const_cast<SelfType*>(const_iterator::hash)->E(const_iterator::index).value;
97 }
98
99 C* operator->() const
100 {
101 return &(operator*());
102 }
103
104 void Remove()
105 {
106 SelfType* theHash = const_cast<SelfType*>(const_iterator::hash);
107 Entry* ee = &theHash->E(const_iterator::index);
108 const C& key = ee->value;
109
110 UPInt hashValue = AltHashF()(key);
111 SPInt index = hashValue & hash->table->sizeMask;
112
113 Entry* entry = &hash->E(index);
114
115 if (entry->IsEmpty() || (entry->GetCachedHash(hash->table->sizeMask) != (UPInt)index)) {
116 return;
117 }
118
119 SPInt naturalIndex = index;
120 SPInt prevIndex = -1;
121
122 while ((entry->GetCachedHash(hash->table->sizeMask) != (UPInt)naturalIndex) || !(entry->value == key)) {
123 prevIndex = index;
124 index = entry->nextInChain;
125 if (index == -1) {
126 return;
127 }
128 entry = &hash->E(index);
129 }
130
131 if (index == (SPInt)const_iterator::index) {
132 if (naturalIndex == index) {
133 if (!entry->IsEndOfChain()) {
134 Entry* nextEntry = &hash->E(entry->nextInChain);
135 entry->Clear();
136 new (entry) Entry(*nextEntry);
137 entry = nextEntry;
139 }
140 } else {
141 hash->E(prevIndex).nextInChain = entry->nextInChain;
142 }
143
144 entry->Clear();
145 --(hash->table->entryCount);
146 } else {
147 assert(false);
148 }
149 }
150
151 private:
152 friend class GHashSetBase<C, HashF, AltHashF, Allocator, Entry>;
153
154 using base = const_iterator;
155 using base::hash;
156 using base::index;
157
158 iterator(SelfType* a_hash, SPInt a_idx) :
159 const_iterator(a_hash, a_idx)
160 {}
161 };
162
163 friend struct iterator;
164
166 table(nullptr)
167 {}
168
169 GHashSetBase(std::int32_t a_sizeHint) :
170 table(0)
171 {
172 SetCapacity(this, a_sizeHint);
173 }
174
175 explicit GHashSetBase([[maybe_unused]] void* a_memAddr) :
176 table(0)
177 {}
178
179 GHashSetBase(void* a_memAddr, std::int32_t a_sizeHint) :
180 table(0)
181 {
182 SetCapacity(a_memAddr, a_sizeHint);
183 }
184
185 GHashSetBase(const SelfType& a_src) :
186 table(0)
187 {
188 Assign(this, a_src);
189 }
190
192 {
193 if (table) {
194 // Delete the entries.
195 for (UPInt i = 0, n = table->sizeMask; i <= n; i++) {
196 Entry* entry = std::addressof(E(i));
197 if (!entry->IsEmpty()) {
198 entry->Free();
199 }
200 }
201
202 Allocator::Free(table);
203 table = nullptr;
204 }
205 }
206
208
209 void Assign(void* a_memAddr, const SelfType& a_src)
210 {
211 Clear();
212 if (a_src.IsEmpty() == false) {
213 SetCapacity(a_memAddr, a_src.GetSize());
214 for (const_iterator it = a_src.Begin(); it != a_src.End(); ++it) {
215 Add(a_memAddr, *it);
216 }
217 }
218 }
219
220 void Clear()
221 {
222 if (table) {
223 for (UPInt i = 0, n = table->sizeMask; i <= n; i++) {
224 Entry* entry = std::addressof(E(i));
225 if (!entry->IsEmpty()) {
226 entry->Clear();
227 }
228 }
229
230 Allocator::Free(table);
231 table = nullptr;
232 }
233 }
234
235 [[nodiscard]] bool IsEmpty() const
236 {
237 return !table || table->entryCount == 0;
238 }
239
240 template <class CRef>
241 void Set(void* a_memAddr, const CRef& a_key)
242 {
243 UPInt hashValue = HashF()(a_key);
244 SPInt index = static_cast<SPInt>(-1);
245
246 if (table) {
247 index = FindIndexCore(a_key, hashValue & table->sizeMask);
248 }
249
250 if (index >= 0) {
251 E(index).value = a_key;
252 } else {
253 Add(a_memAddr, a_key, hashValue);
254 }
255 }
256
257 template <class CRef>
258 inline void Add(void* a_memAddr, const CRef& a_key)
259 {
260 const UPInt hashValue = HashF()(a_key);
261 Add(a_memAddr, a_key, hashValue);
262 }
263
264 template <class K>
265 void RemoveAlt(const K& a_key)
266 {
267 if (!table) {
268 return;
269 }
270
271 const UPInt hashValue = AltHashF()(a_key);
272 SPInt index = hashValue & table->sizeMask;
273
274 Entry* entry = std::addressof(E(index));
275
276 if (entry->IsEmpty() || (entry->GetCachedHash(table->sizeMask) != (UPInt)index)) {
277 return;
278 }
279
280 // Save index
281 const SPInt naturalIndex = index;
282 SPInt prevIndex = -1;
283
284 while ((entry->GetCachedHash(table->sizeMask) != (UPInt)naturalIndex) || !(entry->value == a_key)) {
285 prevIndex = index;
286 index = entry->nextInChain;
287 if (index == -1) {
288 return;
289 }
290 entry = std::addressof(E(index));
291 }
292
293 if (naturalIndex == index) {
294 if (!entry->IsEndOfChain()) {
295 Entry* nextEntry = std::addressof(E(entry->nextInChain));
296 entry->Clear();
297 new (entry) Entry(*nextEntry);
298 entry = nextEntry;
299 }
300 } else {
301 E(prevIndex).nextInChain = entry->nextInChain;
302 }
303
304 entry->Clear();
305 --(table->entryCount);
306 }
307
308 template <class CRef>
309 void Remove(const CRef& a_key)
310 {
311 RemoveAlt(a_key);
312 }
313
314 template <class K>
315 C* Get(const K& a_key)
316 {
317 const SPInt index = FindIndex(a_key);
318 if (index >= 0) {
319 return std::addressof(E(index).value);
320 } else {
321 return 0;
322 }
323 }
324
325 template <class K>
326 const C* Get(const K& key) const
327 {
328 const SPInt index = FindIndex(key);
329 if (index >= 0) {
330 return std::addressof(E(index).value);
331 } else {
332 return 0;
333 }
334 }
335
336 template <class K>
337 C* GetAlt(const K& a_key)
338 {
339 const SPInt index = FindIndexAlt(a_key);
340 if (index >= 0)
341 return std::addressof(E(index).value);
342 return nullptr;
343 }
344
345 template <class K>
346 const C* GetAlt(const K& a_key) const
347 {
348 const SPInt index = FindIndexAlt(a_key);
349 if (index >= 0) {
350 return std::addressof(E(index).value);
351 } else {
352 return nullptr;
353 }
354 }
355
356 template <class K>
357 bool GetAlt(const K& a_key, C* a_val) const
358 {
359 const SPInt index = FindIndexAlt(a_key);
360 if (index >= 0) {
361 if (a_val) {
362 *a_val = E(index).value;
363 }
364 return true;
365 } else {
366 return false;
367 }
368 }
369
370 [[nodiscard]] UPInt GetSize() const
371 {
372 return table ? 0 : (UPInt)table->entryCount;
373 }
374
375 void CheckExpand(void* a_memAddr)
376 {
377 if (!table) {
378 SetRawCapacity(a_memAddr, HashMinSize);
379 } else if (table->entryCount * 5 > (table->sizeMask + 1) * 4) {
380 SetRawCapacity(a_memAddr, (table->sizeMask + 1) * 2);
381 }
382 }
383
384 void Resize(void* a_memAddr, UPInt a_count)
385 {
386 SetCapacity(a_memAddr, a_count);
387 }
388
389 void SetCapacity(void* a_memAddr, UPInt a_newSize)
390 {
391 UPInt newRawSize = (a_newSize * 5) / 4;
392 if (newRawSize <= GetSize()) {
393 return;
394 }
395 SetRawCapacity(a_memAddr, newRawSize);
396 }
397
399 {
400 if (table == 0) {
401 return iterator(0, 0);
402 }
403
404 UPInt idx = 0;
405 while (idx <= table->sizeMask && E(idx).IsEmpty()) {
406 ++idx;
407 }
408 return iterator(this, idx);
409 }
410
412 {
413 return iterator(0, 0);
414 }
415
417 {
418 return const_cast<SelfType*>(this)->begin();
419 }
420
422 {
423 return const_cast<SelfType*>(this)->end();
424 }
425
426 template <class K>
427 iterator Find(const K& a_key)
428 {
429 SPInt index = FindIndex(a_key);
430 if (index >= 0) {
431 return iterator(this, index);
432 }
433 return iterator(0, 0);
434 }
435
436 template <class K>
437 iterator FindAlt(const K& a_key)
438 {
439 SPInt index = FindIndexAlt(a_key);
440 if (index >= 0) {
441 return iterator(this, index);
442 }
443 return iterator(0, 0);
444 }
445
446 template <class K>
447 const_iterator Find(const K& a_key) const
448 {
449 return const_cast<SelfType*>(this)->Find(a_key);
450 }
451
452 template <class K>
453 const_iterator FindAlt(const K& a_key) const
454 {
455 return const_cast<SelfType*>(this)->FindAlt(a_key);
456 }
457
458 private:
459 enum
460 {
461 HashMinSize = 8
462 };
463
464 struct TableType
465 {
466 UPInt entryCount; // 00
467 UPInt sizeMask; // 08
468 //Entry entries[0]; // 10
469 };
470 static_assert(sizeof(TableType) == 0x10);
471
472 template <class K>
473 SPInt FindIndex(const K& a_key) const
474 {
475 if (!table) {
476 return -1;
477 }
478 UPInt hashValue = HashF()(a_key) & table->sizeMask;
479 return FindIndexCore(a_key, hashValue);
480 }
481
482 template <class K>
483 SPInt FindIndexAlt(const K& a_key) const
484 {
485 if (!table) {
486 return -1;
487 }
488 const UPInt hashValue = AltHashF()(a_key) & table->sizeMask;
489 return FindIndexCore(a_key, hashValue);
490 }
491
492 template <class K>
493 SPInt FindIndexCore(const K& a_key, UPInt a_hashValue) const
494 {
495 assert(table);
496 assert((a_hashValue & ~table->sizeMask) == 0);
497
498 UPInt index = a_hashValue;
499 const Entry* entry = std::addressof(E(index));
500
501 if (entry->IsEmpty() || (entry->GetCachedHash(table->sizeMask) != index)) {
502 return -1;
503 }
504
505 for (;;) {
506 assert(entry->GetCachedHash(table->sizeMask) == a_hashValue);
507 if (entry->GetCachedHash(table->sizeMask) == a_hashValue && entry->value == a_key) {
508 return index;
509 }
510 assert(!(entry->value == a_key));
511
512 index = entry->nextInChain;
513 if (index == (UPInt)-1) {
514 break;
515 }
516
517 entry = std::addressof(E(index));
518 assert(!entry->IsEmpty());
519 }
520 return -1;
521 }
522
523 template <class CRef>
524 void Add(void* a_memAddr, const CRef& a_key, UPInt a_hashValue)
525 {
526 CheckExpand(a_memAddr);
527 a_hashValue &= table->sizeMask;
528
529 ++(table->entryCount);
530
531 const SPInt index = a_hashValue;
532 Entry* naturalEntry = &(E(index));
533
534 if (naturalEntry->IsEmpty()) {
535 new (naturalEntry) Entry(a_key, -1);
536 } else {
537 SPInt blankIndex = index;
538 do {
539 blankIndex = (blankIndex + 1) & table->sizeMask;
540 } while (!E(blankIndex).IsEmpty());
541
542 Entry* blankEntry = std::addressof(E(blankIndex));
543
544 if (naturalEntry->GetCachedHash(table->sizeMask) == (UPInt)index) {
545 new (blankEntry) Entry(*naturalEntry);
546 naturalEntry->value = a_key;
547 naturalEntry->nextInChain = blankIndex;
548 } else {
549 SPInt collidedIndex = naturalEntry->GetCachedHash(table->sizeMask);
550 assert(collidedIndex >= 0 && collidedIndex <= (SPInt)table->sizeMask);
551 for (;;) {
552 Entry* entry = std::addressof(E(collidedIndex));
553 if (entry->nextInChain == index) {
554 new (blankEntry) Entry(*naturalEntry);
555 entry->nextInChain = blankIndex;
556 break;
557 }
558 collidedIndex = entry->nextInChain;
559 assert(collidedIndex >= 0 && collidedIndex <= (SPInt)table->sizeMask);
560 }
561
562 naturalEntry->value = a_key;
563 naturalEntry->nextInChain = -1;
564 }
565 }
566
567 naturalEntry->SetCachedHash(a_hashValue);
568 }
569
570 Entry& E(UPInt a_index)
571 {
572 assert(a_index <= table->sizeMask);
573 return *(((Entry*)(table + 1)) + a_index);
574 }
575
576 const Entry& E(UPInt a_index) const
577 {
578 assert(a_index <= table->sizeMask);
579 return *(((Entry*)(table + 1)) + a_index);
580 }
581
582 void SetRawCapacity(void* a_heapAddr, UPInt a_newSize)
583 {
584 if (a_newSize == 0) {
585 Clear();
586 return;
587 }
588
589 if (a_newSize < HashMinSize) {
590 a_newSize = HashMinSize;
591 } else {
592 const auto bits = gfchop(glog2f((float)(a_newSize - 1)) + 1);
593 a_newSize = UPInt(1) << bits;
594 }
595
596 SelfType newHash;
597 newHash.table = static_cast<TableType*>(Allocator::Alloc(a_heapAddr, sizeof(TableType) + sizeof(Entry) * a_newSize));
598 assert(newHash.table);
599
600 newHash.table->entryCount = 0;
601 newHash.table->sizeMask = a_newSize - 1;
602 UPInt i;
603 UPInt n;
604
605 for (i = 0; i < a_newSize; i++) {
606 newHash.E(i).nextInChain = -2;
607 }
608
609 if (table) {
610 for (i = 0, n = table->sizeMask; i <= n; ++i) {
611 Entry* entry = std::addressof(E(i));
612 if (entry->IsEmpty() == false) {
613 newHash.Add(a_heapAddr, entry->value);
614 entry->Clear();
615 }
616 }
617 Allocator::Free(table);
618 }
619
620 // Steal newHash's data.
621 table = newHash.table;
622 newHash.table = nullptr;
623 }
624
625 // members
626 TableType* table; // 00
627 };
628 // size == 0x8
629}
Definition GHashSetBase.h:18
iterator begin()
Definition GHashSetBase.h:398
const_iterator Find(const K &a_key) const
Definition GHashSetBase.h:447
GHashSetBase(std::int32_t a_sizeHint)
Definition GHashSetBase.h:169
GHashSetBase(void *a_memAddr, std::int32_t a_sizeHint)
Definition GHashSetBase.h:179
bool IsEmpty() const
Definition GHashSetBase.h:235
iterator FindAlt(const K &a_key)
Definition GHashSetBase.h:437
void Set(void *a_memAddr, const CRef &a_key)
Definition GHashSetBase.h:241
const_iterator begin() const
Definition GHashSetBase.h:416
~GHashSetBase()
Definition GHashSetBase.h:191
void Remove(const CRef &a_key)
Definition GHashSetBase.h:309
iterator Find(const K &a_key)
Definition GHashSetBase.h:427
C * GetAlt(const K &a_key)
Definition GHashSetBase.h:337
GHashSetBase(void *a_memAddr)
Definition GHashSetBase.h:175
void Resize(void *a_memAddr, UPInt a_count)
Definition GHashSetBase.h:384
UPInt GetSize() const
Definition GHashSetBase.h:370
const C * GetAlt(const K &a_key) const
Definition GHashSetBase.h:346
iterator end()
Definition GHashSetBase.h:411
void SetCapacity(void *a_memAddr, UPInt a_newSize)
Definition GHashSetBase.h:389
void Clear()
Definition GHashSetBase.h:220
C * Get(const K &a_key)
Definition GHashSetBase.h:315
GHashSetBase< C, HashF, AltHashF, Allocator, Entry > SelfType
Definition GHashSetBase.h:20
void RemoveAlt(const K &a_key)
Definition GHashSetBase.h:265
bool GetAlt(const K &a_key, C *a_val) const
Definition GHashSetBase.h:357
GFC_MEMORY_REDEFINE_NEW(GHashSetBase, Allocator::kStatID)
void Assign(void *a_memAddr, const SelfType &a_src)
Definition GHashSetBase.h:209
void Add(void *a_memAddr, const CRef &a_key)
Definition GHashSetBase.h:258
const_iterator end() const
Definition GHashSetBase.h:421
GHashSetBase(const SelfType &a_src)
Definition GHashSetBase.h:185
const_iterator FindAlt(const K &a_key) const
Definition GHashSetBase.h:453
GHashSetBase()
Definition GHashSetBase.h:165
void CheckExpand(void *a_memAddr)
Definition GHashSetBase.h:375
const C * Get(const K &key) const
Definition GHashSetBase.h:326
Definition AbsorbEffect.h:6
constexpr std::int32_t gfchop(float a_val)
Definition GMath.h:7
std::size_t UPInt
Definition SFTypes.h:5
std::ptrdiff_t SPInt
Definition SFTypes.h:8
float glog2f(float a_val)
Definition GMath.h:12
Definition GHashSetBase.h:23
const_iterator()
Definition GHashSetBase.h:25
void operator++()
Definition GHashSetBase.h:42
const_iterator(const SelfType *a_hash, SPInt a_index)
Definition GHashSetBase.h:74
const C * operator->() const
Definition GHashSetBase.h:36
bool IsEnd() const
Definition GHashSetBase.h:66
const SelfType * hash
Definition GHashSetBase.h:79
SPInt index
Definition GHashSetBase.h:80
bool operator==(const const_iterator &a_it) const
Definition GHashSetBase.h:52
const C & operator*() const
Definition GHashSetBase.h:30
bool operator!=(const const_iterator &a_it) const
Definition GHashSetBase.h:61
Definition GHashSetBase.h:87
iterator()
Definition GHashSetBase.h:89
C * operator->() const
Definition GHashSetBase.h:99
C & operator*() const
Definition GHashSetBase.h:93
void Remove()
Definition GHashSetBase.h:104