CommonLibSSE (powerof3)
NiTMapBase.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "RE/M/MemoryManager.h"
4 
5 namespace RE
6 {
7  template <class Key, class T>
8  class NiTMapItem
9  {
10  public:
11  using key_type = Key;
12  using mapped_type = T;
13 
14  // members
15  NiTMapItem* next; // 00
16  key_type first; // 08
18  };
19  static_assert(sizeof(NiTMapItem<std::uint32_t, std::uint64_t>) == 0x18);
20 
21  // hash table with separate chaining
22  template <class Allocator, class Key, class T>
23  class NiTMapBase
24  {
25  private:
26  template <class U>
27  friend class iterator_base;
28 
29  public:
30  using key_type = Key;
31  using mapped_type = T;
33  using size_type = std::uint32_t;
34 
35  template <class U>
37  {
38  public:
39  using difference_type = std::ptrdiff_t;
40  using value_type = U;
41  using pointer = U*;
42  using reference = U&;
43  using iterator_category = std::forward_iterator_tag;
44 
46  _proxy(0),
47  _iter(0),
48  _idx(0)
49  {}
50 
51  iterator_base(const iterator_base& a_rhs) :
52  _proxy(a_rhs._proxy),
53  _iter(a_rhs._iter),
54  _idx(a_rhs._idx)
55  {}
56 
58  _proxy(a_rhs._proxy),
59  _iter(std::move(a_rhs._iter)),
60  _idx(std::move(a_rhs._idx))
61  {
62  assert(_proxy);
63  a_rhs._iter = nullptr;
64  a_rhs._idx = a_rhs._proxy->_capacity;
65  }
66 
67  iterator_base(NiTMapBase* a_proxy, std::uint32_t a_idx) :
68  _proxy(a_proxy),
69  _iter(nullptr),
70  _idx(a_idx)
71  {
72  assert(_proxy);
73  _iter = _proxy->_data[_idx];
74  while (!_iter && _idx < _proxy->_capacity) {
75  ++_idx;
76  _iter = _proxy->_data[_idx];
77  }
78  }
79 
80  iterator_base(NiTMapBase* a_proxy, value_type* a_iter, std::uint32_t a_idx) :
81  _proxy(a_proxy),
82  _iter(a_iter),
83  _idx(a_idx)
84  {
85  assert(_proxy);
86  assert(_iter);
87  }
88 
90  {}
91 
93  {
94  assert(_proxy == a_rhs._proxy);
95  _iter = a_rhs._iter;
96  _idx = a_rhs._idx;
97  }
98 
100  {
101  assert(_proxy == a_rhs._proxy);
102 
103  _iter = std::move(a_rhs._iter);
104  a_rhs._iter = 0;
105 
106  _idx = std::move(a_rhs._idx);
107  a_rhs._idx = a_rhs._proxy->_capacity;
108  }
109 
110  void swap(iterator_base& a_rhs)
111  {
112  assert(_proxy == a_rhs._proxy);
113  std::swap(_iter, a_rhs._iter);
114  std::swap(_idx, a_rhs._idx);
115  }
116 
117  [[nodiscard]] reference operator*() const
118  {
119  assert(_iter);
120  assert(_idx < _proxy->_capacity);
121  return *_iter;
122  }
123 
124  [[nodiscard]] pointer operator->() const
125  {
126  assert(_iter);
127  assert(_idx < _proxy->_capacity);
128  return _iter;
129  }
130 
131  [[nodiscard]] bool operator==(const iterator_base& a_rhs) const
132  {
133  assert(_proxy == a_rhs._proxy);
134 
135  if (_idx != a_rhs._idx) {
136  return false;
137  }
138 
139  if (_idx < _proxy->_capacity) {
140  return _iter == a_rhs._iter;
141  }
142 
143  return true;
144  }
145 
146  [[nodiscard]] bool operator!=(const iterator_base& a_rhs) const
147  {
148  return !operator==(a_rhs);
149  }
150 
151  // prefix
153  {
154  assert(_proxy);
155  assert(_iter);
156  assert(_idx < _proxy->_capacity);
157 
158  if (_iter->next) {
159  _iter = _iter->next;
160  } else {
161  do {
162  ++_idx;
163  _iter = _proxy->_data[_idx];
164  } while (!_iter && _idx < _proxy->_capacity);
165  }
166 
167  return *this;
168  }
169 
170  // postfix
172  {
173  iterator_base tmp(*this);
174  operator++();
175  return tmp;
176  }
177 
178  private:
179  NiTMapBase* _proxy;
180  value_type* _iter;
181  std::uint32_t _idx;
182  };
183 
186 
187  struct AntiBloatAllocator : public Allocator
188  {
190  Allocator(),
191  size(0)
192  {}
193 
194  // members
196  };
197 
198  NiTMapBase(size_type a_capacity = 37) :
199  _capacity(a_capacity),
200  _pad0C(0),
201  _data(0),
202  _allocator()
203  {
204  std::size_t memSize = sizeof(value_type*) * _capacity;
205  _data = malloc<value_type*>(memSize);
206  std::memset(_data, 0, memSize);
207  }
208 
209  virtual ~NiTMapBase() // 00
210  {
211  clear();
212  if (_data) {
213  free(_data);
214  _data = nullptr;
215  }
216  _capacity = 0;
217  }
218 
219  protected:
220  virtual std::uint32_t hash_function(key_type a_key) const; // 01 - { return a_key % _capacity; }
221  virtual bool key_eq(key_type a_lhs, key_type a_rhs) const; // 02 - { return stricmp(a_lhs == a_rhs); }
222  virtual void assign_value(value_type* a_value, key_type a_key, mapped_type a_mapped); // 03 - { a_value->key = a_key; a_value->mapped = a_mapped; }
223  virtual void clear_value(value_type* a_value); // 04 - { return; }
224  virtual value_type* malloc_value() = 0; // 05
225  virtual void free_value(value_type* a_value) = 0; // 06
226 
227  public:
229  {
230  return iterator(this, 0);
231  }
232 
234  {
235  return const_iterator(this, 0);
236  }
237 
239  {
240  return const_iterator(this, 0);
241  }
242 
244  {
245  return iterator(this, _capacity);
246  }
247 
249  {
250  return const_iterator(this, _capacity);
251  }
252 
254  {
255  return const_iterator(this, _capacity);
256  }
257 
258  [[nodiscard]] bool empty() const noexcept
259  {
260  return _allocator.size == 0;
261  }
262 
263  [[nodiscard]] size_type size() const noexcept
264  {
265  return _allocator.size;
266  }
267 
268  void clear()
269  {
270  for (std::uint32_t i = 0; i < _capacity; i++) {
271  while (_data[i]) {
272  auto elem = _data[i];
273  _data[i] = _data[i]->next;
274  clear_value(elem);
275  free_value(elem);
276  }
277  }
278 
279  _allocator.size = 0;
280  }
281 
282  template <class M>
283  bool insert_or_assign(key_type&& a_key, M&& a_obj)
284  {
285  // look up hash table location for key
286  auto index = hash_function(a_key);
287  auto item = _data[index];
288 
289  // search list at hash table location for key
290  while (item) {
291  if (key_eq(a_key, item->key)) {
292  // item already in hash table, set its new value
293  item->val = std::forward<M>(a_obj);
294  return false;
295  }
296  item = item->next;
297  }
298 
299  // add object to beginning of list for this hash table index
300  item = malloc_value();
301 
302  assert(item != 0);
303  assign_value(item, std::move(a_key), std::forward<M>(a_obj));
304  item->next = _data[index];
305  _data[index] = item;
306  ++_allocator.size;
307  return true;
308  }
309 
310  size_type erase(const key_type& a_key)
311  {
312  // look up hash table location for key
313  auto index = hash_function(a_key);
314  auto item = _data[index];
315 
316  value_type* prev = 0;
317  while (item) {
318  if (key_eq(a_key, item->key)) {
319  if (prev) {
320  prev->next = item->next;
321  } else {
322  _data[index] = item->next;
323  }
324  remove_value(item);
325  return 1;
326  }
327  prev = item;
328  item = item->next;
329  }
330  return 0;
331  }
332 
333  iterator find(const Key& a_key)
334  {
335  auto result = do_find(a_key);
336  return result ? iterator(this, result->first, result->second) : end();
337  }
338 
339  const_iterator find(const Key& a_key) const
340  {
341  auto result = do_find(a_key);
342  return result ? const_iterator(this, result->first, result->second) : end();
343  }
344 
345  private:
346  inline void remove_value(value_type* a_value)
347  {
348  clear_value(a_value);
349  free_value(a_value);
350  --_allocator.size;
351  }
352 
353  std::optional<std::pair<value_type*, std::uint32_t>> do_find(const Key& a_key) const
354  {
355  size_type idx = hash_function(a_key);
356  for (auto iter = _data[idx]; iter; iter = iter->next) {
357  if (key_eq(a_key, iter->first)) {
358  return std::make_optional(std::make_pair(iter, idx));
359  }
360  }
361 
362  return std::nullopt;
363  }
364 
365  protected:
366  // members
367  std::uint32_t _capacity; // 08
368  std::uint32_t _pad0C; // 0C
369  value_type** _data; // 10
371  };
372 }
Definition: NiTMapBase.h:24
iterator_base< value_type > iterator
Definition: NiTMapBase.h:184
std::uint32_t size_type
Definition: NiTMapBase.h:33
std::uint32_t _capacity
Definition: NiTMapBase.h:367
bool insert_or_assign(key_type &&a_key, M &&a_obj)
Definition: NiTMapBase.h:283
const_iterator cend() const
Definition: NiTMapBase.h:253
virtual std::uint32_t hash_function(key_type a_key) const
T mapped_type
Definition: NiTMapBase.h:31
iterator_base< const value_type > const_iterator
Definition: NiTMapBase.h:185
const_iterator find(const Key &a_key) const
Definition: NiTMapBase.h:339
virtual ~NiTMapBase()
Definition: NiTMapBase.h:209
Key key_type
Definition: NiTMapBase.h:30
virtual void assign_value(value_type *a_value, key_type a_key, mapped_type a_mapped)
virtual void clear_value(value_type *a_value)
const_iterator cbegin() const
Definition: NiTMapBase.h:238
std::uint32_t _pad0C
Definition: NiTMapBase.h:368
size_type size() const noexcept
Definition: NiTMapBase.h:263
NiTMapBase(size_type a_capacity=37)
Definition: NiTMapBase.h:198
virtual value_type * malloc_value()=0
value_type ** _data
Definition: NiTMapBase.h:369
size_type erase(const key_type &a_key)
Definition: NiTMapBase.h:310
AntiBloatAllocator _allocator
Definition: NiTMapBase.h:370
iterator begin()
Definition: NiTMapBase.h:228
NiTMapItem< Key, T > value_type
Definition: NiTMapBase.h:32
const_iterator begin() const
Definition: NiTMapBase.h:233
virtual bool key_eq(key_type a_lhs, key_type a_rhs) const
bool empty() const noexcept
Definition: NiTMapBase.h:258
iterator end()
Definition: NiTMapBase.h:243
const_iterator end() const
Definition: NiTMapBase.h:248
void clear()
Definition: NiTMapBase.h:268
iterator find(const Key &a_key)
Definition: NiTMapBase.h:333
virtual void free_value(value_type *a_value)=0
Definition: NiTMapBase.h:9
Key key_type
Definition: NiTMapBase.h:11
key_type first
Definition: NiTMapBase.h:16
mapped_type second
Definition: NiTMapBase.h:17
NiTMapItem * next
Definition: NiTMapBase.h:15
T mapped_type
Definition: NiTMapBase.h:12
Definition: AbsorbEffect.h:6
auto make_pair(T1 &&a_first, T2 &&a_second)
Definition: BSTTuple.h:177
void swap(BSTTuple< T1, T2 > &a_lhs, BSTTuple< T1, T2 > &a_rhs) noexcept(noexcept(a_lhs.swap(a_rhs))) requires(std
Definition: BSTTuple.h:212
void free(void *a_ptr)
Definition: MemoryManager.h:187
Definition: EffectArchetypes.h:65
Definition: NiTMapBase.h:188
AntiBloatAllocator()
Definition: NiTMapBase.h:189
size_type size
Definition: NiTMapBase.h:195
Definition: NiTMapBase.h:37
reference operator*() const
Definition: NiTMapBase.h:117
iterator_base()
Definition: NiTMapBase.h:45
iterator_base(iterator_base &&a_rhs)
Definition: NiTMapBase.h:57
iterator_base & operator=(const iterator_base &a_rhs)
Definition: NiTMapBase.h:92
iterator_base(NiTMapBase *a_proxy, value_type *a_iter, std::uint32_t a_idx)
Definition: NiTMapBase.h:80
iterator_base(NiTMapBase *a_proxy, std::uint32_t a_idx)
Definition: NiTMapBase.h:67
pointer operator->() const
Definition: NiTMapBase.h:124
iterator_base(const iterator_base &a_rhs)
Definition: NiTMapBase.h:51
bool operator!=(const iterator_base &a_rhs) const
Definition: NiTMapBase.h:146
U value_type
Definition: NiTMapBase.h:40
iterator_base & operator=(iterator_base &&a_rhs)
Definition: NiTMapBase.h:99
std::ptrdiff_t difference_type
Definition: NiTMapBase.h:39
~iterator_base()
Definition: NiTMapBase.h:89
iterator_base operator++(int)
Definition: NiTMapBase.h:171
void swap(iterator_base &a_rhs)
Definition: NiTMapBase.h:110
U * pointer
Definition: NiTMapBase.h:41
U & reference
Definition: NiTMapBase.h:42
iterator_base & operator++()
Definition: NiTMapBase.h:152
std::forward_iterator_tag iterator_category
Definition: NiTMapBase.h:43
bool operator==(const iterator_base &a_rhs) const
Definition: NiTMapBase.h:131