FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
slotmap.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8// includes, system
9#include <algorithm>
10#include <optional>
11#include <vector>
12
13// includes, feat
15
16namespace FEAT::Util
17{
27 {
28 SlotMapKey() : index(0), generation(0)
29 {
30 }
31 SlotMapKey(std::uint32_t i, std::uint32_t g) : index(i), generation(g)
32 {
33 }
34
35 std::uint32_t index;
36 std::uint32_t generation;
37 };
38
46 template<typename V, typename Key = SlotMapKey>
48 {
49 KeyValuePair(V& v, Key k) : value(v), key(k)
50 {
51 }
52
53 V& value;
54 Key key;
55 };
56
64 template<typename V, typename Key = SlotMapKey>
66 {
67 ConstKeyValuePair(const V& v, Key k) : value(v), key(k)
68 {
69 }
70
71 const V& value;
72 Key key;
73 };
74
147 template<typename V, typename Key = SlotMapKey>
149 {
150 public:
151 using ValueType = V;
152 using KeyType = Key;
153
157 SlotMap() : freelist{0, 0}
158 {
159 // Create initial slot, so that freelist is always valid
160 _slots.emplace_back(Slot());
161 }
162
171 Key insert(V&& value)
172 {
173 std::uint32_t idx = freelist.head;
174
175 // Adjust freelist
176 if(idx == freelist.tail)
177 {
178 // Used up the last Slot. Push a new one to keep freelist valid
179 _slots.push_back(Slot());
180 freelist.head = freelist.tail = (std::uint32_t)_slots.size() - 1;
181 }
182 else
183 {
184 // Move head to next element of freelist
185 freelist.head = _slots[idx].index;
186 }
187
188 Slot& slot = _slots[idx];
189
190 // Point slot to new data
191 slot.index = (std::uint32_t)_data.size();
192
193 // Push new data
194 _data.push_back(std::move(value));
195
196 // Update erase list
197 // Slot for new data is _slots[idx]
198 _erase.push_back(idx);
199
200 return Key(idx, slot.generation);
201 }
202
211 Key insert(const V& value)
212 {
213 std::uint32_t idx = freelist.head;
214
215 if(idx == freelist.tail)
216 {
217 // Used up the last Slot. Push a new one to keep freelist valid
218 _slots.push_back(Slot());
219 freelist.head = freelist.tail = (std::uint32_t)_slots.size() - 1;
220 }
221 else
222 {
223 // Move head to next element of freelist
224 freelist.head = _slots[idx].index;
225 }
226
227 Slot& slot = _slots[idx];
228
229 // Point slot to new data
230 slot.index = static_cast<std::uint32_t>(_data.size());
231
232 // Push new data
233 _data.push_back(value);
234
235 // Update erase list
236 // Slot for new data is _slots[idx]
237 _erase.push_back(idx);
238
239 return Key(idx, slot.generation);
240 }
241
249 void erase(const Key& key)
250 {
251 if(!contains_key(key))
252 {
253 return;
254 }
255 // Retrieve Slot for key
256 Slot& slot = try_get_slot(key);
257
258 // Increment the slots generation
259 // Previous keys are no longer valid
260 slot.generation++;
261
262 // Exchange positions of to-be-deleted element and last element
263 // of _data and _erase for O(1) deletion later
264 std::swap(_data[slot.index], _data[_data.size() - 1]);
265 std::swap(_erase[slot.index], _erase[_erase.size() - 1]);
266
267 // Fix Slot of moved element
268 _slots[_erase[slot.index]].index = slot.index;
269
270 // Actually delete elements
271 _data.pop_back();
272 _erase.pop_back();
273
274 // Slot can now be reused. Add slot to freelist
275 _slots[freelist.tail].index = key.index;
276 freelist.tail = key.index;
277 _slots[freelist.tail].index = freelist.tail;
278 }
279
291 Key replace(Key& key, V&& value)
292 {
293 erase(key);
294 return insert(value);
295 }
296
308 Key replace(Key& key, V& value)
309 {
310 erase(key);
311 return insert(value);
312 }
313
322 bool contains_key(const Key& key) const
323 {
324 return (key.index < _slots.size() && _slots[key.index].generation == key.generation);
325 }
326
335 const V& operator[](const Key& key) const
336 {
337 const Slot& slot = try_get_slot(key);
338 ASSERTM(slot.index < _data.size(), "Invalid slot index.");
339 return _data[slot.index];
340 }
341
350 V& operator[](const Key& key)
351 {
352 Slot& slot = try_get_slot(key);
353 ASSERTM(slot.index < _data.size(), "Invalid slot index.");
354 return _data[slot.index];
355 }
356
363 {
364 _slots.reserve(capacity + 1);
365 _data.reserve(capacity);
366 _slots.reserve(capacity);
367 }
368
375 {
376 return _data.capacity();
377 }
378
384 Index size() const
385 {
386 return _data.size();
387 }
388
389 V* data()
390 {
391 return _data.data();
392 }
393
394 const V* data() const
395 {
396 return _data.data();
397 }
398
399 std::size_t bytes() const
400 {
401 return sizeof(freelist) + _slots.size() * sizeof(Slot) + _data.size() * sizeof(V) +
402 _erase.size() * sizeof(Index);
403 }
404
420 {
421 public:
422 SlotMapIterator(SlotMap<V, Key>& map, Index i) : _slotmap(map), _index(i)
423 {
424 }
425
426 bool operator==(const SlotMapIterator& rhs)
427 {
428 // Iterators are identical if they refer to the same slotmap and point to the same indices
429 return &(this->_slotmap) == &(rhs._slotmap) && this->_index == rhs._index;
430 }
431 bool operator!=(const SlotMapIterator& rhs)
432 {
433 return !(*this == rhs);
434 }
435
436 SlotMapIterator& operator++()
437 {
438 _index++;
439 return *this;
440 }
441
442 KeyValuePair<V, Key> operator*()
443 {
444 // Retrieve slot for current index via erase table
445 std::uint32_t slot_index = _slotmap._erase[_index];
446 Slot& slot = _slotmap._slots[slot_index];
447 return KeyValuePair<V, Key>(_slotmap._data[slot.index], Key(slot_index, slot.generation));
448 }
449
450 private:
451 SlotMap<V, Key>& _slotmap;
452 Index _index;
453 };
454
463 {
464 public:
465 ConstSlotMapIterator(const SlotMap<V, Key>& map, Index i) : _slotmap(map), _index(i)
466 {
467 }
468
469 bool operator==(const ConstSlotMapIterator& rhs)
470 {
471 // Iterators are identical if they refer to the same slotmap and point to the same indices
472 return &(this->_slotmap) == &(rhs._slotmap) && this->_index == rhs._index;
473 }
474 bool operator!=(const ConstSlotMapIterator& rhs)
475 {
476 return !(*this == rhs);
477 }
478
479 ConstSlotMapIterator& operator++()
480 {
481 _index++;
482 return *this;
483 }
484
485 ConstKeyValuePair<V, Key> operator*()
486 {
487 // Retrieve slot for current index via erase table
488 std::uint32_t slot_index = _slotmap._erase[_index];
489 const Slot& slot = _slotmap._slots[slot_index];
490 return ConstKeyValuePair<V, Key>(_slotmap._data[slot.index], Key(slot_index, slot.generation));
491 }
492
493 private:
494 const SlotMap<V, Key>& _slotmap;
495 Index _index;
496 };
497
498 SlotMapIterator begin()
499 {
500 return SlotMapIterator(*this, 0);
501 }
502
503 SlotMapIterator end()
504 {
505 return SlotMapIterator(*this, _data.size());
506 }
507
508 ConstSlotMapIterator begin() const
509 {
510 return ConstSlotMapIterator(*this, 0);
511 }
512
513 ConstSlotMapIterator end() const
514 {
515 return ConstSlotMapIterator(*this, _data.size());
516 }
517
518 private:
522 struct Slot
523 {
524 Slot() : index(0), generation(1)
525 {
526 }
527 Slot(std::uint32_t i, std::uint32_t g) : index(i), generation(g)
528 {
529 }
530
531 std::uint32_t index;
532 std::uint32_t generation;
533 };
534
543 Slot& try_get_slot(const Key& key)
544 {
545 ASSERTM(key.index < _slots.size(), "Invalid SlotMap key. Index exceeds number of slots.");
546 Slot& slot = _slots[key.index];
547 ASSERTM(key.generation == slot.generation, "Invalid SlotMap key. Generation mismatch.");
548 return slot;
549 }
550
551 const Slot& try_get_slot(const Key& key) const
552 {
553 ASSERTM(key.index < _slots.size(), "Invalid SlotMap key. Index exceeds number of slots.");
554 const Slot& slot = _slots[key.index];
555 ASSERTM(key.generation == slot.generation, "Invalid SlotMap key. Generation mismatch.");
556 return slot;
557 }
558
559 struct
560 {
561 std::uint32_t head;
562 std::uint32_t tail;
563 } freelist;
564
565 std::vector<Slot> _slots;
566 std::vector<V> _data;
567 std::vector<std::uint32_t> _erase;
568 };
569
570 template<typename V, typename Key = SlotMapKey>
572 {
573 public:
574 void insert(const Key& key, const V& value)
575 {
576 if(key.index >= _slots.size())
577 {
578 Index extend_by = 1 + key.index - _slots.size();
579 _slots.insert(_slots.end(), extend_by, Slot());
580 }
581
582 Slot& slot = _slots[key.index];
583 slot.value = std::optional<V>(value);
584 slot.generation = key.generation;
585 }
586
587 bool contains_key(const Key& key)
588 {
589 return key.index < _slots.size() && _slots[key.index].generation == key.generation &&
590 _slots[key.index].value.has_value();
591 }
592
601 const V& operator[](const Key& key) const
602 {
603 ASSERTM(key.index < _slots.size(), "Invalid SecondaryMap key. Index exceeds number of slots.");
604 const Slot& slot = _slots[key.index];
605 ASSERTM(slot.value.has_value(), "Invalid SecondaryMap key. Slot is unoccupied.");
606 ASSERTM(key.generation == slot.generation, "Invalid SecondaryMap key. Generation mismatch.");
607 return slot.value.value();
608 }
609
618 V& operator[](const Key& key)
619 {
620 ASSERTM(key.index < _slots.size(), "Invalid SecondaryMap key. Index exceeds number of slots.");
621 Slot& slot = _slots[key.index];
622 ASSERTM(slot.value.has_value(), "Invalid SecondaryMap key. Slot is unoccupied.");
623 ASSERTM(key.generation == slot.generation, "Invalid SecondaryMap key. Generation mismatch.");
624 return slot.value.value();
625 }
626
627 private:
628 struct Slot
629 {
630 Slot() : generation(1), value(std::nullopt)
631 {
632 }
633 explicit Slot(V&& v) : generation(1), value(std::move(v))
634 {
635 }
636
637 std::uint32_t generation;
638 std::optional<V> value;
639 };
640
641 std::vector<Slot> _slots;
642 };
643} // namespace FEAT::Util
#define ASSERTM(expr, msg)
Debug-Assertion macro definition with custom message.
Definition: assertion.hpp:230
V & operator[](const Key &key)
Access Operator.
Definition: slotmap.hpp:618
const V & operator[](const Key &key) const
Access Operator.
Definition: slotmap.hpp:601
Const iterator type for the SlotMap.
Definition: slotmap.hpp:463
Iterator type for the SlotMap.
Definition: slotmap.hpp:420
High-performance associative container.
Definition: slotmap.hpp:149
const V & operator[](const Key &key) const
Access Operator.
Definition: slotmap.hpp:335
Key insert(V &&value)
Insert value into the SlotMap.
Definition: slotmap.hpp:171
void reserve(Index capacity)
Reserve at least capacity space in the SlotMap.
Definition: slotmap.hpp:362
V & operator[](const Key &key)
Access Operator.
Definition: slotmap.hpp:350
SlotMap()
Construct SlotMap with initial capacity zero.
Definition: slotmap.hpp:157
Key replace(Key &key, V &&value)
Replace the value stored at key with value.
Definition: slotmap.hpp:291
bool contains_key(const Key &key) const
Check if given key is still valid.
Definition: slotmap.hpp:322
void erase(const Key &key)
Remove a key from the SlotMap.
Definition: slotmap.hpp:249
Index size() const
Retrieve current size of the SlotMap.
Definition: slotmap.hpp:384
Key insert(const V &value)
Insert a value into the SlotMap.
Definition: slotmap.hpp:211
Key replace(Key &key, V &value)
Replace the value stored at key with value.
Definition: slotmap.hpp:308
Index capacity() const
Retrieve current capacity of the SlotMap.
Definition: slotmap.hpp:374
Slot & try_get_slot(const Key &key)
Helper method to retrieve a slot.
Definition: slotmap.hpp:543
@ value
specifies whether the space should supply basis function values
std::uint64_t Index
Index data type.
Return type for ConstSlotMapIterator.
Definition: slotmap.hpp:66
Return type for SlotMapIterator.
Definition: slotmap.hpp:48
Internal data structure for slots.
Definition: slotmap.hpp:523
Default key type for SlotMap.
Definition: slotmap.hpp:27