Last active
August 15, 2025 13:16
-
-
Save Falconerd/09360fbc9241f5074a67885338908bd8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| USize AlignForward(USize p, USize alignment) { | |
| USize mod; | |
| if (0 == p % alignment) { | |
| return p; | |
| } | |
| mod = p & (alignment - 1); | |
| if (mod != 0) { | |
| p += alignment - mod; | |
| } | |
| return p; | |
| } | |
| //////////////////////////////////////////////////////////////////////// | |
| // ARENA | |
| //////////////////////////////////////////////////////////////////////// | |
| #ifndef DEFAULT_MEMORY_BLOCK_SIZE | |
| #define DEFAULT_MEMORY_BLOCK_SIZE 1024ULL * 1024ULL * 4ULL | |
| #endif | |
| #ifndef DEFAULT_ALIGNMENT | |
| #define DEFAULT_ALIGNMENT 16ULL | |
| #endif | |
| typedef struct MemoryBlock MemoryBlock; | |
| struct MemoryBlock { | |
| void *data; | |
| USize used; | |
| USize capacity; | |
| MemoryBlock *next; | |
| }; | |
| typedef struct Arena Arena; | |
| struct Arena { | |
| MemoryBlock *base_block; | |
| MemoryBlock *curr_block; | |
| }; | |
| void ArenaAppendBlock(Arena *a, USize size, USize alignment) { | |
| void *buffer = nil; | |
| MemoryBlock *block = nil; | |
| USize size_to_allocate = MAX(DEFAULT_MEMORY_BLOCK_SIZE, size); | |
| size_to_allocate = AlignForward(size_to_allocate, alignment); | |
| buffer = MemAlloc(size_to_allocate); | |
| block = MemAlloc(sizeof(MemoryBlock)); | |
| block->data = buffer; | |
| block->capacity = size_to_allocate; | |
| // Shouldn't be required as VirtualAlloc always zeros mem | |
| // However, MemAlloc may point to something else | |
| block->used = 0; | |
| block->next = nil; | |
| if (a->curr_block) { | |
| a->curr_block->next = block; | |
| a->curr_block = block; | |
| } else { | |
| a->base_block = block; | |
| a->curr_block = block; | |
| } | |
| } | |
| void *ArenaAlloc(Arena *a, USize size, USize alignment) { | |
| USize offset; | |
| USize diff; | |
| USize pos = 0; | |
| if (nil == a->base_block) { | |
| ArenaAppendBlock(a, size, alignment); | |
| } | |
| offset = AlignForward(a->curr_block->used, alignment); | |
| if (offset + size > a->curr_block->capacity) { | |
| ArenaAppendBlock(a, size, alignment); | |
| offset = 0; | |
| } | |
| diff = offset - a->curr_block->used; | |
| a->curr_block->used += diff + size; | |
| pos = (USize)a->curr_block->data + offset; | |
| return (void *)pos; | |
| } | |
| void ArenaRelease(Arena *a) { | |
| MemoryBlock *curr = a->base_block; | |
| while (curr) { | |
| USize size = curr->capacity; | |
| void *data = curr->data; | |
| MemoryBlock *block_to_free = curr; | |
| curr = curr->next; | |
| MemFree(data, size); | |
| MemFree(block_to_free, sizeof(MemoryBlock)); | |
| } | |
| a->base_block = nil; | |
| a->curr_block = nil; | |
| } | |
| void *ArenaPush(Arena *a, USize size) { | |
| return ArenaAlloc(a, size, DEFAULT_ALIGNMENT); | |
| } | |
| void ArenaReserve(Arena *a, USize size) { | |
| USize offset; | |
| if (!a->base_block) { | |
| ArenaAppendBlock(a, size, DEFAULT_ALIGNMENT); | |
| } | |
| offset = AlignForward(a->curr_block->used, DEFAULT_ALIGNMENT); | |
| if (offset + size > a->curr_block->capacity) { | |
| ArenaAppendBlock(a, size, DEFAULT_ALIGNMENT); | |
| } | |
| } | |
| void ArenaRewind(Arena *a) { | |
| if (a->base_block) { | |
| MemoryBlock *b = a->base_block; | |
| while (b) { | |
| b->used = 0; | |
| b = b->next; | |
| } | |
| a->curr_block = a->base_block; | |
| } | |
| } | |
| #define ArenaPushStruct(a, T) ArenaAlloc(a, sizeof(T), ALIGNOF(T)) | |
| #define ArenaPushArray(a, count, T) ArenaAlloc(a, (count) * sizeof(T), ALIGNOF(T[1])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment