CommonLibSSE NG
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_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 
317  size_type erase(const key_type& a_key)
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>
658  struct Allocator
659  {
660  public:
661  using size_type = std::uint32_t;
662  using propagate_on_container_move_assignment = std::false_type;
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;
700  using propagate_on_container_move_assignment = std::false_type;
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>>
738  using BSTHashMap =
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:697
BSTScatterTableScrapAllocator(const BSTScatterTableScrapAllocator &)=delete
void * allocate_bytes(std::size_t a_bytes)
Definition: BSTHashMap.h:711
void * get_entries() const noexcept
Definition: BSTHashMap.h:724
void deallocate_bytes(void *a_ptr)
Definition: BSTHashMap.h:718
BSTScatterTableScrapAllocator & operator=(const BSTScatterTableScrapAllocator &)=delete
std::uint32_t size_type
Definition: BSTHashMap.h:699
static constexpr size_type min_size() noexcept
Definition: BSTHashMap.h:709
BSTScatterTableScrapAllocator(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: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: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()
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
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
std::pair< iterator, bool > emplace(Args &&... a_args) requires(std
Definition: BSTHashMap.h:308
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
std::pair< iterator, bool > insert(value_type &&a_value)
Definition: BSTHashMap.h:295
BSTScatterTable()=default
BSTScatterTable & operator=(BSTScatterTable &&a_rhs) requires(std
Definition: BSTHashMap.h:251
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
void insert(InputIt a_first, InputIt a_last) requires(std
Definition: BSTHashMap.h:298
typename Traits::value_type value_type
Definition: BSTHashMap.h:26
bool contains(const key_type &a_key) const
Definition: BSTHashMap.h:327
iterator erase(iterator a_pos)
Definition: BSTHashMap.h:315
std::pair< iterator, bool > insert(const value_type &a_value)
Definition: BSTHashMap.h:294
BSTScatterTable(BSTScatterTable &&a_rhs) noexcept requires(std
Definition: BSTHashMap.h:229
size_type erase(const key_type &a_key)
Definition: BSTHashMap.h:317
BSTScatterTable & operator=(const BSTScatterTable &a_rhs)
Definition: BSTHashMap.h:242
bool empty() const noexcept
Definition: BSTHashMap.h:276
iterator find(const key_type &a_key)
Definition: BSTHashMap.h:324
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
ScrapHeap * GetThreadScrapHeap()
Definition: MemoryManager.h:50
static MemoryManager * GetSingleton()
Definition: MemoryManager.h:29
Definition: ScrapHeap.h:10
void Deallocate(void *a_mem)
void * Allocate(std::size_t a_size, std::size_t a_alignment)
requires(is_builtin_convertible_v< T >) struct GetRawType< T >
Definition: PackUnpack.h:30
NiColor() max(const NiColor &a_lhs, const NiColor &a_rhs)
Definition: ColorUtil.h:71
NiColor() min(const NiColor &a_lhs, const NiColor &a_rhs)
Definition: ColorUtil.h:63
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:788
constexpr bool operator==(const BSTSmartPointer< T1 > &a_lhs, const BSTSmartPointer< T2 > &a_rhs)
Definition: BSTSmartPointer.h:240
void * malloc(std::size_t a_size)
Definition: MemoryManager.h:98
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, std::source_location a_loc=std::source_location::current())
Definition: PCH.h:660
scope_exit(EF) -> scope_exit< EF >
Definition: ActorValueList.h:28
Definition: CRC.h:104
Definition: BSTHashMap.h:608
BSTScatterTableHeapAllocator & operator=(BSTScatterTableHeapAllocator &&a_rhs) noexcept
Definition: BSTHashMap.h:623
std::true_type propagate_on_container_move_assignment
Definition: BSTHashMap.h:611
BSTScatterTableHeapAllocator(BSTScatterTableHeapAllocator &&a_rhs) noexcept
Definition: BSTHashMap.h:616
BSTScatterTableHeapAllocator(const BSTScatterTableHeapAllocator &)=delete
void * get_entries() const noexcept
Definition: BSTHashMap.h:642
BSTScatterTableHeapAllocator & operator=(const BSTScatterTableHeapAllocator &)=delete
void * allocate_bytes(std::size_t a_bytes)
Definition: BSTHashMap.h:634
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
static constexpr size_type min_size() noexcept
Definition: BSTHashMap.h:671
void * allocate_bytes(std::size_t a_bytes)
Definition: BSTHashMap.h:673
void * get_entries() const noexcept
Definition: BSTHashMap.h:681
Allocator & operator=(Allocator &&)=delete
void deallocate_bytes([[maybe_unused]] 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
Allocator & operator=(const Allocator &)=delete
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