From b3bd3df103a5a75d267b2b79e85558768b1dc4bb Mon Sep 17 00:00:00 2001 From: "@syxhe" Date: Sun, 23 Mar 2025 22:11:15 -0500 Subject: Fix a whole bunch of shit, create an arena implementation --- src/arena.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 src/arena.c (limited to 'src/arena.c') diff --git a/src/arena.c b/src/arena.c new file mode 100644 index 0000000..d340f3a --- /dev/null +++ b/src/arena.c @@ -0,0 +1,183 @@ +#include "arena.h" +#include "shared.h" + +#include +#include +#include +#include +#include + +typedef struct an { + void *membase; + void *memcur; + size_t allocated; + size_t used; + + struct an *next; +} arenanode; + +typedef struct arena { + arenanode *start; + arenanode *current; + + // For keeping track of the largest possible thing that can be allocated to one node + size_t node_memspace; +} arena; + +int arenanode_init(arenanode **an, size_t bytes) { + (*an) = xcalloc(1, sizeof(**an)); + if(!(*an)) + return -1; + + (*an)->allocated = bytes; + (*an)->used = 0; + (*an)->next = NULL; + + void *mem = xcalloc(bytes, 1); + if(!mem) { + free((*an)); + (*an) = NULL; + return -1; + } + + (*an)->membase = mem; + (*an)->memcur = mem; + + return 0; +} + +int arena_init(arena **a, size_t bytes) { + if(!ISPOWOF2(MEM_ALIGN_BYTES)) + XALLOC_EXIT(" \"MEM_ALIGN_BYTES\" is not a power of 2. Refusing to create a new arena"); + + (*a) = xcalloc(1, sizeof(**a)); + if(!(*a)) + return -1; + (*a)->start = NULL; + (*a)->current = NULL; + (*a)->node_memspace = bytes; + + arenanode *base; + if(arenanode_init(&base, bytes) < 0) { + free(*a); + (*a) = NULL; + return -1; + } + + (*a)->start = base; + (*a)->current = base; + + return 0; +} + +void* arena_alloc(arena * const arena, size_t bytes) { + if(!arena) { + errno = EINVAL; + return NULL; + } + if(bytes > arena->node_memspace) { + errno = ENOMEM; + return NULL; + } + if(!ISPOWOF2(MEM_ALIGN_BYTES)) + XALLOC_EXIT(" \"MEM_ALIGN_BYTES\" is not a power of 2. Refusing to allocate any memory"); + + if(bytes > ((arena->current)->allocated - (arena->current)->used)) { + arenanode *new; + if(arenanode_init(&new, arena->node_memspace) < 0) + return NULL; + + arena->current->next = new; + arena->current = new; + } + + size_t alignment = MEM_ALIGN(bytes); + size_t offset = bytes + alignment; + + void *mem = arena->current->memcur; + arena->current->memcur = (void*)(((uint8_t*)arena->current->memcur) + offset); + + arena->current->used += offset; + + return mem; + + // Note: This implementation assumes that malloc provides already-aligned memory. If it + // doesn't, that sucks and blows everything up +} + +int arena_free(arena **arena) { + if(!arena) { + errno = EINVAL; + return -1; + } + if(!(*arena)) { + errno = EINVAL; + return -1; + } + + (*arena)->current = (*arena)->start; + for(arenanode *n; (*arena)->current != NULL;) { + n = (*arena)->current->next; + + free((*arena)->current->membase); + free((*arena)->current); + + (*arena)->current = n; + } + free((*arena)); + (*arena) = NULL; + + return 0; +} + +int arena_clear(arena **arena) { + if(!arena) { + errno = EINVAL; + return -1; + } + if(!(*arena)) { + errno = EINVAL; + return -1; + } + + size_t bytes = (*arena)->node_memspace; + + int ret = 0; + if((ret = arena_free(arena)) < 0) + return ret; + return arena_init(arena, bytes); +} + + + +// Simple Arena is an arena that can't expand whenever allocating memory, meaning what you originally allocated is what you get + +typedef arena simplearena; + +int simplearena_init(simplearena **a, size_t bytes) { + return arena_init(a, bytes); +} + +void* simplearena_alloc(simplearena * const a, size_t bytes) { + // The criteria to allocate new memory in arena_alloc is 'bytes > ((a->current)->allocated - (a->current)->used)', so if this + // is true, just return NULL & set errno + + if(!a) { + errno = EINVAL; + return NULL; + } + if(bytes > ((a->current)->allocated - (a->current)->used)) { + errno = ENOMEM; + return NULL; + } + + return arena_alloc(a, bytes); +} + +int simplearena_free(simplearena **a) { + return arena_free(a); +} + +int simplearena_clear(simplearena **a) { + return arena_clear(a); +} \ No newline at end of file -- cgit v1.2.3