Plasma Engine  2.0
Loading...
Searching...
No Matches
IdTable_inl.h
1
2// ***** Const Iterator *****
3
4template <typename IdType, typename ValueType>
6 : m_IdTable(idTable)
7 , m_CurrentIndex(0)
8 , m_CurrentCount(0)
9{
10 if (m_IdTable.IsEmpty())
11 return;
12
13 while (m_IdTable.m_pEntries[m_CurrentIndex].id.m_InstanceIndex != m_CurrentIndex)
14 {
15 ++m_CurrentIndex;
16 }
17}
18
19template <typename IdType, typename ValueType>
21{
22 return m_CurrentCount < m_IdTable.m_Count;
23}
24
25template <typename IdType, typename ValueType>
29 return m_IdTable.m_pEntries == it2.m_IdTable.m_pEntries && m_CurrentIndex == it2.m_CurrentIndex;
30}
32template <typename IdType, typename ValueType>
35{
36 return !(*this == it2);
38
39template <typename IdType, typename ValueType>
41{
42 return m_IdTable.m_pEntries[m_CurrentIndex].id;
44
45template <typename IdType, typename ValueType>
46PL_FORCE_INLINE const ValueType& plIdTableBase<IdType, ValueType>::ConstIterator::Value() const
47{
48 return m_IdTable.m_pEntries[m_CurrentIndex].value;
49}
50
51template <typename IdType, typename ValueType>
53{
54 ++m_CurrentCount;
55 if (m_CurrentCount == m_IdTable.m_Count)
56 return;
57
58 do
59 {
60 ++m_CurrentIndex;
61 } while (m_IdTable.m_pEntries[m_CurrentIndex].id.m_InstanceIndex != m_CurrentIndex);
62}
64template <typename IdType, typename ValueType>
67 Next();
68}
69
70
71// ***** Iterator *****
72
73template <typename IdType, typename ValueType>
75 : ConstIterator(idTable)
77}
78
79template <typename IdType, typename ValueType>
81{
82 return this->m_IdTable.m_pEntries[this->m_CurrentIndex].value;
83}
84
86// ***** plIdTableBase *****
87
88template <typename IdType, typename ValueType>
90{
91 m_pEntries = nullptr;
92 m_Count = 0;
93 m_Capacity = 0;
94 m_FreelistEnqueue = -1;
95 m_FreelistDequeue = 0;
96 m_pAllocator = pAllocator;
97}
99template <typename IdType, typename ValueType>
102 m_pEntries = nullptr;
103 m_Count = 0;
104 m_Capacity = 0;
105 m_FreelistEnqueue = -1;
106 m_FreelistDequeue = 0;
107 m_pAllocator = pAllocator;
108
109 *this = other;
111
112template <typename IdType, typename ValueType>
114{
115 for (IndexType i = 0; i < m_Capacity; ++i)
117 if (m_pEntries[i].id.m_InstanceIndex == i)
118 {
119 plMemoryUtils::Destruct(&m_pEntries[i].value, 1);
120 }
121 }
123 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntries);
124 m_Capacity = 0;
126
127template <typename IdType, typename ValueType>
129{
130 Clear();
131 Reserve(rhs.m_Capacity);
132
133 for (IndexType i = 0; i < rhs.m_Capacity; ++i)
135 Entry& entry = m_pEntries[i];
136
137 entry.id = rhs.m_pEntries[i].id;
138 if (entry.id.m_InstanceIndex == i)
139 {
140 plMemoryUtils::CopyConstruct(&entry.value, rhs.m_pEntries[i].value, 1);
141 }
142 }
143
144 m_Count = rhs.m_Count;
145 m_FreelistDequeue = rhs.m_FreelistDequeue;
146}
147
148template <typename IdType, typename ValueType>
150{
151 if (m_Capacity >= capacity + CAPACITY_ALIGNMENT)
152 return;
153
154 const plUInt64 uiCurCap64 = static_cast<plUInt64>(this->m_Capacity);
155 plUInt64 uiNewCapacity64 = uiCurCap64 + (uiCurCap64 / 2);
156
157 uiNewCapacity64 = plMath::Max<plUInt64>(uiNewCapacity64, capacity + CAPACITY_ALIGNMENT);
158
159 // the maximum value must leave room for the capacity alignment computation below (without overflowing the 32 bit range)
160 uiNewCapacity64 = plMath::Min<plUInt64>(uiNewCapacity64, 0xFFFFFFFFllu - (CAPACITY_ALIGNMENT - 1));
161
162 uiNewCapacity64 = (uiNewCapacity64 + (CAPACITY_ALIGNMENT - 1)) & ~(CAPACITY_ALIGNMENT - 1);
163
164 SetCapacity(static_cast<IndexType>(uiNewCapacity64 & 0xFFFFFFFF));
165}
166
167template <typename IdType, typename ValueType>
168PL_ALWAYS_INLINE typename plIdTableBase<IdType, ValueType>::IndexType plIdTableBase<IdType, ValueType>::GetCount() const
169{
170 return m_Count;
171}
172
173template <typename IdType, typename ValueType>
174PL_ALWAYS_INLINE bool plIdTableBase<IdType, ValueType>::IsEmpty() const
175{
176 return m_Count == 0;
177}
178
179template <typename IdType, typename ValueType>
181{
182 for (IndexType i = 0; i < m_Capacity; ++i)
183 {
184 Entry& entry = m_pEntries[i];
185
186 if (entry.id.m_InstanceIndex == i)
187 {
188 plMemoryUtils::Destruct(&entry.value, 1);
189 ++entry.id.m_Generation;
190 }
191
192 entry.id.m_InstanceIndex = static_cast<decltype(entry.id.m_InstanceIndex)>(i + 1);
193 }
194
195 m_FreelistDequeue = 0;
196 m_FreelistEnqueue = m_Capacity - 1;
197 m_Count = 0;
198}
199
200template <typename IdType, typename ValueType>
201IdType plIdTableBase<IdType, ValueType>::Insert(const ValueType& value)
202{
203 Reserve(m_Count + 1);
204
205 const IndexType uiNewIndex = m_FreelistDequeue;
206 Entry& entry = m_pEntries[uiNewIndex];
207
208 m_FreelistDequeue = entry.id.m_InstanceIndex;
209 entry.id.m_InstanceIndex = static_cast<decltype(entry.id.m_InstanceIndex)>(uiNewIndex);
210
211 plMemoryUtils::CopyConstruct(&entry.value, value, 1);
212
213 ++m_Count;
214
215 return entry.id;
216}
217
218template <typename IdType, typename ValueType>
220{
221 Reserve(m_Count + 1);
222
223 const IndexType uiNewIndex = m_FreelistDequeue;
224 Entry& entry = m_pEntries[uiNewIndex];
225
226 m_FreelistDequeue = entry.id.m_InstanceIndex;
227 entry.id.m_InstanceIndex = static_cast<decltype(entry.id.m_InstanceIndex)>(uiNewIndex);
228
229 plMemoryUtils::MoveConstruct<ValueType>(&entry.value, std::move(value));
230
231 ++m_Count;
232
233 return entry.id;
234}
235
236template <typename IdType, typename ValueType>
237bool plIdTableBase<IdType, ValueType>::Remove(const IdType id, ValueType* out_pOldValue /*= nullptr*/)
238{
239 if (m_Capacity <= id.m_InstanceIndex)
240 return false;
241
242 const IndexType uiIndex = id.m_InstanceIndex;
243 Entry& entry = m_pEntries[uiIndex];
244 if (!entry.id.IsIndexAndGenerationEqual(id))
245 return false;
246
247 if (out_pOldValue != nullptr)
248 *out_pOldValue = std::move(m_pEntries[uiIndex].value);
249
250 plMemoryUtils::Destruct(&entry.value, 1);
251
252 entry.id.m_InstanceIndex = m_pEntries[m_FreelistEnqueue].id.m_InstanceIndex;
253 ++entry.id.m_Generation;
254
255 // at wrap around, prevent generation from becoming 0, to ensure that a zero initialized array could ever contain a valid ID
256 if (entry.id.m_Generation == 0)
257 entry.id.m_Generation = 1;
258
259 m_pEntries[m_FreelistEnqueue].id.m_InstanceIndex = static_cast<decltype(entry.id.m_InstanceIndex)>(uiIndex);
260 m_FreelistEnqueue = uiIndex;
261
262 --m_Count;
263 return true;
264}
265
266template <typename IdType, typename ValueType>
267PL_FORCE_INLINE bool plIdTableBase<IdType, ValueType>::TryGetValue(const IdType id, ValueType& out_value) const
268{
269 const IndexType index = id.m_InstanceIndex;
270 if (index < m_Capacity && m_pEntries[index].id.IsIndexAndGenerationEqual(id))
271 {
272 out_value = m_pEntries[index].value;
273 return true;
274 }
275 return false;
276}
277
278template <typename IdType, typename ValueType>
279PL_FORCE_INLINE bool plIdTableBase<IdType, ValueType>::TryGetValue(const IdType id, ValueType*& out_pValue) const
280{
281 const IndexType index = id.m_InstanceIndex;
282 if (index < m_Capacity && m_pEntries[index].id.IsIndexAndGenerationEqual(id))
283 {
284 out_pValue = &m_pEntries[index].value;
285 return true;
286 }
287 return false;
288}
289
290template <typename IdType, typename ValueType>
291PL_FORCE_INLINE const ValueType& plIdTableBase<IdType, ValueType>::operator[](const IdType id) const
292{
293 PL_ASSERT_DEBUG(id.m_InstanceIndex < m_Capacity, "Out of bounds access. Table has {0} elements, trying to access element at index {1}.",
294 m_Capacity, id.m_InstanceIndex);
295 const Entry& entry = m_pEntries[id.m_InstanceIndex];
296 PL_ASSERT_DEBUG(entry.id.IsIndexAndGenerationEqual(id), "Stale access. Trying to access a value (generation: {0}) that has been removed and replaced by a new value (generation: {1})", entry.id.m_Generation, id.m_Generation);
297
298 return entry.value;
299}
300
301template <typename IdType, typename ValueType>
302PL_FORCE_INLINE ValueType& plIdTableBase<IdType, ValueType>::operator[](const IdType id)
303{
304 PL_ASSERT_DEBUG(id.m_InstanceIndex < m_Capacity, "Out of bounds access. Table has {0} elements, trying to access element at index {1}.", m_Capacity, id.m_InstanceIndex);
305
306 Entry& entry = m_pEntries[id.m_InstanceIndex];
307
308 PL_ASSERT_DEBUG(entry.id.IsIndexAndGenerationEqual(id), "Stale access. Trying to access a value (generation: {0}) that has been removed and replaced by a new value (generation: {1})", static_cast<int>(entry.id.m_Generation), id.m_Generation);
309
310 return entry.value;
311}
312
313template <typename IdType, typename ValueType>
314PL_FORCE_INLINE const ValueType& plIdTableBase<IdType, ValueType>::GetValueUnchecked(const IndexType index) const
315{
316 PL_ASSERT_DEBUG(index < m_Capacity, "Out of bounds access. Table has {0} elements, trying to access element at index {1}.", m_Capacity, index);
317 return m_pEntries[index].value;
318}
319
320template <typename IdType, typename ValueType>
321PL_FORCE_INLINE ValueType& plIdTableBase<IdType, ValueType>::GetValueUnchecked(const IndexType index)
322{
323 PL_ASSERT_DEBUG(index < m_Capacity, "Out of bounds access. Table has {0} elements, trying to access element at index {1}.", m_Capacity, index);
324 return m_pEntries[index].value;
325}
326
327template <typename IdType, typename ValueType>
328PL_FORCE_INLINE bool plIdTableBase<IdType, ValueType>::Contains(const IdType id) const
329{
330 const IndexType index = id.m_InstanceIndex;
331 return index < m_Capacity && m_pEntries[index].id.IsIndexAndGenerationEqual(id);
332}
333
334template <typename IdType, typename ValueType>
339
340template <typename IdType, typename ValueType>
345
346template <typename IdType, typename ValueType>
348{
349 return m_pAllocator;
350}
351
352template <typename IdType, typename ValueType>
354{
355 if (m_pEntries == nullptr)
356 return true;
357
358 IndexType uiIndex = m_FreelistDequeue;
359 const Entry* pEntry = m_pEntries + uiIndex;
360
361 while (pEntry->id.m_InstanceIndex < m_Capacity)
362 {
363 uiIndex = pEntry->id.m_InstanceIndex;
364 pEntry = m_pEntries + uiIndex;
365 }
366
367 return uiIndex == m_FreelistEnqueue;
368}
369
370
371// private methods
372template <typename IdType, typename ValueType>
373void plIdTableBase<IdType, ValueType>::SetCapacity(IndexType uiCapacity)
374{
375 Entry* pNewEntries = PL_NEW_RAW_BUFFER(m_pAllocator, Entry, (size_t)uiCapacity);
376
377 for (IndexType i = 0; i < m_Capacity; ++i)
378 {
379 pNewEntries[i].id = m_pEntries[i].id;
380
381 if (m_pEntries[i].id.m_InstanceIndex == i)
382 {
383 plMemoryUtils::RelocateConstruct(&pNewEntries[i].value, &m_pEntries[i].value, 1);
384 }
385 }
386
387 PL_DELETE_RAW_BUFFER(m_pAllocator, m_pEntries);
388 m_pEntries = pNewEntries;
389
390 InitializeFreelist(m_Capacity, uiCapacity);
391 m_Capacity = uiCapacity;
392}
393
394template <typename IdType, typename ValueType>
395inline void plIdTableBase<IdType, ValueType>::InitializeFreelist(IndexType uiStart, IndexType uiEnd)
396{
397 for (IndexType i = uiStart; i < uiEnd; ++i)
398 {
399 IdType& id = m_pEntries[i].id;
400 id = IdType(i + 1, 1); // initialize generation with 1, to prevent 0 from being a valid ID
401 }
402
403 m_FreelistEnqueue = uiEnd - 1;
404}
405
406
407template <typename IdType, typename V, typename A>
409 : plIdTableBase<IdType, V>(A::GetAllocator())
410{
411}
412
413template <typename IdType, typename V, typename A>
415 : plIdTableBase<IdType, V>(pAllocator)
416{
417}
418
419template <typename IdType, typename V, typename A>
421 : plIdTableBase<IdType, V>(other, A::GetAllocator())
422{
423}
424
425template <typename IdType, typename V, typename A>
427 : plIdTableBase<IdType, V>(other, A::GetAllocator())
428{
429}
430
431template <typename IdType, typename V, typename A>
433{
435}
436
437template <typename IdType, typename V, typename A>
439{
441}
Base class for all memory allocators.
Definition Allocator.h:23
Const iterator.
Definition IdTable.h:25
bool IsValid() const
Checks whether this iterator points to a valid element.
Definition IdTable_inl.h:20
const ValueType & Value() const
Returns the 'value' of the element that this iterator points to.
Definition IdTable_inl.h:46
bool operator==(const typename plIdTableBase< IdType, ValueType >::ConstIterator &it2) const
Checks whether the two iterators point to the same element.
Definition IdTable_inl.h:26
void Next()
Advances the iterator to the next element in the map. The iterator will not be valid anymore,...
Definition IdTable_inl.h:52
void operator++()
Shorthand for 'Next'.
Definition IdTable_inl.h:65
IdType Id() const
Returns the 'id' of the element that this iterator points to.
Definition IdTable_inl.h:40
bool operator!=(const typename plIdTableBase< IdType, ValueType >::ConstIterator &it2) const
Checks whether the two iterators point to the same element.
Definition IdTable_inl.h:33
Implementation of an id mapping table which stores id/value pairs.
Definition IdTable.h:18
~plIdTableBase()
Destructor.
Definition IdTable_inl.h:113
IndexType GetCount() const
Returns the number of active entries in the table.
Definition IdTable_inl.h:168
const ValueType & operator[](const IdType id) const
Returns the value to the given id. Does bounds checks in debug builds.
Definition IdTable_inl.h:291
bool TryGetValue(const IdType id, ValueType &out_value) const
Returns if an entry with the given id was found and if found writes out the corresponding value to ou...
Definition IdTable_inl.h:267
void Clear()
Clears the table.
Definition IdTable_inl.h:180
void Reserve(IndexType capacity)
Expands the table so it can at least store the given capacity.
Definition IdTable_inl.h:149
Iterator GetIterator()
Returns an Iterator to the very first element.
Definition IdTable_inl.h:335
const ValueType & GetValueUnchecked(const IndexType index) const
Returns the value at the given index. Does bounds checks in debug builds but does not check for stale...
Definition IdTable_inl.h:314
bool Contains(const IdType id) const
Returns if the table contains an entry corresponding to the given id.
Definition IdTable_inl.h:328
void operator=(const plIdTableBase< IdType, ValueType > &rhs)
Copies the data from another table into this one.
Definition IdTable_inl.h:128
plIdTableBase(plAllocator *pAllocator)
Creates an empty id-table. Does not allocate any data yet.
Definition IdTable_inl.h:89
bool IsFreelistValid() const
Returns whether the internal free-list is valid. For testing purpose only.
Definition IdTable_inl.h:353
bool Remove(const IdType id, ValueType *out_pOldValue=nullptr)
Removes the entry with the given id. Returns if an entry was removed and optionally writes out the ol...
Definition IdTable_inl.h:237
IdType Insert(const ValueType &value)
Inserts the value into the table and returns the corresponding id.
Definition IdTable_inl.h:201
bool IsEmpty() const
Returns true, if the table does not contain any elements.
Definition IdTable_inl.h:174
plAllocator * GetAllocator() const
Returns the allocator that is used by this instance.
Definition IdTable_inl.h:347
Definition IdTable.h:171
static void CopyConstruct(Destination *pDestination, const Source &copy, size_t uiCount=1)
Constructs uiCount objects of type T in a raw buffer at pDestination, by creating uiCount copies of c...
static void RelocateConstruct(T *pDestination, T *pSource, size_t uiCount=1)
Constructs uiCount objects of type T in a raw buffer at pDestination from an existing array of object...
static void MoveConstruct(T *pDestination, T &&source)
Constructs an object of type T in a raw buffer at pDestination, by using move construction from sourc...
static void Destruct(T *pDestination, size_t uiCount=1)
Destructs uiCount objects of type T at pDestination.
constexpr PL_ALWAYS_INLINE T Min(T f1, T f2)
Returns the smaller value, f1 or f2.
Definition Math_inl.h:27
constexpr PL_ALWAYS_INLINE T Max(T f1, T f2)
Returns the greater value, f1 or f2.
Definition Math_inl.h:39
Iterator with write access.
Definition IdTable.h:60
ValueType & Value()
Returns the 'value' of the element that this iterator points to.
Definition IdTable_inl.h:80