From 203b60cf656d00f39a63c09d7d12bda644ce8c6b Mon Sep 17 00:00:00 2001 From: laentropia Date: Tue, 26 May 2026 13:52:28 -0600 Subject: [PATCH 1/5] refactor: xmake is now in use --- .gitignore | 6 ++ CMakeLists.txt | 97 ---------------------------- include/{arena.h => lae_arena.h} | 6 +- src/{arena.c => lae_arena.c} | 95 +++++++++++++-------------- src/main.c | 2 +- test/CMakeLists.txt | 107 ------------------------------- test/test_arena.c | 2 +- xmake.lua | 87 +++++++++++++++++++++++++ 8 files changed, 142 insertions(+), 260 deletions(-) delete mode 100644 CMakeLists.txt rename include/{arena.h => lae_arena.h} (96%) rename src/{arena.c => lae_arena.c} (60%) delete mode 100644 test/CMakeLists.txt create mode 100644 xmake.lua diff --git a/.gitignore b/.gitignore index 0bd57ed..d1a83ec 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,12 @@ out/ out/Debug/ out/Release/ +# xmake +xmake/ +xmake/* +.xmake +.xmake/* + # Cmake files CMakeCache.txt CMakeFiles/ diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index b350ff7..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,97 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project( - arena - VERSION 1.0 - LANGUAGES C) - -# ------------------------------------------------ -# C standard — no compiler extensions -# ------------------------------------------------ -set(CMAKE_C_STANDARD 11) -set(CMAKE_C_STANDARD_REQUIRED ON) -set(CMAKE_C_EXTENSIONS OFF) - -# Export compile_commands.json (clangd / IDEs) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - -# ------------------------------------------------ -# Is this the root project or embedded (CPM / FetchContent)? -# ------------------------------------------------ -if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) - set(ARENA_IS_TOP_LEVEL ON) -else() - set(ARENA_IS_TOP_LEVEL OFF) -endif() - -# ------------------------------------------------ -# Options -# ------------------------------------------------ -option(ARENA_BUILD_TESTS "Build arena tests" ${ARENA_IS_TOP_LEVEL}) -option(ARENA_BUILD_EXAMPLE "Build arena example" ${ARENA_IS_TOP_LEVEL}) -option(ARENA_ENABLE_INSTALL "Install arena" ${ARENA_IS_TOP_LEVEL}) -option(ARENA_ENABLE_SANITIZERS "Enable Address Sanitizer in tests" ON) - -# ------------------------------------------------ -# Portable warning flags -# ------------------------------------------------ -if(MSVC) - set(ARENA_WARNING_FLAGS /W4) -else() - set(ARENA_WARNING_FLAGS -Wall -Wextra -Wpedantic) -endif() - -# ================================================================ -# LIBRARY -# ================================================================ -add_library(arena src/arena.c) - -# Namespaced alias → consumers can write arena::arena -add_library(arena::arena ALIAS arena) - -target_include_directories( - arena PUBLIC $ - $) - -# Propagate C11 requirement to consumers -target_compile_features(arena PUBLIC c_std_11) - -# Warnings only for the lib itself, not propagated -target_compile_options(arena PRIVATE ${ARENA_WARNING_FLAGS}) - -# ================================================================ -# EXAMPLE (optional, only when top-level) -# ================================================================ -if(ARENA_BUILD_EXAMPLE) - add_executable(arena_example src/main.c) - target_link_libraries(arena_example PRIVATE arena) -endif() - -# ================================================================ -# TESTS -# ================================================================ -if(ARENA_BUILD_TESTS) - enable_testing() - add_subdirectory(test) -endif() - -# ================================================================ -# INSTALL -# ================================================================ -if(ARENA_ENABLE_INSTALL) - include(GNUInstallDirs) - - install( - TARGETS arena - EXPORT arenaTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - - install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - - install( - EXPORT arenaTargets - FILE arenaTargets.cmake - NAMESPACE arena:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/arena) -endif() diff --git a/include/arena.h b/include/lae_arena.h similarity index 96% rename from include/arena.h rename to include/lae_arena.h index a9a03fe..8a9f786 100644 --- a/include/arena.h +++ b/include/lae_arena.h @@ -1,5 +1,5 @@ -#ifndef ARENA_H -#define ARENA_H +#ifndef LAE_ARENA_H +#define LAE_ARENA_H #include #include @@ -61,4 +61,4 @@ ArenaSizeResult arena_get_align_padding(Arena* arena, size_t alignment); // I shouldn't cover. ArenaErr arena_ensure_capacity(Arena* arena, size_t size, size_t alignment); -#endif // !ARENA_H +#endif // !RENA_H diff --git a/src/arena.c b/src/lae_arena.c similarity index 60% rename from src/arena.c rename to src/lae_arena.c index 7d7c34d..4ea4bbc 100644 --- a/src/arena.c +++ b/src/lae_arena.c @@ -1,4 +1,4 @@ -#include "arena.h" +#include "lae_arena.h" #include #include #include @@ -6,13 +6,12 @@ #include struct Arena { - uint8_t *buffer; - size_t capacity; - size_t offset; + uint8_t* buffer; + size_t capacity; + size_t offset; }; - -ArenaErr arena_init(Arena **arena, size_t capacity) { +ArenaErr arena_init(Arena** arena, size_t capacity) { if (arena == NULL) { return ARENA_NULL_ARG; } @@ -21,20 +20,20 @@ ArenaErr arena_init(Arena **arena, size_t capacity) { return ARENA_INVALID_SIZE; } - Arena *new_arena = malloc(sizeof(Arena)); + Arena* new_arena = malloc(sizeof(Arena)); if (new_arena == NULL) { return ARENA_BAD_ALLOC; } - void *buffer = malloc(capacity); + void* buffer = malloc(capacity); if (buffer == NULL) { return ARENA_BAD_ALLOC; } - *new_arena = (Arena) { - .buffer = buffer, + *new_arena = (Arena){ + .buffer = buffer, .capacity = capacity, - .offset = 0, + .offset = 0, }; *arena = new_arena; @@ -42,14 +41,14 @@ ArenaErr arena_init(Arena **arena, size_t capacity) { return ARENA_OK; } -ArenaErr arena_destroy(Arena **arena) { +ArenaErr arena_destroy(Arena** arena) { if (arena == NULL || *arena == NULL) { return ARENA_NULL_ARG; } free((*arena)->buffer); - (*arena)->buffer = NULL; - (*arena)->offset = 0; + (*arena)->buffer = NULL; + (*arena)->offset = 0; (*arena)->capacity = 0; free(*arena); *arena = NULL; @@ -57,44 +56,47 @@ ArenaErr arena_destroy(Arena **arena) { return ARENA_OK; } -ArenaPointer arena_alloc(Arena *arena, size_t size, size_t alignment) { +ArenaPointer arena_alloc(Arena* arena, size_t size, size_t alignment) { if (arena == NULL) { - return (ArenaPointer) {.is_valid = false, .err = ARENA_NULL_ARG}; + return (ArenaPointer){.is_valid = false, .err = ARENA_NULL_ARG}; } if (size < 1) { - return (ArenaPointer) {.is_valid = false, .err = ARENA_INVALID_SIZE}; + return (ArenaPointer){.is_valid = false, .err = ARENA_INVALID_SIZE}; } if (alignment < 1) { - return (ArenaPointer) {.is_valid = false, .err = ARENA_INVALID_ALIGN}; + return (ArenaPointer){.is_valid = false, .err = ARENA_INVALID_ALIGN}; } ArenaSizeResult padding = arena_get_align_padding(arena, alignment); if (!padding.is_valid) { - return (ArenaPointer) {.is_valid = false, .err = padding.err}; + return (ArenaPointer){.is_valid = false, .err = padding.err}; } ArenaErr cap_err = arena_ensure_capacity(arena, size, alignment); - if(cap_err != ARENA_OK) { - return (ArenaPointer) {.is_valid = false, .err = ARENA_OUT_OF_SPACE}; + if (cap_err != ARENA_OK) { + return (ArenaPointer){.is_valid = false, .err = ARENA_OUT_OF_SPACE}; } if (arena->offset + padding.val + size > arena->capacity) { - return (ArenaPointer) {.is_valid = false, .err = ARENA_OUT_OF_SPACE}; + return (ArenaPointer){.is_valid = false, .err = ARENA_OUT_OF_SPACE}; } if (arena->offset > SIZE_MAX - padding.val - size) { - return (ArenaPointer) {.is_valid = false, .err = ARENA_CAPACITY_OVERFLOW}; + return (ArenaPointer){.is_valid = false, + .err = ARENA_CAPACITY_OVERFLOW}; } size_t aligned_offset = arena->offset + padding.val; arena->offset = aligned_offset + size; - return (ArenaPointer) {.is_valid = true, .offset = aligned_offset, .arena = arena}; + return (ArenaPointer){.is_valid = true, + .offset = aligned_offset, + .arena = arena}; } -ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment) { +ArenaErr arena_ensure_capacity(Arena* arena, size_t size, size_t alignment) { if (arena == NULL) { return ARENA_NULL_ARG; } @@ -150,38 +152,36 @@ ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment) { } } -ArenaPointer arena_push(Arena *arena, void *data, size_t size, size_t alignment) { +ArenaPointer +arena_push(Arena* arena, void* data, size_t size, size_t alignment) { if (arena == NULL || data == NULL) { - return (ArenaPointer) {.is_valid = false, .err = ARENA_NULL_ARG}; + return (ArenaPointer){.is_valid = false, .err = ARENA_NULL_ARG}; } if (size < 1) { - return (ArenaPointer) {.is_valid = false, .err = ARENA_INVALID_SIZE}; + return (ArenaPointer){.is_valid = false, .err = ARENA_INVALID_SIZE}; } if (size < 1) { - return (ArenaPointer) {.is_valid = false, .err = ARENA_INVALID_ALIGN}; + return (ArenaPointer){.is_valid = false, .err = ARENA_INVALID_ALIGN}; } ArenaErr err = arena_ensure_capacity(arena, size, alignment); if (err != ARENA_OK) { - return (ArenaPointer) {.is_valid = false, .err = err}; + return (ArenaPointer){.is_valid = false, .err = err}; } ArenaPointer pointer = arena_alloc(arena, size, alignment); if (!pointer.is_valid) { return pointer; } - - memcpy( - arena_unwrap_pointer(pointer), - data, - size); + + memcpy(arena_unwrap_pointer(pointer), data, size); return pointer; } -ArenaErr arena_realloc(Arena *arena, size_t new_capacity) { +ArenaErr arena_realloc(Arena* arena, size_t new_capacity) { if (arena == NULL) { return ARENA_NULL_ARG; } @@ -190,43 +190,36 @@ ArenaErr arena_realloc(Arena *arena, size_t new_capacity) { return ARENA_INVALID_SIZE; } - uint8_t *tmp = realloc(arena->buffer, new_capacity); + uint8_t* tmp = realloc(arena->buffer, new_capacity); if (tmp == NULL) { return ARENA_BAD_ALLOC; } - arena->buffer = tmp; + arena->buffer = tmp; arena->capacity = new_capacity; return ARENA_OK; } - - -ArenaSizeResult arena_get_align_padding(Arena *arena, size_t alignment) { +ArenaSizeResult arena_get_align_padding(Arena* arena, size_t alignment) { if (arena == NULL) { - return (ArenaSizeResult){ .is_valid = false, .err = ARENA_NULL_ARG }; + return (ArenaSizeResult){.is_valid = false, .err = ARENA_NULL_ARG}; } if (alignment == 0 || (alignment & (alignment - 1)) != 0) { - return (ArenaSizeResult){ .is_valid = false, .err = ARENA_INVALID_ALIGN }; + return (ArenaSizeResult){.is_valid = false, .err = ARENA_INVALID_ALIGN}; } uintptr_t current_address = (uintptr_t)(arena->buffer + arena->offset); - size_t mask = alignment - 1; + size_t mask = alignment - 1; size_t padding = (size_t)(-current_address) & mask; - return (ArenaSizeResult){ - .is_valid = true, - .val = padding - }; + return (ArenaSizeResult){.is_valid = true, .val = padding}; } -void *arena_unwrap_pointer(ArenaPointer p) { +void* arena_unwrap_pointer(ArenaPointer p) { if (!p.is_valid) { return NULL; } return p.arena->buffer + p.offset; } - - diff --git a/src/main.c b/src/main.c index 02a75d8..c5bc80b 100644 --- a/src/main.c +++ b/src/main.c @@ -1,4 +1,4 @@ -#include "arena.h" +#include "lae_arena.h" #include int main(void) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index 94b0088..0000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,107 +0,0 @@ -# ================================================================ -# FIND CMOCKA (system → FetchContent as fallback) -# ================================================================ -find_package(cmocka QUIET) - -if(NOT cmocka_FOUND) - message( - STATUS "[arena] cmocka not found on system — fetching with FetchContent...") - - include(FetchContent) - FetchContent_Declare( - cmocka - GIT_REPOSITORY https://git.cryptomilk.org/projects/cmocka.git - GIT_TAG cmocka-1.1.7 - GIT_SHALLOW TRUE) - - # Static lib only, no cmocka examples or self-tests - set(WITH_STATIC_LIB - ON - CACHE BOOL "" FORCE) - set(WITH_SHARED_LIB - OFF - CACHE BOOL "" FORCE) - set(WITH_CMOCKERY_SUPPORT - OFF - CACHE BOOL "" FORCE) - set(WITH_EXAMPLES - OFF - CACHE BOOL "" FORCE) - set(UNIT_TESTING - OFF - CACHE BOOL "" FORCE) - set(PICKY_DEVELOPER - OFF - CACHE BOOL "" FORCE) - - FetchContent_MakeAvailable(cmocka) - - # Normalize the target name (varies across cmocka versions) - if(NOT TARGET cmocka::cmocka) - if(TARGET cmocka-static) - add_library(cmocka::cmocka ALIAS cmocka-static) - elseif(TARGET cmocka) - add_library(cmocka::cmocka ALIAS cmocka) - else() - message( - WARNING - "[arena] Could not create cmocka::cmocka target — skipping tests.") - return() - endif() - endif() -endif() - -# ================================================================ -# DETECT ADDRESS SANITIZER SUPPORT -# ================================================================ -set(ARENA_USE_ASAN OFF) - -if(ARENA_ENABLE_SANITIZERS) - if(MSVC) - if(MSVC_VERSION GREATER_EQUAL 1928) - set(ARENA_USE_ASAN ON) - else() - message(STATUS "[arena] MSVC < 16.9: ASAN not available.") - endif() - elseif(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang" AND NOT WIN32) - include(CheckCCompilerFlag) - check_c_compiler_flag(-fsanitize=address ARENA_COMPILER_HAS_ASAN) - if(ARENA_COMPILER_HAS_ASAN) - set(ARENA_USE_ASAN ON) - else() - message(STATUS "[arena] Compiler does not support -fsanitize=address.") - endif() - else() - message(STATUS "[arena] Unknown platform/compiler — ASAN skipped.") - endif() - - if(ARENA_USE_ASAN) - message(STATUS "[arena] Address Sanitizer enabled.") - endif() -endif() - -# ================================================================ -# TEST EXECUTABLE -# ================================================================ -add_executable(test_arena test_arena.c) - -target_link_libraries(test_arena PRIVATE arena cmocka::cmocka) - -target_compile_features(test_arena PRIVATE c_std_11) - -# Apply ASAN flags per compiler -if(ARENA_USE_ASAN) - if(MSVC) - target_compile_options(test_arena PRIVATE /fsanitize=address) - else() - target_compile_options(test_arena PRIVATE -fsanitize=address - -fno-omit-frame-pointer) - target_link_options(test_arena PRIVATE -fsanitize=address) - endif() -endif() - -# ================================================================ -# CTEST REGISTRATION -# ================================================================ -add_test(NAME arena_tests COMMAND test_arena) -set_tests_properties(arena_tests PROPERTIES TIMEOUT 30) diff --git a/test/test_arena.c b/test/test_arena.c index 756b524..1d86f8b 100644 --- a/test/test_arena.c +++ b/test/test_arena.c @@ -9,7 +9,7 @@ #include #include -#include "arena.h" +#include "lae_arena.h" static void test_push_3_ints(void **state) { (void) state; diff --git a/xmake.lua b/xmake.lua new file mode 100644 index 0000000..0f0c677 --- /dev/null +++ b/xmake.lua @@ -0,0 +1,87 @@ +set_project("lae_arena") +set_version("1.0.0") + +set_languages("c11") + +add_rules("mode.debug", "mode.release") + +-- clang compile commands +add_rules("plugin.compile_commands.autoupdate") + +-- ========================================================= +-- Options +-- ========================================================= + +option("tests") +set_default(false) +set_showmenu(true) +option_end() + +option("example") +set_default(false) +set_showmenu(true) +option_end() + +option("asan") +set_default(false) +set_showmenu(true) +option_end() + +-- ========================================================= +-- Packages +-- ========================================================= + +add_requires("cmocka", { optional = true }) -- For tests + +-- ========================================================= +-- Library +-- ========================================================= + +target("lae_arena") +set_kind("static") + +add_files("src/lae_arena.c") + +add_headerfiles("include/*.h") + +add_includedirs("include", { public = true }) + +if is_mode("debug") then + add_cflags("-Wall", "-Wextra", "-Wpedantic") +end + +-- ========================================================= +-- Example executable +-- ========================================================= + +if has_config("example") then + target("example") + set_kind("binary") + + add_files("src/main.c") + + add_deps("lae_arena") +end + +-- ========================================================= +-- Tests +-- ========================================================= + +if has_config("tests") then + target("test_arena") + set_kind("binary") + + add_files("test/test_arena.c") + + add_deps("lae_arena") + + add_packages("cmocka") + + add_tests("default") + + if has_config("asan") then + add_cflags("-fsanitize=address", "-fno-omit-frame-pointer", { force = true }) + + add_ldflags("-fsanitize=address", { force = true }) + end +end From f3a5ecf807e8565888a4099f17c021fbb2970690 Mon Sep 17 00:00:00 2001 From: laentropia Date: Sat, 6 Jun 2026 09:15:59 -0600 Subject: [PATCH 2/5] refactor: changed to xmake, added lae_allocator dep --- src/lae_arena.c | 47 ++++++++++++++++++++++++----------------------- xmake.lua | 6 ++++++ 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/lae_arena.c b/src/lae_arena.c index 4ea4bbc..559dec2 100644 --- a/src/lae_arena.c +++ b/src/lae_arena.c @@ -1,4 +1,5 @@ #include "lae_arena.h" +#include "lae_allocator.h" #include #include #include @@ -6,12 +7,12 @@ #include struct Arena { - uint8_t* buffer; - size_t capacity; - size_t offset; + uint8_t *buffer; + size_t capacity; + size_t offset; }; -ArenaErr arena_init(Arena** arena, size_t capacity) { +ArenaErr arena_init(Arena **arena, size_t capacity) { if (arena == NULL) { return ARENA_NULL_ARG; } @@ -20,20 +21,20 @@ ArenaErr arena_init(Arena** arena, size_t capacity) { return ARENA_INVALID_SIZE; } - Arena* new_arena = malloc(sizeof(Arena)); + Arena *new_arena = malloc(sizeof(Arena)); if (new_arena == NULL) { return ARENA_BAD_ALLOC; } - void* buffer = malloc(capacity); + void *buffer = malloc(capacity); if (buffer == NULL) { return ARENA_BAD_ALLOC; } *new_arena = (Arena){ - .buffer = buffer, + .buffer = buffer, .capacity = capacity, - .offset = 0, + .offset = 0, }; *arena = new_arena; @@ -41,14 +42,14 @@ ArenaErr arena_init(Arena** arena, size_t capacity) { return ARENA_OK; } -ArenaErr arena_destroy(Arena** arena) { +ArenaErr arena_destroy(Arena **arena) { if (arena == NULL || *arena == NULL) { return ARENA_NULL_ARG; } free((*arena)->buffer); - (*arena)->buffer = NULL; - (*arena)->offset = 0; + (*arena)->buffer = NULL; + (*arena)->offset = 0; (*arena)->capacity = 0; free(*arena); *arena = NULL; @@ -56,7 +57,7 @@ ArenaErr arena_destroy(Arena** arena) { return ARENA_OK; } -ArenaPointer arena_alloc(Arena* arena, size_t size, size_t alignment) { +ArenaPointer arena_alloc(Arena *arena, size_t size, size_t alignment) { if (arena == NULL) { return (ArenaPointer){.is_valid = false, .err = ARENA_NULL_ARG}; } @@ -85,18 +86,18 @@ ArenaPointer arena_alloc(Arena* arena, size_t size, size_t alignment) { if (arena->offset > SIZE_MAX - padding.val - size) { return (ArenaPointer){.is_valid = false, - .err = ARENA_CAPACITY_OVERFLOW}; + .err = ARENA_CAPACITY_OVERFLOW}; } size_t aligned_offset = arena->offset + padding.val; arena->offset = aligned_offset + size; return (ArenaPointer){.is_valid = true, - .offset = aligned_offset, - .arena = arena}; + .offset = aligned_offset, + .arena = arena}; } -ArenaErr arena_ensure_capacity(Arena* arena, size_t size, size_t alignment) { +ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment) { if (arena == NULL) { return ARENA_NULL_ARG; } @@ -153,7 +154,7 @@ ArenaErr arena_ensure_capacity(Arena* arena, size_t size, size_t alignment) { } ArenaPointer -arena_push(Arena* arena, void* data, size_t size, size_t alignment) { +arena_push(Arena *arena, void *data, size_t size, size_t alignment) { if (arena == NULL || data == NULL) { return (ArenaPointer){.is_valid = false, .err = ARENA_NULL_ARG}; } @@ -181,7 +182,7 @@ arena_push(Arena* arena, void* data, size_t size, size_t alignment) { return pointer; } -ArenaErr arena_realloc(Arena* arena, size_t new_capacity) { +ArenaErr arena_realloc(Arena *arena, size_t new_capacity) { if (arena == NULL) { return ARENA_NULL_ARG; } @@ -190,17 +191,17 @@ ArenaErr arena_realloc(Arena* arena, size_t new_capacity) { return ARENA_INVALID_SIZE; } - uint8_t* tmp = realloc(arena->buffer, new_capacity); + uint8_t *tmp = realloc(arena->buffer, new_capacity); if (tmp == NULL) { return ARENA_BAD_ALLOC; } - arena->buffer = tmp; + arena->buffer = tmp; arena->capacity = new_capacity; return ARENA_OK; } -ArenaSizeResult arena_get_align_padding(Arena* arena, size_t alignment) { +ArenaSizeResult arena_get_align_padding(Arena *arena, size_t alignment) { if (arena == NULL) { return (ArenaSizeResult){.is_valid = false, .err = ARENA_NULL_ARG}; } @@ -211,13 +212,13 @@ ArenaSizeResult arena_get_align_padding(Arena* arena, size_t alignment) { uintptr_t current_address = (uintptr_t)(arena->buffer + arena->offset); - size_t mask = alignment - 1; + size_t mask = alignment - 1; size_t padding = (size_t)(-current_address) & mask; return (ArenaSizeResult){.is_valid = true, .val = padding}; } -void* arena_unwrap_pointer(ArenaPointer p) { +void *arena_unwrap_pointer(ArenaPointer p) { if (!p.is_valid) { return NULL; } diff --git a/xmake.lua b/xmake.lua index 0f0c677..67afb3b 100644 --- a/xmake.lua +++ b/xmake.lua @@ -31,7 +31,11 @@ option_end() -- Packages -- ========================================================= +-- Run xmake repo --add lae-repo https://laentropia-homelab.tail7368da.ts.net/laentropia/xmake-repo.git +-- to add my repo :) + add_requires("cmocka", { optional = true }) -- For tests +add_requires("lae_allocator") -- ========================================================= -- Library @@ -40,6 +44,8 @@ add_requires("cmocka", { optional = true }) -- For tests target("lae_arena") set_kind("static") +add_packages("lae_allocator") + add_files("src/lae_arena.c") add_headerfiles("include/*.h") From 2dcef95b2e1b871f615b015eadbb6695596be2fc Mon Sep 17 00:00:00 2001 From: laentropia Date: Sat, 6 Jun 2026 09:48:18 -0600 Subject: [PATCH 3/5] refactor: arena uses Allocator --- include/lae_arena.h | 29 +++++------- src/lae_arena.c | 33 ++++++++----- test/test_arena.c | 111 +++++++++++++++++++++++++------------------- xmake.lua | 11 +++-- 4 files changed, 101 insertions(+), 83 deletions(-) diff --git a/include/lae_arena.h b/include/lae_arena.h index 8a9f786..b9f7bf3 100644 --- a/include/lae_arena.h +++ b/include/lae_arena.h @@ -1,6 +1,7 @@ #ifndef LAE_ARENA_H #define LAE_ARENA_H +#include "lae_allocator.h" #include #include #include @@ -23,7 +24,7 @@ typedef struct { union { ArenaErr err; struct { - Arena* arena; + Arena *arena; size_t offset; }; }; @@ -33,32 +34,24 @@ typedef struct { bool is_valid; union { ArenaErr err; - Arena* arena; - }; -} ArenaResult; - -typedef struct { - bool is_valid; - union { - ArenaErr err; - size_t val; + size_t val; }; } ArenaSizeResult; -ArenaErr arena_init(Arena** arena, size_t capacity); -ArenaErr arena_destroy(Arena** arena); +ArenaErr arena_init(Arena **arena, Allocator allocator, size_t capacity); +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 - arena_push(Arena* arena, void* data, size_t size, size_t alignment); -ArenaErr arena_realloc(Arena* arena, size_t new_capacity); -void* arena_unwrap_pointer(ArenaPointer p); +arena_push_data(Arena *arena, void *data, size_t size, size_t alignment); +ArenaErr arena_resize(Arena *arena, size_t new_capacity); +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, // its protected against SIZE_MAX but anything that // is big may break it, still, is an edge case that // 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 diff --git a/src/lae_arena.c b/src/lae_arena.c index 559dec2..0d08a25 100644 --- a/src/lae_arena.c +++ b/src/lae_arena.c @@ -10,9 +10,11 @@ struct Arena { uint8_t *buffer; size_t capacity; 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) { return ARENA_NULL_ARG; } @@ -21,13 +23,14 @@ ArenaErr arena_init(Arena **arena, size_t capacity) { return ARENA_INVALID_SIZE; } - Arena *new_arena = malloc(sizeof(Arena)); + Arena *new_arena = allocator.alloc(allocator.ctx, sizeof(Arena)); if (new_arena == NULL) { return ARENA_BAD_ALLOC; } - void *buffer = malloc(capacity); + void *buffer = allocator.alloc(allocator.ctx, capacity); if (buffer == NULL) { + allocator.free(allocator.ctx, new_arena, capacity); return ARENA_BAD_ALLOC; } @@ -35,6 +38,7 @@ ArenaErr arena_init(Arena **arena, size_t capacity) { .buffer = buffer, .capacity = capacity, .offset = 0, + .allocator = allocator, }; *arena = new_arena; @@ -47,11 +51,12 @@ ArenaErr arena_destroy(Arena **arena) { return ARENA_NULL_ARG; } - free((*arena)->buffer); - (*arena)->buffer = NULL; - (*arena)->offset = 0; - (*arena)->capacity = 0; - free(*arena); + Arena *tmp = *arena; + tmp->allocator.free(tmp->allocator.ctx, tmp->buffer, tmp->capacity); + tmp->buffer = NULL; + tmp->offset = 0; + tmp->capacity = 0; + tmp->allocator.free(tmp->allocator.ctx, *arena, sizeof(Arena)); *arena = NULL; return ARENA_OK; @@ -146,7 +151,7 @@ ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment) { new_capacity = required; } - ArenaErr err = arena_realloc(arena, new_capacity); + ArenaErr err = arena_resize(arena, new_capacity); if (err != ARENA_OK) { return err; } @@ -154,7 +159,7 @@ ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment) { } 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) { 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; } -ArenaErr arena_realloc(Arena *arena, size_t new_capacity) { +ArenaErr arena_resize(Arena *arena, size_t new_capacity) { if (arena == NULL) { return ARENA_NULL_ARG; } @@ -191,7 +196,11 @@ ArenaErr arena_realloc(Arena *arena, size_t new_capacity) { 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) { return ARENA_BAD_ALLOC; } diff --git a/test/test_arena.c b/test/test_arena.c index 1d86f8b..63e84bb 100644 --- a/test/test_arena.c +++ b/test/test_arena.c @@ -1,90 +1,106 @@ +#include +#include +#include #include -#include #include #include #include #include -#include -#include #include -#include +#include "lae_allocator.h" #include "lae_arena.h" static void test_push_3_ints(void **state) { - (void) state; + (void)state; 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; - 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_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; - 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_int_equal(30, *(int*)arena_unwrap_pointer(result)); + assert_int_equal(30, *(int *)arena_unwrap_pointer(result)); 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_int_equal(40, *(int*)arena_unwrap_pointer(result)); + assert_int_equal(40, *(int *)arena_unwrap_pointer(result)); arena_destroy(&arena); } static void test_push_3_ints_2_doubles(void **state) { - (void) state; + (void)state; Arena *arena; assert_uint_equal( - arena_init(&arena, (sizeof(int) * 3) + (sizeof(double) * 2)), - ARENA_OK - ); + arena_init( + &arena, + allocator_default(), + (sizeof(int) * 3) + (sizeof(double) * 2)), + ARENA_OK); 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_int_equal(20, *(int*)arena_unwrap_pointer(result)); + assert_int_equal(20, *(int *)arena_unwrap_pointer(result)); 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_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; - 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_int_equal(30, *(int*)arena_unwrap_pointer(result)); + assert_int_equal(30, *(int *)arena_unwrap_pointer(result)); 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_int_equal(40, *(int*)arena_unwrap_pointer(result)); + assert_int_equal(40, *(int *)arena_unwrap_pointer(result)); 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_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); } static void test_init_arena_0_cap(void **state) { - (void) state; + (void)state; 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) { - (void) state; + (void)state; 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)); 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) { - (void) state; + (void)state; 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)); 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) { - (void) state; + (void)state; 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); 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) { - (void) state; + (void)state; 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); 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) { - (void) state; + (void)state; 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); 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) { - (void) state; + (void)state; 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)); 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) { - (void) state; + (void)state; 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)); 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) { - (void) state; + (void)state; 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); 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) { - (void) state; + (void)state; 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); assert_int_equal(err, ARENA_INVALID_ALIGN); @@ -209,6 +225,5 @@ int main(void) { cmocka_unit_test(test_arena_ensure_capacity_size_max), }; - return cmocka_run_group_tests(tests, NULL, NULL); } diff --git a/xmake.lua b/xmake.lua index 67afb3b..34b97f0 100644 --- a/xmake.lua +++ b/xmake.lua @@ -44,7 +44,7 @@ add_requires("lae_allocator") target("lae_arena") set_kind("static") -add_packages("lae_allocator") +add_packages("lae_allocator", { public = true }) add_files("src/lae_arena.c") @@ -64,9 +64,10 @@ if has_config("example") then target("example") set_kind("binary") - add_files("src/main.c") - add_deps("lae_arena") + add_packages("lae_allocator") + + add_files("src/main.c") end -- ========================================================= @@ -77,12 +78,12 @@ if has_config("tests") then target("test_arena") set_kind("binary") - add_files("test/test_arena.c") - add_deps("lae_arena") add_packages("cmocka") + add_files("test/test_arena.c") + add_tests("default") if has_config("asan") then From 73dc05bc6309469c365395bf978efa3e0bf87c42 Mon Sep 17 00:00:00 2001 From: laentropia Date: Mon, 8 Jun 2026 19:10:38 -0600 Subject: [PATCH 4/5] addition: allocator generator and functions --- include/lae_arena.h | 11 ++++++++ src/lae_arena.c | 63 ++++++++++++++++++++++++++++++++++++++++----- xmake.lua | 4 +-- 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/include/lae_arena.h b/include/lae_arena.h index b9f7bf3..cd52638 100644 --- a/include/lae_arena.h +++ b/include/lae_arena.h @@ -30,6 +30,15 @@ typedef struct { }; } ArenaPointer; +typedef struct { + bool is_valid; + + union { + ArenaErr err; + Allocator allocator; + }; +} ArenaAllocResult; + typedef struct { bool is_valid; union { @@ -54,4 +63,6 @@ ArenaSizeResult arena_get_align_padding(Arena *arena, size_t alignment); // I shouldn't cover. ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment); +ArenaAllocResult arena_get_allocator(Arena *arena); + #endif // !RENA_H diff --git a/src/lae_arena.c b/src/lae_arena.c index 0d08a25..e8ee80c 100644 --- a/src/lae_arena.c +++ b/src/lae_arena.c @@ -1,5 +1,6 @@ #include "lae_arena.h" #include "lae_allocator.h" +#include #include #include #include @@ -14,6 +15,16 @@ struct Arena { Allocator allocator; }; +static void *arena_allocator_alloc(void *ctx, size_t size, size_t alignment); +static void *arena_allocator_realloc( + void *ctx, + void *pointer, + size_t old_size, + size_t new_size, + size_t alignment); +static void +arena_allocator_free(void *ctx, void *pointer, size_t size, size_t alignment); + ArenaErr arena_init(Arena **arena, Allocator allocator, size_t capacity) { if (arena == NULL) { return ARENA_NULL_ARG; @@ -23,14 +34,15 @@ ArenaErr arena_init(Arena **arena, Allocator allocator, size_t capacity) { return ARENA_INVALID_SIZE; } - Arena *new_arena = allocator.alloc(allocator.ctx, sizeof(Arena)); + Arena *new_arena = + allocator.alloc(allocator.ctx, sizeof(Arena), alignof(Arena)); if (new_arena == NULL) { return ARENA_BAD_ALLOC; } - void *buffer = allocator.alloc(allocator.ctx, capacity); + void *buffer = allocator.alloc(allocator.ctx, capacity, 0); if (buffer == NULL) { - allocator.free(allocator.ctx, new_arena, capacity); + allocator.free(allocator.ctx, new_arena, capacity, 0); return ARENA_BAD_ALLOC; } @@ -52,11 +64,12 @@ ArenaErr arena_destroy(Arena **arena) { } Arena *tmp = *arena; - tmp->allocator.free(tmp->allocator.ctx, tmp->buffer, tmp->capacity); + tmp->allocator.free(tmp->allocator.ctx, tmp->buffer, tmp->capacity, 0); tmp->buffer = NULL; tmp->offset = 0; tmp->capacity = 0; - tmp->allocator.free(tmp->allocator.ctx, *arena, sizeof(Arena)); + tmp->allocator + .free(tmp->allocator.ctx, *arena, sizeof(Arena), alignof(Arena)); *arena = NULL; return ARENA_OK; @@ -200,7 +213,8 @@ ArenaErr arena_resize(Arena *arena, size_t new_capacity) { arena->allocator.ctx, arena->buffer, arena->capacity, - new_capacity); + new_capacity, + 0); if (tmp == NULL) { return ARENA_BAD_ALLOC; } @@ -233,3 +247,40 @@ void *arena_unwrap_pointer(ArenaPointer p) { } return p.arena->buffer + p.offset; } + +static void *arena_allocator_alloc(void *ctx, size_t size, size_t alignment) { + Arena *arena = ctx; + + return arena_unwrap_pointer(arena_alloc(arena, size, alignment)); +} + +static void *arena_allocator_realloc( + void *ctx, + void *pointer, + size_t old_size, + size_t new_size, + size_t alignment) { + return NULL; +} + +static void +arena_allocator_free(void *ctx, void *pointer, size_t size, size_t alignment) { + return; +} + +ArenaAllocResult arena_get_allocator(Arena *arena) { + if (arena == NULL) { + return (ArenaAllocResult){ + .is_valid = false, + .err = ARENA_NULL_ARG, + }; + } + + Allocator allocator = { + .alloc = arena_allocator_alloc, + .realloc = arena_allocator_realloc, + .free = arena_allocator_free, + .ctx = arena}; + + return (ArenaAllocResult){.is_valid = true, .allocator = allocator}; +} diff --git a/xmake.lua b/xmake.lua index 34b97f0..6001592 100644 --- a/xmake.lua +++ b/xmake.lua @@ -78,12 +78,12 @@ if has_config("tests") then target("test_arena") set_kind("binary") + add_files("test/test_arena.c") + add_deps("lae_arena") add_packages("cmocka") - add_files("test/test_arena.c") - add_tests("default") if has_config("asan") then From 0af6a0f10496d7a344f63cb14e365066dc7461b9 Mon Sep 17 00:00:00 2001 From: laentropia Date: Wed, 10 Jun 2026 10:21:43 -0600 Subject: [PATCH 5/5] test/refactor: lock approach taken, best one --- include/lae_arena.h | 8 +++++-- src/lae_arena.c | 33 ++++++++++++++++++++++++--- test/test_arena.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/include/lae_arena.h b/include/lae_arena.h index cd52638..d367551 100644 --- a/include/lae_arena.h +++ b/include/lae_arena.h @@ -17,6 +17,7 @@ typedef enum { ARENA_INVALID_SIZE, ARENA_INVALID_ALIGN, ARENA_CAPACITY_OVERFLOW, + ARENA_LOCKED, } ArenaErr; typedef struct { @@ -37,7 +38,7 @@ typedef struct { ArenaErr err; Allocator allocator; }; -} ArenaAllocResult; +} ArenaAllocator; typedef struct { bool is_valid; @@ -63,6 +64,9 @@ ArenaSizeResult arena_get_align_padding(Arena *arena, size_t alignment); // I shouldn't cover. ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment); -ArenaAllocResult arena_get_allocator(Arena *arena); +ArenaErr arena_lock_growth(Arena *arena); +ArenaErr arena_unlock_growth(Arena *arena); + +ArenaAllocator arena_get_allocator(Arena *arena); #endif // !RENA_H diff --git a/src/lae_arena.c b/src/lae_arena.c index e8ee80c..6214628 100644 --- a/src/lae_arena.c +++ b/src/lae_arena.c @@ -12,6 +12,7 @@ struct Arena { size_t capacity; size_t offset; + bool growth_locked; Allocator allocator; }; @@ -50,6 +51,7 @@ ArenaErr arena_init(Arena **arena, Allocator allocator, size_t capacity) { .buffer = buffer, .capacity = capacity, .offset = 0, + .growth_locked = false, .allocator = allocator, }; @@ -68,6 +70,7 @@ ArenaErr arena_destroy(Arena **arena) { tmp->buffer = NULL; tmp->offset = 0; tmp->capacity = 0; + tmp->growth_locked = false; tmp->allocator .free(tmp->allocator.ctx, *arena, sizeof(Arena), alignof(Arena)); *arena = NULL; @@ -209,6 +212,10 @@ ArenaErr arena_resize(Arena *arena, size_t new_capacity) { return ARENA_INVALID_SIZE; } + if (arena->growth_locked) { + return ARENA_LOCKED; + } + uint8_t *tmp = arena->allocator.realloc( arena->allocator.ctx, arena->buffer, @@ -241,6 +248,24 @@ ArenaSizeResult arena_get_align_padding(Arena *arena, size_t alignment) { return (ArenaSizeResult){.is_valid = true, .val = padding}; } +ArenaErr arena_lock_growth(Arena *arena) { + if (arena == NULL) { + return ARENA_NULL_ARG; + } + + arena->growth_locked = true; + return ARENA_OK; +} + +ArenaErr arena_unlock_growth(Arena *arena) { + if (arena == NULL) { + return ARENA_NULL_ARG; + } + + arena->growth_locked = false; + return ARENA_OK; +} + void *arena_unwrap_pointer(ArenaPointer p) { if (!p.is_valid) { return NULL; @@ -268,19 +293,21 @@ arena_allocator_free(void *ctx, void *pointer, size_t size, size_t alignment) { return; } -ArenaAllocResult arena_get_allocator(Arena *arena) { +ArenaAllocator arena_get_allocator(Arena *arena) { if (arena == NULL) { - return (ArenaAllocResult){ + return (ArenaAllocator){ .is_valid = false, .err = ARENA_NULL_ARG, }; } + arena->growth_locked = true; + Allocator allocator = { .alloc = arena_allocator_alloc, .realloc = arena_allocator_realloc, .free = arena_allocator_free, .ctx = arena}; - return (ArenaAllocResult){.is_valid = true, .allocator = allocator}; + return (ArenaAllocator){.is_valid = true, .allocator = allocator}; } diff --git a/test/test_arena.c b/test/test_arena.c index 63e84bb..18697d6 100644 --- a/test/test_arena.c +++ b/test/test_arena.c @@ -209,6 +209,59 @@ static void test_arena_ensure_capacity_align_max(void **state) { arena_destroy(&arena); } +static void test_arena_allocator_valid_allocation(void **state) { + (void)state; + + Arena *arena; + assert_uint_equal(arena_init(&arena, allocator_default(), 64), ARENA_OK); + + ArenaAllocator result = arena_get_allocator(arena); + assert_true(result.is_valid); + + Allocator arena_allocator = result.allocator; + + int *x = + arena_allocator.alloc(arena_allocator.ctx, sizeof(int), alignof(int)); + + assert_non_null(x); + + *x = 34; + assert_int_equal(*x, 34); + + arena_destroy(&arena); +} + +static void test_arena_allocatro_many_allocations(void **state) { + (void)state; + + Arena *arena; + assert_uint_equal(arena_init(&arena, allocator_default(), 64), ARENA_OK); + + ArenaAllocator result = arena_get_allocator(arena); + assert_true(result.is_valid); + + Allocator arena_allocator = result.allocator; + for (int i = 0; i < 10; i++) { + int *x = arena_allocator.alloc( + arena_allocator.ctx, + sizeof(int), + alignof(int)); + + assert_non_null(x); + } + + arena_destroy(&arena); +} + +static void test_arena_allocator_from_null_arena(void **state) { + (void)state; + + Arena *arena = NULL; + + ArenaAllocator result = arena_get_allocator(arena); + assert_false(result.is_valid); +} + int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_push_3_ints), @@ -223,6 +276,7 @@ int main(void) { cmocka_unit_test(test_arena_ensure_capacity_align_max), cmocka_unit_test(test_arena_ensure_capacity_size_0), cmocka_unit_test(test_arena_ensure_capacity_size_max), + cmocka_unit_test(test_arena_allocator_valid_allocation), }; return cmocka_run_group_tests(tests, NULL, NULL);