RavEngine
Loading...
Searching...
No Matches
NvFlowArray.h
1// Redistribution and use in source and binary forms, with or without
2// modification, are permitted provided that the following conditions
3// are met:
4// * Redistributions of source code must retain the above copyright
5// notice, this list of conditions and the following disclaimer.
6// * Redistributions in binary form must reproduce the above copyright
7// notice, this list of conditions and the following disclaimer in the
8// documentation and/or other materials provided with the distribution.
9// * Neither the name of NVIDIA CORPORATION nor the names of its
10// contributors may be used to endorse or promote products derived
11// from this software without specific prior written permission.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24//
25// Copyright (c) 2014-2022 NVIDIA Corporation. All rights reserved.
26
27#pragma once
28
29#define NV_FLOW_ARRAY_CACHE_ENABLED 1
30
31#include <new>
32#include <utility>
33
34template<class T, NvFlowUint64 staticCapacity = 0u, void(prerelease)(void* data, NvFlowUint64 size) = nullptr>
36{
37 #if NV_FLOW_ARRAY_CACHE_ENABLED
38 static const NvFlowUint64 s_staticCapacity = staticCapacity;
39 #else
40 static const NvFlowUint64 s_staticCapacity = 0u;
41 #endif
42
43 T* data = nullptr;
44 NvFlowUint64 capacity = 0u;
45 NvFlowUint64 size = 0u;
46 unsigned char cache[s_staticCapacity * sizeof(T) + 8u];
47
48 void release()
49 {
50 for (NvFlowUint64 i = 0; i < capacity; i++)
51 {
52 data[i].~T();
53 }
54 if (data != nullptr && (T*)cache != data)
55 {
56 operator delete[](data);
57 }
58 data = nullptr;
59 capacity = 0u;
60 size = 0u;
61 }
62
63 void move(NvFlowArray& rhs)
64 {
65 data = rhs.data;
66 capacity = rhs.capacity;
67 size = rhs.size;
68 if (rhs.data == (T*)rhs.cache)
69 {
70 data = (T*)cache;
71 for (NvFlowUint64 idx = 0u; idx < capacity; idx++)
72 {
73 new(data + idx) T(std::move(rhs.data[idx]));
74 }
75 }
76 // to match destructed state
77 rhs.data = nullptr;
78 rhs.capacity = 0u;
79 rhs.size = 0u;
80 }
81
82 void reserve(NvFlowUint64 requestedCapacity)
83 {
84 if (requestedCapacity <= capacity)
85 {
86 return;
87 }
88
89 NvFlowUint64 newSize = size;
90 NvFlowUint64 newCapacity = capacity;
91 if (newCapacity < s_staticCapacity)
92 {
93 newCapacity = s_staticCapacity;
94 }
95 if (newCapacity == 0u)
96 {
97 newCapacity = 1u;
98 }
99 while (newCapacity < requestedCapacity)
100 {
101 newCapacity *= 2u;
102 }
103
104 T* newData = (T*)(newCapacity <= s_staticCapacity ? (void*)cache : operator new[](newCapacity * sizeof(T)));
105 // copy to new
106 for (NvFlowUint64 i = 0; i < newSize; i++)
107 {
108 new(newData + i) T(std::move(data[i]));
109 }
110 for (NvFlowUint64 i = newSize; i < newCapacity; i++)
111 {
112 new(newData + i) T();
113 }
114 if (prerelease)
115 {
116 prerelease(data + size, capacity - size);
117 }
118 // cleanup old
119 release();
120 // commit new
121 data = newData;
122 capacity = newCapacity;
123 size = newSize;
124 }
125
127 {
128 reserve(s_staticCapacity);
129 }
130
132 {
133 move(rhs);
134 }
135
137 {
138 if (prerelease)
139 {
140 prerelease(data, capacity);
141 }
142 release();
143 }
144
145 T& operator[](NvFlowUint64 idx)
146 {
147 return data[idx];
148 }
149
150 const T& operator[](NvFlowUint64 idx) const
151 {
152 return data[idx];
153 }
154
155 NvFlowUint64 allocateBack()
156 {
157 reserve(size + 1);
158 size++;
159 return size - 1;
160 }
161
162 void pushBack(const T& v)
163 {
164 operator[](allocateBack()) = v;
165 }
166
167 T& back()
168 {
169 return operator[](size - 1);
170 }
171
172 void popBack()
173 {
174 size--;
175 }
176};
177
179template <class T, NvFlowUint64 staticCapacity = 0u, void(prerelease)(void* data, NvFlowUint64 size) = nullptr>
180NV_FLOW_INLINE void NvFlowArray_copy(NvFlowArray<T, staticCapacity, prerelease>& dst, const NvFlowArray<T, staticCapacity, prerelease>& src)
181{
182 dst.size = 0u;
183 dst.reserve(src.size);
184 dst.size = src.size;
185 for (NvFlowUint64 idx = 0u; idx < dst.size; idx++)
186 {
187 dst[idx] = src[idx];
188 }
189}
190
191template<class T>
192NV_FLOW_INLINE void NvFlowArrayPointer_prerelease(void* dataIn, NvFlowUint64 size)
193{
194 T* data = (T*)dataIn;
195 for (NvFlowUint64 idx = 0u; idx < size; idx++)
196 {
197 if (data[idx])
198 {
199 delete data[idx];
200 data[idx] = nullptr;
201 }
202 }
203}
204
205template<class T>
206NV_FLOW_INLINE void NvFlowArrayPointer_allocate(T*& ptr)
207{
208 ptr = new T();
209}
210
211template<class T, NvFlowUint64 staticCapacity = 0u>
212struct NvFlowArrayPointer : public NvFlowArray<T, staticCapacity, NvFlowArrayPointer_prerelease<T>>
213{
215 {
216 }
218 {
219 }
221 {
222 }
223 T allocateBackPointer()
224 {
225 NvFlowUint64 allocIdx = this->allocateBack();
226 if (!(*this)[allocIdx])
227 {
228 NvFlowArrayPointer_allocate((*this)[allocIdx]);
229 }
230 return (*this)[allocIdx];
231 }
232 void pushBackPointer(const T& v)
233 {
234 NvFlowUint64 allocIdx = this->allocateBack();
235 deletePointerAtIndex(allocIdx);
236 (*this)[allocIdx] = v;
237 }
238 void swapPointers(NvFlowUint64 idxA, NvFlowUint64 idxB)
239 {
240 T temp = (*this)[idxA];
241 (*this)[idxA] = (*this)[idxB];
242 (*this)[idxB] = temp;
243 }
244 void removeSwapPointerAtIndex(NvFlowUint64 idx)
245 {
246 swapPointers(idx, this->size - 1u);
247 this->size--;
248 }
249 void removeSwapPointer(T ptr)
250 {
251 for (NvFlowUint64 idx = 0u; idx < this->size; idx++)
252 {
253 if ((*this)[idx] == ptr)
254 {
255 removeSwapPointerAtIndex(idx);
256 break;
257 }
258 }
259 }
260 void deletePointerAtIndex(NvFlowUint64 idx)
261 {
262 if ((*this)[idx])
263 {
264 delete (*this)[idx];
265 (*this)[idx] = nullptr;
266 }
267 }
268 void deletePointers()
269 {
270 this->size = this->capacity;
271 for (NvFlowUint64 idx = 0u; idx < this->size; idx++)
272 {
273 deletePointerAtIndex(idx);
274 }
275 this->size = 0u;
276 }
277};
278
279template<class T, NvFlowUint64 staticCapacity = 0u>
281{
283 NvFlowUint64 freeIdx = 0u;
284 NvFlowUint64 frontIdx = 0u;
285 NvFlowUint64 backIdx = 0u;
286
288 {
289 }
291 arr(std::move(rhs.arr)),
292 freeIdx(rhs.freeIdx),
293 frontIdx(rhs.frontIdx),
294 backIdx(rhs.backIdx)
295 {
296 }
298 {
299 }
300
301 T& front()
302 {
303 return arr[frontIdx];
304 }
305
306 T& back()
307 {
308 return arr[(backIdx - 1u) & (arr.size - 1)];
309 }
310
311 NvFlowUint64 activeCount()
312 {
313 return (backIdx - frontIdx) & (arr.size - 1);
314 }
315
316 NvFlowUint64 freeCount()
317 {
318 return (frontIdx - freeIdx) & (arr.size - 1);
319 }
320
321 void popFront()
322 {
323 frontIdx = (frontIdx + 1u) & (arr.size - 1);
324 }
325
326 void popFree()
327 {
328 freeIdx = (freeIdx + 1u) & (arr.size - 1);
329 }
330
331 T& operator[](NvFlowUint64 idx)
332 {
333 return arr[(frontIdx + idx) & (arr.size - 1)];
334 }
335
336 const T& operator[](NvFlowUint64 idx) const
337 {
338 return arr[(frontIdx + idx) & (arr.size - 1)];
339 }
340
341 NvFlowUint64 allocateBack()
342 {
343 if (arr.size == 0u)
344 {
345 arr.allocateBack();
346 }
347 if (freeCount() > 0u)
348 {
349 auto tmp = arr[freeIdx];
350 arr[freeIdx] = arr[backIdx];
351 arr[backIdx] = tmp;
352 popFree();
353 }
354 else if ((activeCount() + 1u) > (arr.size - 1))
355 {
356 NvFlowUint64 oldSize = arr.size;
357 arr.reserve(2u * oldSize);
358 arr.size = 2u * oldSize;
359 if (backIdx < frontIdx)
360 {
361 for (NvFlowUint64 idx = 0u; idx < backIdx; idx++)
362 {
363 auto tmp = arr[idx + oldSize];
364 arr[idx + oldSize] = arr[idx];
365 arr[idx] = tmp;
366 }
367 backIdx += oldSize;
368 }
369 }
370 NvFlowUint64 allocIdx = backIdx;
371 backIdx = (backIdx + 1u) & (arr.size - 1);
372 return allocIdx;
373 }
374
375 void pushBack(const T& v)
376 {
377 NvFlowUint64 allocIdx = allocateBack();
378 arr.deletePointerAtIndex(allocIdx);
379 arr[allocIdx] = v;
380 }
381
382 T allocateBackPointer()
383 {
384 NvFlowUint64 allocIdx = allocateBack();
385 if (!arr[allocIdx])
386 {
387 NvFlowArrayPointer_allocate(arr[allocIdx]);
388 }
389 return arr[allocIdx];
390 }
391
392 void deletePointers()
393 {
394 arr.deletePointers();
395 }
396};
Definition NvFlowArray.h:213
Definition NvFlowArray.h:36
Definition NvFlowArray.h:281