36 struct GenerationalIndex {
38 uint32_t generation = 0;
40 bool operator==(
const GenerationalIndex &rhs)
const
42 return index == rhs.index && generation == rhs.generation;
46 class GenerationalIndexAllocator
48 struct AllocatorEntry {
50 uint32_t generation = 0;
53 std::vector<AllocatorEntry> m_entries;
54 std::vector<uint32_t> m_freeIndices;
57 GenerationalIndex allocate()
59 if (m_freeIndices.size() > 0) {
60 uint32_t index = m_freeIndices.back();
61 m_freeIndices.pop_back();
63 m_entries[index].generation += 1;
64 m_entries[index].isLive =
true;
66 return { index, m_entries[index].generation };
70 if (m_entries.size() + 1 >= (std::numeric_limits<uint32_t>::max)()) {
71 throw std::length_error(std::string(
"Maximum number of values inside GenerationalIndexArray reached: ") + std::to_string(m_entries.size()));
74 m_entries.push_back({
true, 0 });
75 return {
static_cast<uint32_t
>(m_entries.size()) - 1, 0 };
79 bool deallocate(GenerationalIndex index)
82 m_entries[index.index].isLive =
false;
83 m_freeIndices.emplace_back(index.index);
90 bool isLive(GenerationalIndex index)
const noexcept
92 return index.index < m_entries.size() &&
93 m_entries[index.index].generation == index.generation &&
94 m_entries[index.index].isLive;
103 class GenerationalIndexArray
113 std::vector<std::optional<Entry>> m_entries;
114 GenerationalIndexAllocator m_allocator;
118 void set(
const GenerationalIndex index, T &&value)
120 while (m_entries.size() <= index.index)
121 m_entries.emplace_back(std::nullopt);
124 uint32_t previousGeneration = 0;
126 const auto &previousEntry = m_entries[index.index];
128 previousGeneration = previousEntry->generation;
130 assert(index.generation >= previousGeneration);
133 m_entries[index.index] = std::optional<Entry>{ { index.generation, std::move(value) } };
137 GenerationalIndex insert(T &&value)
139 const auto index = m_allocator.allocate();
140 set(index, std::move(value));
145 void erase(GenerationalIndex index)
147 if (m_allocator.deallocate(index))
148 m_entries[index.index] = std::nullopt;
152 T *get(GenerationalIndex index)
154 if (index.index >= m_entries.size())
157 auto &entry = m_entries[index.index];
158 if (entry && entry->generation == index.generation) {
159 return &entry->value;
166 const T *get(GenerationalIndex index)
const noexcept
168 return const_cast<const T *
>(
const_cast<GenerationalIndexArray *
>(
this)->get(index));
174 const auto numEntries = entriesSize();
176 for (
auto i = decltype(numEntries){ 0 }; i < numEntries; ++i) {
177 const auto index = indexAtEntry(i);
179 if (index != std::nullopt)
186 uint32_t entriesSize() const noexcept
189 return static_cast<uint32_t
>(m_entries.size());
193 std::optional<GenerationalIndex> indexAtEntry(uint32_t entryIndex)
const
195 if (entryIndex >= entriesSize())
198 const auto &entry = m_entries[entryIndex];
202 GenerationalIndex index = { entryIndex, entry->generation };
204 if (m_allocator.isLive(index))
The main namespace of the KDBindings library.