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