1 #ifndef NTA_SLOTMAP_H_INCLUDED
2 #define NTA_SLOTMAP_H_INCLUDED
4 #include "nta/Option.h"
5 #include "nta/IDFactory.h"
6 #include "nta/format.h"
12 template<
typename IndexType = std::
size_t,
typename GenType = u
int16_t>
14 using index_type = IndexType;
15 using gen_type = GenType;
18 return idx == rhs.idx && gen == rhs.gen;
21 return !(*
this == rhs);
27 template<
typename IndexType,
typename GenType>
30 return format(
"{ .idx = {}, .gen = {} }", arg.idx, arg.gen);
33 template<
typename IndexType,
typename GenType>
38 template<
typename IndexType,
typename GenType>
62 bool is_free(value_type
id)
const;
75 template<
typename IndexType,
typename GenType>
78 return { .idx = ++m_last_id, .gen = 0 };
87 template<
typename IndexType,
typename GenType>
92 template<
typename IndexType,
typename GenType>
94 if (
id.idx > m_last_id)
return true;
95 for (
const auto& id2 : m_free) {
96 if (
id == id2)
return true;
104 template<
typename T,
typename IndexType = std::
size_t,
typename GenType = u
int16_t>
107 using value_type = T;
109 using const_iterator =
const T*;
110 using reverse_iterator = std::reverse_iterator<iterator>;
111 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
112 using reference = T&;
113 using const_reference =
const T&;
114 using index_type = IndexType;
115 using size_type = IndexType;
116 using gen_type = GenType;
118 using storage_type =
typename std::aligned_storage_t<
sizeof(T),
alignof(T)>;
120 void grow() { reserve(m_cap == 0 ? DEFAULT_CAP : m_cap << 1); }
121 void remove_impl(
Key k,
bool gen_bump);
123 reference _get_raw(index_type idx)
const {
124 return reinterpret_cast<T*
>(std::launder(&m_data[0]))[idx];
128 storage_type* m_data{};
129 index_type* m_slot_idxes{};
134 index_type m_free_head{};
136 constexpr
static size_type DEFAULT_CAP = 4;
141 size_type size()
const {
return m_size; }
142 size_type capacity()
const {
return m_cap; }
143 size_type cap()
const {
return m_cap; }
144 bool is_empty()
const {
return m_size == 0; }
145 bool empty()
const {
return is_empty(); }
151 T& at_unsafe(
Key k) {
return at(k).unwrap(); }
152 const T& at_unsafe(
Key k)
const {
return at(k).unwrap(); }
154 gen_type get_curr_gen(index_type idx)
const {
return idx < m_cap ? m_slots[idx].gen : 0; }
155 gen_type get_curr_gen(
Key k)
const {
return get_curr_gen(k.idx); }
156 Key get_curr_key(index_type idx)
const {
return {.idx = idx, .gen = get_curr_gen(idx)}; }
157 Key get_curr_key(
Key k)
const {
return get_curr_key(k.idx); }
158 bool is_free(index_type key_idx)
const;
159 bool is_free(
Key k)
const {
return is_free(k.idx); }
161 Key add(
const T& elem);
162 Key push(
const T& elem) {
return add(elem); }
164 template<
typename... Args>
165 Key emplace(Args&&... args) {
return add(T(std::forward<Args>(args)...)); }
170 template<
typename... Args>
171 bool insert_emplace(
Key k, Args&&... args);
173 void reserve(size_type new_cap);
178 void erase(
Key k) { remove(k); }
181 iterator begin() {
return &_get_raw(0); }
182 const_iterator begin()
const {
return cbegin(); }
183 iterator end() {
return begin() + m_size; }
184 const_iterator end()
const {
return cend(); }
185 const_iterator cbegin()
const {
186 return reinterpret_cast<const T*
>(std::launder(&m_data[0]));
188 const_iterator cend()
const {
return cbegin() + m_size; }
189 reverse_iterator rbegin() {
return reverse_iterator(end()); }
190 const_reverse_iterator rbegin()
const {
return crbegin(); }
191 reverse_iterator rend() {
return reverse_iterator(begin()); }
192 const_reverse_iterator rend()
const {
return crend(); }
193 const_reverse_iterator crbegin() {
return const_reverse_iterator(cend()); }
194 const_reverse_iterator crend() {
return const_reverse_iterator(cbegin()); }
197 template<
typename T,
typename IndexType,
typename GenType>
199 std::destroy(m_data, m_data + m_size);
201 std::destroy(m_slots, m_slots + m_cap);
203 std::destroy(m_slot_idxes, m_slot_idxes + m_cap);
204 std::free(m_slot_idxes);
205 m_size = m_cap = m_free_head = 0;
207 template<
typename T,
typename IndexType,
typename GenType>
208 bool SlotMap<T, IndexType, GenType>::is_free(index_type key_idx)
const {
209 if (m_size == m_cap)
return false;
210 for (index_type idx = m_free_head;; idx = m_slots[idx].idx) {
211 if (idx == key_idx)
return true;
212 if (idx == m_slots[idx].idx)
break;
216 template<
typename T,
typename IndexType,
typename GenType>
217 Option<T&> SlotMap<T, IndexType, GenType>::at_impl(SlotMap<T, IndexType, GenType>::Key k)
const {
219 const Key& key = m_slots[k.idx];
224 template<
typename T,
typename IndexType,
typename GenType>
225 void SlotMap<T, IndexType, GenType>::reserve(size_type new_cap) {
226 if (new_cap <= m_cap)
return;
228 storage_type* new_data;
230 index_type* new_idxes;
232 new_data =
static_cast<storage_type*
>(std::aligned_alloc(
alignof(T),
233 sizeof(T) * new_cap));
234 new_slots =
static_cast<Key*
>(std::aligned_alloc(
alignof(Key),
235 sizeof(Key) * new_cap));
236 new_idxes =
static_cast<index_type*
>(std::aligned_alloc(
alignof(index_type),
237 sizeof(index_type) * new_cap));
239 std::uninitialized_copy(m_data, m_data + m_size, new_data);
240 std::uninitialized_copy(m_slots, m_slots + m_cap, new_slots);
241 std::uninitialized_copy(m_slot_idxes, m_slot_idxes + m_size, new_idxes);
243 std::destroy(m_data, m_data + m_size);
245 std::destroy(m_slots, m_slots + m_cap);
247 std::destroy(m_slot_idxes, m_slot_idxes + m_size);
248 std::free(m_slot_idxes);
252 m_slot_idxes = new_idxes;
254 for (index_type idx = m_cap; idx < new_cap; idx++) {
255 m_slots[idx].gen = 0;
257 m_slots[idx].idx = std::min(idx+1, new_cap-1);
259 if (m_size == m_cap) {
261 }
else for (index_type idx = m_free_head;; idx = m_slots[idx].idx) {
262 if (idx == m_slots[idx].idx) {
263 m_slots[idx].idx = m_cap;
269 template<
typename T,
typename IndexType,
typename GenType>
270 template<
typename... Args>
271 bool SlotMap<T, IndexType, GenType>::insert_emplace(Key k, Args&&... args) {
272 if (m_size == m_cap)
return false;
275 for (index_type idx = m_free_head;; idx = m_slots[idx].idx) {
276 if (idx == k.idx)
break;
277 if (idx == m_slots[idx].idx)
return false;
280 if (k.gen != m_slots[k.idx].gen)
return false;
282 if (m_size == m_cap) grow();
283 new(&m_data[m_size]) T(std::forward<Args>(args)...);
285 if (k.idx == m_free_head) {
286 m_free_head = m_slots[k.idx].idx;
287 }
else if (k.idx == m_slots[k.idx].idx) {
288 m_slots[prev_idx].idx = prev_idx;
290 m_slots[prev_idx].idx = m_slots[k.idx].idx;
292 m_slots[k.idx].idx = m_size;
293 m_slot_idxes[m_size++] = k.idx;
296 template<
typename T,
typename IndexType,
typename GenType>
298 return insert_emplace(k, elem);
300 template<
typename T,
typename IndexType,
typename GenType>
302 if (m_size == m_cap) grow();
303 new(&m_data[m_size]) T(elem);
305 index_type key_idx = m_free_head;
306 m_free_head = m_slots[key_idx].idx;
308 m_slots[key_idx].idx = m_size;
309 m_slot_idxes[m_size++] = key_idx;
310 return {.idx = key_idx, .gen = m_slots[key_idx].gen};
312 template<
typename T,
typename IndexType,
typename GenType>
313 void SlotMap<T, IndexType, GenType>::remove_impl(SlotMap<T, IndexType, GenType>::Key k,
bool gen_bump) {
314 if (k.idx >= m_cap)
return;
315 Key& key = m_slots[k.idx];
316 if (key.gen != k.gen)
return;
317 if (is_free(k.idx))
return;
320 _get_raw(key.idx).~T();
322 std::swap(m_data[key.idx], m_data[m_size]);
324 m_slots[m_slot_idxes[m_size]].idx = key.idx;
325 m_slot_idxes[key.idx] = m_slot_idxes[m_size];
327 key.idx = m_free_head;
328 if (gen_bump) key.gen++;
331 template<
typename T,
typename IndexType,
typename GenType>
332 void SlotMap<T, IndexType, GenType>::remove(SlotMap<T, IndexType, GenType>::Key k) {
333 remove_impl(k,
true);
335 template<
typename T,
typename IndexType,
typename GenType>
337 remove_impl(k,
false);
339 template<
typename T,
typename IndexType,
typename GenType>
341 for (index_type i = 0; i < m_cap; i++) remove({.idx = i, .gen = m_slots[i].gen});
347 template<
typename IndexType,
typename GenType>
348 struct hash<
nta::utils::SlotMapKey<IndexType, GenType>> {
351 std::hash<GenType>()(key.gen));
356 #endif // NTA_SLOTMAP_H_INCLUDED