19 template <std::
size_t, std::
size_t>
class Allocator>
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&>);
42 entry_type() =
default;
43 entry_type(
const entry_type&) =
delete;
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>)
49 if (a_rhs.has_value()) {
50 const auto rnext = a_rhs.next;
51 emplace(std::move(a_rhs).steal(), rnext);
55 ~entry_type()
noexcept { destroy(); };
57 entry_type& operator=(
const entry_type&) =
delete;
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>)
63 if (
this != std::addressof(a_rhs)) {
65 if (a_rhs.has_value()) {
66 const auto rnext = a_rhs.next;
67 emplace(std::move(a_rhs).steal(), rnext);
73 [[nodiscard]]
bool has_value()
const noexcept {
return next !=
nullptr; }
76 noexcept(std::is_nothrow_destructible_v<value_type>)
79 std::destroy_at(std::addressof(value_data.value));
86 void emplace(Arg&& a_value,
const entry_type* a_next)
87 noexcept(std::is_nothrow_constructible_v<value_type, Arg>)
89 static_assert(std::same_as<std::decay_t<Arg>,
value_type>);
91 std::construct_at(std::addressof(value_data.value), std::forward<Arg>(a_value));
92 next =
const_cast<entry_type*
>(a_next);
97 noexcept(std::is_nothrow_move_constructible_v<value_type>&&
98 std::is_nothrow_destructible_v<value_type>)
103 assert(!has_value());
117 value_union value_data;
118 entry_type* next{
nullptr };
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;
131 iterator_base() =
default;
132 ~iterator_base() =
default;
134 iterator_base(
const volatile iterator_base&) =
delete;
135 iterator_base& operator=(
const volatile iterator_base&) =
delete;
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),
145 iterator_base& operator=(
const iterator_base<V>& a_rhs)
noexcept
146 requires(std::convertible_to<typename iterator_base<V>::reference, reference>)
148 assert(_last == a_rhs._last);
149 _first = a_rhs._first;
154 [[nodiscard]] reference operator*() const noexcept
157 assert(_first->has_value());
158 return _first->value_data.value;
162 [[nodiscard]]
bool operator==(
const iterator_base<V>& a_rhs)
const noexcept
164 assert(_last == a_rhs._last);
165 return _first == a_rhs._first;
168 iterator_base& operator++() noexcept
174 iterator_base operator++(
int)
noexcept
176 iterator_base result = *
this;
181 [[nodiscard]] pointer operator->() const noexcept
187 friend class BSTScatterTable;
189 iterator_base(entry_type* a_first, entry_type* a_last) noexcept :
193 assert(!!_first == !!_last);
194 assert(_first <= _last);
195 if (iterable() && !_first->has_value()) {
200 [[nodiscard]] entry_type* get_entry() const noexcept {
return _first; }
204 friend class iterator_base;
206 [[nodiscard]]
bool iterable() const noexcept {
return _first && _last && _first != _last; }
213 }
while (_first != _last && !_first->has_value());
216 entry_type* _first{
nullptr };
217 entry_type* _last{
nullptr };
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))
237 assert(a_rhs.empty());
244 if (
this != std::addressof(a_rhs)) {
252 requires(std::same_as<typename allocator_type::propagate_on_container_move_assignment, std::true_type>)
254 if (
this != std::addressof(a_rhs)) {
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);
263 assert(a_rhs.empty());
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()); }
272 [[nodiscard]]
iterator end() noexcept {
return make_iterator<iterator>(); }
276 [[nodiscard]]
bool empty() const noexcept {
return 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();
295 std::pair<iterator, bool>
insert(
value_type&& a_value) {
return do_insert(std::move(a_value)); }
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>)
302 for (; a_first != a_last; ++a_first) {
303 insert(*std::move(a_first));
307 template <
class... Args>
308 std::pair<iterator, bool>
emplace(Args&&... a_args)
309 requires(std::constructible_from<
value_type, Args...>)
319 const auto pos =
find(a_key);
320 const auto result = pos !=
end() ?
erase(pos) : pos;
321 return result !=
end() ? 1 : 0;
331 if (a_count <= _capacity) {
335 const auto oldCap = _capacity;
336 const auto oldEntries = get_entries();
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);
343 if (cap > 1u << 31) {
347 const auto entries = allocate(
static_cast<size_type>(cap));
352 return std::make_pair(
static_cast<size_type>(cap), entries);
355 const auto setCap = [&](
size_type a_newCap) {
356 _capacity = a_newCap;
361 if (newEntries == oldEntries) {
362 std::uninitialized_default_construct_n(oldEntries + oldCap, newCap - oldCap);
363 std::vector<value_type> todo;
364 todo.reserve(
size());
366 auto& entry = oldEntries[i];
367 if (entry.has_value()) {
368 todo.emplace_back(std::move(entry).steal());
373 std::make_move_iterator(todo.begin()),
374 std::make_move_iterator(todo.end()));
377 std::uninitialized_default_construct_n(newEntries, newCap);
379 set_entries(newEntries);
383 auto& entry = oldEntries[i];
384 if (entry.has_value()) {
385 insert(std::move(entry).steal());
388 std::destroy_n(oldEntries, oldCap);
389 deallocate(oldEntries);
397 return traits_type::unwrap_key(a_value);
400 [[nodiscard]] entry_type* allocate(
size_type a_count)
402 return static_cast<entry_type*
>(_allocator.allocate_bytes(
sizeof(entry_type) * a_count));
405 void deallocate(entry_type* a_entry) { _allocator.deallocate_bytes(a_entry); }
409 assert(a_pos !=
end());
410 const auto entry = a_pos.get_entry();
411 assert(entry !=
nullptr);
412 assert(entry->has_value());
414 if (entry->next == _sentinel) {
415 if (
auto prev = &get_entry_for(unwrap_key(entry->value_data.value)); prev != entry) {
416 while (prev->next != entry) {
419 prev->next =
const_cast<entry_type*
>(_sentinel);
424 *entry = std::move(*entry->next);
428 return make_iterator<iterator>(entry + 1);
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)))
436 return make_iterator<Iter>();
439 auto entry = &get_entry_for(a_key);
440 if (entry->has_value()) {
442 if (key_eq(unwrap_key(entry->value_data.value), a_key)) {
443 return make_iterator<Iter>(entry);
447 }
while (entry != _sentinel);
450 return make_iterator<Iter>();
454 [[nodiscard]] std::pair<iterator, bool> do_insert(P&& a_value)
455 requires(std::same_as<std::decay_t<P>,
value_type>)
457 if (
const auto it =
find(unwrap_key(a_value)); it !=
end()) {
458 return std::make_pair(it,
false);
467 const auto entry = &get_entry_for(unwrap_key(a_value));
468 if (entry->has_value()) {
469 const auto free = &get_free_entry();
470 const auto wouldve = &get_entry_for(unwrap_key(entry->value_data.value));
471 if (wouldve == entry) {
472 free->emplace(std::forward<P>(a_value), std::exchange(entry->next,
free));
473 return std::make_pair(make_iterator<iterator>(
free),
true);
476 while (prev->next != entry) {
481 *
free = std::move(*entry);
483 entry->emplace(std::forward<P>(a_value), _sentinel);
485 return std::make_pair(make_iterator<iterator>(entry),
true);
488 entry->emplace(std::forward<P>(a_value), _sentinel);
489 return std::make_pair(make_iterator<iterator>(entry),
true);
493 void free_resources()
496 assert(get_entries() !=
nullptr);
497 std::destroy_n(get_entries(), _capacity);
498 deallocate(get_entries());
499 set_entries(
nullptr);
505 assert(get_entries() ==
nullptr);
506 assert(_capacity == 0);
510 [[nodiscard]] entry_type& get_entry_for(
const key_type& a_key)
const
511 noexcept(
noexcept(hash_function(a_key)))
513 assert(get_entries() !=
nullptr);
514 assert(std::has_single_bit(_capacity));
516 const auto hash = hash_function(a_key);
517 const auto idx = hash & (_capacity - 1);
518 return get_entries()[idx];
521 [[nodiscard]] entry_type* get_entries() const noexcept {
return static_cast<entry_type*
>(_allocator.get_entries()); }
523 [[nodiscard]] entry_type& get_free_entry() noexcept
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;
534 [](
const auto& a_entry)
noexcept {
535 return !a_entry.has_value();
539 const auto entries = get_entries();
540 while (entries[_good].has_value()) {
541 _good = (_good + 1) & (_capacity - 1);
543 return entries[_good];
547 noexcept(std::is_nothrow_constructible_v<hasher>&&
548 std::is_nothrow_invocable_v<const hasher&, const key_type&>)
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&>)
557 return static_cast<bool>(
key_equal()(a_lhs, a_rhs));
560 template <
class Iter>
561 [[nodiscard]] Iter make_iterator() const noexcept
563 return Iter(get_entries() + _capacity, get_entries() + _capacity);
566 template <
class Iter>
567 [[nodiscard]] Iter make_iterator(entry_type* a_first)
const noexcept
569 return Iter(a_first, get_entries() + _capacity);
572 void set_entries(entry_type* a_entries)
noexcept { _allocator.set_entries(a_entries); }
575 std::uint64_t _pad00{ 0 };
576 std::uint32_t _pad08{ 0 };
584 template <
class Key,
class T>
606 template <std::
size_t S, std::
size_t A>
617 _entries(std::exchange(a_rhs._entries,
nullptr))
625 if (
this != std::addressof(a_rhs)) {
626 assert(_entries ==
nullptr);
627 _entries = std::exchange(a_rhs._entries,
nullptr);
636 assert(a_bytes % S == 0);
642 [[nodiscard]]
void*
get_entries() const noexcept {
return _entries; }
643 void set_entries(
void* a_entries)
noexcept { _entries =
static_cast<std::byte*
>(a_entries); }
647 std::uint64_t _pad00{ 0 };
648 std::byte* _entries{
nullptr };
651 template <std::u
int32_t N>
655 static_assert(N > 0 && std::has_single_bit(N));
657 template <std::
size_t S, std::
size_t A>
675 assert(a_bytes % S == 0);
676 return a_bytes <= N * S ? _buffer :
nullptr;
681 [[nodiscard]]
void*
get_entries() const noexcept {
return _entries; }
685 assert(a_entries == _buffer || a_entries ==
nullptr);
686 _entries =
static_cast<std::byte*
>(a_entries);
690 alignas(A) std::byte _buffer[N * S]{
static_cast<std::byte
>(0) };
691 std::byte* _entries{
nullptr };
695 template <std::
size_t S, std::
size_t A>
713 assert(_allocator !=
nullptr);
714 assert(a_bytes % S == 0);
715 return _allocator->
Allocate(a_bytes, 0x10);
720 assert(_allocator !=
nullptr);
724 [[nodiscard]]
void*
get_entries() const noexcept {
return _entries; }
725 void set_entries(
void* a_entries)
noexcept { _entries =
static_cast<std::byte*
>(a_entries); }
730 std::byte* _entries{
nullptr };
736 class Hash = BSCRC32<Key>,
737 class KeyEq = std::equal_to<Key>>
748 static_assert(std::forward_iterator<_dummy_bsthashmap::iterator>);
754 class KeyEq = std::equal_to<Key>>
767 class KeyEq = std::equal_to<Key>>
779 class KeyEq = std::equal_to<Key>>
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()=default
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
BSTScatterTableScrapAllocator()=default
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
void * Allocate(std::size_t a_size, std::size_t a_alignment)
void Deallocate(void *a_mem)
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 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()=default
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()=default
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
Allocator(Allocator &&)=delete
Definition BSTHashMap.h:653
Definition BSTHashMap.h:108
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