CommonLibSSE (powerof3)
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"
5 #include "RE/M/MemoryManager.h"
6 
7 namespace 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;
32  using const_reference = const value_type&;
33  using pointer = value_type*;
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 
312  size_type erase(const key_type& a_key)
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>
653  struct Allocator
654  {
655  public:
656  using size_type = std::uint32_t;
657  using propagate_on_container_move_assignment = std::false_type;
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;
695  using propagate_on_container_move_assignment = std::false_type;
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>>
733  using BSTHashMap =
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: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(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: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: CRC.h:104
Definition: BSTHashMap.h:603
BSTScatterTableHeapAllocator & operator=(BSTScatterTableHeapAllocator &&a_rhs) noexcept
Definition: BSTHashMap.h:618
std::true_type propagate_on_container_move_assignment
Definition: BSTHashMap.h:606
BSTScatterTableHeapAllocator(BSTScatterTableHeapAllocator &&a_rhs) noexcept
Definition: BSTHashMap.h:611
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 & operator=(const Allocator &)=delete
Definition: BSTHashMap.h:648
Definition: BSTTuple.h:9