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
184{
185 this->allocationLock.Lock();
186 this->objects = rhs.objects;
187 this->size = rhs.size;
188 this->allocationLock.Unlock();
189}
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();
240 alloc_for_each_in_tuple(this->objects);
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();
256 erase_index_for_each_in_tuple(this->objects, id);
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();
270 erase_index_swap_for_each_in_tuple(this->objects, id);
271 this->allocationLock.Unlock();
272 this->size--;
273}
274
275//------------------------------------------------------------------------------
278template<uint MAX_ALLOCS, class ...TYPES>
279inline const uint32_t
281{
282 n_assert2(this->numReaders > 0, "Size requires a read lock");
283 return this->size;
284}
285
286//------------------------------------------------------------------------------
289template<uint MAX_ALLOCS, class ...TYPES>
290inline void
292{
293 this->allocationLock.Lock();
294 reserve_for_each_in_tuple(this->objects, num);
295 this->allocationLock.Unlock();
296 // Size is still the same.
297}
298
299//------------------------------------------------------------------------------
302template<uint MAX_ALLOCS, class ...TYPES>
303inline void
305{
306 this->allocationLock.Enter();
307 clear_for_each_in_tuple(this->objects);
308 this->size = 0;
309 this->allocationLock.Leave();
310}
311
312//------------------------------------------------------------------------------
315template<uint MAX_ALLOCS, class ...TYPES>
316template<int MEMBER>
317inline tuple_array_t<MEMBER, TYPES...>&
319{
320 n_assert(this->owners[index] == Threading::Thread::GetMyThreadId());
321 return std::get<MEMBER>(this->objects)[index];
322}
323
324//------------------------------------------------------------------------------
327template<uint MAX_ALLOCS, class ...TYPES>
328template<int MEMBER>
329inline const tuple_array_t<MEMBER, TYPES...>&
331{
332 // Allow const get when no thread is owning the element as well
333 n_assert(this->owners[index] == Threading::Thread::GetMyThreadId() || this->owners[index] == Threading::InvalidThreadId);
334 return std::get<MEMBER>(this->objects)[index];
335}
336
337//------------------------------------------------------------------------------
340template<uint MAX_ALLOCS, class ...TYPES>
341template<int MEMBER>
342inline const tuple_array_t<MEMBER, TYPES...>&
344{
345 // Allow const get when no thread is owning the element as well
346 n_assert(this->owners[index] == Threading::Thread::GetMyThreadId() || this->owners[index] == Threading::InvalidThreadId);
347 return std::get<MEMBER>(this->objects)[index];
348}
349
350//------------------------------------------------------------------------------
353template<uint MAX_ALLOCS, class ...TYPES>
354template<int MEMBER>
355inline void
357{
358 n_assert(this->owners[index] == Threading::Thread::GetMyThreadId());
359 std::get<MEMBER>(this->objects)[index] = type;
360}
361
362//------------------------------------------------------------------------------
365template<uint MAX_ALLOCS, class ...TYPES>
366template<int MEMBER>
367inline const Util::Array<tuple_array_t<MEMBER, TYPES...>>&
369{
370 return std::get<MEMBER>(this->objects);
371}
372
373//------------------------------------------------------------------------------
376template<uint MAX_ALLOCS, class ...TYPES>
377template<int MEMBER>
378inline Util::Array<tuple_array_t<MEMBER, TYPES...>>&
380{
381 return std::get<MEMBER>(this->objects);
382}
383
384//------------------------------------------------------------------------------
387template<uint MAX_ALLOCS, class ...TYPES>
388void
389ArrayAllocatorSafe<MAX_ALLOCS, TYPES...>::Set(const uint32_t index, TYPES... values)
390{
391 set_for_each_in_tuple(this->objects, index, values...);
392}
393
394//------------------------------------------------------------------------------
397template<uint MAX_ALLOCS, class ...TYPES>
398void
400{
401 this->size = this->GetArray<0>().Size();
402}
403
404//------------------------------------------------------------------------------
407template<uint MAX_ALLOCS, class ...TYPES>
408void
410{
411 Threading::ThreadId myThread = Threading::Thread::GetMyThreadId();
413 n_assert(currentThread == Threading::InvalidThreadId);
414}
415
416//------------------------------------------------------------------------------
419template<uint MAX_ALLOCS, class ...TYPES>
420bool
422{
423 Threading::ThreadId myThread = Threading::Thread::GetMyThreadId();
424 if (this->owners[index] == myThread)
425 return false;
426
427 // Spinlock
429 {
430 Threading::Thread::YieldThread();
431 };
432 return true;
433}
434
435//------------------------------------------------------------------------------
438template<uint MAX_ALLOCS, class ...TYPES>
439void
441{
442 n_assert(this->owners[index] == Threading::Thread::GetMyThreadId());
444}
445
446} // namespace Util
Definition spinlock.h:21
The ArrayAllocatorSafe provides a thread safe variadic list of types which is to be contained in the ...
Definition arrayallocatorsafe.h:65
bool Acquire(const uint32_t index)
Acquire element, asserts if false and returns true if this call acquired.
Definition arrayallocatorsafe.h:421
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:389
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:330
void Reserve(uint32_t size)
grow capacity of arrays to size
Definition arrayallocatorsafe.h:291
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:356
void Release(const uint32_t index)
Release an object, the next thread that acquires may use this instance as it fits.
Definition arrayallocatorsafe.h:440
Util::Array< tuple_array_t< MEMBER, TYPES... > > & GetArray()
get array
Definition arrayallocatorsafe.h:379
void UpdateSize()
Any reserve and direct array access might mess with the size.
Definition arrayallocatorsafe.h:399
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:318
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:368
void TryAcquire(const uint32_t index)
Spinlock to acquire.
Definition arrayallocatorsafe.h:409
const tuple_array_t< MEMBER, TYPES... > & Get(const uint32_t index) const
same as 32 bit get, but const
Definition arrayallocatorsafe.h:343
void Clear()
clear entire allocator and start from scratch.
Definition arrayallocatorsafe.h:304
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_assert2(exp, msg)
Definition debug.h:51
#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
Definition arrayallocatorsafe.h:44
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:31