diff --git a/src/arena.c b/src/arena.c index 5774c28..1e73be6 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1,40 +1,93 @@ + internal Arena * -arena_initialize(u64 size) +arena_initialize(u64 size, b8 growable) { Arena *result = 0; - - void *backing_buffer = malloc(size); + void *backing_buffer = platform_memory_reserve(size); if (backing_buffer != NULL) { - result = (Arena*) backing_buffer; + platform_memory_commit(backing_buffer, ARENA_INITIAL_COMMIT_SIZE); - result->buffer = backing_buffer; - result->offset = sizeof(Arena); - result->size = sizeof(Arena) + size; + result = (Arena*) backing_buffer; + result->backing_buffer = (u64*) backing_buffer; + result->current = result; + result->prev = 0; + + // rhjr: immutable arena header + result->base_pos = + memory_align(sizeof(Arena), ARENA_DEFAULT_ALIGNMENT); + result->offset = result->base_pos; + + result->growable = growable; + result->size = size; } + // rhjr: arenas should be instantiated early on in the programs lifetime, that + // is why this assertion will also be used in production. + ASSERT(result != 0); + return result; +} + +internal Arena * +arena_initialize_default() +{ + Arena *result = arena_initialize(ARENA_DEFAULT_RESERVE_SIZE, 1); return result; } internal void * arena_allocate(Arena *arena, u64 size) { - void *result = 0; + Arena *current = arena->current; + u64 pos_cur = current->base_pos + current->offset; + u64 pos_mem = memory_align(pos_cur, ARENA_DEFAULT_ALIGNMENT); + u64 pos_new = pos_mem + size; - if (arena->offset + size <= arena->size) + if (current->size < pos_new && current->growable) { - result = (void*)((u64) arena->buffer + (u64) arena->offset); - arena->offset += size; + Arena *new_memory_bock; + + if (size > ARENA_DEFAULT_RESERVE_SIZE) + { + // rhjr: TODO add support for allocations larger then a single page, in a + // single allocation call. + ASSERT(0); + } + else + { + new_memory_bock = arena_initialize_default(); + + if (new_memory_bock) + { + stack_push(arena->current, new_memory_bock, prev); + + current = new_memory_bock; + + pos_mem = + memory_align(current->offset, ARENA_DEFAULT_ALIGNMENT); + pos_new = current->offset + size; + } + + } - memset(result, 0, size); } - return result; + void *memory = (void*)((u64) current->backing_buffer + pos_mem); + arena->offset = pos_new; + + platform_memory_commit(memory, size); + memset(memory, 0, size); + + return memory; } internal void arena_release(Arena *arena) { - arena->offset = 0; + for (Arena *node = arena->current, *prev = 0; node != 0; node = prev) + { + prev = node->prev; + platform_memory_release(node, node->size); + } } diff --git a/src/arena.h b/src/arena.h index b07866f..c58f2b9 100644 --- a/src/arena.h +++ b/src/arena.h @@ -1,19 +1,30 @@ #ifndef ARENA_H #define ARENA_H +#define ARENA_INITIAL_COMMIT_SIZE sizeof(struct Arena) +#define ARENA_DEFAULT_ALIGNMENT 0 + +#ifndef ARENA_DEFAULT_RESERVE_SIZE +# define ARENA_DEFAULT_RESERVE_SIZE KB(4) +#endif // ARENA_DEFAULT_RESERVE_SIZE + typedef struct Arena Arena; struct Arena { - u64 *buffer; + struct Arena *current; + struct Arena *prev; + u64 *backing_buffer; + u64 base_pos; u64 offset; u64 size; + b8 growable; }; -internal Arena * arena_initialize(u64 size); +//= rhjr: arenas -internal void * arena_allocate(Arena *arena, u64 size); -internal void arena_release(Arena *arena); +internal Arena * arena_initialize(u64 size, b8 growable); +internal Arena * arena_initialize_default(); -//= rhjr: arena helpers +internal void * arena_allocate(Arena *arena, u64 size); #define arena_push_array(arena, type, count) \ (type*) arena_allocate((arena), sizeof(type) * (count)) @@ -21,8 +32,12 @@ internal void arena_release(Arena *arena); #define arena_push(arena, type) \ (type*) arena_allocate((arena), sizeof(type)) +internal void arena_release(Arena *arena); + //= rhjr: memory helpers +#define memory_align(x, b) ((b != 0) ? (((x) + (b) - 1) & (~(b - 1))) : (x)) + #define memory_zero(s,z) memset((s), 0, (z)) #define memory_zero_struct(s) memory_zero((s), sizeof(*(s)))