Gaia-ECS v0.9.3
A simple and powerful entity component system
Loading...
Searching...
No Matches
stack_allocator.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cinttypes>
5
6#include "gaia/mem/raw_data_holder.h"
7
8namespace gaia {
9 namespace mem {
10 namespace detail {
13 uint32_t prev;
15 uint32_t off : 8;
17 uint32_t cnt : 24;
18 void (*dtor)(void*, uint32_t);
19 };
20 } // namespace detail
21
22 // MSVC might warn about applying additional padding to an instance of StackAllocator.
23 // This is perfectly fine, but might make builds with warning-as-error turned on to fail.
24 GAIA_MSVC_WARNING_PUSH()
25 GAIA_MSVC_WARNING_DISABLE(4324)
26
29 template <uint32_t CapacityInBytes = 1024>
32
36 uint32_t m_pos = 0;
38 uint32_t m_posPrev = 0;
40 uint32_t m_allocs = 0;
41
42 public:
44 // Aligned used so the sentinel object can be stored properly
45 const auto bufferMemAddr = (uintptr_t)((uint8_t*)m_buffer);
46 m_posPrev = m_pos = padding<alignof(alloc_info)>(bufferMemAddr);
47 }
48
50 reset();
51 }
52
53 StackAllocator(const StackAllocator&) = delete;
55 StackAllocator& operator=(const StackAllocator&) = delete;
56 StackAllocator& operator=(StackAllocator&&) = delete;
57
62 template <typename T>
63 GAIA_NODISCARD T* alloc(uint32_t cnt) {
64 constexpr auto sizeT = (uint32_t)sizeof(T);
65 const auto addrBuff = (uintptr_t)((uint8_t*)m_buffer);
66 const auto addrAllocInfo = align<alignof(alloc_info)>(addrBuff + m_pos);
67 const auto addrAllocData = align<alignof(T)>(addrAllocInfo + sizeof(alloc_info));
68 const auto off = (uint32_t)(addrAllocData - addrAllocInfo);
69
70 // There has to be some space left in the buffer
71 const bool isFull = (uint32_t)(addrAllocData - addrBuff) + sizeT * cnt >= CapacityInBytes;
72 if GAIA_UNLIKELY (isFull) {
73 GAIA_ASSERT(!isFull && "Allocation space exceeded on StackAllocator");
74 return nullptr;
75 }
76
77 // Memory sentinel
78 auto* pInfo = (alloc_info*)addrAllocInfo;
79 pInfo->prev = m_posPrev;
80 pInfo->off = off;
81 pInfo->cnt = cnt;
82 pInfo->dtor = [](void* ptr, uint32_t cnt) {
83 core::call_dtor_n((T*)ptr, cnt);
84 };
85
86 // Constructing the object is necessary
87 auto* pData = (T*)addrAllocData;
88 core::call_ctor_raw_n(pData, cnt);
89
90 // Allocation start offset
91 m_posPrev = (uint32_t)(addrAllocInfo - addrBuff);
92 // Point to the next free space (not necessary aligned yet)
93 m_pos = m_posPrev + pInfo->off + sizeT * cnt;
94
95 ++m_allocs;
96 return pData;
97 }
98
102 void free([[maybe_unused]] void* pData, [[maybe_unused]] uint32_t cnt) {
103 GAIA_ASSERT(pData != nullptr);
104 GAIA_ASSERT(cnt > 0);
105 GAIA_ASSERT(m_allocs > 0);
106
107 const auto addrBuff = (uintptr_t)((uint8_t*)m_buffer);
108
109 // Destroy the last allocated object
110 const auto addrAllocInfo = addrBuff + m_posPrev;
111 auto* pInfo = (alloc_info*)addrAllocInfo;
112 const auto addrAllocData = addrAllocInfo + pInfo->off;
113 void* pInfoData = (void*)addrAllocData;
114 GAIA_ASSERT(pData == pInfoData);
115 GAIA_ASSERT(pInfo->cnt == cnt);
116 pInfo->dtor(pInfoData, pInfo->cnt);
117
118 m_pos = m_posPrev;
119 m_posPrev = pInfo->prev;
120 --m_allocs;
121 }
122
124 void reset() {
125 const auto addrBuff = (uintptr_t)((uint8_t*)m_buffer);
126
127 // Destroy allocated objects back-to-front
128 auto pos = m_posPrev;
129 while (m_allocs > 0) {
130 const auto addrAllocInfo = addrBuff + pos;
131 auto* pInfo = (alloc_info*)addrAllocInfo;
132 const auto addrAllocData = addrAllocInfo + pInfo->off;
133 pInfo->dtor((void*)addrAllocData, pInfo->cnt);
134 pos = pInfo->prev;
135
136 --m_allocs;
137 }
138
139 GAIA_ASSERT(m_allocs == 0);
140
141 m_pos = 0;
142 m_posPrev = 0;
143 m_allocs = 0;
144 }
145
146 GAIA_NODISCARD constexpr uint32_t capacity() {
147 return CapacityInBytes;
148 }
149 };
150
151 GAIA_MSVC_WARNING_POP()
152 } // namespace mem
153} // namespace gaia
Stack allocator capable of instantiating any default-constructible object on stack....
Definition stack_allocator.h:30
void reset()
Frees all allocated objects from the buffer.
Definition stack_allocator.h:124
GAIA_NODISCARD T * alloc(uint32_t cnt)
Allocates.
Definition stack_allocator.h:63
void free(void *pData, uint32_t cnt)
Frees the last allocated object from the stack.
Definition stack_allocator.h:102
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition stack_allocator.h:11
uint32_t cnt
The number of requested bytes to allocate.
Definition stack_allocator.h:17
uint32_t off
Offset of data area from info area in bytes.
Definition stack_allocator.h:15
uint32_t prev
Byte offset of the previous allocation.
Definition stack_allocator.h:13
Definition raw_data_holder.h:12