From cec0cd966bc241278bb8c5204e5ad294020f3720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Fri, 12 Jun 2026 21:39:16 +0200 Subject: [PATCH] Add pool alocator based on arena --- src/arena.c | 55 ++++++++++++++++++++++++++++++ src/arena.h | 29 ++++++++++++++-- src/main.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 177 insertions(+), 3 deletions(-) diff --git a/src/arena.c b/src/arena.c index 7abd917..d68a117 100644 --- a/src/arena.c +++ b/src/arena.c @@ -154,3 +154,58 @@ void arena_reset(Arena *arena) { arena_reset_to(arena, 0); } + + +// Pool + +APool *apool_create_ex(Arena *arena, U32 n_elements, U32 element_size, U32 element_align) +{ + Assert(IsPow2(element_align)); + U32 align = element_align; + if (element_align < alignof(APoolElement)) { + element_align = alignof(APoolElement); + } + U32 size = AlignUp(element_size, element_align); + + APool *pool = arena_push_type(arena, APool); + pool->align = align; + pool->element_size = size; + pool->arena = arena; + pool->n_elements = n_elements; + pool->free_list = NULL; + pool->start == NULL; + + if (size != APOOL_AUTOGROW) { + U32 total_size = n_elements * size; // Note(nos): guard against unreasonable sizes + U8 * start = arena_push(arena, total_size, align); + for (U32 i = 0; i < total_size; i += size) { + APoolElement *element = (APoolElement *)&start[i]; + element->next = pool->free_list; + pool->free_list = element; + } + pool->start = start; + } + + return pool; +} + +void *apool_alloc(APool *pool) +{ + APoolElement *element = pool->free_list; + if (element != NULL) { + pool->free_list = element->next; + } else if(pool->n_elements == APOOL_AUTOGROW) { + element = arena_push(pool->arena, pool->element_size, pool->align); + } + + return element; +} + +void apool_free(APool *pool, void *ptr) +{ + if (ptr != NULL) { + APoolElement *element = (APoolElement *)ptr; + element->next = pool->free_list; + pool->free_list = element; + } +} diff --git a/src/arena.h b/src/arena.h index 11fa372..0a666ed 100644 --- a/src/arena.h +++ b/src/arena.h @@ -35,8 +35,8 @@ struct ATemp { Arena *arena; U64 total_offset; }; -#ifndef ArenaParams_Default -#define ArenaParams_Default { .size = MB(32), .commit_size = KB(64) } +#ifndef ArenaOptions_Default +#define ArenaOptions_Default (&(ArenaOptions){ .size = MB(32), .commit_size = KB(64) }) #endif StaticAssert(sizeof(MemoryBlock) <= 64); @@ -66,3 +66,28 @@ static INLINE U64 arena_used(const Arena *arena) const MemoryBlock *block = arena->current; return block->arena_offset + block->first_free; } + + +typedef union APoolElement APoolElement; +union APoolElement { + APoolElement *next; // offset from start to next free block (when not allocated) +}; + +typedef struct APool APool; +struct APool { + APoolElement *free_list; // free list + U8 *start; // start of user buffer + Arena *arena; + U32 element_size; // aligned size of each block + U32 n_elements; // total number of blocks + U32 align; // alignment +}; +enum { + APOOL_AUTOGROW = 0 +}; + +#define apool_create(arena, n_elements, type) \ + apool_create_ex(arena, n_elements, sizeof(type), alignof(type)); +APool *apool_create_ex(Arena *arena, U32 n_elements, U32 element_size, uint32_t element_align); +void *apool_alloc(APool *pool); +void apool_free(APool *pool, void *element); diff --git a/src/main.c b/src/main.c index 0ce6997..d596b7b 100644 --- a/src/main.c +++ b/src/main.c @@ -191,12 +191,106 @@ void miniarena_test1(void) } +typedef struct PoolTest PoolTest; +struct PoolTest{ + U32 n; + char name[32]; + PoolTest *next; +}; + +void apool_test(void) +{ + Arena arena; + arena_init(&arena, ArenaOptions_Default); + APool *pool = apool_create_ex(&arena, 16, sizeof(PoolTest), alignof(PoolTest)); + PoolTest *list = NULL; + for (U32 i = 0; i < U32_Max; i++) { + PoolTest *pt = apool_alloc(pool); + if (pt == NULL){ + break; + } + pt->n = i; + pt->next = list; + list = pt; + } + for (PoolTest *p = list; p; p = p->next){ + printf("Pooltest %u\n",p->n); + } + + PoolTest *next; + U32 count = 0; + for (PoolTest *p = list; count < 7 && p; p = next){ + count++; + next = p->next; + printf("Pooltest freeing %u\n",p->n); + apool_free(pool, p); + } + list = NULL; + for (U32 i = 0; i < U32_Max; i++) { + PoolTest *pt = apool_alloc(pool); + if (pt == NULL){ + break; + } + pt->n = i; + pt->next = list; + list = pt; + } + for (PoolTest *p = list; p; p = p->next){ + printf("Pooltest %u\n",p->n); + } + +} + +void apool_test_autogrow(void) +{ + Arena arena; + arena_init(&arena, ArenaOptions_Default); + APool *pool = apool_create(&arena, APOOL_AUTOGROW, PoolTest); + PoolTest *list = NULL; + for (U32 i = 0; i < 4; i++) { + PoolTest *pt = apool_alloc(pool); + if (pt == NULL){ + break; + } + pt->n = i; + pt->next = list; + list = pt; + } + for (PoolTest *p = list; p; p = p->next){ + printf("Pooltest %u\n",p->n); + } + + PoolTest *next; + U32 count = 0; + for (PoolTest *p = list; count < 3 && p; p = next){ + count++; + next = p->next; + printf("Pooltest freeing %u\n",p->n); + apool_free(pool, p); + } + list = NULL; + for (U32 i = 0; i < 5; i++) { + PoolTest *pt = apool_alloc(pool); + if (pt == NULL){ + break; + } + pt->n = i; + pt->next = list; + list = pt; + } + for (PoolTest *p = list; p; p = p->next){ + printf("Pooltest %u\n",p->n); + } + +} + int main(int argc, char *argv[]) { // arena_test_1(); // arena_test_2(); // arena_test_3(); // arena_test_4(); - miniarena_test1(); +// miniarena_test1(); + apool_test_autogrow(); }