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