CommonLibVR
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 _first(a_rhs._first),
135 _last(a_rhs._last)
136 {}
137
138 template <class V>
139 iterator_base& operator=(const iterator_base<V>& a_rhs) noexcept //
140 requires(std::convertible_to<typename iterator_base<V>::reference, reference>)
141 {
142 assert(_last == a_rhs._last);
143 _first = a_rhs._first;
144 _last = a_rhs._last;
145 return *this;
146 }
147
148 [[nodiscard]] reference operator*() const noexcept
149 {
150 assert(iterable());
151 assert(_first->has_value());
152 return _first->value;
153 }
154
155 template <class V>
156 [[nodiscard]] bool operator==(const iterator_base<V>& a_rhs) const noexcept
157 {
158 assert(_last == a_rhs._last);
159 return _first == a_rhs._first;
160 }
161
162 iterator_base& operator++() noexcept
163 {
164 seek();
165 return *this;
166 }
167
168 iterator_base operator++(int) noexcept
169 {
170 iterator_base result = *this;
171 ++result;
172 return result;
173 }
174
175 [[nodiscard]] pointer operator->() const noexcept
176 {
177 return &**this;
178 }
179
180 protected:
181 friend class BSTScatterTable;
182
183 iterator_base(entry_type* a_first, entry_type* a_last) noexcept :
184 _first(a_first),
185 _last(a_last)
186 {
187 assert(!!_first == !!_last); // both or neither have values
188 assert(_first <= _last);
189 if (iterable() && !_first->has_value()) {
190 seek();
191 }
192 }
193
194 [[nodiscard]] entry_type* get_entry() const noexcept { return _first; }
195
196 private:
197 template <class>
198 friend class iterator_base;
199
200 [[nodiscard]] bool iterable() const noexcept { return _first && _last && _first != _last; }
201
202 void seek() noexcept
203 {
204 assert(iterable());
205 do {
206 ++_first;
207 } while (_first != _last && !_first->has_value());
208 }
209
210 entry_type* _first{ nullptr };
211 entry_type* _last{ nullptr };
212 };
213
214 public:
215 using allocator_type = Allocator<sizeof(entry_type), alignof(entry_type)>;
216 using iterator = iterator_base<value_type>;
217 using const_iterator = iterator_base<const value_type>;
218
219 BSTScatterTable() = default;
220
221 BSTScatterTable(const BSTScatterTable& a_rhs) { insert(a_rhs.begin(), a_rhs.end()); }
222
223 BSTScatterTable(BSTScatterTable&& a_rhs) noexcept //
224 requires(std::same_as<typename allocator_type::propagate_on_container_move_assignment, std::true_type>) :
225 _capacity(std::exchange(a_rhs._capacity, 0)),
226 _free(std::exchange(a_rhs._free, 0)),
227 _good(std::exchange(a_rhs._good, 0)),
228 _sentinel(a_rhs._sentinel),
229 _allocator(std::move(a_rhs._allocator))
230 {
231 assert(a_rhs.empty());
232 }
233
234 ~BSTScatterTable() { free_resources(); }
235
237 {
238 if (this != std::addressof(a_rhs)) {
239 clear();
240 insert(a_rhs.begin(), a_rhs.end());
241 }
242 return *this;
243 }
244
246 requires(std::same_as<typename allocator_type::propagate_on_container_move_assignment, std::true_type>)
247 {
248 if (this != std::addressof(a_rhs)) {
249 free_resources();
250
251 _capacity = std::exchange(a_rhs._capacity, 0);
252 _free = std::exchange(a_rhs._free, 0);
253 _good = std::exchange(a_rhs._good, 0);
254 _sentinel = a_rhs._sentinel;
255 _allocator = std::move(a_rhs._allocator);
256
257 assert(a_rhs.empty());
258 }
259 return *this;
260 }
261
262 [[nodiscard]] iterator begin() noexcept { return make_iterator<iterator>(get_entries()); }
263 [[nodiscard]] const_iterator begin() const noexcept { return make_iterator<const_iterator>(get_entries()); }
264 [[nodiscard]] const_iterator cbegin() const noexcept { return make_iterator<const_iterator>(get_entries()); }
265
266 [[nodiscard]] iterator end() noexcept { return make_iterator<iterator>(); }
267 [[nodiscard]] const_iterator end() const noexcept { return make_iterator<const_iterator>(); }
268 [[nodiscard]] const_iterator cend() const noexcept { return make_iterator<const_iterator>(); }
269
270 [[nodiscard]] bool empty() const noexcept { return size() == 0; }
271 [[nodiscard]] size_type size() const noexcept { return _capacity - _free; }
272
273 void clear()
274 {
275 if (size() > 0) {
276 const auto entries = get_entries();
277 assert(entries != nullptr);
278 for (size_type i = 0; i < _capacity; ++i) {
279 entries[i].destroy();
280 }
281 _free = _capacity;
282 _good = 0;
283 }
284
285 assert(empty());
286 }
287
288 std::pair<iterator, bool> insert(const value_type& a_value) { return do_insert(a_value); }
289 std::pair<iterator, bool> insert(value_type&& a_value) { return do_insert(std::move(a_value)); }
290
291 template <std::input_iterator InputIt>
292 void insert(InputIt a_first, InputIt a_last) //
293 requires(std::convertible_to<std::iter_reference_t<InputIt>, const_reference>)
294 {
295 reserve(size() + static_cast<size_type>(std::distance(a_first, a_last)));
296 for (; a_first != a_last; ++a_first) {
297 insert(*std::move(a_first));
298 }
299 }
300
301 template <class... Args>
302 std::pair<iterator, bool> emplace(Args&&... a_args) //
303 requires(std::constructible_from<value_type, Args...>)
304 {
305 return insert(value_type(std::forward<Args>(a_args)...));
306 }
307
308 iterator erase(const_iterator a_pos) { return do_erase(a_pos); }
309 iterator erase(iterator a_pos) { return do_erase(a_pos); }
310
312 {
313 const auto pos = find(a_key);
314 const auto result = pos != end() ? erase(pos) : pos;
315 return result != end() ? 1 : 0;
316 }
317
318 [[nodiscard]] iterator find(const key_type& a_key) { return do_find<iterator>(a_key); }
319 [[nodiscard]] const_iterator find(const key_type& a_key) const { return do_find<const_iterator>(a_key); }
320
321 [[nodiscard]] bool contains(const key_type& a_key) const { return find(a_key) != end(); }
322
323 void reserve(size_type a_count)
324 {
325 if (a_count <= _capacity) {
326 return;
327 }
328
329 const auto oldCap = _capacity;
330 const auto oldEntries = get_entries();
331
332 const auto [newCap, newEntries] = [&]() {
333 constexpr std::uint64_t min = allocator_type::min_size();
334 static_assert(min > 0 && std::has_single_bit(min));
335 const auto cap = std::max(std::bit_ceil<std::uint64_t>(a_count), min);
336 assert(cap >= min);
337 if (cap > 1u << 31) {
338 stl::report_and_fail("a buffer grew too large"sv);
339 }
340
341 const auto entries = allocate(static_cast<size_type>(cap));
342 if (!entries) {
343 stl::report_and_fail("failed to handle an allocation"sv);
344 }
345
346 return std::make_pair(static_cast<size_type>(cap), entries);
347 }();
348
349 const auto setCap = [&](size_type a_newCap) {
350 _capacity = a_newCap;
351 _free = _capacity;
352 _good = 0;
353 };
354
355 if (newEntries == oldEntries) {
356 std::uninitialized_default_construct_n(oldEntries + oldCap, newCap - oldCap);
357 std::vector<value_type> todo;
358 todo.reserve(size());
359 for (size_type i = 0; i < oldCap; ++i) {
360 auto& entry = oldEntries[i];
361 if (entry.has_value()) {
362 todo.emplace_back(std::move(entry).steal());
363 }
364 }
365 setCap(newCap);
366 insert(
367 std::make_move_iterator(todo.begin()),
368 std::make_move_iterator(todo.end()));
369 } else {
370 // in with the new
371 std::uninitialized_default_construct_n(newEntries, newCap);
372 setCap(newCap);
373 set_entries(newEntries);
374
375 if (oldEntries) { // out with the old
376 for (size_type i = 0; i < oldCap; ++i) {
377 auto& entry = oldEntries[i];
378 if (entry.has_value()) {
379 insert(std::move(entry).steal());
380 }
381 }
382 std::destroy_n(oldEntries, oldCap);
383 deallocate(oldEntries);
384 }
385 }
386 }
387
388 private:
389 [[nodiscard]] static const key_type& unwrap_key(const value_type& a_value) noexcept
390 {
391 return traits_type::unwrap_key(a_value);
392 }
393
394 [[nodiscard]] entry_type* allocate(size_type a_count)
395 {
396 return static_cast<entry_type*>(_allocator.allocate_bytes(sizeof(entry_type) * a_count));
397 }
398
399 void deallocate(entry_type* a_entry) { _allocator.deallocate_bytes(a_entry); }
400
401 [[nodiscard]] iterator do_erase(const_iterator a_pos)
402 {
403 assert(a_pos != end());
404 const auto entry = a_pos.get_entry();
405 assert(entry != nullptr);
406 assert(entry->has_value());
407
408 if (entry->next == _sentinel) { // end of chain
409 if (auto prev = &get_entry_for(unwrap_key(entry->value)); prev != entry) {
410 while (prev->next != entry) {
411 prev = prev->next;
412 }
413 prev->next = const_cast<entry_type*>(_sentinel); // detach from chain
414 }
415
416 entry->destroy();
417 } else { // move next into current
418 *entry = std::move(*entry->next);
419 }
420
421 ++_free;
422 return make_iterator<iterator>(entry + 1);
423 }
424
425 template <class Iter>
426 [[nodiscard]] Iter do_find(const key_type& a_key) const //
427 noexcept(noexcept(hash_function(a_key)) && noexcept(key_eq(a_key, a_key)))
428 {
429 if (empty()) {
430 return make_iterator<Iter>();
431 }
432
433 auto entry = &get_entry_for(a_key);
434 if (entry->has_value()) {
435 do { // follow chain
436 if (key_eq(unwrap_key(entry->value), a_key)) {
437 return make_iterator<Iter>(entry);
438 } else {
439 entry = entry->next;
440 }
441 } while (entry != _sentinel);
442 }
443
444 return make_iterator<Iter>();
445 }
446
447 template <class P>
448 [[nodiscard]] std::pair<iterator, bool> do_insert(P&& a_value) //
449 requires(std::same_as<std::decay_t<P>, value_type>)
450 {
451 if (const auto it = find(unwrap_key(a_value)); it != end()) { // already exists
452 return std::make_pair(it, false);
453 }
454
455 if (_free == 0) { // no free entries
456 reserve(_capacity + 1);
457 assert(_free > 0);
458 }
459
460 const stl::scope_exit decrement{ [&]() noexcept { --_free; } };
461 const auto entry = &get_entry_for(unwrap_key(a_value));
462 if (entry->has_value()) { // slot is taken, resolve conflict
463 const auto free = &get_free_entry();
464 const auto wouldve = &get_entry_for(unwrap_key(entry->value));
465 if (wouldve == entry) { // hash collision
466 free->emplace(std::forward<P>(a_value), std::exchange(entry->next, free));
467 return std::make_pair(make_iterator<iterator>(free), true);
468 } else { // how did we get here?
469 auto prev = wouldve;
470 while (prev->next != entry) {
471 prev = prev->next;
472 }
473
474 // evict current value and detach from chain
475 *free = std::move(*entry);
476 prev->next = free;
477 entry->emplace(std::forward<P>(a_value), _sentinel);
478
479 return std::make_pair(make_iterator<iterator>(entry), true);
480 }
481 } else { // its free realestate
482 entry->emplace(std::forward<P>(a_value), _sentinel);
483 return std::make_pair(make_iterator<iterator>(entry), true);
484 }
485 }
486
487 void free_resources()
488 {
489 if (_capacity > 0) {
490 assert(get_entries() != nullptr);
491 std::destroy_n(get_entries(), _capacity);
492 deallocate(get_entries());
493 set_entries(nullptr);
494 _capacity = 0;
495 _free = 0;
496 _good = 0;
497 }
498
499 assert(get_entries() == nullptr);
500 assert(_capacity == 0);
501 assert(_free == 0);
502 }
503
504 [[nodiscard]] entry_type& get_entry_for(const key_type& a_key) const //
505 noexcept(noexcept(hash_function(a_key)))
506 {
507 assert(get_entries() != nullptr);
508 assert(std::has_single_bit(_capacity));
509
510 const auto hash = hash_function(a_key);
511 const auto idx = hash & (_capacity - 1); // quick modulo
512 return get_entries()[idx];
513 }
514
515 [[nodiscard]] entry_type* get_entries() const noexcept { return static_cast<entry_type*>(_allocator.get_entries()); }
516
517 [[nodiscard]] entry_type& get_free_entry() noexcept
518 {
519 assert(_free > 0);
520 assert(get_entries() != nullptr);
521 assert(std::has_single_bit(_capacity));
522 assert([&]() noexcept {
523 const auto begin = get_entries();
524 const auto end = get_entries() + _capacity;
525 return std::find_if(
526 begin,
527 end,
528 [](const auto& a_entry) noexcept {
529 return !a_entry.has_value();
530 }) != end;
531 }());
532
533 const auto entries = get_entries();
534 while (entries[_good].has_value()) {
535 _good = (_good + 1) & (_capacity - 1); // wrap around w/ quick modulo
536 }
537 return entries[_good];
538 }
539
540 [[nodiscard]] size_type hash_function(const key_type& a_key) const //
541 noexcept(std::is_nothrow_constructible_v<hasher>&&
542 std::is_nothrow_invocable_v<const hasher&, const key_type&>)
543 {
544 return static_cast<size_type>(hasher()(a_key));
545 }
546
547 [[nodiscard]] bool key_eq(const key_type& a_lhs, const key_type& a_rhs) const //
548 noexcept(std::is_nothrow_constructible_v<key_equal>&&
549 std::is_nothrow_invocable_v<const key_equal&, const key_type&, const key_type&>)
550 {
551 return static_cast<bool>(key_equal()(a_lhs, a_rhs));
552 }
553
554 template <class Iter>
555 [[nodiscard]] Iter make_iterator() const noexcept
556 {
557 return Iter(get_entries() + _capacity, get_entries() + _capacity);
558 }
559
560 template <class Iter>
561 [[nodiscard]] Iter make_iterator(entry_type* a_first) const noexcept
562 {
563 return Iter(a_first, get_entries() + _capacity);
564 }
565
566 void set_entries(entry_type* a_entries) noexcept { _allocator.set_entries(a_entries); }
567
568 // members
569 std::uint64_t _pad00{ 0 }; // 00
570 std::uint32_t _pad08{ 0 }; // 08
571 size_type _capacity{ 0 }; // 0C - total # of slots, always a power of 2
572 size_type _free{ 0 }; // 10 - # of free slots
573 size_type _good{ 0 }; // 14 - last free index
574 const entry_type* _sentinel{ reinterpret_cast<const entry_type*>(detail::BSTScatterTableSentinel) }; // 18 - signals end of chain
575 allocator_type _allocator; // 20
576 };
577
578 template <class Key, class T>
580 {
581 public:
582 using key_type = Key;
583 using mapped_type = T;
585
586 [[nodiscard]] static const key_type& unwrap_key(const value_type& a_value) noexcept { return a_value.first; }
587 };
588
589 template <class Key>
591 {
592 public:
593 using key_type = Key;
594 using mapped_type = void;
596
597 [[nodiscard]] static const key_type& unwrap_key(const value_type& a_value) noexcept { return a_value; }
598 };
599
600 template <std::size_t S, std::size_t A>
602 {
603 public:
604 using size_type = std::uint32_t;
606
609
611 _entries(std::exchange(a_rhs._entries, nullptr))
612 {}
613
616
618 {
619 if (this != std::addressof(a_rhs)) {
620 assert(_entries == nullptr);
621 _entries = std::exchange(a_rhs._entries, nullptr);
622 }
623 return *this;
624 }
625
626 [[nodiscard]] static constexpr size_type min_size() noexcept { return 1u << 3; }
627
628 [[nodiscard]] void* allocate_bytes(std::size_t a_bytes)
629 {
630 assert(a_bytes % S == 0);
631 return malloc(a_bytes);
632 }
633
634 void deallocate_bytes(void* a_ptr) { free(a_ptr); }
635
636 [[nodiscard]] void* get_entries() const noexcept { return _entries; }
637 void set_entries(void* a_entries) noexcept { _entries = static_cast<std::byte*>(a_entries); }
638
639 private:
640 // members
641 std::uint64_t _pad00{ 0 }; // 00 (20)
642 std::byte* _entries{ nullptr }; // 08 (28)
643 };
644
645 template <std::uint32_t N>
647 {
648 public:
649 static_assert(N > 0 && std::has_single_bit(N));
650
651 template <std::size_t S, std::size_t A>
653 {
654 public:
655 using size_type = std::uint32_t;
657
658 Allocator() = default;
659 Allocator(const Allocator&) = delete;
660 Allocator(Allocator&&) = delete;
661 ~Allocator() = default;
662 Allocator& operator=(const Allocator&) = delete;
664
665 [[nodiscard]] static constexpr size_type min_size() noexcept { return N; }
666
667 [[nodiscard]] void* allocate_bytes(std::size_t a_bytes)
668 {
669 assert(a_bytes % S == 0);
670 return a_bytes <= N * S ? _buffer : nullptr;
671 }
672
673 void deallocate_bytes([[maybe_unused]] void* a_ptr) { assert(a_ptr == _buffer); }
674
675 [[nodiscard]] void* get_entries() const noexcept { return _entries; }
676
677 void set_entries(void* a_entries) noexcept
678 {
679 assert(a_entries == _buffer || a_entries == nullptr);
680 _entries = static_cast<std::byte*>(a_entries);
681 }
682
683 private:
684 alignas(A) std::byte _buffer[N * S]{ static_cast<std::byte>(0) }; // 00 (20)
685 std::byte* _entries{ nullptr }; // ??
686 };
687 };
688
689 template <std::size_t S, std::size_t A>
691 {
692 public:
693 using size_type = std::uint32_t;
695
702
703 [[nodiscard]] static constexpr size_type min_size() noexcept { return 1u << 3; }
704
705 [[nodiscard]] void* allocate_bytes(std::size_t a_bytes)
706 {
707 assert(_allocator != nullptr);
708 assert(a_bytes % S == 0);
709 return _allocator->Allocate(a_bytes, 0x10);
710 }
711
712 void deallocate_bytes(void* a_ptr)
713 {
714 assert(_allocator != nullptr);
715 _allocator->Deallocate(a_ptr);
716 }
717
718 [[nodiscard]] void* get_entries() const noexcept { return _entries; }
719 void set_entries(void* a_entries) noexcept { _entries = static_cast<std::byte*>(a_entries); }
720
721 private:
722 // members
723 ScrapHeap* _allocator{ MemoryManager::GetSingleton()->GetThreadScrapHeap() }; // 00 (20)
724 std::byte* _entries{ nullptr }; // 08 (28)
725 };
726
727 template <
728 class Key,
729 class T,
730 class Hash = BSCRC32<Key>,
731 class KeyEq = std::equal_to<Key>>
734 Hash,
735 KeyEq,
738
739 namespace detail
740 {
741 using _dummy_bsthashmap = BSTHashMap<int, int>;
742 static_assert(std::forward_iterator<_dummy_bsthashmap::iterator>);
743 }
744
745 template <
746 class Key,
747 class Hash = BSCRC32<Key>,
748 class KeyEq = std::equal_to<Key>>
749 using BSTSet =
751 Hash,
752 KeyEq,
755
756 template <
757 class Key,
758 class T,
759 std::uint32_t N,
760 class Hash = BSCRC32<Key>,
761 class KeyEq = std::equal_to<Key>>
764 Hash,
765 KeyEq,
768
769 template <
770 class Key,
771 class T,
772 class Hash = BSCRC32<Key>,
773 class KeyEq = std::equal_to<Key>>
776 Hash,
777 KeyEq,
780
781 using UnkKey = std::uintptr_t;
782 using UnkValue = std::uintptr_t;
783}
Definition BSTHashMap.h:691
BSTScatterTableScrapAllocator(const BSTScatterTableScrapAllocator &)=delete
void * allocate_bytes(std::size_t a_bytes)
Definition BSTHashMap.h:705
void deallocate_bytes(void *a_ptr)
Definition BSTHashMap.h:712
std::uint32_t size_type
Definition BSTHashMap.h:693
void * get_entries() const noexcept
Definition BSTHashMap.h:718
static constexpr size_type min_size() noexcept
Definition BSTHashMap.h:703
BSTScatterTableScrapAllocator(BSTScatterTableScrapAllocator &&)=delete
BSTScatterTableScrapAllocator & operator=(const BSTScatterTableScrapAllocator &)=delete
std::false_type propagate_on_container_move_assignment
Definition BSTHashMap.h:694
void set_entries(void *a_entries) noexcept
Definition BSTHashMap.h:719
BSTScatterTableScrapAllocator & operator=(BSTScatterTableScrapAllocator &&)=delete
Definition BSTHashMap.h:580
static const key_type & unwrap_key(const value_type &a_value) noexcept
Definition BSTHashMap.h:586
Key key_type
Definition BSTHashMap.h:582
T mapped_type
Definition BSTHashMap.h:583
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:302
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:292
std::pair< iterator, bool > insert(value_type &&a_value)
Definition BSTHashMap.h:289
iterator end() noexcept
Definition BSTHashMap.h:266
void reserve(size_type a_count)
Definition BSTHashMap.h:323
const_iterator end() const noexcept
Definition BSTHashMap.h:267
iterator begin() noexcept
Definition BSTHashMap.h:262
BSTScatterTable(BSTScatterTable &&a_rhs) noexcept
Definition BSTHashMap.h:223
~BSTScatterTable()
Definition BSTHashMap.h:234
void clear()
Definition BSTHashMap.h:273
value_type & reference
Definition BSTHashMap.h:31
const_iterator cbegin() const noexcept
Definition BSTHashMap.h:264
std::int32_t difference_type
Definition BSTHashMap.h:28
size_type size() const noexcept
Definition BSTHashMap.h:271
Hash hasher
Definition BSTHashMap.h:29
BSTScatterTable & operator=(const BSTScatterTable &a_rhs)
Definition BSTHashMap.h:236
typename Traits::key_type key_type
Definition BSTHashMap.h:24
iterator erase(const_iterator a_pos)
Definition BSTHashMap.h:308
const_iterator begin() const noexcept
Definition BSTHashMap.h:263
iterator_base< value_type > iterator
Definition BSTHashMap.h:216
Allocator< sizeof(entry_type), alignof(entry_type)> allocator_type
Definition BSTHashMap.h:215
const_iterator find(const key_type &a_key) const
Definition BSTHashMap.h:319
const_iterator cend() const noexcept
Definition BSTHashMap.h:268
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:221
Traits traits_type
Definition BSTHashMap.h:23
iterator_base< const value_type > const_iterator
Definition BSTHashMap.h:217
BSTScatterTable & operator=(BSTScatterTable &&a_rhs)
Definition BSTHashMap.h:245
typename Traits::value_type value_type
Definition BSTHashMap.h:26
bool contains(const key_type &a_key) const
Definition BSTHashMap.h:321
std::pair< iterator, bool > insert(const value_type &a_value)
Definition BSTHashMap.h:288
iterator erase(iterator a_pos)
Definition BSTHashMap.h:309
size_type erase(const key_type &a_key)
Definition BSTHashMap.h:311
bool empty() const noexcept
Definition BSTHashMap.h:270
iterator find(const key_type &a_key)
Definition BSTHashMap.h:318
Definition BSTHashMap.h:591
static const key_type & unwrap_key(const value_type &a_value) noexcept
Definition BSTHashMap.h:597
key_type value_type
Definition BSTHashMap.h:595
Key key_type
Definition BSTHashMap.h:593
void mapped_type
Definition BSTHashMap.h:594
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:782
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:781
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:602
void * get_entries() const noexcept
Definition BSTHashMap.h:636
void * allocate_bytes(std::size_t a_bytes)
Definition BSTHashMap.h:628
BSTScatterTableHeapAllocator & operator=(const BSTScatterTableHeapAllocator &)=delete
std::true_type propagate_on_container_move_assignment
Definition BSTHashMap.h:605
BSTScatterTableHeapAllocator & operator=(BSTScatterTableHeapAllocator &&a_rhs) noexcept
Definition BSTHashMap.h:617
BSTScatterTableHeapAllocator(BSTScatterTableHeapAllocator &&a_rhs) noexcept
Definition BSTHashMap.h:610
BSTScatterTableHeapAllocator(const BSTScatterTableHeapAllocator &)=delete
void deallocate_bytes(void *a_ptr)
Definition BSTHashMap.h:634
static constexpr size_type min_size() noexcept
Definition BSTHashMap.h:626
void set_entries(void *a_entries) noexcept
Definition BSTHashMap.h:637
std::uint32_t size_type
Definition BSTHashMap.h:604
Definition BSTHashMap.h:653
Allocator(const Allocator &)=delete
std::false_type propagate_on_container_move_assignment
Definition BSTHashMap.h:656
void * get_entries() const noexcept
Definition BSTHashMap.h:675
Allocator & operator=(Allocator &&)=delete
static constexpr size_type min_size() noexcept
Definition BSTHashMap.h:665
Allocator & operator=(const Allocator &)=delete
void deallocate_bytes(void *a_ptr)
Definition BSTHashMap.h:673
void set_entries(void *a_entries) noexcept
Definition BSTHashMap.h:677
std::uint32_t size_type
Definition BSTHashMap.h:655
void * allocate_bytes(std::size_t a_bytes)
Definition BSTHashMap.h:667
Definition BSTHashMap.h:647
Definition BSTTuple.h:9