Nebula
Loading...
Searching...
No Matches
arrayallocatorsafe.h
Go to the documentation of this file.
1#pragma once
2//------------------------------------------------------------------------------
24//------------------------------------------------------------------------------
25#include "types.h"
26#include "util/pinnedarray.h"
28#include "threading/spinlock.h"
29#include <tuple>
30#include "tupleutility.h"
31#include "ids/id.h"
32
33// use this macro to safetly access an array allocator from within a scope
34#define __Lock(name, element) auto __allocator_lock_##name##__ = Util::AllocatorLock(&name, element);
35
36// use this macro when we need to retrieve an allocator and lock it with an explicit name
37#define __LockName(allocator, name, element) auto __allocator_lock_##name##__ = Util::AllocatorLock(allocator, element);
38
39namespace Util
40{
41
42template<class T>
44{
48 {
49 this->didAcquire = this->allocator->Acquire(this->element);
50 };
51
53 {
54 if (this->didAcquire)
55 this->allocator->Release(this->element);
56 }
57
59 uint32_t element;
61};
62
63template <uint MAX_ALLOCS = 0xFFFF, class ... TYPES>
65{
66public:
69
72
75
78
81
84
86 uint32_t Alloc();
87
89 void EraseIndex(const uint32_t id);
90
92 void EraseIndexSwap(const uint32_t id);
93
95 template <int MEMBER>
96 tuple_array_t<MEMBER, TYPES...>& Get(const uint32_t index);
97
99 template <int MEMBER>
100 const tuple_array_t<MEMBER, TYPES...>& ConstGet(const uint32_t index) const;
101
103 template <int MEMBER>
104 const tuple_array_t<MEMBER, TYPES...>& Get(const uint32_t index) const;
105
107 template <int MEMBER>
108 void Set(const uint32_t index, const tuple_array_t<MEMBER, TYPES...>& type);
109
111 template <int MEMBER>
112 const Util::Array<tuple_array_t<MEMBER, TYPES...>>& GetArray() const;
113
115 template <int MEMBER>
116 Util::Array<tuple_array_t<MEMBER, TYPES...>>& GetArray();
117
119 void Set(const uint32_t index, TYPES...);
120
122 const uint32_t Size() const;
123
125 void Reserve(uint32_t size);
126
128 void Clear();
129
133
135 void TryAcquire(const uint32_t index);
137 bool Acquire(const uint32_t index);
139 void Release(const uint32_t index);
140
141protected:
142
143 uint32_t size;
144 std::tuple<Util::PinnedArray<MAX_ALLOCS, TYPES>...> objects;
146
148};
149
150//------------------------------------------------------------------------------
153template<uint MAX_ALLOCS, class ...TYPES>
154inline
160
161//------------------------------------------------------------------------------
164template<uint MAX_ALLOCS, class ...TYPES>
165inline
167{
168 this->allocationLock.Lock();
169 rhs.allocationLock.Lock();
170 this->objects = rhs.objects;
171 this->size = rhs.size;
172 rhs.Clear();
173
174 this->allocationLock.Unlock();
175 rhs.allocationLock.Unlock();
176}
177
178//------------------------------------------------------------------------------
181template<uint MAX_ALLOCS, class ...TYPES>
182inline
190
191//------------------------------------------------------------------------------
194template<uint MAX_ALLOCS, class ...TYPES>
195inline
200
201//------------------------------------------------------------------------------
204template<uint MAX_ALLOCS, class ...TYPES>
205inline void
207{
208 this->allocationLock.Lock();
209 this->objects = rhs.objects;
210 this->size = rhs.size;
211 this->allocationLock.Unlock();
212}
213
214//------------------------------------------------------------------------------
217template<uint MAX_ALLOCS, class ...TYPES>
218inline void
220{
221 this->allocationLock.Lock();
222 rhs.allocationLock.Lock();
223 this->objects = rhs.objects;
224 this->size = rhs.size;
225 rhs.Clear();
226
227 this->allocationLock.Unlock();
228 rhs.allocationLock.Unlock();
229}
230
231//------------------------------------------------------------------------------
235template<uint MAX_ALLOCS, class ...TYPES>
236inline uint32_t
238{
239 this->allocationLock.Lock();
241 auto i = this->size++;
242 this->owners.Append(Threading::Thread::GetMyThreadId());
243 this->allocationLock.Unlock();
244 return i;
245}
246
247//------------------------------------------------------------------------------
250template<uint MAX_ALLOCS, class ...TYPES>
251inline void
253{
254 n_assert(this->owners[id] == Threading::Thread::GetMyThreadId());
255 this->allocationLock.Lock();
257 this->allocationLock.Unlock();
258 this->size--;
259}
260
261//------------------------------------------------------------------------------
264template<uint MAX_ALLOCS, class ...TYPES>
265inline void
267{
268 n_assert(this->owners[id] == Threading::Thread::GetMyThreadId());
269 this->allocationLock.Lock();
271 this->allocationLock.Unlock();
272 this->size--;
273}
274
275//------------------------------------------------------------------------------
278template<uint MAX_ALLOCS, class ...TYPES>
279inline const uint32_t
281{
282 return this->size;
283}
284
285//------------------------------------------------------------------------------
288template<uint MAX_ALLOCS, class ...TYPES>
289inline void
291{
292 this->allocationLock.Lock();
294 this->allocationLock.Unlock();
295 // Size is still the same.
296}
297
298//------------------------------------------------------------------------------
301template<uint MAX_ALLOCS, class ...TYPES>
302inline void
304{
305 this->allocationLock.Lock();
307 this->size = 0;
308 this->allocationLock.Unlock();
309}
310
311//------------------------------------------------------------------------------
314template<uint MAX_ALLOCS, class ...TYPES>
315template<int MEMBER>
316inline tuple_array_t<MEMBER, TYPES...>&
318{
319 n_assert(this->owners[index] == Threading::Thread::GetMyThreadId());
320 return std::get<MEMBER>(this->objects)[index];
321}
322
323//------------------------------------------------------------------------------
326template<uint MAX_ALLOCS, class ...TYPES>
327template<int MEMBER>
328inline const tuple_array_t<MEMBER, TYPES...>&
330{
331 // Allow const get when no thread is owning the element as well
332 n_assert(this->owners[index] == Threading::Thread::GetMyThreadId() || this->owners[index] == Threading::InvalidThreadId);
333 return std::get<MEMBER>(this->objects)[index];
334}
335
336//------------------------------------------------------------------------------
339template<uint MAX_ALLOCS, class ...TYPES>
340template<int MEMBER>
341inline const tuple_array_t<MEMBER, TYPES...>&
343{
344 // Allow const get when no thread is owning the element as well
345 n_assert(this->owners[index] == Threading::Thread::GetMyThreadId() || this->owners[index] == Threading::InvalidThreadId);
346 return std::get<MEMBER>(this->objects)[index];
347}
348
349//------------------------------------------------------------------------------
352template<uint MAX_ALLOCS, class ...TYPES>
353template<int MEMBER>
354inline void
356{
357 n_assert(this->owners[index] == Threading::Thread::GetMyThreadId());
358 std::get<MEMBER>(this->objects)[index] = type;
359}
360
361//------------------------------------------------------------------------------
364template<uint MAX_ALLOCS, class ...TYPES>
365template<int MEMBER>
366inline const Util::Array<tuple_array_t<MEMBER, TYPES...>>&
368{
369 return std::get<MEMBER>(this->objects);
370}
371
372//------------------------------------------------------------------------------
375template<uint MAX_ALLOCS, class ...TYPES>
376template<int MEMBER>
377inline Util::Array<tuple_array_t<MEMBER, TYPES...>>&
379{
380 return std::get<MEMBER>(this->objects);
381}
382
383//------------------------------------------------------------------------------
386template<uint MAX_ALLOCS, class ...TYPES>
387void
388ArrayAllocatorSafe<MAX_ALLOCS, TYPES...>::Set(const uint32_t index, TYPES... values)
389{
390 set_for_each_in_tuple(this->objects, index, values...);
391}
392
393//------------------------------------------------------------------------------
396template<uint MAX_ALLOCS, class ...TYPES>
397void
402
403//------------------------------------------------------------------------------
406template<uint MAX_ALLOCS, class ...TYPES>
407void
409{
410 Threading::ThreadId myThread = Threading::Thread::GetMyThreadId();
412 n_assert(currentThread == Threading::InvalidThreadId);
413}
414
415//------------------------------------------------------------------------------
418template<uint MAX_ALLOCS, class ...TYPES>
419bool
421{
422 Threading::ThreadId myThread = Threading::Thread::GetMyThreadId();
423 if (this->owners[index] == myThread)
424 return false;
425
426 // Spinlock
428 {
429 Threading::Thread::YieldThread();
430 };
431 return true;
432}
433
434//------------------------------------------------------------------------------
437template<uint MAX_ALLOCS, class ...TYPES>
438void
440{
441 n_assert(this->owners[index] == Threading::Thread::GetMyThreadId());
443}
444
445} // namespace Util
Definition spinlock.h:21
bool Acquire(const uint32_t index)
Acquire element, asserts if false and returns true if this call acquired.
Definition arrayallocatorsafe.h:420
uint32_t size
Definition arrayallocatorsafe.h:143
~ArrayAllocatorSafe()
destructor
Definition arrayallocatorsafe.h:196
void operator=(const ArrayAllocatorSafe< MAX_ALLOCS, TYPES... > &rhs)
assign operator
Definition arrayallocatorsafe.h:206
const uint32_t Size() const
get number of used indices
Definition arrayallocatorsafe.h:280
void Set(const uint32_t index, TYPES...)
set for each in tuple
Definition arrayallocatorsafe.h:388
uint32_t Alloc()
allocate a new resource
Definition arrayallocatorsafe.h:237
const tuple_array_t< MEMBER, TYPES... > & ConstGet(const uint32_t index) const
Get const explicitly.
Definition arrayallocatorsafe.h:329
void Reserve(uint32_t size)
grow capacity of arrays to size
Definition arrayallocatorsafe.h:290
Threading::Spinlock allocationLock
Definition arrayallocatorsafe.h:147
void EraseIndex(const uint32_t id)
Erase element for each.
Definition arrayallocatorsafe.h:252
void Set(const uint32_t index, const tuple_array_t< MEMBER, TYPES... > &type)
set single item
Definition arrayallocatorsafe.h:355
void Release(const uint32_t index)
Release an object, the next thread that acquires may use this instance as it fits.
Definition arrayallocatorsafe.h:439
Util::Array< tuple_array_t< MEMBER, TYPES... > > & GetArray()
get array
Definition arrayallocatorsafe.h:378
void UpdateSize()
Any reserve and direct array access might mess with the size.
Definition arrayallocatorsafe.h:398
ArrayAllocatorSafe(const ArrayAllocatorSafe< MAX_ALLOCS, TYPES... > &rhs)
copy constructor
Definition arrayallocatorsafe.h:183
Util::PinnedArray< MAX_ALLOCS, Threading::ThreadId > owners
Definition arrayallocatorsafe.h:145
tuple_array_t< MEMBER, TYPES... > & Get(const uint32_t index)
get single item from resource
Definition arrayallocatorsafe.h:317
std::tuple< Util::PinnedArray< MAX_ALLOCS, TYPES >... > objects
Definition arrayallocatorsafe.h:144
void operator=(ArrayAllocatorSafe< MAX_ALLOCS, TYPES... > &&rhs)
move operator
Definition arrayallocatorsafe.h:219
ArrayAllocatorSafe()
constructor
Definition arrayallocatorsafe.h:155
void EraseIndexSwap(const uint32_t id)
Erase element for each.
Definition arrayallocatorsafe.h:266
const Util::Array< tuple_array_t< MEMBER, TYPES... > > & GetArray() const
get array const reference
Definition arrayallocatorsafe.h:367
void TryAcquire(const uint32_t index)
Spinlock to acquire.
Definition arrayallocatorsafe.h:408
const tuple_array_t< MEMBER, TYPES... > & Get(const uint32_t index) const
same as 32 bit get, but const
Definition arrayallocatorsafe.h:342
void Clear()
clear entire allocator and start from scratch.
Definition arrayallocatorsafe.h:303
ArrayAllocatorSafe(ArrayAllocatorSafe< MAX_ALLOCS, TYPES... > &&rhs)
move constructor
Definition arrayallocatorsafe.h:166
Nebula's dynamic array class.
Definition array.h:60
Definition pinnedarray.h:17
#define n_assert(exp)
Definition debug.h:50
int Exchange(int volatile *dest, int value)
interlocked exchange
Definition gccinterlocked.cc:94
int CompareExchange(int volatile *dest, int exchange, int comparand)
interlocked compare-exchange
Definition gccinterlocked.cc:112
static const ThreadId InvalidThreadId
Definition linuxthreadid.h:16
pthread_t ThreadId
Definition linuxthreadid.h:15
int64_t ThreadIdStorage
Definition linuxthreadid.h:17
A pinned array is an array which manages its own virtual memory.
Definition String.cs:6
void erase_index_for_each_in_tuple(std::tuple< Ts... > &tuple, uint32_t i, std::index_sequence< Is... >)
Entry point for erasing an element.
Definition tupleutility.h:207
void reserve_for_each_in_tuple(std::tuple< Ts... > &tuple, uint32_t size, std::index_sequence< Is... >)
Entry point for reserving in each array.
Definition tupleutility.h:294
void alloc_for_each_in_tuple(std::tuple< Ts... > &tuple, std::index_sequence< Is... >)
Unpacks allocations for each member in a tuble.
Definition tupleutility.h:146
void clear_for_each_in_tuple(std::tuple< Ts... > &tuple, std::index_sequence< Is... >)
Unpacks allocations for each member in a tuple.
Definition tupleutility.h:166
void set_for_each_in_tuple(std::tuple< Ts... > &tuple, uint32_t i, std::index_sequence< Is... >, TYPES const &... values)
Entry point for setting values in each array at an index.
Definition tupleutility.h:274
get_template_type_t< std::tuple_element_t< MEMBER, std::tuple< Util::Array< TYPES >... > > > tuple_array_t
Get type of contained element in Util::Array stored in std::tuple.
Definition tupleutility.h:334
void erase_index_swap_for_each_in_tuple(std::tuple< Ts... > &tuple, uint32_t i, std::index_sequence< Is... >)
Entry point for erasing an element by swapping with the last and reducing size.
Definition tupleutility.h:231
T * allocator
Definition arrayallocatorsafe.h:60
bool didAcquire
Definition arrayallocatorsafe.h:58
uint32_t element
Definition arrayallocatorsafe.h:59
~AllocatorLock()
Definition arrayallocatorsafe.h:52
AllocatorLock(T *allocator, uint32_t element)
Definition arrayallocatorsafe.h:45
unsigned int uint
Definition types.h:33