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