CommonLibSSE (powerof3)
Loading...
Searching...
No Matches
BSTHashMap.h
Go to the documentation of this file.
1#pragma once
2
3#include "RE/B/BSTTuple.h"
4#include "RE/C/CRC.h"
6
7namespace RE
8{
9 namespace detail
10 {
11 static constexpr std::uint8_t BSTScatterTableSentinel[] = { 0xDEu, 0xADu, 0xBEu, 0xEFu };
12 }
13
14 // scatter table with chaining
15 template <
16 class Hash,
17 class KeyEqual,
18 class Traits,
19 template <std::size_t, std::size_t> class Allocator>
21 {
22 public:
23 using traits_type = Traits;
24 using key_type = typename Traits::key_type;
25 using mapped_type = typename Traits::mapped_type;
26 using value_type = typename Traits::value_type;
27 using size_type = std::uint32_t;
28 using difference_type = std::int32_t;
29 using hasher = Hash;
30 using key_equal = KeyEqual;
34 using const_pointer = const value_type*;
35
36 static_assert(std::is_invocable_r_v<size_type, const hasher&, const key_type&>);
37 static_assert(std::is_invocable_r_v<bool, const key_equal&, const key_type&, const key_type&>);
38
39 private:
40 struct entry_type
41 {
42 entry_type() = default;
43 entry_type(const entry_type&) = delete;
44
45 entry_type(entry_type&& a_rhs) //
46 noexcept(std::is_nothrow_move_constructible_v<value_type>&&
47 std::is_nothrow_destructible_v<value_type>)
48 {
49 if (a_rhs.has_value()) {
50 const auto rnext = a_rhs.next;
51 emplace(std::move(a_rhs).steal(), rnext);
52 }
53 }
54
55 ~entry_type() noexcept { destroy(); };
56
57 entry_type& operator=(const entry_type&) = delete;
58
59 entry_type& operator=(entry_type&& a_rhs) //
60 noexcept(std::is_nothrow_move_constructible_v<value_type>&&
61 std::is_nothrow_destructible_v<value_type>)
62 {
63 if (this != std::addressof(a_rhs)) {
64 destroy();
65 if (a_rhs.has_value()) {
66 const auto rnext = a_rhs.next;
67 emplace(std::move(a_rhs).steal(), rnext);
68 }
69 }
70 return *this;
71 }
72
73 [[nodiscard]] bool has_value() const noexcept { return next != nullptr; }
74
75 void destroy() //
76 noexcept(std::is_nothrow_destructible_v<value_type>)
77 {
78 if (has_value()) {
79 std::destroy_at(std::addressof(value));
80 next = nullptr;
81 }
82 assert(!has_value());
83 }
84
85 template <class Arg>
86 void emplace(Arg&& a_value, const entry_type* a_next) //
87 noexcept(std::is_nothrow_constructible_v<value_type, Arg>)
88 {
89 static_assert(std::same_as<std::decay_t<Arg>, value_type>);
90 destroy();
91 std::construct_at(std::addressof(value), std::forward<Arg>(a_value));
92 next = const_cast<entry_type*>(a_next);
93 assert(has_value());
94 }
95
96 [[nodiscard]] value_type steal() && //
97 noexcept(std::is_nothrow_move_constructible_v<value_type>&&
98 std::is_nothrow_destructible_v<value_type>)
99 {
100 assert(has_value());
101 value_type val = std::move(value);
102 destroy();
103 assert(!has_value());
104 return val;
105 }
106
107 union
108 {
109 value_type value;
110 std::byte buffer[sizeof(value_type)]{ static_cast<std::byte>(0) };
111 };
112 entry_type* next{ nullptr };
113 };
114
115 template <class U>
116 class iterator_base
117 {
118 public:
119 using difference_type = std::ptrdiff_t;
120 using value_type = std::remove_const_t<U>;
121 using pointer = value_type*;
122 using reference = value_type&;
123 using iterator_category = std::forward_iterator_tag;
124
125 iterator_base() = default;
126 ~iterator_base() = default;
127
128 iterator_base(const volatile iterator_base&) = delete;
129 iterator_base& operator=(const volatile iterator_base&) = delete;
130
131 template <class V>
132 iterator_base(const iterator_base<V>& a_rhs) noexcept //
133 requires(std::convertible_to<typename iterator_base<V>::reference, reference>)
134 :
135 _first(a_rhs._first),
136 _last(a_rhs._last)
137 {}
138
139 template <class V>
140 iterator_base& operator=(const iterator_base<V>& a_rhs) noexcept //
141 requires(std::convertible_to<typename iterator_base<V>::reference, reference>)
142 {
143 assert(_last == a_rhs._last);
144 _first = a_rhs._first;
145 _last = a_rhs._last;
146 return *this;
147 }
148
149 [[nodiscard]] reference operator*() const noexcept
150 {
151 assert(iterable());
152 assert(_first->has_value());
153 return _first->value;
154 }
155
156 template <class V>
157 [[nodiscard]] bool operator==(const iterator_base<V>& a_rhs) const noexcept
158 {
159 assert(_last == a_rhs._last);
160 return _first == a_rhs._first;
161 }
162
163 iterator_base& operator++() noexcept
164 {
165 seek();
166 return *this;
167 }
168
169 iterator_base operator++(int) noexcept
170 {
171 iterator_base result = *this;
172 ++result;
173 return result;
174 }
175
176 [[nodiscard]] pointer operator->() const noexcept
177 {
178 return &**this;
179 }
180
181 protected:
182 friend class BSTScatterTable;
183
184 iterator_base(entry_type* a_first, entry_type* a_last) noexcept :
185 _first(a_first),
186 _last(a_last)
187 {
188 assert(!!_first == !!_last); // both or neither have values
189 assert(_first <= _last);
190 if (iterable() && !_first->has_value()) {
191 seek();
192 }
193 }
194
195 [[nodiscard]] entry_type* get_entry() const noexcept { return _first; }
196
197 private:
198 template <class>
199 friend class iterator_base;
200
201 [[nodiscard]] bool iterable() const noexcept { return _first && _last && _first != _last; }
202
203 void seek() noexcept
204 {
205 assert(iterable());
206 do {
207 ++_first;
208 } while (_first != _last && !_first->has_value());
209 }
210
211 entry_type* _first{ nullptr };
212 entry_type* _last{ nullptr };
213 };
214
215 public:
216 using allocator_type = Allocator<sizeof(entry_type), alignof(entry_type)>;
217 using iterator = iterator_base<value_type>;
218 using const_iterator = iterator_base<const value_type>;
219
220 BSTScatterTable() = default;
221
222 BSTScatterTable(const BSTScatterTable& a_rhs) { insert(a_rhs.begin(), a_rhs.end()); }
223
224 BSTScatterTable(BSTScatterTable&& a_rhs) noexcept //
225 requires(std::same_as<typename allocator_type::propagate_on_container_move_assignment, std::true_type>)
226 :
227 _capacity(std::exchange(a_rhs._capacity, 0)),
228 _free(std::exchange(a_rhs._free, 0)),
229 _good(std::exchange(a_rhs._good, 0)),
230 _sentinel(a_rhs._sentinel),
231 _allocator(std::move(a_rhs._allocator))
232 {
233 assert(a_rhs.empty());
234 }
235
236 ~BSTScatterTable() { free_resources(); }
237
239 {
240 if (this != std::addressof(a_rhs)) {
241 clear();
242 insert(a_rhs.begin(), a_rhs.end());
243 }
244 return *this;
245 }
246
248 requires(std::same_as<typename allocator_type::propagate_on_container_move_assignment, std::true_type>)
249 {
250 if (this != std::addressof(a_rhs)) {
251 free_resources();
252
253 _capacity = std::exchange(a_rhs._capacity, 0);
254 _free = std::exchange(a_rhs._free, 0);
255 _good = std::exchange(a_rhs._good, 0);
256 _sentinel = a_rhs._sentinel;
257 _allocator = std::move(a_rhs._allocator);
258
259 assert(a_rhs.empty());
260 }
261 return *this;
262 }
263
264 [[nodiscard]] iterator begin() noexcept { return make_iterator<iterator>(get_entries()); }
265 [[nodiscard]] const_iterator begin() const noexcept { return make_iterator<const_iterator>(get_entries()); }
266 [[nodiscard]] const_iterator cbegin() const noexcept { return make_iterator<const_iterator>(get_entries()); }
267
268 [[nodiscard]] iterator end() noexcept { return make_iterator<iterator>(); }
269 [[nodiscard]] const_iterator end() const noexcept { return make_iterator<const_iterator>(); }
270 [[nodiscard]] const_iterator cend() const noexcept { return make_iterator<const_iterator>(); }
271
272 [[nodiscard]] bool empty() const noexcept { return size() == 0; }
273 [[nodiscard]] size_type size() const noexcept { return _capacity - _free; }
274
275 void clear()
276 {
277 if (size() > 0) {
278 const auto entries = get_entries();
279 assert(entries != nullptr);
280 for (size_type i = 0; i < _capacity; ++i) {
281 entries[i].destroy();
282 }
283 _free = _capacity;
284 _good = 0;
285 }
286
287 assert(empty());
288 }
289
290 std::pair<iterator, bool> insert(const value_type& a_value) { return do_insert(a_value); }
291 std::pair<iterator, bool> insert(value_type&& a_value) { return do_insert(std::move(a_value)); }
292
293 template <std::input_iterator InputIt>
294 void insert(InputIt a_first, InputIt a_last) //
295 requires(std::convertible_to<std::iter_reference_t<InputIt>, const_reference>)
296 {
297 reserve(size() + static_cast<size_type>(std::distance(a_first, a_last)));
298 for (; a_first != a_last; ++a_first) {
299 insert(*std::move(a_first));
300 }
301 }
302
303 template <class... Args>
304 std::pair<iterator, bool> emplace(Args&&... a_args) //
305 requires(std::constructible_from<value_type, Args...>)
306 {
307 return insert(value_type(std::forward<Args>(a_args)...));
308 }
309
310 iterator erase(const_iterator a_pos) { return do_erase(a_pos); }
311 iterator erase(iterator a_pos) { return do_erase(a_pos); }
312
314 {
315 const auto pos = find(a_key);
316 const auto result = pos != end() ? erase(pos) : pos;
317 return result != end() ? 1 : 0;
318 }
319
320 [[nodiscard]] iterator find(const key_type& a_key) { return do_find<iterator>(a_key); }
321 [[nodiscard]] const_iterator find(const key_type& a_key) const { return do_find<const_iterator>(a_key); }
322
323 [[nodiscard]] bool contains(const key_type& a_key) const { return find(a_key) != end(); }
324
325 void reserve(size_type a_count)
326 {
327 if (a_count <= _capacity) {
328 return;
329 }
330
331 const auto oldCap = _capacity;
332 const auto oldEntries = get_entries();
333
334 const auto [newCap, newEntries] = [&]() {
335 constexpr std::uint64_t min = allocator_type::min_size();
336 static_assert(min > 0 && std::has_single_bit(min));
337 const auto cap = std::max(std::bit_ceil<std::uint64_t>(a_count), min);
338 assert(cap >= min);
339 if (cap > 1u << 31) {
340 stl::report_and_fail("a buffer grew too large"sv);
341 }
342
343 const auto entries = allocate(static_cast<size_type>(cap));
344 if (!entries) {
345 stl::report_and_fail("failed to handle an allocation"sv);
346 }
347
348 return std::make_pair(static_cast<size_type>(cap), entries);
349 }();
350
351 const auto setCap = [&](size_type a_newCap) {
352 _capacity = a_newCap;
353 _free = _capacity;
354 _good = 0;
355 };
356
357 if (newEntries == oldEntries) {
358 std::uninitialized_default_construct_n(oldEntries + oldCap, newCap - oldCap);
359 std::vector<value_type> todo;
360 todo.reserve(size());
361 for (size_type i = 0; i < oldCap; ++i) {
362 auto& entry = oldEntries[i];
363 if (entry.has_value()) {
364 todo.emplace_back(std::move(entry).steal());
365 }
366 }
367 setCap(newCap);
368 insert(
369 std::make_move_iterator(todo.begin()),
370 std::make_move_iterator(todo.end()));
371 } else {
372 // in with the new
373 std::uninitialized_default_construct_n(newEntries, newCap);
374 setCap(newCap);
375 set_entries(newEntries);
376
377 if (oldEntries) { // out with the old
378 for (size_type i = 0; i < oldCap; ++i) {
379 auto& entry = oldEntries[i];
380 if (entry.has_value()) {
381 insert(std::move(entry).steal());
382 }
383 }
384 std::destroy_n(oldEntries, oldCap);
385 deallocate(oldEntries);
386 }
387 }
388 }
389
390 private:
391 [[nodiscard]] static const key_type& unwrap_key(const value_type& a_value) noexcept
392 {
393 return traits_type::unwrap_key(a_value);
394 }
395
396 [[nodiscard]] entry_type* allocate(size_type a_count)
397 {
398 return static_cast<entry_type*>(_allocator.allocate_bytes(sizeof(entry_type) * a_count));
399 }
400
401 void deallocate(entry_type* a_entry) { _allocator.deallocate_bytes(a_entry); }
402
403 [[nodiscard]] iterator do_erase(const_iterator a_pos)
404 {
405 assert(a_pos != end());
406 const auto entry = a_pos.get_entry();
407 assert(entry != nullptr);
408 assert(entry->has_value());
409
410 if (entry->next == _sentinel) { // end of chain
411 if (auto prev = &get_entry_for(unwrap_key(entry->value)); prev != entry) {
412 while (prev->next != entry) {
413 prev = prev->next;
414 }
415 prev->next = const_cast<entry_type*>(_sentinel); // detach from chain
416 }
417
418 entry->destroy();
419 } else { // move next into current
420 *entry = std::move(*entry->next);
421 }
422
423 ++_free;
424 return make_iterator<iterator>(entry + 1);
425 }
426
427 template <class Iter>
428 [[nodiscard]] Iter do_find(const key_type& a_key) const //
429 noexcept(noexcept(hash_function(a_key)) && noexcept(key_eq(a_key, a_key)))
430 {
431 if (empty()) {
432 return make_iterator<Iter>();
433 }
434
435 auto entry = &get_entry_for(a_key);
436 if (entry->has_value()) {
437 do { // follow chain
438 if (key_eq(unwrap_key(entry->value), a_key)) {
439 return make_iterator<Iter>(entry);
440 } else {
441 entry = entry->next;
442 }
443 } while (entry != _sentinel);
444 }
445
446 return make_iterator<Iter>();
447 }
448
449 template <class P>
450 [[nodiscard]] std::pair<iterator, bool> do_insert(P&& a_value) //
451 requires(std::same_as<std::decay_t<P>, value_type>)
452 {
453 if (const auto it = find(unwrap_key(a_value)); it != end()) { // already exists
454 return std::make_pair(it, false);
455 }
456
457 if (_free == 0) { // no free entries
458 reserve(_capacity + 1);
459 assert(_free > 0);
460 }
461
462 const stl::scope_exit decrement{ [&]() noexcept { --_free; } };
463 const auto entry = &get_entry_for(unwrap_key(a_value));
464 if (entry->has_value()) { // slot is taken, resolve conflict
465 const auto free = &get_free_entry();
466 const auto wouldve = &get_entry_for(unwrap_key(entry->value));
467 if (wouldve == entry) { // hash collision
468 free->emplace(std::forward<P>(a_value), std::exchange(entry->next, free));
469 return std::make_pair(make_iterator<iterator>(free), true);
470 } else { // how did we get here?
471 auto prev = wouldve;
472 while (prev->next != entry) {
473 prev = prev->next;
474 }
475
476 // evict current value and detach from chain
477 *free = std::move(*entry);
478 prev->next = free;
479 entry->emplace(std::forward<P>(a_value), _sentinel);
480
481 return std::make_pair(make_iterator<iterator>(entry), true);
482 }
483 } else { // its free realestate
484 entry->emplace(std::forward<P>(a_value), _sentinel);
485 return std::make_pair(make_iterator<iterator>(entry), true);
486 }
487 }
488
489 void free_resources()
490 {
491 if (_capacity > 0) {
492 assert(get_entries() != nullptr);
493 std::destroy_n(get_entries(), _capacity);
494 deallocate(get_entries());
495 set_entries(nullptr);
496 _capacity = 0;
497 _free = 0;
498 _good = 0;
499 }
500
501 assert(get_entries() == nullptr);
502 assert(_capacity == 0);
503 assert(_free == 0);
504 }
505
506 [[nodiscard]] entry_type& get_entry_for(const key_type& a_key) const //
507 noexcept(noexcept(hash_function(a_key)))
508 {
509 assert(get_entries() != nullptr);
510 assert(std::has_single_bit(_capacity));
511
512 const auto hash = hash_function(a_key);
513 const auto idx = hash & (_capacity - 1); // quick modulo
514 return get_entries()[idx];
515 }
516
517 [[nodiscard]] entry_type* get_entries() const noexcept { return static_cast<entry_type*>(_allocator.get_entries()); }
518
519 [[nodiscard]] entry_type& get_free_entry() noexcept
520 {
521 assert(_free > 0);
522 assert(get_entries() != nullptr);
523 assert(std::has_single_bit(_capacity));
524 assert([&]() noexcept {
525 const auto begin = get_entries();
526 const auto end = get_entries() + _capacity;
527 return std::find_if(
528 begin,
529 end,
530 [](const auto& a_entry) noexcept {
531 return !a_entry.has_value();
532 }) != end;
533 }());
534
535 const auto entries = get_entries();
536 while (entries[_good].has_value()) {
537 _good = (_good + 1) & (_capacity - 1); // wrap around w/ quick modulo
538 }
539 return entries[_good];
540 }
541
542 [[nodiscard]] size_type hash_function(const key_type& a_key) const //
543 noexcept(std::is_nothrow_constructible_v<hasher>&&
544 std::is_nothrow_invocable_v<const hasher&, const key_type&>)
545 {
546 return static_cast<size_type>(hasher()(a_key));
547 }
548
549 [[nodiscard]] bool key_eq(const key_type& a_lhs, const key_type& a_rhs) const //
550 noexcept(std::is_nothrow_constructible_v<key_equal>&&
551 std::is_nothrow_invocable_v<const key_equal&, const key_type&, const key_type&>)
552 {
553 return static_cast<bool>(key_equal()(a_lhs, a_rhs));
554 }
555
556 template <class Iter>
557 [[nodiscard]] Iter make_iterator() const noexcept
558 {
559 return Iter(get_entries() + _capacity, get_entries() + _capacity);
560 }
561
562 template <class Iter>
563 [[nodiscard]] Iter make_iterator(entry_type* a_first) const noexcept
564 {
565 return Iter(a_first, get_entries() + _capacity);
566 }
567
568 void set_entries(entry_type* a_entries) noexcept { _allocator.set_entries(a_entries); }
569
570 // members
571 std::uint64_t _pad00{ 0 }; // 00
572 std::uint32_t _pad08{ 0 }; // 08
573 size_type _capacity{ 0 }; // 0C - total # of slots, always a power of 2
574 size_type _free{ 0 }; // 10 - # of free slots
575 size_type _good{ 0 }; // 14 - last free index
576 const entry_type* _sentinel{ reinterpret_cast<const entry_type*>(detail::BSTScatterTableSentinel) }; // 18 - signals end of chain
577 allocator_type _allocator; // 20
578 };
579
580 template <class Key, class T>
582 {
583 public:
584 using key_type = Key;
585 using mapped_type = T;
587
588 [[nodiscard]] static const key_type& unwrap_key(const value_type& a_value) noexcept { return a_value.first; }
589 };
590
591 template <class Key>
593 {
594 public:
595 using key_type = Key;
596 using mapped_type = void;
598
599 [[nodiscard]] static const key_type& unwrap_key(const value_type& a_value) noexcept { return a_value; }
600 };
601
602 template <std::size_t S, std::size_t A>
604 {
605 public:
606 using size_type = std::uint32_t;
608
611
613 _entries(std::exchange(a_rhs._entries, nullptr))
614 {}
615
618
620 {
621 if (this != std::addressof(a_rhs)) {
622 assert(_entries == nullptr);
623 _entries = std::exchange(a_rhs._entries, nullptr);
624 }
625 return *this;
626 }
627
628 [[nodiscard]] static constexpr size_type min_size() noexcept { return 1u << 3; }
629
630 [[nodiscard]] void* allocate_bytes(std::size_t a_bytes)
631 {
632 assert(a_bytes % S == 0);
633 return malloc(a_bytes);
634 }
635
636 void deallocate_bytes(void* a_ptr) { free(a_ptr); }
637
638 [[nodiscard]] void* get_entries() const noexcept { return _entries; }
639 void set_entries(void* a_entries) noexcept { _entries = static_cast<std::byte*>(a_entries); }
640
641 private:
642 // members
643 std::uint64_t _pad00{ 0 }; // 00 (20)
644 std::byte* _entries{ nullptr }; // 08 (28)
645 };
646
647 template <std::uint32_t N>
649 {
650 public:
651 static_assert(N > 0 && std::has_single_bit(N));
652
653 template <std::size_t S, std::size_t A>
655 {
656 public:
657 using size_type = std::uint32_t;
659
660 Allocator() = default;
661 Allocator(const Allocator&) = delete;
662 Allocator(Allocator&&) = delete;
663 ~Allocator() = default;
664 Allocator& operator=(const Allocator&) = delete;
666
667 [[nodiscard]] static constexpr size_type min_size() noexcept { return N; }
668
669 [[nodiscard]] void* allocate_bytes(std::size_t a_bytes)
670 {
671 assert(a_bytes % S == 0);
672 return a_bytes <= N * S ? _buffer : nullptr;
673 }
674
675 void deallocate_bytes([[maybe_unused]] void* a_ptr) { assert(a_ptr == _buffer); }
676
677 [[nodiscard]] void* get_entries() const noexcept { return _entries; }
678
679 void set_entries(void* a_entries) noexcept
680 {
681 assert(a_entries == _buffer || a_entries == nullptr);
682 _entries = static_cast<std::byte*>(a_entries);
683 }
684
685 private:
686 alignas(A) std::byte _buffer[N * S]{ static_cast<std::byte>(0) }; // 00 (20)
687 std::byte* _entries{ nullptr }; // ??
688 };
689 };
690
691 template <std::size_t S, std::size_t A>
693 {
694 public:
695 using size_type = std::uint32_t;
697
704
705 [[nodiscard]] static constexpr size_type min_size() noexcept { return 1u << 3; }
706
707 [[nodiscard]] void* allocate_bytes(std::size_t a_bytes)
708 {
709 assert(_allocator != nullptr);
710 assert(a_bytes % S == 0);
711 return _allocator->Allocate(a_bytes, 0x10);
712 }
713
714 void deallocate_bytes(void* a_ptr)
715 {
716 assert(_allocator != nullptr);
717 _allocator->Deallocate(a_ptr);
718 }
719
720 [[nodiscard]] void* get_entries() const noexcept { return _entries; }
721 void set_entries(void* a_entries) noexcept { _entries = static_cast<std::byte*>(a_entries); }
722
723 private:
724 // members
725 ScrapHeap* _allocator{ MemoryManager::GetSingleton()->GetThreadScrapHeap() }; // 00 (20)
726 std::byte* _entries{ nullptr }; // 08 (28)
727 };
728
729 template <
730 class Key,
731 class T,
732 class Hash = BSCRC32<Key>,
733 class KeyEq = std::equal_to<Key>>
736 Hash,
737 KeyEq,
740
741 namespace detail
742 {
743 using _dummy_bsthashmap = BSTHashMap<int, int>;
744 static_assert(std::forward_iterator<_dummy_bsthashmap::iterator>);
745 }
746
747 template <
748 class Key,
749 class Hash = BSCRC32<Key>,
750 class KeyEq = std::equal_to<Key>>
751 using BSTSet =
753 Hash,
754 KeyEq,
757
758 template <
759 class Key,
760 class T,
761 std::uint32_t N,
762 class Hash = BSCRC32<Key>,
763 class KeyEq = std::equal_to<Key>>
766 Hash,
767 KeyEq,
770
771 template <
772 class Key,
773 class T,
774 class Hash = BSCRC32<Key>,
775 class KeyEq = std::equal_to<Key>>
778 Hash,
779 KeyEq,
782
783 using UnkKey = std::uintptr_t;
784 using UnkValue = std::uintptr_t;
785}
Definition BSTHashMap.h:693
BSTScatterTableScrapAllocator(const BSTScatterTableScrapAllocator &)=delete
void * allocate_bytes(std::size_t a_bytes)
Definition BSTHashMap.h:707
void deallocate_bytes(void *a_ptr)
Definition BSTHashMap.h:714
std::uint32_t size_type
Definition BSTHashMap.h:695
void * get_entries() const noexcept
Definition BSTHashMap.h:720
static constexpr size_type min_size() noexcept
Definition BSTHashMap.h:705
BSTScatterTableScrapAllocator(BSTScatterTableScrapAllocator &&)=delete
BSTScatterTableScrapAllocator & operator=(const BSTScatterTableScrapAllocator &)=delete
std::false_type propagate_on_container_move_assignment
Definition BSTHashMap.h:696
void set_entries(void *a_entries) noexcept
Definition BSTHashMap.h:721
BSTScatterTableScrapAllocator & operator=(BSTScatterTableScrapAllocator &&)=delete
Definition BSTHashMap.h:582
static const key_type & unwrap_key(const value_type &a_value) noexcept
Definition BSTHashMap.h:588
Key key_type
Definition BSTHashMap.h:584
T mapped_type
Definition BSTHashMap.h:585
Definition BSTHashMap.h:21
const value_type & const_reference
Definition BSTHashMap.h:32
typename Traits::mapped_type mapped_type
Definition BSTHashMap.h:25
std::pair< iterator, bool > emplace(Args &&... a_args)
Definition BSTHashMap.h:304
std::uint32_t size_type
Definition BSTHashMap.h:27
KeyEqual key_equal
Definition BSTHashMap.h:30
void insert(InputIt a_first, InputIt a_last)
Definition BSTHashMap.h:294
std::pair< iterator, bool > insert(value_type &&a_value)
Definition BSTHashMap.h:291
iterator end() noexcept
Definition BSTHashMap.h:268
void reserve(size_type a_count)
Definition BSTHashMap.h:325
const_iterator end() const noexcept
Definition BSTHashMap.h:269
iterator begin() noexcept
Definition BSTHashMap.h:264
BSTScatterTable(BSTScatterTable &&a_rhs) noexcept
Definition BSTHashMap.h:224
~BSTScatterTable()
Definition BSTHashMap.h:236
void clear()
Definition BSTHashMap.h:275
value_type & reference
Definition BSTHashMap.h:31
const_iterator cbegin() const noexcept
Definition BSTHashMap.h:266
std::int32_t difference_type
Definition BSTHashMap.h:28
size_type size() const noexcept
Definition BSTHashMap.h:273
Hash hasher
Definition BSTHashMap.h:29
BSTScatterTable & operator=(const BSTScatterTable &a_rhs)
Definition BSTHashMap.h:238
typename Traits::key_type key_type
Definition BSTHashMap.h:24
iterator erase(const_iterator a_pos)
Definition BSTHashMap.h:310
const_iterator begin() const noexcept
Definition BSTHashMap.h:265
iterator_base< value_type > iterator
Definition BSTHashMap.h:217
Allocator< sizeof(entry_type), alignof(entry_type)> allocator_type
Definition BSTHashMap.h:216
const_iterator find(const key_type &a_key) const
Definition BSTHashMap.h:321
const_iterator cend() const noexcept
Definition BSTHashMap.h:270
value_type * pointer
Definition BSTHashMap.h:33
BSTScatterTable()=default
const value_type * const_pointer
Definition BSTHashMap.h:34
BSTScatterTable(const BSTScatterTable &a_rhs)
Definition BSTHashMap.h:222
Traits traits_type
Definition BSTHashMap.h:23
iterator_base< const value_type > const_iterator
Definition BSTHashMap.h:218
BSTScatterTable & operator=(BSTScatterTable &&a_rhs)
Definition BSTHashMap.h:247
typename Traits::value_type value_type
Definition BSTHashMap.h:26
bool contains(const key_type &a_key) const
Definition BSTHashMap.h:323
std::pair< iterator, bool > insert(const value_type &a_value)
Definition BSTHashMap.h:290
iterator erase(iterator a_pos)
Definition BSTHashMap.h:311
size_type erase(const key_type &a_key)
Definition BSTHashMap.h:313
bool empty() const noexcept
Definition BSTHashMap.h:272
iterator find(const key_type &a_key)
Definition BSTHashMap.h:320
Definition BSTHashMap.h:593
static const key_type & unwrap_key(const value_type &a_value) noexcept
Definition BSTHashMap.h:599
key_type value_type
Definition BSTHashMap.h:597
Key key_type
Definition BSTHashMap.h:595
void mapped_type
Definition BSTHashMap.h:596
static MemoryManager * GetSingleton()
Definition MemoryManager.h:29
ScrapHeap * GetThreadScrapHeap()
Definition MemoryManager.h:50
Definition ScrapHeap.h:10
void * Allocate(std::size_t a_size, std::size_t a_alignment)
void Deallocate(void *a_mem)
Definition PCH.h:155
static constexpr std::uint8_t BSTScatterTableSentinel[]
Definition BSTHashMap.h:11
Definition AbsorbEffect.h:6
std::uintptr_t UnkValue
Definition BSTHashMap.h:784
T * malloc()
Definition MemoryManager.h:113
constexpr bool operator==(const BSTSmartPointer< T1 > &a_lhs, const BSTSmartPointer< T2 > &a_rhs)
Definition BSTSmartPointer.h:241
void free(void *a_ptr)
Definition MemoryManager.h:187
std::uintptr_t UnkKey
Definition BSTHashMap.h:783
void report_and_fail(std::string_view a_msg, std::source_location a_loc=std::source_location::current())
Definition PCH.h:397
Definition EffectArchetypes.h:65
Definition CRC.h:104
Definition BSTHashMap.h:604
void * get_entries() const noexcept
Definition BSTHashMap.h:638
void * allocate_bytes(std::size_t a_bytes)
Definition BSTHashMap.h:630
BSTScatterTableHeapAllocator & operator=(const BSTScatterTableHeapAllocator &)=delete
std::true_type propagate_on_container_move_assignment
Definition BSTHashMap.h:607
BSTScatterTableHeapAllocator & operator=(BSTScatterTableHeapAllocator &&a_rhs) noexcept
Definition BSTHashMap.h:619
BSTScatterTableHeapAllocator(BSTScatterTableHeapAllocator &&a_rhs) noexcept
Definition BSTHashMap.h:612
BSTScatterTableHeapAllocator(const BSTScatterTableHeapAllocator &)=delete
void deallocate_bytes(void *a_ptr)
Definition BSTHashMap.h:636
static constexpr size_type min_size() noexcept
Definition BSTHashMap.h:628
void set_entries(void *a_entries) noexcept
Definition BSTHashMap.h:639
std::uint32_t size_type
Definition BSTHashMap.h:606
Definition BSTHashMap.h:655
Allocator(const Allocator &)=delete
std::false_type propagate_on_container_move_assignment
Definition BSTHashMap.h:658
void * get_entries() const noexcept
Definition BSTHashMap.h:677
Allocator & operator=(Allocator &&)=delete
static constexpr size_type min_size() noexcept
Definition BSTHashMap.h:667
Allocator & operator=(const Allocator &)=delete
void deallocate_bytes(void *a_ptr)
Definition BSTHashMap.h:675
void set_entries(void *a_entries) noexcept
Definition BSTHashMap.h:679
std::uint32_t size_type
Definition BSTHashMap.h:657
void * allocate_bytes(std::size_t a_bytes)
Definition BSTHashMap.h:669
Definition BSTHashMap.h:649
Definition BSTTuple.h:9