Plasma Engine  2.0
Loading...
Searching...
No Matches
DynamicArray_inl.h
1
2template <typename T>
4 : m_pAllocator(pAllocator)
5{
6}
7
8template <typename T>
9plDynamicArrayBase<T>::plDynamicArrayBase(T* pInplaceStorage, plUInt32 uiCapacity, plAllocator* pAllocator)
10 : m_pAllocator(pAllocator)
11{
12 m_pAllocator.SetFlags(Storage::External);
13 this->m_uiCapacity = uiCapacity;
14 this->m_pElements = pInplaceStorage;
15}
16
17template <typename T>
19 : m_pAllocator(pAllocator)
20{
21 plArrayBase<T, plDynamicArrayBase<T>>::operator=((plArrayPtr<const T>)other); // redirect this to the plArrayPtr version
23
24template <typename T>
26 : m_pAllocator(pAllocator)
27{
28 *this = std::move(other);
29}
30
31template <typename T>
33 : m_pAllocator(pAllocator)
35 plArrayBase<T, plDynamicArrayBase<T>>::operator=(other);
36}
38template <typename T>
40{
41 this->Clear();
42
43 if (m_pAllocator.GetFlags() == Storage::Owned)
44 {
45 // only delete our storage, if we own it
46 PL_DELETE_RAW_BUFFER(this->m_pAllocator, this->m_pElements);
47 }
48
49 this->m_uiCapacity = 0;
50 this->m_pElements = nullptr;
51}
52
53template <typename T>
55{
56 plArrayBase<T, plDynamicArrayBase<T>>::operator=((plArrayPtr<const T>)rhs); // redirect this to the plArrayPtr version
57}
58
59template <typename T>
61{
62 // Clear any existing data (calls destructors if necessary)
63 this->Clear();
64
65 if (this->m_pAllocator.GetPtr() == rhs.m_pAllocator.GetPtr() && rhs.m_pAllocator.GetFlags() == Storage::Owned) // only move the storage of rhs, if it owns it
66 {
67 if (this->m_pAllocator.GetFlags() == Storage::Owned)
68 {
69 // only delete our storage, if we own it
70 PL_DELETE_RAW_BUFFER(this->m_pAllocator, this->m_pElements);
71 }
72
73 // we now own this storage
74 this->m_pAllocator.SetFlags(Storage::Owned);
75
76 // move the data over from the other array
77 this->m_uiCount = rhs.m_uiCount;
78 this->m_uiCapacity = rhs.m_uiCapacity;
79 this->m_pElements = rhs.m_pElements;
80
81 // reset the other array to not reference the data anymore
82 rhs.m_pElements = nullptr;
83 rhs.m_uiCount = 0;
84 rhs.m_uiCapacity = 0;
85 }
86 else
87 {
88 // Ensure we have enough data.
89 this->Reserve(rhs.m_uiCount);
90 this->m_uiCount = rhs.m_uiCount;
91
93 this->GetElementsPtr(), rhs.GetElementsPtr() /* vital to remap rhs.m_pElements to absolute ptr */, rhs.m_uiCount);
94
95 rhs.m_uiCount = 0;
96 }
97}
98
99template <typename T>
101{
102 if (this->m_pAllocator.GetFlags() == Storage::External && other.m_pAllocator.GetFlags() == Storage::External)
103 {
104 constexpr plUInt32 InplaceStorageSize = 64;
105
106 struct alignas(PL_ALIGNMENT_OF(T)) Tmp
107 {
108 plUInt8 m_StaticData[InplaceStorageSize * sizeof(T)];
109 };
110
111 const plUInt32 localSize = this->m_uiCount;
112 const plUInt32 otherLocalSize = other.m_uiCount;
113
114 if (localSize <= InplaceStorageSize && otherLocalSize <= InplaceStorageSize && localSize <= other.m_uiCapacity &&
115 otherLocalSize <= this->m_uiCapacity)
116 {
117
118 Tmp tmp;
119 plMemoryUtils::RelocateConstruct(reinterpret_cast<T*>(tmp.m_StaticData), this->GetElementsPtr(), localSize);
120 plMemoryUtils::RelocateConstruct(this->GetElementsPtr(), other.GetElementsPtr(), otherLocalSize);
121 plMemoryUtils::RelocateConstruct(other.GetElementsPtr(), reinterpret_cast<T*>(tmp.m_StaticData), localSize);
122
123 plMath::Swap(this->m_pAllocator, other.m_pAllocator);
124 plMath::Swap(this->m_uiCount, other.m_uiCount);
125
126 return; // successfully swapped in place
127 }
128
129 // temp buffer was insufficient -> fallthrough
130 }
131
132 if (this->m_pAllocator.GetFlags() == Storage::External)
133 {
134 // enforce using own storage
135 this->Reserve(this->m_uiCapacity + 1);
136 }
137
138 if (other.m_pAllocator.GetFlags() == Storage::External)
139 {
140 // enforce using own storage
141 other.Reserve(other.m_uiCapacity + 1);
142 }
143
144 // no external storage involved -> swap pointers
145 plMath::Swap(this->m_pAllocator, other.m_pAllocator);
146 this->DoSwap(other);
147}
148
149template <typename T>
150void plDynamicArrayBase<T>::SetCapacity(plUInt32 uiCapacity)
151{
152 // do NOT early out here, it is vital that this function does its thing even if the old capacity would be sufficient
153
154 if (this->m_pAllocator.GetFlags() == Storage::Owned && uiCapacity > this->m_uiCapacity)
155 {
156 this->m_pElements = PL_EXTEND_RAW_BUFFER(this->m_pAllocator, this->m_pElements, this->m_uiCount, uiCapacity);
157 }
158 else
159 {
160 T* pOldElements = GetElementsPtr();
161
162 T* pNewElements = PL_NEW_RAW_BUFFER(this->m_pAllocator, T, uiCapacity);
163 plMemoryUtils::RelocateConstruct(pNewElements, pOldElements, this->m_uiCount);
164
165 if (this->m_pAllocator.GetFlags() == Storage::Owned)
166 {
167 PL_DELETE_RAW_BUFFER(this->m_pAllocator, pOldElements);
168 }
169
170 // after any resize, we definitely own the storage
171 this->m_pAllocator.SetFlags(Storage::Owned);
172 this->m_pElements = pNewElements;
173 }
174
175 this->m_uiCapacity = uiCapacity;
176}
177
178template <typename T>
179void plDynamicArrayBase<T>::Reserve(plUInt32 uiCapacity)
180{
181 if (this->m_uiCapacity >= uiCapacity)
182 return;
183
184 const plUInt64 uiCurCap64 = static_cast<plUInt64>(this->m_uiCapacity);
185 plUInt64 uiNewCapacity64 = uiCurCap64 + (uiCurCap64 / 2);
186
187 uiNewCapacity64 = plMath::Max<plUInt64>(uiNewCapacity64, uiCapacity);
188
189 constexpr plUInt64 uiMaxCapacity = 0xFFFFFFFFllu - (CAPACITY_ALIGNMENT - 1);
190
191 // the maximum value must leave room for the capacity alignment computation below (without overflowing the 32 bit range)
192 uiNewCapacity64 = plMath::Min<plUInt64>(uiNewCapacity64, uiMaxCapacity);
193
194 uiNewCapacity64 = (uiNewCapacity64 + (CAPACITY_ALIGNMENT - 1)) & ~(CAPACITY_ALIGNMENT - 1);
195
196 PL_ASSERT_DEV(uiCapacity <= uiNewCapacity64, "The requested capacity of {} elements exceeds the maximum possible capacity of {} elements.", uiCapacity, uiMaxCapacity);
197
198 SetCapacity(static_cast<plUInt32>(uiNewCapacity64 & 0xFFFFFFFF));
199}
200
201template <typename T>
203{
204 if (m_pAllocator.GetFlags() == Storage::External)
205 return;
206
207 if (this->IsEmpty())
208 {
209 // completely deallocate all data, if the array is empty.
210 PL_DELETE_RAW_BUFFER(this->m_pAllocator, this->m_pElements);
211 this->m_uiCapacity = 0;
212 }
213 else
214 {
215 const plUInt32 uiNewCapacity = (this->m_uiCount + (CAPACITY_ALIGNMENT - 1)) & ~(CAPACITY_ALIGNMENT - 1);
216 if (this->m_uiCapacity != uiNewCapacity)
217 SetCapacity(uiNewCapacity);
218 }
219}
220
221template <typename T>
222PL_ALWAYS_INLINE T* plDynamicArrayBase<T>::GetElementsPtr()
223{
224 return this->m_pElements;
225}
226
227template <typename T>
228PL_ALWAYS_INLINE const T* plDynamicArrayBase<T>::GetElementsPtr() const
229{
230 return this->m_pElements;
231}
232
233template <typename T>
235{
236 if (this->m_pAllocator.GetFlags() == Storage::External)
237 return 0;
238
239 return (plUInt64)this->m_uiCapacity * (plUInt64)sizeof(T);
240}
241
242template <typename T, typename A>
244 : plDynamicArrayBase<T>(A::GetAllocator())
245{
246}
247
248template <typename T, typename A>
250 : plDynamicArrayBase<T>(pAllocator)
251{
252}
253
254template <typename T, typename A>
256 : plDynamicArrayBase<T>(other, A::GetAllocator())
257{
258}
259
260template <typename T, typename A>
262 : plDynamicArrayBase<T>(other, A::GetAllocator())
263{
264}
265
266template <typename T, typename A>
268 : plDynamicArrayBase<T>(other, A::GetAllocator())
269{
270}
271
272template <typename T, typename A>
274 : plDynamicArrayBase<T>(std::move(other), other.GetAllocator())
275{
276}
277
278template <typename T, typename A>
280 : plDynamicArrayBase<T>(std::move(other), other.GetAllocator())
281{
282}
283
284template <typename T, typename A>
286{
288}
289
290template <typename T, typename A>
292{
294}
295
296template <typename T, typename A>
298{
300}
301
302template <typename T, typename A>
304{
305 plDynamicArrayBase<T>::operator=(std::move(rhs));
306}
307
308template <typename T, typename A>
310{
311 plDynamicArrayBase<T>::operator=(std::move(rhs));
312}
313
314template <typename T, typename AllocatorWrapper>
316{
317 return plArrayPtr<const T* const>(dynArray.GetData(), dynArray.GetCount());
318}
319
320template <typename T, typename AllocatorWrapper>
321plArrayPtr<const T> plMakeArrayPtr(const plDynamicArray<T, AllocatorWrapper>& dynArray)
322{
323 return plArrayPtr<const T>(dynArray.GetData(), dynArray.GetCount());
324}
325
326template <typename T, typename AllocatorWrapper>
327plArrayPtr<T> plMakeArrayPtr(plDynamicArray<T, AllocatorWrapper>& in_dynArray)
328{
329 return plArrayPtr<T>(in_dynArray.GetData(), in_dynArray.GetCount());
330}
Base class for all memory allocators.
Definition Allocator.h:23
Base class for all array containers. Implements all the basic functionality that only requires a poin...
Definition ArrayBase.h:19
T * GetData()
Returns a pointer to the array data, or nullptr if the array is empty.
Definition ArrayBase_inl.h:423
plUInt32 m_uiCount
The number of elements used from the array.
Definition ArrayBase.h:203
plUInt32 m_uiCapacity
Definition ArrayBase.h:206
T * m_pElements
Definition ArrayBase.h:200
plUInt32 GetCount() const
Returns the number of active elements in the array.
Definition ArrayBase_inl.h:172
This class encapsulates an array and it's size. It is recommended to use this class instead of plain ...
Definition ArrayPtr.h:37
Implementation of a dynamically growing array.
Definition DynamicArray.h:14
~plDynamicArrayBase()
Destructor.
Definition DynamicArray_inl.h:39
void Swap(plDynamicArrayBase< T > &other)
swaps the contents of this array with another one
Definition DynamicArray_inl.h:100
plUInt64 GetHeapMemoryUsage() const
Returns the amount of bytes that are currently allocated on the heap.
Definition DynamicArray_inl.h:234
plDynamicArrayBase(plAllocator *pAllocator)
Creates an empty array. Does not allocate any data yet.
Definition DynamicArray_inl.h:3
void Compact()
Tries to compact the array to avoid wasting memory. The resulting capacity is at least 'GetCount' (no...
Definition DynamicArray_inl.h:202
void Reserve(plUInt32 uiCapacity)
Expands the array so it can at least store the given capacity.
Definition DynamicArray_inl.h:179
void operator=(const plDynamicArrayBase< T > &rhs)
Copies the data from some other contiguous array into this one.
Definition DynamicArray_inl.h:54
Definition DynamicArray.h:81
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...
plUInt8 GetFlags() const
Returns the flags value only.
Definition PointerWithFlags.h:66
void SetFlags(plUInt8 uiFlags)
Changes only the flags value. The given value must fit into the reserved bits.
Definition PointerWithFlags.h:73
constexpr PL_ALWAYS_INLINE T Min(T f1, T f2)
Returns the smaller value, f1 or f2.
Definition Math_inl.h:27
PL_ALWAYS_INLINE void Swap(T &ref_f1, T &ref_f2)
Swaps the values in the two variables f1 and f2.
Definition Math_inl.h:224
constexpr PL_ALWAYS_INLINE T Max(T f1, T f2)
Returns the greater value, f1 or f2.
Definition Math_inl.h:39