CppCommon  1.0.4.1
C++ Common Library
allocator_arena.inl
Go to the documentation of this file.
1 
9 namespace CppCommon {
10 
11 template <class TAuxMemoryManager>
12 inline 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 {
23  reset(capacity);
24 }
25 
26 template <class TAuxMemoryManager>
27 inline 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 
41 template <class TAuxMemoryManager>
42 inline 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 
138 template <class TAuxMemoryManager>
139 inline 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 
161 template <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 
174 template <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 
194 template <class TAuxMemoryManager>
195 inline 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 
216 template <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 
232 template <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 
252 template <class TAuxMemoryManager>
253 inline 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.
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.
const uint8_t * buffer() const noexcept
Arena buffer.
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.
Definition: token_bucket.h:15