From d6ad1c76027ec15bfe5e573bcfdbdb3ffebd0f53 Mon Sep 17 00:00:00 2001 From: Ivar Fatland Date: Sat, 6 Dec 2025 14:19:53 +0100 Subject: [PATCH] arena allocators are fully implemented --- borrow_allocator.c | 10 +++--- buffer_allocator.c | 6 ++-- cig.h | 6 ++-- test_arena_allocator.c | 79 ++++++++++++++++++++++++++++++++++++++++++ test_std_allocator.c | 1 + 5 files changed, 92 insertions(+), 10 deletions(-) create mode 100644 test_arena_allocator.c diff --git a/borrow_allocator.c b/borrow_allocator.c index 0697b59..8c5ced5 100644 --- a/borrow_allocator.c +++ b/borrow_allocator.c @@ -4,7 +4,7 @@ #include #include -void *borrow_allocator_alloc_func(borrow_allocator_t *this, size_t bytes) { +static void *borrow_allocator_alloc_func(borrow_allocator_t *this, size_t bytes) { linked_allocation_node_t *node = malloc(sizeof(*this->head) + bytes); if (node == NULL) { return NULL; } node->prev = NULL; @@ -17,7 +17,7 @@ void *borrow_allocator_alloc_func(borrow_allocator_t *this, size_t bytes) { return &node->data; } -void *borrow_allocator_resize_func(borrow_allocator_t *this, void *old_ptr, size_t bytes) { +static void *borrow_allocator_resize_func(borrow_allocator_t *this, void *old_ptr, size_t bytes) { linked_allocation_node_t *old_node = PTR_FROM_FIELD_PTR(linked_allocation_node_t, data, old_ptr); linked_allocation_node_t *new_node = realloc(old_node, sizeof(*old_node) + bytes); if (new_node == NULL) { return NULL; } @@ -31,7 +31,7 @@ void *borrow_allocator_resize_func(borrow_allocator_t *this, void *old_ptr, size } // TODO: remove -void borrow_allocator_free(borrow_allocator_t *this, void *old_ptr) { +static void borrow_allocator_free(borrow_allocator_t *this, void *old_ptr) { linked_allocation_node_t *node = PTR_FROM_FIELD_PTR(linked_allocation_node_t, data, old_ptr); if (node->prev != NULL) { node->prev->next = node->next; } if (node->next != NULL) { node->next->prev = node->prev; } @@ -43,7 +43,7 @@ void borrow_allocator_free(borrow_allocator_t *this, void *old_ptr) { free(node); } -void borrow_allocator_free_all(borrow_allocator_t *this) { +static void borrow_allocator_free_all(borrow_allocator_t *this) { if (this->head == NULL) { return; } @@ -57,7 +57,7 @@ void borrow_allocator_free_all(borrow_allocator_t *this) { this->head = NULL; } -size_t borrow_allocator_count_allocations(borrow_allocator_t *this) { +static size_t borrow_allocator_count_allocations(borrow_allocator_t *this) { size_t output = 0; for (linked_allocation_node_t *node = this->head; node != NULL; node = node->next) { output++; diff --git a/buffer_allocator.c b/buffer_allocator.c index 6a72541..2f0b259 100644 --- a/buffer_allocator.c +++ b/buffer_allocator.c @@ -1,6 +1,6 @@ #include "cig.h" -void *buffer_allocator_alloc(buffer_allocator_t *this, size_t bytes) { +static void *buffer_allocator_alloc(buffer_allocator_t *this, size_t bytes) { size_t address_of_new_data = (size_t) &this->data[this->size]; size_t offset = address_of_new_data % MAX_ALIGN; size_t new_size = this->size + offset + bytes; @@ -13,7 +13,7 @@ void *buffer_allocator_alloc(buffer_allocator_t *this, size_t bytes) { return ptr; } -void *buffer_allocator_resize(buffer_allocator_t *this, void *old_ptr, size_t bytes) { +static void *buffer_allocator_resize(buffer_allocator_t *this, void *old_ptr, size_t bytes) { void *new_ptr = buffer_allocator_alloc(this, bytes); if (new_ptr == NULL) { return NULL; @@ -26,7 +26,7 @@ void *buffer_allocator_resize(buffer_allocator_t *this, void *old_ptr, size_t by return new_ptr; } -void buffer_allocator_reset(buffer_allocator_t *this) { +static void buffer_allocator_reset(buffer_allocator_t *this) { this->size = 0; } diff --git a/cig.h b/cig.h index febc9f0..bd2425a 100644 --- a/cig.h +++ b/cig.h @@ -92,14 +92,16 @@ typedef struct arena_allocator { uint8_t *data; } arena_allocator_t; -#define arena_allocator_value(INITIAL_CAPACITY) ((arena_allocator_t) { \ - .allocator=borrow_allocator_create(), \ +#define arena_allocator_value(BACKING_ALLOCATOR, INITIAL_CAPACITY) ((arena_allocator_t) { \ + .allocator=BACKING_ALLOCATOR, \ .size=0, \ .capacity=INITIAL_CAPACITY, \ .data=NULL \ }) allocator_t allocator_from_arena(arena_allocator_t *this); +#define arena_allocator_create(BACKING_ALLOCATOR, INITIAL_CAPACITY) \ + allocator_from_arena(&arena_allocator_value(BACKING_ALLOCATOR, INITIAL_CAPACITY)) // dynamic arrays ////////////////////////////////////////////////////////////// diff --git a/test_arena_allocator.c b/test_arena_allocator.c new file mode 100644 index 0000000..3fb3e55 --- /dev/null +++ b/test_arena_allocator.c @@ -0,0 +1,79 @@ +#include +#include +#include "cig.h" + +Test(arena_allocator, test) { + with_borrow(backing) { + allocator_t arena = arena_allocator_create(backing, 4 * MB); + for ( size_t i = 0; i < 1000; i++ ) { + allocator_reset(arena); + allocator_alloc(arena, 4 * MB); + } + + borrow_allocator_t *concrete = (borrow_allocator_t*)backing.this; + size_t n_allocations = 0; + for (linked_allocation_node_t *node = concrete->head; node != NULL; node = node->next) { + n_allocations++; + } + cr_assert_eq(n_allocations, 1); + } + + with_borrow(backing) { + allocator_t arena = arena_allocator_create(backing, 0); + for ( size_t i = 0; i < 1000; i++ ) { + allocator_reset(arena); + allocator_alloc(arena, 1 * MB); + allocator_alloc(arena, 1 * MB); + allocator_alloc(arena, 1 * MB); + allocator_alloc(arena, 1 * MB); + } + + borrow_allocator_t *concrete = (borrow_allocator_t*)backing.this; + size_t n_allocations = 0; + for (linked_allocation_node_t *node = concrete->head; node != NULL; node = node->next) { + n_allocations++; + } + cr_assert_eq(n_allocations, 1); + } + + with_borrow(backing) { + allocator_t arena = arena_allocator_create(backing, 0); + for ( size_t i = 0; i < 1000; i++ ) { + allocator_reset(arena); + allocator_alloc(arena, 1 * MB); + allocator_alloc(arena, 1 * MB); + allocator_alloc(arena, 1 * MB); + allocator_alloc(arena, 1 * MB); + } + + borrow_allocator_t *concrete_borrow = (borrow_allocator_t*)backing.this; + arena_allocator_t *concrete_arena = (arena_allocator_t*)arena.this; + size_t n_allocations = 0; + for (linked_allocation_node_t *node = concrete_borrow->head; node != NULL; node = node->next) { + n_allocations++; + } + cr_assert_eq(n_allocations, 1); + cr_assert_eq(concrete_arena->capacity, 4 * MB); + } + + with_borrow(backing) { + allocator_t arena = arena_allocator_create(backing, 0); + for ( size_t i = 0; i < 1000; i++ ) { + allocator_reset(arena); + allocator_alloc(arena, 1); + allocator_alloc(arena, 1); + allocator_alloc(arena, 1); + allocator_alloc(arena, 1); + } + + borrow_allocator_t *concrete_borrow = (borrow_allocator_t*)backing.this; + arena_allocator_t *concrete_arena = (arena_allocator_t*)arena.this; + size_t n_allocations = 0; + for (linked_allocation_node_t *node = concrete_borrow->head; node != NULL; node = node->next) { + n_allocations++; + } + cr_assert_eq(n_allocations, 1); + const size_t expected_capacity = 4 * MAX_ALIGN; + cr_assert_eq(concrete_arena->capacity, expected_capacity); + } +} diff --git a/test_std_allocator.c b/test_std_allocator.c index aac07f3..a0df2b5 100644 --- a/test_std_allocator.c +++ b/test_std_allocator.c @@ -9,4 +9,5 @@ Test(std_allocator, test) { void *new_ptr = allocator_resize(this, ptr, 1024*1024*500); cr_assert(new_ptr != ((void *)0), "non null from realloc"); cr_assert(new_ptr != ptr, "realloc is not the same ptr as malloc"); + free(new_ptr); }