From b8db582098a866aa56c62d0b2b6351ea08411f6b Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sat, 24 Feb 2024 20:27:06 +0000 Subject: [PATCH] Implement growing arena --- mem/include/arena/mem_arena.h | 8 ++ mem/src/arena/mem_arena.c | 151 ++++++++++++++++++++++++++++++++-- 2 files changed, 154 insertions(+), 5 deletions(-) diff --git a/mem/include/arena/mem_arena.h b/mem/include/arena/mem_arena.h index 2ab423c..96c2366 100644 --- a/mem/include/arena/mem_arena.h +++ b/mem/include/arena/mem_arena.h @@ -4,4 +4,12 @@ #include "aliases.h" #include +typedef struct growing_arena Arena; + +bool mem_arena_init(Arena **arena, u64 base_capacity); +void *mem_arena_alloc(Arena *arena, u64 size); +void *mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment); +void mem_arena_clear(Arena *arena); +void mem_arena_free(Arena **arena); + #endif // !MEM_ARENA_H diff --git a/mem/src/arena/mem_arena.c b/mem/src/arena/mem_arena.c index 411b71a..ae3ba04 100644 --- a/mem/src/arena/mem_arena.c +++ b/mem/src/arena/mem_arena.c @@ -18,13 +18,158 @@ struct base_arena { BaseArena *next; }; +struct growing_arena { + BaseArena *active_arena; + u64 count; + u64 initial_capacity; +}; + internal bool base_arena_init(BaseArena *arena, u64 capacity); -internal void *base_arena_alloc(BaseArena *arena, u64 size); internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size, u64 alignment); internal void base_arena_clear(BaseArena *arena); internal void base_arena_free(BaseArena *arena); +// PUBLIC API + +bool mem_arena_init(Arena **arena, u64 base_capacity) { + if (!arena || *arena) { + return false; + } + + *arena = (Arena *)malloc(sizeof(Arena)); + Arena *arena_ptr = *arena; + if (!arena_ptr) { + return false; + } + + memset(arena_ptr, 0, sizeof(Arena)); + + arena_ptr->active_arena = (BaseArena *)malloc(sizeof(BaseArena)); + if (!(arena_ptr->active_arena)) { + return false; + } + + memset(arena_ptr->active_arena, 0, sizeof(BaseArena)); + + if (!base_arena_init(arena_ptr->active_arena, base_capacity)) { + return false; + } + + arena_ptr->count = 1; + arena_ptr->initial_capacity = base_capacity; + + return true; +} + +void *mem_arena_alloc(Arena *arena, u64 size) { + return mem_arena_alloc_aligned(arena, size, DEFAULT_ALIGNMENT); +} + +void *mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment) { + if (!arena || !(arena->active_arena)) { + return NULL; + } + + void *output = base_arena_alloc_aligned(arena->active_arena, size, alignment); + if (!output) { + if (arena->active_arena->next) { + arena->active_arena = arena->active_arena->next; + } else { + arena->active_arena->next = (BaseArena *)malloc(sizeof(BaseArena)); + if (!(arena->active_arena->next)) { + return NULL; + } + + memset(arena->active_arena->next, 0, sizeof(BaseArena)); + + if (!base_arena_init(arena->active_arena->next, + arena->initial_capacity)) { + free(arena->active_arena->next); + return NULL; + } + + arena->active_arena->next->prev = arena->active_arena; + arena->active_arena = arena->active_arena->next; + + ++(arena->count); + } + + output = base_arena_alloc_aligned(arena->active_arena, size, alignment); + if (!output) { + return NULL; + } + } + + memset(output, 0, size); + + return output; +} + +void mem_arena_clear(Arena *arena) { + if (!arena) { + return; + } + + BaseArena *new_active = NULL; + while (arena->active_arena) { + base_arena_clear(arena->active_arena); + + arena->active_arena = arena->active_arena->prev; + + if (arena->active_arena) { + new_active = arena->active_arena; + } + } + + arena->active_arena = new_active; +} + +void mem_arena_free(Arena **arena) { + if (!arena) { + return; + } + + Arena *arena_ptr = *arena; + + BaseArena *current; + BaseArena *next; + BaseArena *prev; + + current = arena_ptr->active_arena->next; + while (current) { + next = current->next; + + base_arena_free(current); + free(current); + + current = next; + } + + current = arena_ptr->active_arena->prev; + while (current) { + prev = current->prev; + + base_arena_free(current); + free(current); + + current = prev; + } + + base_arena_free(arena_ptr->active_arena); + + free(arena_ptr->active_arena); + arena_ptr->active_arena = NULL; + + arena_ptr->count = 0; + arena_ptr->initial_capacity = 0; + + free(*arena); + *arena = NULL; +} + +// INTERNAL FUNCTIONS + internal bool base_arena_init(BaseArena *arena, u64 capacity) { if (!arena || arena->buf) { return false; @@ -45,10 +190,6 @@ internal bool base_arena_init(BaseArena *arena, u64 capacity) { return true; } -internal void *base_arena_alloc(BaseArena *arena, u64 size) { - return base_arena_alloc_aligned(arena, size, DEFAULT_ALIGNMENT); -} - internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size, u64 alignment) { if (!arena) {