Compare commits

17 Commits

Author SHA1 Message Date
229ea200cd Merge pull request 'refactor-xmake' (#2) from refactor-xmake into main
Reviewed-on: #2
2026-06-10 10:30:25 -06:00
0af6a0f104 test/refactor: lock approach taken, best one 2026-06-10 10:21:43 -06:00
73dc05bc63 addition: allocator generator and functions 2026-06-08 19:10:38 -06:00
2dcef95b2e refactor: arena uses Allocator 2026-06-06 09:48:18 -06:00
f3a5ecf807 refactor: changed to xmake, added lae_allocator dep 2026-06-06 09:15:59 -06:00
203b60cf65 refactor: xmake is now in use 2026-05-26 13:52:28 -06:00
78640a3288 fix: formatting 2026-05-26 13:11:10 -06:00
ff97f5fc2f Change cmakelists 2026-05-20 18:53:21 -06:00
a91123b71a Fix for test construction 2026-05-20 17:00:02 -06:00
b2bbb85fcc Merge pull request 'refactor-consistency' (#1) from refactor-consistency into main
Reviewed-on: #1
2026-05-13 20:32:20 -06:00
fb832eab06 refactor: tests adapted and succesfully passed 2026-05-13 20:25:55 -06:00
6c91e1f681 refactor: init and destroy, alloc now first ensures cap
its better usability and is better that it ensures capacity in alloc
like that is what is supposed to be like damn, why i did it like that
2026-05-13 20:10:40 -06:00
f981ba92a8 refactor: Arena is opaque, init returns error code
Is to make it more consistent, i need to change also later arraylist the
init function so its also more consistent, next is making alloc ensure
capacity first so no using it first or some shit.
2026-05-13 19:57:49 -06:00
7c7c68381c Update test/CMakeLists.txt 2026-04-23 12:09:34 -06:00
7af0ca7556 Update CMakeLists.txt 2026-04-23 12:09:07 -06:00
945aa9a27f better compatility cmake 2026-04-23 12:00:35 -06:00
8ebaf06d11 changed project name 2026-04-23 11:58:59 -06:00
9 changed files with 575 additions and 354 deletions

6
.gitignore vendored
View File

@@ -7,6 +7,12 @@ out/
out/Debug/
out/Release/
# xmake
xmake/
xmake/*
.xmake
.xmake/*
# Cmake files
CMakeCache.txt
CMakeFiles/

View File

@@ -1,39 +0,0 @@
cmake_minimum_required(VERSION 3.20)
project(calculator VERSION 1.0 LANGUAGES C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Export compile_commands.json (para clangd)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_compile_options(
-Wall
-Wextra
-Wpedantic
)
include_directories(include)
add_library(arena_lib
src/arena.c
)
add_executable(arena_main src/main.c)
target_link_libraries(arena_main arena_lib)
function(enable_sanitizers target)
target_compile_options(${target} PRIVATE -fsanitize=address -fno-omit-frame-pointer)
target_link_options(${target} PRIVATE -fsanitize=address)
endfunction()
# ------------------------
# Testing
# ------------------------
enable_testing()
add_subdirectory(test)

View File

@@ -1,16 +1,13 @@
#ifndef ARENA_H
#define ARENA_H
#ifndef LAE_ARENA_H
#define LAE_ARENA_H
#include <stdint.h>
#include <stdlib.h>
#include "lae_allocator.h"
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct {
uint8_t *buffer;
size_t capacity;
size_t offset;
} Arena;
typedef struct Arena Arena;
typedef enum {
ARENA_OK = 0,
@@ -20,6 +17,7 @@ typedef enum {
ARENA_INVALID_SIZE,
ARENA_INVALID_ALIGN,
ARENA_CAPACITY_OVERFLOW,
ARENA_LOCKED,
} ArenaErr;
typedef struct {
@@ -35,11 +33,12 @@ typedef struct {
typedef struct {
bool is_valid;
union {
ArenaErr err;
Arena arena;
Allocator allocator;
};
} ArenaResult;
} ArenaAllocator;
typedef struct {
bool is_valid;
@@ -49,12 +48,13 @@ typedef struct {
};
} ArenaSizeResult;
ArenaResult arena_init(size_t capacity);
void 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_push(Arena *arena, void *data, size_t size, size_t alignment);
ArenaErr arena_realloc(Arena *arena, size_t new_capacity);
ArenaPointer
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);
@@ -64,4 +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);
#endif // !ARENA_H
ArenaErr arena_lock_growth(Arena *arena);
ArenaErr arena_unlock_growth(Arena *arena);
ArenaAllocator arena_get_allocator(Arena *arena);
#endif // !RENA_H

View File

@@ -1,203 +0,0 @@
#include "arena.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
ArenaResult arena_init(size_t capacity) {
if (capacity < 1) {
return (ArenaResult) {.is_valid = false, .err = ARENA_INVALID_SIZE};
}
void *buffer = malloc(capacity);
if (buffer == NULL) {
return (ArenaResult) {.is_valid = false, .err = ARENA_BAD_ALLOC};
}
Arena new_arena = {
.buffer = buffer,
.capacity = capacity,
.offset = 0,
};
return (ArenaResult) {.is_valid = true, .arena = new_arena};
}
void arena_destroy(Arena *arena) {
free(arena->buffer);
arena->buffer = NULL;
arena->offset = 0;
arena->capacity = 0;
}
ArenaPointer arena_alloc(Arena *arena, size_t size, size_t alignment) {
if (arena == NULL) {
return (ArenaPointer) {.is_valid = false, .err = ARENA_NULL_ARG};
}
if (size < 1) {
return (ArenaPointer) {.is_valid = false, .err = ARENA_INVALID_SIZE};
}
if (alignment < 1) {
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};
}
if (arena->offset + padding.val + size > arena->capacity) {
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};
}
size_t aligned_offset = arena->offset + padding.val;
arena->offset = aligned_offset + size;
return (ArenaPointer) {.is_valid = true, .offset = aligned_offset, .arena = arena};
}
ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment) {
if (arena == NULL) {
return ARENA_NULL_ARG;
}
if (size == 0 || size == SIZE_MAX) {
return ARENA_INVALID_SIZE;
}
if (alignment == 0 || (alignment & (alignment - 1)) != 0) {
return ARENA_INVALID_ALIGN;
}
ArenaSizeResult padding_res = arena_get_align_padding(arena, alignment);
if (!padding_res.is_valid) {
return padding_res.err;
}
size_t padding = padding_res.val;
while (true) {
size_t required;
if (arena->offset > SIZE_MAX - padding) {
return ARENA_CAPACITY_OVERFLOW;
}
required = arena->offset + padding;
if (required > SIZE_MAX - size) {
return ARENA_CAPACITY_OVERFLOW;
}
required += size;
if (required <= arena->capacity) {
return ARENA_OK;
}
size_t new_capacity;
if (arena->capacity > SIZE_MAX / 2) {
return ARENA_CAPACITY_OVERFLOW;
}
new_capacity = arena->capacity * 2;
if (new_capacity < required) {
new_capacity = required;
}
ArenaErr err = arena_realloc(arena, new_capacity);
if (err != ARENA_OK) {
return err;
}
}
}
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};
}
if (size < 1) {
return (ArenaPointer) {.is_valid = false, .err = ARENA_INVALID_SIZE};
}
if (size < 1) {
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};
}
ArenaPointer pointer = arena_alloc(arena, size, alignment);
if (!pointer.is_valid) {
return pointer;
}
memcpy(
arena_unwrap_pointer(pointer),
data,
size);
return pointer;
}
ArenaErr arena_realloc(Arena *arena, size_t new_capacity) {
if (arena == NULL) {
return ARENA_NULL_ARG;
}
if (new_capacity < 1) {
return ARENA_INVALID_SIZE;
}
uint8_t *tmp = realloc(arena->buffer, new_capacity);
if (tmp == NULL) {
return ARENA_BAD_ALLOC;
}
arena->buffer = tmp;
arena->capacity = new_capacity;
return ARENA_OK;
}
ArenaSizeResult arena_get_align_padding(Arena *arena, size_t alignment) {
if (arena == NULL) {
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 };
}
uintptr_t current_address = (uintptr_t)(arena->buffer + arena->offset);
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) {
if (!p.is_valid) {
return NULL;
}
return p.arena->buffer + p.offset;
}

313
src/lae_arena.c Normal file
View File

@@ -0,0 +1,313 @@
#include "lae_arena.h"
#include "lae_allocator.h"
#include <stdalign.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
struct Arena {
uint8_t *buffer;
size_t capacity;
size_t offset;
bool growth_locked;
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;
}
if (capacity < 1) {
return ARENA_INVALID_SIZE;
}
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, 0);
if (buffer == NULL) {
allocator.free(allocator.ctx, new_arena, capacity, 0);
return ARENA_BAD_ALLOC;
}
*new_arena = (Arena){
.buffer = buffer,
.capacity = capacity,
.offset = 0,
.growth_locked = false,
.allocator = allocator,
};
*arena = new_arena;
return ARENA_OK;
}
ArenaErr arena_destroy(Arena **arena) {
if (arena == NULL || *arena == NULL) {
return ARENA_NULL_ARG;
}
Arena *tmp = *arena;
tmp->allocator.free(tmp->allocator.ctx, tmp->buffer, tmp->capacity, 0);
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;
return ARENA_OK;
}
ArenaPointer arena_alloc(Arena *arena, size_t size, size_t alignment) {
if (arena == NULL) {
return (ArenaPointer){.is_valid = false, .err = ARENA_NULL_ARG};
}
if (size < 1) {
return (ArenaPointer){.is_valid = false, .err = ARENA_INVALID_SIZE};
}
if (alignment < 1) {
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};
}
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 (arena->offset + padding.val + size > arena->capacity) {
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};
}
size_t aligned_offset = arena->offset + padding.val;
arena->offset = aligned_offset + size;
return (ArenaPointer){.is_valid = true,
.offset = aligned_offset,
.arena = arena};
}
ArenaErr arena_ensure_capacity(Arena *arena, size_t size, size_t alignment) {
if (arena == NULL) {
return ARENA_NULL_ARG;
}
if (size == 0 || size == SIZE_MAX) {
return ARENA_INVALID_SIZE;
}
if (alignment == 0 || (alignment & (alignment - 1)) != 0) {
return ARENA_INVALID_ALIGN;
}
ArenaSizeResult padding_res = arena_get_align_padding(arena, alignment);
if (!padding_res.is_valid) {
return padding_res.err;
}
size_t padding = padding_res.val;
while (true) {
size_t required;
if (arena->offset > SIZE_MAX - padding) {
return ARENA_CAPACITY_OVERFLOW;
}
required = arena->offset + padding;
if (required > SIZE_MAX - size) {
return ARENA_CAPACITY_OVERFLOW;
}
required += size;
if (required <= arena->capacity) {
return ARENA_OK;
}
size_t new_capacity;
if (arena->capacity > SIZE_MAX / 2) {
return ARENA_CAPACITY_OVERFLOW;
}
new_capacity = arena->capacity * 2;
if (new_capacity < required) {
new_capacity = required;
}
ArenaErr err = arena_resize(arena, new_capacity);
if (err != ARENA_OK) {
return err;
}
}
}
ArenaPointer
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};
}
if (size < 1) {
return (ArenaPointer){.is_valid = false, .err = ARENA_INVALID_SIZE};
}
if (size < 1) {
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};
}
ArenaPointer pointer = arena_alloc(arena, size, alignment);
if (!pointer.is_valid) {
return pointer;
}
memcpy(arena_unwrap_pointer(pointer), data, size);
return pointer;
}
ArenaErr arena_resize(Arena *arena, size_t new_capacity) {
if (arena == NULL) {
return ARENA_NULL_ARG;
}
if (new_capacity < 1) {
return ARENA_INVALID_SIZE;
}
if (arena->growth_locked) {
return ARENA_LOCKED;
}
uint8_t *tmp = arena->allocator.realloc(
arena->allocator.ctx,
arena->buffer,
arena->capacity,
new_capacity,
0);
if (tmp == NULL) {
return ARENA_BAD_ALLOC;
}
arena->buffer = tmp;
arena->capacity = new_capacity;
return ARENA_OK;
}
ArenaSizeResult arena_get_align_padding(Arena *arena, size_t alignment) {
if (arena == NULL) {
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};
}
uintptr_t current_address = (uintptr_t)(arena->buffer + arena->offset);
size_t mask = alignment - 1;
size_t padding = (size_t)(-current_address) & mask;
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;
}
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;
}
ArenaAllocator arena_get_allocator(Arena *arena) {
if (arena == NULL) {
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 (ArenaAllocator){.is_valid = true, .allocator = allocator};
}

View File

@@ -1,4 +1,4 @@
#include "arena.h"
#include "lae_arena.h"
#include <stdlib.h>
int main(void) {

View File

@@ -1,15 +0,0 @@
find_package(cmocka REQUIRED)
add_executable(test_arena test_arena.c)
target_link_libraries(test_arena
arena_lib
cmocka::cmocka
)
enable_sanitizers(test_arena)
target_compile_options(test_arena PRIVATE -fsanitize=address -fno-omit-frame-pointer)
target_link_options(test_arena PRIVATE -fsanitize=address)
add_test(NAME arena_tests COMMAND test_arena)

View File

@@ -1,93 +1,108 @@
#include <cmocka.h>
#include <limits.h>
#include <setjmp.h>
#include <stdalign.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <setjmp.h>
#include <cmocka.h>
#include <string.h>
#include <limits.h>
#include "arena.h"
#include "lae_allocator.h"
#include "lae_arena.h"
static void test_push_3_ints(void **state) {
(void) state;
(void)state;
ArenaResult value = arena_init(sizeof(int) * 3);
assert_true(value.is_valid);
Arena arena = value.arena;
Arena *arena;
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;
ArenaResult value = arena_init((sizeof(int) * 3) + (sizeof(double) * 2));
assert_true(value.is_valid);
Arena arena = value.arena;
Arena *arena;
assert_uint_equal(
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;
ArenaResult arena = arena_init(0);
assert_false(arena.is_valid);
assert_int_equal(arena.err, ARENA_INVALID_SIZE);
Arena *arena;
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;
ArenaResult value = arena_init(64);
assert_true(value.is_valid);
Arena arena = value.arena;
Arena *arena;
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_int_equal(pointer.err, ARENA_INVALID_SIZE);
@@ -95,13 +110,12 @@ static void test_arena_alloc_size_0(void **state) {
}
static void test_arena_alloc_size_max(void **state) {
(void) state;
(void)state;
ArenaResult value = arena_init(64);
assert_true(value.is_valid);
Arena arena = value.arena;
Arena *arena;
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_int_equal(pointer.err, ARENA_OUT_OF_SPACE);
@@ -109,13 +123,12 @@ static void test_arena_alloc_size_max(void **state) {
}
static void test_arena_alloc_align_0(void **state) {
(void) state;
(void)state;
ArenaResult value = arena_init(64);
assert_true(value.is_valid);
Arena arena = value.arena;
Arena *arena;
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_int_equal(pointer.err, ARENA_INVALID_ALIGN);
@@ -123,13 +136,12 @@ static void test_arena_alloc_align_0(void **state) {
}
static void test_arena_alloc_align_max(void **state) {
(void) state;
(void)state;
ArenaResult value = arena_init(64);
assert_true(value.is_valid);
Arena arena = value.arena;
Arena *arena;
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_int_equal(pointer.err, ARENA_INVALID_ALIGN);
@@ -137,13 +149,12 @@ static void test_arena_alloc_align_max(void **state) {
}
static void test_arena_align_size_0(void **state) {
(void) state;
(void)state;
ArenaResult value = arena_init(64);
assert_true(value.is_valid);
Arena arena = value.arena;
Arena *arena;
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_int_equal(pointer.err, ARENA_INVALID_ALIGN);
@@ -151,57 +162,106 @@ static void test_arena_align_size_0(void **state) {
}
static void test_arena_ensure_capacity_size_0(void **state) {
(void) state;
(void)state;
ArenaResult value = arena_init(64);
assert_true(value.is_valid);
Arena arena = value.arena;
Arena *arena;
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);
arena_destroy(&arena);
}
static void test_arena_ensure_capacity_size_max(void **state) {
(void) state;
(void)state;
ArenaResult value = arena_init(64);
assert_true(value.is_valid);
Arena arena = value.arena;
Arena *arena;
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);
arena_destroy(&arena);
}
static void test_arena_ensure_capacity_align_0(void **state) {
(void) state;
(void)state;
ArenaResult value = arena_init(64);
assert_true(value.is_valid);
Arena arena = value.arena;
Arena *arena;
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);
arena_destroy(&arena);
}
static void test_arena_ensure_capacity_align_max(void **state) {
(void) state;
(void)state;
ArenaResult value = arena_init(64);
assert_true(value.is_valid);
Arena arena = value.arena;
Arena *arena;
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);
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),
@@ -216,8 +276,8 @@ 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);
}

94
xmake.lua Normal file
View File

@@ -0,0 +1,94 @@
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
-- =========================================================
-- 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
-- =========================================================
target("lae_arena")
set_kind("static")
add_packages("lae_allocator", { public = true })
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_deps("lae_arena")
add_packages("lae_allocator")
add_files("src/main.c")
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