34void *MEM_Alloc(
int size);
35void MEM_Free(
void *ptr);
38# define _DEBUG_MEMBLOCK 1
41static constexpr size_t DefaultBlock = 256;
43enum class alloc_source_e {
48template<
typename a
class,
size_t blocksize>
61 using type = uint16_t;
66 using type = uint32_t;
71 using type = uint64_t;
74template<
typename a
class,
size_t blocksize>
78 static constexpr size_t bitsNeeded = blocksize <= 0x80 ? 8
79 : blocksize <= 0x8000 ? 16
80 : blocksize <= 0x80000000 ? 32
87 bool usedDataAvailable()
const;
88 bool freeDataAvailable()
const;
96 alloc_source_e source;
97 static constexpr uint16_t typeSize =
sizeof(aclass);
98 alignas(
alignof(aclass))
char data[
sizeof(aclass)];
104 offset_t prev_data[blocksize];
105 offset_t next_data[blocksize];
109 bool has_free_data : 1;
110 bool has_used_data : 1;
112 offset_t data[
sizeof(aclass)];
115 block_s<aclass, blocksize> *prev_block;
116 block_s<aclass, blocksize> *next_block;
119 static constexpr size_t headersize = offsetof(
info_t, data);
120 static constexpr size_t dataoffset = 0;
121 static constexpr size_t datasize =
sizeof(
info_t);
124template<
typename a
class,
size_t blocksize>
125block_s<aclass, blocksize>::block_s()
130 for (curr = 0; curr < blocksize - 1; ++curr) {
131 offset_t next = curr + 1;
132 header = &data[curr];
133 header->source = alloc_source_e::SourceBlock;
134 header->index = curr;
135 prev_data[next] = curr;
136 next_data[curr] = next;
139 header = &data[curr];
140 header->source = alloc_source_e::SourceBlock;
141 header->index = blocksize - 1;
142 prev_data[0] = blocksize - 1;
143 next_data[blocksize - 1] = 0;
145 prev_block = next_block =
nullptr;
147 has_free_data =
true;
148 has_used_data =
false;
151 : prev_block(
nullptr)
152 , next_block(
nullptr)
157template<
typename a
class,
size_t blocksize>
158bool block_s<aclass, blocksize>::usedDataAvailable()
const
160 return has_used_data;
163template<
typename a
class,
size_t blocksize>
164bool block_s<aclass, blocksize>::freeDataAvailable()
const
166 return has_free_data;
170template<
typename a
class,
size_t blocksize = DefaultBlock>
173 static_assert(blocksize >= 2,
"Minimum 2x class preallocation required!!");
180 void Free(
void *ptr)
noexcept;
181 void FreeAll()
noexcept;
184 size_t BlockMemory();
189 using block_offset_t =
typename block_t::offset_t;
192 block_t *m_FreeBlock;
193 block_t *m_StartUsedBlock;
194 block_t *m_StartFullBlock;
201 void *TakeFree(block_t *block, uintptr_t free_data);
202 size_t Count(
const block_t *block);
205template<
typename a
class,
size_t blocksize = DefaultBlock>
206class MEM_BlockAlloc_enum
211 aclass *NextElement();
212 aclass *CurrentElement();
221 using offset_t =
typename block_t::offset_t;
224 block_t *m_CurrentBlock;
227 offset_t m_CurrentData;
228 blockType_e m_CurrentBlockType;
232template<
typename a,
size_t b>
233MEM_BlockAlloc<a, b>::MEM_BlockAlloc()
238 m_FreeBlock =
nullptr;
248template<
typename a,
size_t b>
249MEM_BlockAlloc<a, b>::~MEM_BlockAlloc()
258template<
typename a,
size_t b>
259void *MEM_BlockAlloc<a, b>::Alloc()
262 block_t *block =
new (MEM_Alloc(
sizeof(block_t))) block_t();
264 LL_SafeAddFirst(m_Block, block, next_block, prev_block);
267 return (
void *)block->data;
270 block_offset_t free_data;
271 block_offset_t next_data;
273 if (m_StartUsedBlock) {
274 used_block = m_StartUsedBlock;
276 free_data = used_block->free_data;
277 next_data = used_block->next_data[free_data];
279 if (next_data == free_data) {
282 m_StartUsedBlock = used_block->next_block;
284 LL_SafeRemoveRoot(m_StartUsedBlock, used_block, next_block, prev_block);
285 LL_SafeAddFirst(m_StartFullBlock, used_block, next_block, prev_block);
287 used_block->has_free_data =
false;
288 return TakeFree(used_block, free_data);
293 used_block = m_FreeBlock;
294 m_FreeBlock =
nullptr;
295 free_data = used_block->free_data;
296 next_data = used_block->next_data[free_data];
300 used_block =
new (MEM_Alloc(
sizeof(block_t))) block_t();
306 LL_SafeAddFirst(m_StartUsedBlock, used_block, next_block, prev_block);
309 const block_offset_t prev_data = used_block->prev_data[free_data];
311 used_block->next_data[prev_data] = next_data;
312 used_block->prev_data[next_data] = prev_data;
313 used_block->free_data = next_data;
314 used_block->has_free_data =
true;
316 if (!used_block->usedDataAvailable()) {
317 used_block->used_data = free_data;
318 used_block->has_used_data =
true;
319 used_block->next_data[free_data] = free_data;
320 used_block->prev_data[free_data] = free_data;
321 return used_block->data[free_data].data;
324 return TakeFree(used_block, free_data);
328template<
typename a
class,
size_t blocksize>
329void *MEM_BlockAlloc<aclass, blocksize>::TakeFree(block_t *block, uintptr_t free_data)
331 const block_offset_t used_data = block->used_data;
332 const block_offset_t prev_data = block->prev_data[used_data];
334 block->next_data[prev_data] = (block_offset_t)free_data;
335 block->prev_data[used_data] = (block_offset_t)free_data;
336 block->next_data[free_data] = used_data;
337 block->prev_data[free_data] = prev_data;
338 return block->data[free_data].data;
341template<
typename a,
size_t b>
342void MEM_BlockAlloc<a, b>::Free(
void *ptr)
noexcept
345 block_t *block = (block_t*)ptr - offsetof(block_t, data);
347 LL_SafeRemoveRoot(m_Block, block, next_block, prev_block);
353 typename block_t::info_t *header =
354 reinterpret_cast<typename block_t::info_t *
>(
static_cast<unsigned char *
>(ptr) - block_t::headersize);
355 const block_offset_t used_data = header->index;
357 block_t *
const block = (block_t *)((uint8_t *)header - used_data * block_t::datasize - block_t::dataoffset);
358 const block_offset_t next_data = block->next_data[used_data];
359 if (next_data == used_data) {
360 LL_SafeRemoveRoot(m_StartUsedBlock, block, next_block, prev_block);
365 MEM_Free(m_FreeBlock);
366 m_FreeBlock =
nullptr;
370 block->has_used_data =
false;
372 const block_offset_t free_data = block->free_data;
373 const block_offset_t prev_data = block->prev_data[free_data];
375 block->next_data[prev_data] = used_data;
376 block->prev_data[free_data] = used_data;
377 block->next_data[used_data] = free_data;
378 block->prev_data[used_data] = prev_data;
380 const block_offset_t prev_data = block->prev_data[used_data];
382 block->next_data[prev_data] = next_data;
383 block->prev_data[next_data] = prev_data;
384 block->used_data = next_data;
385 block->has_used_data =
true;
387 if (block->freeDataAvailable()) {
388 const block_offset_t free_data = block->free_data;
389 const block_offset_t prev_data = block->prev_data[free_data];
391 block->next_data[prev_data] = used_data;
392 block->prev_data[free_data] = used_data;
393 block->next_data[used_data] = free_data;
394 block->prev_data[used_data] = prev_data;
398 if (m_StartFullBlock == block) {
399 m_StartFullBlock = block->next_block;
402 LL_SafeRemoveRoot(m_StartFullBlock, block, next_block, prev_block);
403 LL_SafeAddFirst(m_StartUsedBlock, block, next_block, prev_block);
405 block->free_data = used_data;
406 block->has_free_data =
true;
407 block->prev_data[used_data] = used_data;
408 block->next_data[used_data] = used_data;
413template<
typename a,
size_t b>
414void MEM_BlockAlloc<a, b>::FreeAll() noexcept
418 block_t *next = m_Block;
419 for (block = next; block; block = next) {
420 next = block->next_block;
422 a *ptr = (a *)block->data;
429 while ((block = m_StartFullBlock) !=
nullptr) {
430 if (block->usedDataAvailable()) {
431 a *ptr = (a *)block->data[block->used_data].data;
434 block = m_StartFullBlock;
438 while ((block = m_StartUsedBlock) !=
nullptr) {
439 if (block->usedDataAvailable()) {
440 a *ptr = (a *)block->data[block->used_data].data;
448 MEM_Free(m_FreeBlock);
449 m_FreeBlock =
nullptr;
454template<
typename a,
size_t b>
455size_t MEM_BlockAlloc<a, b>::Count(
const block_t *list)
459 for (
const block_t *block = list; block; block = block->next_block) {
465 for (
const block_t *block = list; block; block = block->next_block) {
466 if (!block->usedDataAvailable()) {
470 const block_offset_t used_data = block->used_data;
471 block_offset_t current_used_data = used_data;
475 current_used_data = block->next_data[current_used_data];
476 }
while (current_used_data != used_data);
483template<
typename a,
size_t b>
484size_t MEM_BlockAlloc<a, b>::Count()
487 return Count(m_Block);
489 return Count(m_StartFullBlock) + Count(m_StartUsedBlock);
493template<
typename a,
size_t b>
494size_t MEM_BlockAlloc<a, b>::BlockCount()
499template<
typename a,
size_t b>
500size_t MEM_BlockAlloc<a, b>::BlockMemory()
505template<
typename a,
size_t b>
509 m_CurrentBlock =
nullptr;
511 m_CurrentBlockType = MEM_BlockAlloc_enum::used;
515template<
typename a,
size_t b>
516a *MEM_BlockAlloc_enum<a, b>::NextElement()
519 if (!m_CurrentBlock) {
520 m_CurrentBlock = m_Owner->m_Block;
522 m_CurrentBlock = m_CurrentBlock->next_block;
524 return (a *)m_CurrentBlock;
527 while (!m_CurrentBlock) {
528 switch (m_CurrentBlockType) {
529 case blockType_e::used:
530 m_CurrentBlock = m_Owner->m_StartUsedBlock;
532 case blockType_e::full:
533 m_CurrentBlock = m_Owner->m_StartFullBlock;
539 reinterpret_cast<uint8_t&
>(m_CurrentBlockType)++;
542 for (; m_CurrentBlock; m_CurrentBlock = m_CurrentBlock->next_block) {
543 if (m_CurrentBlock->usedDataAvailable()) {
544 m_CurrentData = m_CurrentBlock->used_data;
545 return reinterpret_cast<a *
>(m_CurrentBlock->data[m_CurrentData].data);
550 m_CurrentData = m_CurrentBlock->next_data[m_CurrentData];
552 if (m_CurrentData == m_CurrentBlock->used_data) {
554 m_CurrentBlock = m_CurrentBlock->next_block;
558 return reinterpret_cast<a *
>(m_CurrentBlock->data[m_CurrentData].data);
562template<
typename a,
size_t b>
563a *MEM_BlockAlloc_enum<a, b>::CurrentElement()
565 return m_CurrentBlock;
568template<
typename a,
size_t b>
571 return allocator.Alloc();
574template<
typename a,
size_t b>
577 return allocator.Free(ptr);
Definition mem_blockalloc.h:207
Definition mem_blockalloc.h:172
Definition mem_blockalloc.h:76
Definition mem_blockalloc.h:94
Definition mem_blockalloc.h:52