Skip to content

Instantly share code, notes, and snippets.

@Falconerd
Last active August 15, 2025 13:16
Show Gist options
  • Select an option

  • Save Falconerd/09360fbc9241f5074a67885338908bd8 to your computer and use it in GitHub Desktop.

Select an option

Save Falconerd/09360fbc9241f5074a67885338908bd8 to your computer and use it in GitHub Desktop.
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