anton_render/src/base/base_arena.c
2025-05-17 21:45:29 +02:00

152 lines
3.2 KiB
C

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//~ Base arena implementation
internal Arena *
arena_alloc_()
{
U64 reserve_size = g_arena_default_reserve_size;
U64 commit_size = g_arena_default_commit_size;
// TODO align to page sizes
// Reserve/commit initial block
void *base = 0;
if(base == 0) // TODO(anton): can have optional backing buffer
{
base = os_reserve(reserve_size);
os_commit(base, commit_size);
}
// Extract arena header and fill it
Arena *arena = (Arena *)base;
arena->current = arena;
arena->commit_size = commit_size;
arena->reserve_size = reserve_size;
arena->base_pos = 0;
arena->pos = ARENA_HEADER_SIZE;
arena->commit = commit_size;
arena->reserve = reserve_size;
return arena;
}
internal void
arena_release(Arena *arena)
{
// Go back in chain and release
for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
{
prev = n->prev;
os_release(n, n->reserve);
}
}
internal void *
arena_push(Arena *arena, U64 size, U64 align)
{
Arena *current = arena->current;
U64 pos_pre = AlignPow2(current->pos, align);
U64 pos_post = pos_pre + size;
// TODO(anton): Add chaining etc. Now we always just put up a new block.
// Commit new pages if needed, that is if the new position of the arena pointer
// is larger than the current commit adress.
if(current->commit < pos_post)
{
U64 commit_post_aligned = pos_post + current->commit_size - 1;
commit_post_aligned -= commit_post_aligned % current->commit_size;
// Now commit_post_aligned is aligned
U64 commit_post_clamped = ClampTop(commit_post_aligned, current->reserve);
U64 commit_size = commit_post_clamped - current->commit;
U8 *commit_ptr = (U8 *)current + current->commit;
os_commit(commit_ptr, commit_size);
current->commit = commit_post_clamped;
}
// Push to current block
void *result = 0;
if(current->commit >= pos_post)
{
result = (U8 *)current+pos_pre;
current->pos = pos_post;
}
if(result == 0)
{
LOG("FATAL ERROR IN ARENA ALLOC");
ExitProcess(0);
}
return result;
}
internal U64
arena_pos(Arena *arena)
{
Arena *current = arena->current;
U64 pos = current->base_pos + current->pos;
return pos;
}
internal void
arena_pop_to(Arena *arena, U64 pos)
{
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
Arena *current = arena->current;
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
{
prev = current->prev;
os_release(current, current->reserve);
}
arena->current = current;
U64 new_pos = big_pos - current->base_pos;
AssertAlways(new_pos <= current->pos);
current->pos = new_pos;
}
internal void
arena_clear(Arena *arena)
{
arena_pop_to(arena, 0);
}
internal void
arena_pop(Arena *arena, U64 amt)
{
U64 pos_old = arena_pos(arena);
U64 pos_new = pos_old;
if(amt < pos_old)
{
pos_new = pos_old - amt;
}
arena_pop_to(arena, pos_new);
}
//- rjf: temporary arena scopes
internal Temp
temp_begin(Arena *arena)
{
U64 pos = arena_pos(arena);
Temp temp = {arena, pos};
return temp;
}
internal void
temp_end(Temp temp)
{
arena_pop_to(temp.arena, temp.pos);
}