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;
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; }
79 std::destroy_at(std::addressof(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), 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());
110 std::byte buffer[
sizeof(
value_type)]{
static_cast<std::byte
>(0) };
112 entry_type* next{
nullptr };
116 class iterator_base :
117 public boost::stl_interfaces::iterator_interface<
119 std::forward_iterator_tag,
124 boost::stl_interfaces::iterator_interface<
126 std::forward_iterator_tag,
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;
136 iterator_base() =
default;
137 ~iterator_base() =
default;
139 iterator_base(
const volatile iterator_base&) =
delete;
140 iterator_base&
operator=(
const volatile iterator_base&) =
delete;
143 iterator_base(
const iterator_base<V>& a_rhs) noexcept
145 _first(a_rhs._first),
150 iterator_base&
operator=(
const iterator_base<V>& a_rhs) noexcept
153 assert(_last == a_rhs._last);
154 _first = a_rhs._first;
159 [[nodiscard]]
reference operator*() const noexcept
162 assert(_first->has_value());
163 return _first->value;
167 [[nodiscard]]
bool operator==(
const iterator_base<V>& a_rhs)
const noexcept
169 assert(_last == a_rhs._last);
170 return _first == a_rhs._first;
173 iterator_base& operator++() noexcept
179 using super::operator++;
184 iterator_base(entry_type* a_first, entry_type* a_last) noexcept :
188 assert(!!_first == !!_last);
189 assert(_first <= _last);
190 if (iterable() && !_first->has_value()) {
195 [[nodiscard]] entry_type* get_entry() const noexcept {
return _first; }
199 friend class iterator_base;
201 [[nodiscard]]
bool iterable() const noexcept {
return _first && _last && _first != _last; }
208 }
while (_first != _last && !_first->has_value());
211 entry_type* _first{
nullptr };
212 entry_type* _last{
nullptr };
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))
232 assert(a_rhs.empty());
239 if (
this != std::addressof(a_rhs)) {
247 requires(std::same_as<typename allocator_type::propagate_on_container_move_assignment, std::true_type>)
249 if (
this != std::addressof(a_rhs)) {
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);
258 assert(a_rhs.empty());
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()); }
267 [[nodiscard]]
iterator end() noexcept {
return make_iterator<iterator>(); }
271 [[nodiscard]]
bool empty() const noexcept {
return 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();
290 std::pair<iterator, bool>
insert(
value_type&& a_value) {
return do_insert(std::move(a_value)); }
292 template <std::input_iterator InputIt>
293 void insert(InputIt a_first, InputIt a_last)
297 for (; a_first != a_last; ++a_first) {
298 insert(*std::move(a_first));
302 template <
class... Args>
303 std::pair<iterator, bool>
emplace(Args&&... a_args)
304 requires(std::constructible_from<value_type, Args...>)
314 const auto pos =
find(a_key);
315 const auto result = pos !=
end() ?
erase(pos) : pos;
316 return result !=
end() ? 1 : 0;
326 if (a_count <= _capacity) {
330 const auto oldCap = _capacity;
331 const auto oldEntries = get_entries();
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);
338 if (cap > 1u << 31) {
342 const auto entries = allocate(
static_cast<size_type>(cap));
350 const auto setCap = [&](
size_type a_newCap) {
351 _capacity = a_newCap;
356 if (newEntries == oldEntries) {
357 std::uninitialized_default_construct_n(oldEntries + oldCap, newCap - oldCap);
358 std::vector<value_type> todo;
359 todo.reserve(
size());
361 auto& entry = oldEntries[i];
362 if (entry.has_value()) {
363 todo.emplace_back(std::move(entry).steal());
368 std::make_move_iterator(todo.begin()),
369 std::make_move_iterator(todo.end()));
372 std::uninitialized_default_construct_n(newEntries, newCap);
374 set_entries(newEntries);
378 auto& entry = oldEntries[i];
379 if (entry.has_value()) {
380 insert(std::move(entry).steal());
383 std::destroy_n(oldEntries, oldCap);
384 deallocate(oldEntries);
392 return traits_type::unwrap_key(a_value);
395 [[nodiscard]] entry_type* allocate(
size_type a_count)
397 return static_cast<entry_type*
>(_allocator.allocate_bytes(
sizeof(entry_type) * a_count));
400 void deallocate(entry_type* a_entry) { _allocator.deallocate_bytes(a_entry); }
404 assert(a_pos !=
end());
405 const auto entry = a_pos.get_entry();
406 assert(entry !=
nullptr);
407 assert(entry->has_value());
409 if (entry->next == _sentinel) {
410 if (
auto prev = &get_entry_for(unwrap_key(entry->value)); prev != entry) {
411 while (prev->next != entry) {
414 prev->next =
const_cast<entry_type*
>(_sentinel);
419 *entry = std::move(*entry->next);
423 return make_iterator<iterator>(entry + 1);
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)))
431 return make_iterator<Iter>();
434 auto entry = &get_entry_for(a_key);
435 if (entry->has_value()) {
437 if (key_eq(unwrap_key(entry->value), a_key)) {
438 return make_iterator<Iter>(entry);
442 }
while (entry != _sentinel);
445 return make_iterator<Iter>();
449 [[nodiscard]] std::pair<iterator, bool> do_insert(P&& a_value)
452 if (
const auto it =
find(unwrap_key(a_value)); it !=
end()) {
462 const auto entry = &get_entry_for(unwrap_key(a_value));
463 if (entry->has_value()) {
464 const auto free = &get_free_entry();
465 const auto wouldve = &get_entry_for(unwrap_key(entry->value));
466 if (wouldve == entry) {
467 free->emplace(std::forward<P>(a_value), std::exchange(entry->next,
free));
471 while (prev->next != entry) {
476 *
free = std::move(*entry);
478 entry->emplace(std::forward<P>(a_value), _sentinel);
483 entry->emplace(std::forward<P>(a_value), _sentinel);
488 void free_resources()
491 assert(get_entries() !=
nullptr);
492 std::destroy_n(get_entries(), _capacity);
493 deallocate(get_entries());
494 set_entries(
nullptr);
500 assert(get_entries() ==
nullptr);
501 assert(_capacity == 0);
505 [[nodiscard]] entry_type& get_entry_for(
const key_type& a_key)
const
506 noexcept(noexcept(hash_function(a_key)))
508 assert(get_entries() !=
nullptr);
509 assert(std::has_single_bit(_capacity));
511 const auto hash = hash_function(a_key);
512 const auto idx = hash & (_capacity - 1);
513 return get_entries()[idx];
516 [[nodiscard]] entry_type* get_entries() const noexcept {
return static_cast<entry_type*
>(_allocator.get_entries()); }
518 [[nodiscard]] entry_type& get_free_entry() noexcept
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;
529 [](
const auto& a_entry) noexcept {
530 return !a_entry.has_value();
534 const auto entries = get_entries();
535 while (entries[_good].has_value()) {
536 _good = (_good + 1) & (_capacity - 1);
538 return entries[_good];
542 noexcept(std::is_nothrow_constructible_v<hasher>&&
543 std::is_nothrow_invocable_v<const hasher&, const key_type&>)
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&>)
552 return static_cast<bool>(
key_equal()(a_lhs, a_rhs));
555 template <
class Iter>
556 [[nodiscard]] Iter make_iterator() const noexcept
558 return Iter(get_entries() + _capacity, get_entries() + _capacity);
561 template <
class Iter>
562 [[nodiscard]] Iter make_iterator(entry_type* a_first)
const noexcept
564 return Iter(a_first, get_entries() + _capacity);
567 void set_entries(entry_type* a_entries) noexcept { _allocator.set_entries(a_entries); }
570 std::uint64_t _pad00{ 0 };
571 std::uint32_t _pad08{ 0 };
579 template <
class Key,
class T>
601 template <std::
size_t S, std::
size_t A>
612 _entries(std::exchange(a_rhs._entries,
nullptr))
620 if (
this != std::addressof(a_rhs)) {
621 assert(_entries ==
nullptr);
622 _entries = std::exchange(a_rhs._entries,
nullptr);
631 assert(a_bytes % S == 0);
637 [[nodiscard]]
void*
get_entries() const noexcept {
return _entries; }
638 void set_entries(
void* a_entries) noexcept { _entries =
static_cast<std::byte*
>(a_entries); }
642 std::uint64_t _pad00{ 0 };
643 std::byte* _entries{
nullptr };
646 template <std::u
int32_t N>
650 static_assert(N > 0 && std::has_single_bit(N));
652 template <std::
size_t S, std::
size_t A>
670 assert(a_bytes % S == 0);
671 return a_bytes <= N * S ? _buffer :
nullptr;
676 [[nodiscard]]
void*
get_entries() const noexcept {
return _entries; }
680 assert(a_entries == _buffer || a_entries ==
nullptr);
681 _entries =
static_cast<std::byte*
>(a_entries);
685 alignas(A) std::byte _buffer[N * S]{
static_cast<std::byte
>(0) };
686 std::byte* _entries{
nullptr };
690 template <std::
size_t S, std::
size_t A>
708 assert(_allocator !=
nullptr);
709 assert(a_bytes % S == 0);
710 return _allocator->
Allocate(a_bytes, 0x10);
715 assert(_allocator !=
nullptr);
719 [[nodiscard]]
void*
get_entries() const noexcept {
return _entries; }
720 void set_entries(
void* a_entries) noexcept { _entries =
static_cast<std::byte*
>(a_entries); }
725 std::byte* _entries{
nullptr };
731 class Hash = BSCRC32<Key>,
732 class KeyEq = std::equal_to<Key>>
749 class KeyEq = std::equal_to<Key>>
762 class KeyEq = std::equal_to<Key>>
774 class KeyEq = std::equal_to<Key>>
Definition: BSTHashMap.h:692
BSTScatterTableScrapAllocator(const BSTScatterTableScrapAllocator &)=delete
void * allocate_bytes(std::size_t a_bytes)
Definition: BSTHashMap.h:706
void * get_entries() const noexcept
Definition: BSTHashMap.h:719
void deallocate_bytes(void *a_ptr)
Definition: BSTHashMap.h:713
BSTScatterTableScrapAllocator & operator=(const BSTScatterTableScrapAllocator &)=delete
std::uint32_t size_type
Definition: BSTHashMap.h:694
static constexpr size_type min_size() noexcept
Definition: BSTHashMap.h:704
~BSTScatterTableScrapAllocator()=default
BSTScatterTableScrapAllocator(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
BSTScatterTableScrapAllocator()=default
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:21
const value_type & const_reference
Definition: BSTHashMap.h:32
typename Traits::mapped_type mapped_type
Definition: BSTHashMap.h:25
std::uint32_t size_type
Definition: BSTHashMap.h:27
KeyEqual key_equal
Definition: BSTHashMap.h:30
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()
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
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
std::pair< iterator, bool > emplace(Args &&... a_args) requires(std
Definition: BSTHashMap.h:303
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
std::pair< iterator, bool > insert(value_type &&a_value)
Definition: BSTHashMap.h:290
BSTScatterTable()=default
BSTScatterTable & operator=(BSTScatterTable &&a_rhs) requires(std
Definition: BSTHashMap.h:246
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
void insert(InputIt a_first, InputIt a_last) requires(std
Definition: BSTHashMap.h:293
typename Traits::value_type value_type
Definition: BSTHashMap.h:26
bool contains(const key_type &a_key) const
Definition: BSTHashMap.h:322
iterator erase(iterator a_pos)
Definition: BSTHashMap.h:310
std::pair< iterator, bool > insert(const value_type &a_value)
Definition: BSTHashMap.h:289
BSTScatterTable(BSTScatterTable &&a_rhs) noexcept requires(std
Definition: BSTHashMap.h:224
size_type erase(const key_type &a_key)
Definition: BSTHashMap.h:312
BSTScatterTable & operator=(const BSTScatterTable &a_rhs)
Definition: BSTHashMap.h:237
bool empty() const noexcept
Definition: BSTHashMap.h:271
iterator find(const key_type &a_key)
Definition: BSTHashMap.h:319
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
ScrapHeap * GetThreadScrapHeap()
Definition: MemoryManager.h:50
static MemoryManager * GetSingleton()
Definition: MemoryManager.h:29
Definition: ScrapHeap.h:8
void Deallocate(void *a_mem)
void * Allocate(std::size_t a_size, std::size_t a_alignment)
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
auto make_pair(T1 &&a_first, T2 &&a_second)
Definition: BSTTuple.h:177
std::uintptr_t UnkValue
Definition: BSTHashMap.h:783
constexpr bool operator==(const BSTSmartPointer< T1 > &a_lhs, const BSTSmartPointer< T2 > &a_rhs)
Definition: BSTSmartPointer.h:241
void * malloc(std::size_t a_size)
Definition: MemoryManager.h:98
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:579
scope_exit(EF) -> scope_exit< EF >
requires(std::invocable< std::remove_reference_t< EF >>) class scope_exit
Definition: PCH.h:148
Definition: NiBinaryStream.h:94
Definition: BSTHashMap.h:603
BSTScatterTableHeapAllocator & operator=(BSTScatterTableHeapAllocator &&a_rhs) noexcept
Definition: BSTHashMap.h:618
~BSTScatterTableHeapAllocator()=default
std::true_type propagate_on_container_move_assignment
Definition: BSTHashMap.h:606
BSTScatterTableHeapAllocator(BSTScatterTableHeapAllocator &&a_rhs) noexcept
Definition: BSTHashMap.h:611
BSTScatterTableHeapAllocator()=default
BSTScatterTableHeapAllocator(const BSTScatterTableHeapAllocator &)=delete
void * get_entries() const noexcept
Definition: BSTHashMap.h:637
BSTScatterTableHeapAllocator & operator=(const BSTScatterTableHeapAllocator &)=delete
void * allocate_bytes(std::size_t a_bytes)
Definition: BSTHashMap.h:629
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
static constexpr size_type min_size() noexcept
Definition: BSTHashMap.h:666
void * allocate_bytes(std::size_t a_bytes)
Definition: BSTHashMap.h:668
void * get_entries() const noexcept
Definition: BSTHashMap.h:676
Allocator & operator=(Allocator &&)=delete
void deallocate_bytes([[maybe_unused]] 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
Allocator(Allocator &&)=delete
Allocator & operator=(const Allocator &)=delete
Definition: BSTHashMap.h:648