refactor: arena uses Allocator

This commit is contained in:
2026-06-06 09:48:18 -06:00
parent f3a5ecf807
commit 2dcef95b2e
4 changed files with 101 additions and 83 deletions

View File

@@ -1,6 +1,7 @@
#ifndef LAE_ARENA_H #ifndef LAE_ARENA_H
#define LAE_ARENA_H #define LAE_ARENA_H
#include "lae_allocator.h"
#include <inttypes.h> #include <inttypes.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@@ -23,20 +24,12 @@ typedef struct {
union { union {
ArenaErr err; ArenaErr err;
struct { struct {
Arena* arena; Arena *arena;
size_t offset; size_t offset;
}; };
}; };
} ArenaPointer; } ArenaPointer;
typedef struct {
bool is_valid;
union {
ArenaErr err;
Arena* arena;
};
} ArenaResult;
typedef struct { typedef struct {
bool is_valid; bool is_valid;
union { union {
@@ -45,20 +38,20 @@ typedef struct {
}; };
} ArenaSizeResult; } ArenaSizeResult;
ArenaErr arena_init(Arena** arena, size_t capacity); ArenaErr arena_init(Arena **arena, Allocator allocator, size_t capacity);
ArenaErr arena_destroy(Arena** arena); ArenaErr arena_destroy(Arena **arena);
ArenaPointer arena_alloc(Arena* arena, size_t size, size_t alignment); ArenaPointer arena_alloc(Arena *arena, size_t size, size_t alignment);
ArenaPointer ArenaPointer
arena_push(Arena* arena, void* data, size_t size, size_t alignment); arena_push_data(Arena *arena, void *data, size_t size, size_t alignment);
ArenaErr arena_realloc(Arena* arena, size_t new_capacity); ArenaErr arena_resize(Arena *arena, size_t new_capacity);
void* arena_unwrap_pointer(ArenaPointer p); void *arena_unwrap_pointer(ArenaPointer p);
ArenaSizeResult arena_get_align_padding(Arena* arena, size_t alignment); ArenaSizeResult arena_get_align_padding(Arena *arena, size_t alignment);
// can take big sizes but of sourse there is a limit, // can take big sizes but of sourse there is a limit,
// its protected against SIZE_MAX but anything that // its protected against SIZE_MAX but anything that
// is big may break it, still, is an edge case that // is big may break it, still, is an edge case that
// I shouldn't cover. // I shouldn't cover.
ArenaErr arena_ensure_capacity(Arena* arena, size_t size, size_t alignment); ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment);
#endif // !RENA_H #endif // !RENA_H

View File

@@ -10,9 +10,11 @@ struct Arena {
uint8_t *buffer; uint8_t *buffer;
size_t capacity; size_t capacity;
size_t offset; size_t offset;
Allocator allocator;
}; };
ArenaErr arena_init(Arena **arena, size_t capacity) { ArenaErr arena_init(Arena **arena, Allocator allocator, size_t capacity) {
if (arena == NULL) { if (arena == NULL) {
return ARENA_NULL_ARG; return ARENA_NULL_ARG;
} }
@@ -21,13 +23,14 @@ ArenaErr arena_init(Arena **arena, size_t capacity) {
return ARENA_INVALID_SIZE; return ARENA_INVALID_SIZE;
} }
Arena *new_arena = malloc(sizeof(Arena)); Arena *new_arena = allocator.alloc(allocator.ctx, sizeof(Arena));
if (new_arena == NULL) { if (new_arena == NULL) {
return ARENA_BAD_ALLOC; return ARENA_BAD_ALLOC;
} }
void *buffer = malloc(capacity); void *buffer = allocator.alloc(allocator.ctx, capacity);
if (buffer == NULL) { if (buffer == NULL) {
allocator.free(allocator.ctx, new_arena, capacity);
return ARENA_BAD_ALLOC; return ARENA_BAD_ALLOC;
} }
@@ -35,6 +38,7 @@ ArenaErr arena_init(Arena **arena, size_t capacity) {
.buffer = buffer, .buffer = buffer,
.capacity = capacity, .capacity = capacity,
.offset = 0, .offset = 0,
.allocator = allocator,
}; };
*arena = new_arena; *arena = new_arena;
@@ -47,11 +51,12 @@ ArenaErr arena_destroy(Arena **arena) {
return ARENA_NULL_ARG; return ARENA_NULL_ARG;
} }
free((*arena)->buffer); Arena *tmp = *arena;
(*arena)->buffer = NULL; tmp->allocator.free(tmp->allocator.ctx, tmp->buffer, tmp->capacity);
(*arena)->offset = 0; tmp->buffer = NULL;
(*arena)->capacity = 0; tmp->offset = 0;
free(*arena); tmp->capacity = 0;
tmp->allocator.free(tmp->allocator.ctx, *arena, sizeof(Arena));
*arena = NULL; *arena = NULL;
return ARENA_OK; return ARENA_OK;
@@ -146,7 +151,7 @@ ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment) {
new_capacity = required; new_capacity = required;
} }
ArenaErr err = arena_realloc(arena, new_capacity); ArenaErr err = arena_resize(arena, new_capacity);
if (err != ARENA_OK) { if (err != ARENA_OK) {
return err; return err;
} }
@@ -154,7 +159,7 @@ ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment) {
} }
ArenaPointer ArenaPointer
arena_push(Arena *arena, void *data, size_t size, size_t alignment) { arena_push_data(Arena *arena, void *data, size_t size, size_t alignment) {
if (arena == NULL || data == NULL) { if (arena == NULL || data == NULL) {
return (ArenaPointer){.is_valid = false, .err = ARENA_NULL_ARG}; return (ArenaPointer){.is_valid = false, .err = ARENA_NULL_ARG};
} }
@@ -182,7 +187,7 @@ arena_push(Arena *arena, void *data, size_t size, size_t alignment) {
return pointer; return pointer;
} }
ArenaErr arena_realloc(Arena *arena, size_t new_capacity) { ArenaErr arena_resize(Arena *arena, size_t new_capacity) {
if (arena == NULL) { if (arena == NULL) {
return ARENA_NULL_ARG; return ARENA_NULL_ARG;
} }
@@ -191,7 +196,11 @@ ArenaErr arena_realloc(Arena *arena, size_t new_capacity) {
return ARENA_INVALID_SIZE; return ARENA_INVALID_SIZE;
} }
uint8_t *tmp = realloc(arena->buffer, new_capacity); uint8_t *tmp = arena->allocator.realloc(
arena->allocator.ctx,
arena->buffer,
arena->capacity,
new_capacity);
if (tmp == NULL) { if (tmp == NULL) {
return ARENA_BAD_ALLOC; return ARENA_BAD_ALLOC;
} }

View File

@@ -1,90 +1,106 @@
#include <cmocka.h>
#include <limits.h>
#include <setjmp.h>
#include <stdalign.h> #include <stdalign.h>
#include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <setjmp.h>
#include <cmocka.h>
#include <string.h> #include <string.h>
#include <limits.h>
#include "lae_allocator.h"
#include "lae_arena.h" #include "lae_arena.h"
static void test_push_3_ints(void **state) { static void test_push_3_ints(void **state) {
(void) state; (void)state;
Arena *arena; Arena *arena;
assert_uint_equal(arena_init(&arena, sizeof(int) * 3), ARENA_OK); assert_uint_equal(
arena_init(&arena, allocator_default(), sizeof(int) * 3),
ARENA_OK);
int int_to_push = 20; int int_to_push = 20;
ArenaPointer result = arena_push(arena, &int_to_push, sizeof(int), alignof(int)); ArenaPointer result =
arena_push_data(arena, &int_to_push, sizeof(int), alignof(int));
assert_true(result.is_valid); assert_true(result.is_valid);
assert_int_equal(20, *(int*)arena_unwrap_pointer(result)); assert_int_equal(20, *(int *)arena_unwrap_pointer(result));
assert_int_equal(20, *(int*)arena_unwrap_pointer(result)); assert_int_equal(20, *(int *)arena_unwrap_pointer(result));
int_to_push = 30; int_to_push = 30;
result = arena_push(arena, &int_to_push, sizeof(int), alignof(int)); result = arena_push_data(arena, &int_to_push, sizeof(int), alignof(int));
assert_true(result.is_valid); assert_true(result.is_valid);
assert_int_equal(30, *(int*)arena_unwrap_pointer(result)); assert_int_equal(30, *(int *)arena_unwrap_pointer(result));
int_to_push = 40; int_to_push = 40;
result = arena_push(arena, &int_to_push, sizeof(int), alignof(int)); result = arena_push_data(arena, &int_to_push, sizeof(int), alignof(int));
assert_true(result.is_valid); assert_true(result.is_valid);
assert_int_equal(40, *(int*)arena_unwrap_pointer(result)); assert_int_equal(40, *(int *)arena_unwrap_pointer(result));
arena_destroy(&arena); arena_destroy(&arena);
} }
static void test_push_3_ints_2_doubles(void **state) { static void test_push_3_ints_2_doubles(void **state) {
(void) state; (void)state;
Arena *arena; Arena *arena;
assert_uint_equal( assert_uint_equal(
arena_init(&arena, (sizeof(int) * 3) + (sizeof(double) * 2)), arena_init(
ARENA_OK &arena,
); allocator_default(),
(sizeof(int) * 3) + (sizeof(double) * 2)),
ARENA_OK);
int int_to_push = 20; int int_to_push = 20;
ArenaPointer result = arena_push(arena, &int_to_push, sizeof(int), alignof(int)); ArenaPointer result =
arena_push_data(arena, &int_to_push, sizeof(int), alignof(int));
assert_true(result.is_valid); assert_true(result.is_valid);
assert_int_equal(20, *(int*)arena_unwrap_pointer(result)); assert_int_equal(20, *(int *)arena_unwrap_pointer(result));
double double_to_push = 4.57; double double_to_push = 4.57;
result = arena_push(arena, &double_to_push, sizeof(double), alignof(double)); result = arena_push_data(
arena,
&double_to_push,
sizeof(double),
alignof(double));
assert_true(result.is_valid); assert_true(result.is_valid);
assert_double_equal(4.57, *(double*)arena_unwrap_pointer(result), 1e-6); assert_double_equal(4.57, *(double *)arena_unwrap_pointer(result), 1e-6);
int_to_push = 30; int_to_push = 30;
result = arena_push(arena, &int_to_push, sizeof(int), alignof(int)); result = arena_push_data(arena, &int_to_push, sizeof(int), alignof(int));
assert_true(result.is_valid); assert_true(result.is_valid);
assert_int_equal(30, *(int*)arena_unwrap_pointer(result)); assert_int_equal(30, *(int *)arena_unwrap_pointer(result));
int_to_push = 40; int_to_push = 40;
result = arena_push(arena, &int_to_push, sizeof(int), alignof(int)); result = arena_push_data(arena, &int_to_push, sizeof(int), alignof(int));
assert_true(result.is_valid); assert_true(result.is_valid);
assert_int_equal(40, *(int*)arena_unwrap_pointer(result)); assert_int_equal(40, *(int *)arena_unwrap_pointer(result));
double_to_push = 267.33; double_to_push = 267.33;
result = arena_push(arena, &double_to_push, sizeof(double), alignof(double)); result = arena_push_data(
arena,
&double_to_push,
sizeof(double),
alignof(double));
assert_true(result.is_valid); assert_true(result.is_valid);
assert_double_equal(267.33, *(double*)arena_unwrap_pointer(result), 1e-6); assert_double_equal(267.33, *(double *)arena_unwrap_pointer(result), 1e-6);
arena_destroy(&arena); arena_destroy(&arena);
} }
static void test_init_arena_0_cap(void **state) { static void test_init_arena_0_cap(void **state) {
(void) state; (void)state;
Arena *arena; Arena *arena;
assert_int_equal(arena_init(&arena, 0), ARENA_INVALID_SIZE); assert_int_equal(
arena_init(&arena, allocator_default(), 0),
ARENA_INVALID_SIZE);
} }
static void test_arena_alloc_size_0(void **state) { static void test_arena_alloc_size_0(void **state) {
(void) state; (void)state;
Arena *arena; Arena *arena;
assert_uint_equal(arena_init(&arena, 64), ARENA_OK); assert_uint_equal(arena_init(&arena, allocator_default(), 64), ARENA_OK);
ArenaPointer pointer = arena_alloc(arena, 0, alignof(int)); ArenaPointer pointer = arena_alloc(arena, 0, alignof(int));
assert_false(pointer.is_valid); assert_false(pointer.is_valid);
@@ -94,10 +110,10 @@ static void test_arena_alloc_size_0(void **state) {
} }
static void test_arena_alloc_size_max(void **state) { static void test_arena_alloc_size_max(void **state) {
(void) state; (void)state;
Arena *arena; Arena *arena;
assert_uint_equal(arena_init(&arena, 64), ARENA_OK); assert_uint_equal(arena_init(&arena, allocator_default(), 64), ARENA_OK);
ArenaPointer pointer = arena_alloc(arena, SIZE_MAX, alignof(int)); ArenaPointer pointer = arena_alloc(arena, SIZE_MAX, alignof(int));
assert_false(pointer.is_valid); assert_false(pointer.is_valid);
@@ -107,10 +123,10 @@ static void test_arena_alloc_size_max(void **state) {
} }
static void test_arena_alloc_align_0(void **state) { static void test_arena_alloc_align_0(void **state) {
(void) state; (void)state;
Arena *arena; Arena *arena;
assert_uint_equal(arena_init(&arena, 64), ARENA_OK); assert_uint_equal(arena_init(&arena, allocator_default(), 64), ARENA_OK);
ArenaPointer pointer = arena_alloc(arena, sizeof(int), 0); ArenaPointer pointer = arena_alloc(arena, sizeof(int), 0);
assert_false(pointer.is_valid); assert_false(pointer.is_valid);
@@ -120,10 +136,10 @@ static void test_arena_alloc_align_0(void **state) {
} }
static void test_arena_alloc_align_max(void **state) { static void test_arena_alloc_align_max(void **state) {
(void) state; (void)state;
Arena *arena; Arena *arena;
assert_uint_equal(arena_init(&arena, 64), ARENA_OK); assert_uint_equal(arena_init(&arena, allocator_default(), 64), ARENA_OK);
ArenaPointer pointer = arena_alloc(arena, sizeof(int), SIZE_MAX); ArenaPointer pointer = arena_alloc(arena, sizeof(int), SIZE_MAX);
assert_false(pointer.is_valid); assert_false(pointer.is_valid);
@@ -133,10 +149,10 @@ static void test_arena_alloc_align_max(void **state) {
} }
static void test_arena_align_size_0(void **state) { static void test_arena_align_size_0(void **state) {
(void) state; (void)state;
Arena *arena; Arena *arena;
assert_uint_equal(arena_init(&arena, 64), ARENA_OK); assert_uint_equal(arena_init(&arena, allocator_default(), 64), ARENA_OK);
ArenaPointer pointer = arena_alloc(arena, sizeof(int), 0); ArenaPointer pointer = arena_alloc(arena, sizeof(int), 0);
assert_false(pointer.is_valid); assert_false(pointer.is_valid);
@@ -146,10 +162,10 @@ static void test_arena_align_size_0(void **state) {
} }
static void test_arena_ensure_capacity_size_0(void **state) { static void test_arena_ensure_capacity_size_0(void **state) {
(void) state; (void)state;
Arena *arena; Arena *arena;
assert_uint_equal(arena_init(&arena, 64), ARENA_OK); assert_uint_equal(arena_init(&arena, allocator_default(), 64), ARENA_OK);
ArenaErr err = arena_ensure_capacity(arena, 0, alignof(int)); ArenaErr err = arena_ensure_capacity(arena, 0, alignof(int));
assert_int_equal(err, ARENA_INVALID_SIZE); assert_int_equal(err, ARENA_INVALID_SIZE);
@@ -158,10 +174,10 @@ static void test_arena_ensure_capacity_size_0(void **state) {
} }
static void test_arena_ensure_capacity_size_max(void **state) { static void test_arena_ensure_capacity_size_max(void **state) {
(void) state; (void)state;
Arena *arena; Arena *arena;
assert_uint_equal(arena_init(&arena, 64), ARENA_OK); assert_uint_equal(arena_init(&arena, allocator_default(), 64), ARENA_OK);
ArenaErr err = arena_ensure_capacity(arena, SIZE_MAX, alignof(int)); ArenaErr err = arena_ensure_capacity(arena, SIZE_MAX, alignof(int));
assert_int_equal(err, ARENA_INVALID_SIZE); assert_int_equal(err, ARENA_INVALID_SIZE);
@@ -170,10 +186,10 @@ static void test_arena_ensure_capacity_size_max(void **state) {
} }
static void test_arena_ensure_capacity_align_0(void **state) { static void test_arena_ensure_capacity_align_0(void **state) {
(void) state; (void)state;
Arena *arena; Arena *arena;
assert_uint_equal(arena_init(&arena, 64), ARENA_OK); assert_uint_equal(arena_init(&arena, allocator_default(), 64), ARENA_OK);
ArenaErr err = arena_ensure_capacity(arena, sizeof(int), 0); ArenaErr err = arena_ensure_capacity(arena, sizeof(int), 0);
assert_int_equal(err, ARENA_INVALID_ALIGN); assert_int_equal(err, ARENA_INVALID_ALIGN);
@@ -182,10 +198,10 @@ static void test_arena_ensure_capacity_align_0(void **state) {
} }
static void test_arena_ensure_capacity_align_max(void **state) { static void test_arena_ensure_capacity_align_max(void **state) {
(void) state; (void)state;
Arena *arena; Arena *arena;
assert_uint_equal(arena_init(&arena, 64), ARENA_OK); assert_uint_equal(arena_init(&arena, allocator_default(), 64), ARENA_OK);
ArenaErr err = arena_ensure_capacity(arena, sizeof(int), SIZE_MAX); ArenaErr err = arena_ensure_capacity(arena, sizeof(int), SIZE_MAX);
assert_int_equal(err, ARENA_INVALID_ALIGN); assert_int_equal(err, ARENA_INVALID_ALIGN);
@@ -209,6 +225,5 @@ int main(void) {
cmocka_unit_test(test_arena_ensure_capacity_size_max), cmocka_unit_test(test_arena_ensure_capacity_size_max),
}; };
return cmocka_run_group_tests(tests, NULL, NULL); return cmocka_run_group_tests(tests, NULL, NULL);
} }

View File

@@ -44,7 +44,7 @@ add_requires("lae_allocator")
target("lae_arena") target("lae_arena")
set_kind("static") set_kind("static")
add_packages("lae_allocator") add_packages("lae_allocator", { public = true })
add_files("src/lae_arena.c") add_files("src/lae_arena.c")
@@ -64,9 +64,10 @@ if has_config("example") then
target("example") target("example")
set_kind("binary") set_kind("binary")
add_files("src/main.c")
add_deps("lae_arena") add_deps("lae_arena")
add_packages("lae_allocator")
add_files("src/main.c")
end end
-- ========================================================= -- =========================================================
@@ -77,12 +78,12 @@ if has_config("tests") then
target("test_arena") target("test_arena")
set_kind("binary") set_kind("binary")
add_files("test/test_arena.c")
add_deps("lae_arena") add_deps("lae_arena")
add_packages("cmocka") add_packages("cmocka")
add_files("test/test_arena.c")
add_tests("default") add_tests("default")
if has_config("asan") then if has_config("asan") then