CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
allocator_arena.inl
Go to the documentation of this file.
1
9namespace CppCommon {
10
11template <class TAuxMemoryManager>
12inline ArenaMemoryManager<TAuxMemoryManager>::ArenaMemoryManager(TAuxMemoryManager& auxiliary, size_t capacity)
13 : _allocated(0),
14 _allocations(0),
15 _auxiliary(auxiliary),
16 _current(nullptr),
17 _reserved(0),
18 _external(false),
19 _buffer(nullptr),
20 _capacity(0),
21 _size(0)
22{
24}
25
26template <class TAuxMemoryManager>
27inline ArenaMemoryManager<TAuxMemoryManager>::ArenaMemoryManager(TAuxMemoryManager& auxiliary, void* buffer, size_t capacity)
28 : _allocated(0),
29 _allocations(0),
30 _auxiliary(auxiliary),
31 _current(nullptr),
32 _reserved(0),
33 _external(true),
34 _buffer(nullptr),
35 _capacity(0),
36 _size(0)
37{
39}
40
41template <class TAuxMemoryManager>
42inline void* ArenaMemoryManager<TAuxMemoryManager>::malloc(size_t size, size_t alignment)
43{
44 assert((size > 0) && "Allocated block size must be greater than zero!");
45 assert(Memory::IsValidAlignment(alignment) && "Alignment must be valid!");
46
47 if (_external)
48 {
49 // Allocate memory from the external memory block
50 uint8_t* buffer = _buffer + _size;
51 uint8_t* aligned = Memory::Align(buffer, alignment);
52 size_t aligned_size = size + (aligned - buffer);
53
54 // Check if there is enough free space to allocate the block
55 if (aligned_size <= (_capacity - _size))
56 {
57 // Memory allocated
58 _size += aligned_size;
59
60 // Update allocation statistics
61 _allocated += size;
62 ++_allocations;
63
64 return aligned;
65 }
66
67 // Not enough memory... use auxiliary memory manager
68 void* result = _auxiliary.malloc(size, alignment);
69 if (result != nullptr)
70 {
71 // Update allocation statistics
72 _allocated += size;
73 ++_allocations;
74
75 // Increase the required reserved memory size
76 _reserved += size;
77 }
78 return result;
79 }
80 else
81 {
82 if (_current != nullptr)
83 {
84 // Allocate memory from the current arena page
85 uint8_t* buffer = _current->buffer + _current->size;
86 uint8_t* aligned = Memory::Align(buffer, alignment);
87 size_t aligned_size = size + (aligned - buffer);
88
89 // Check if there is enough free space to allocate the block
90 if (aligned_size <= (_current->capacity - _current->size))
91 {
92 // Memory allocated
93 _current->size += aligned_size;
94
95 // Update allocation statistics
96 _allocated += size;
97 ++_allocations;
98
99 return aligned;
100 }
101 }
102
103 // Increase the required reserved memory size
104 size_t next_reserved = 2 * _reserved;
105 while (next_reserved < size)
106 next_reserved *= 2;
107
108 // Allocate a new arena page
109 Page* current = AllocateArena(next_reserved, _current);
110 if (current != nullptr)
111 {
112 // Update the current arena page
113 _current = current;
114
115 // Increase the required reserved memory size
116 _reserved = next_reserved;
117
118 // Allocate memory from the current arena page
119 uint8_t* buffer = _current->buffer + _current->size;
120 uint8_t* aligned = Memory::Align(buffer, alignment);
121 size_t aligned_size = size + (aligned - buffer);
122
123 // Memory allocated
124 _current->size += aligned_size;
125
126 // Update allocation statistics
127 _allocated += size;
128 ++_allocations;
129
130 return aligned;
131 }
132
133 // Not enough memory...
134 return nullptr;
135 }
136}
137
138template <class TAuxMemoryManager>
139inline void ArenaMemoryManager<TAuxMemoryManager>::free(void* ptr, size_t size)
140{
141 assert((ptr != nullptr) && "Deallocated block must be valid!");
142
143 if (_external)
144 {
145 // Free memory block in auxiliary memory manager
146 if ((ptr < _buffer) || (ptr >= (_buffer + _size)))
147 _auxiliary.free(ptr, size);
148 }
149 else
150 {
151 // Free memory block in auxiliary memory manager
152 if (_current == nullptr)
153 _auxiliary.free(ptr, size);
154 }
155
156 // Update allocation statistics
157 _allocated -= size;
158 --_allocations;
159}
160
161template <class TAuxMemoryManager>
163{
164 assert((_allocated == 0) && "Memory leak detected! Allocated memory size must be zero!");
165 assert((_allocations == 0) && "Memory leak detected! Count of active memory allocations must be zero!");
166
167 // Expand internal arena buffer to fit auxiliary allocated storage
168 if (!_external)
169 reset(_reserved);
170
171 _size = 0;
172}
173
174template <class TAuxMemoryManager>
176{
177 assert((capacity > 0) && "Arena capacity must be greater than zero!");
178
179 assert((_allocated == 0) && "Memory leak detected! Allocated memory size must be zero!");
180 assert((_allocations == 0) && "Memory leak detected! Count of active memory allocations must be zero!");
181
182 // Clear previous allocations
183 clear();
184
185 // Allocate a new arena page
186 Page* current = AllocateArena(capacity, _current);
187 if (current != nullptr)
188 _current = current;
189
190 // Set initial reserved memory size
191 _reserved = capacity;
192}
193
194template <class TAuxMemoryManager>
195inline void ArenaMemoryManager<TAuxMemoryManager>::reset(void* buffer, size_t capacity)
196{
197 assert((buffer != nullptr) && "Arena buffer must be valid!");
198 assert((capacity > 0) && "Arena buffer capacity must be greater than zero!");
199
200 assert((_allocated == 0) && "Memory leak detected! Allocated memory size must be zero!");
201 assert((_allocations == 0) && "Memory leak detected! Count of active memory allocations must be zero!");
202
203 // Clear previous allocations
204 clear();
205
206 // Initialize an external arena buffer
207 _external = true;
208 _buffer = (uint8_t*)buffer;
209 _capacity = capacity;
210 _size = 0;
211
212 // Set initial reserved memory size
213 _reserved = capacity;
214}
215
216template <class TAuxMemoryManager>
218{
219 assert((_allocated == 0) && "Memory leak detected! Allocated memory size must be zero!");
220 assert((_allocations == 0) && "Memory leak detected! Count of active memory allocations must be zero!");
221
222 // Clear arena
223 ClearArena();
224
225 // Clear external buffer
226 _external = false;
227 _buffer = nullptr;
228 _capacity = 0;
229 _size = 0;
230}
231
232template <class TAuxMemoryManager>
234{
235 // Allocate a new arena page
236 uint8_t* buffer = (uint8_t*)_auxiliary.malloc(sizeof(Page) + capacity + alignof(std::max_align_t));
237 Page* page = (Page*)buffer;
238 if (page != nullptr)
239 {
240 // Prepare and return a new arena page
241 page->buffer = buffer + sizeof(Page);
242 page->capacity = capacity;
243 page->size = 0;
244 page->prev = prev;
245 return page;
246 }
247
248 // Out of memory...
249 return nullptr;
250}
251
252template <class TAuxMemoryManager>
253inline void ArenaMemoryManager<TAuxMemoryManager>::ClearArena()
254{
255 if (!_external)
256 {
257 // Clear all arena pages
258 while (_current != nullptr)
259 {
260 Page* prev = _current->prev;
261 _auxiliary.free(_current, sizeof(Page) + _current->capacity + alignof(std::max_align_t));
262 _current = prev;
263 }
264 }
265}
266
267} // namespace CppCommon
Arena memory manager class.
void clear()
Clear arena memory allocator.
void reset()
Reset the memory manager.
const uint8_t * buffer() const noexcept
Arena buffer.
void * malloc(size_t size, size_t alignment=alignof(std::max_align_t))
Allocate a new memory block of the given size.
size_t capacity() const noexcept
Arena capacity.
void free(void *ptr, size_t size)
Free the previously allocated memory block.
ArenaMemoryManager(TAuxMemoryManager &auxiliary)
Initialize arena memory manager with an auxiliary memory manager.
static bool IsValidAlignment(size_t alignment) noexcept
Is the given alignment valid?
Definition memory.inl:13
static T * Align(const T *address, size_t alignment=alignof(T), bool upwards=true) noexcept
Align pointer (upwards or downwards)
Definition memory.inl:29
C++ Common project definitions.