diff --git a/include/arena.h b/include/arena.h index 18a9470..b55c4c1 100644 --- a/include/arena.h +++ b/include/arena.h @@ -36,6 +36,14 @@ typedef struct { }; } ArenaResult; +typedef struct { + bool is_valid; + union { + ArenaErr err; + size_t val; + }; +} SizeResult; + ArenaResult arena_init(size_t size); void arena_destroy(Arena *arena); @@ -43,6 +51,7 @@ ArenaPointer arena_alloc(Arena *arena, size_t size, size_t alignment); ArenaErr arena_push(Arena *arena, void *data, size_t size, size_t alignment); ArenaErr arena_realloc(Arena *arena, size_t new_size); -size_t align_arena_offset(Arena *arena, size_t alignment); +SizeResult align_arena_offset(Arena *arena, size_t alignment); +SizeResult arena_compute_necessary_capacity(size_t capacity, size_t elem_size); #endif // !ARENA_H diff --git a/src/arena.c b/src/arena.c index f084b39..4022d62 100644 --- a/src/arena.c +++ b/src/arena.c @@ -55,8 +55,16 @@ ArenaPointer arena_alloc(Arena *arena, size_t size, size_t alignment) { return err; } - size_t new_offset = align_arena_offset(arena, alignment); - if (new_offset + size >= arena->size) { + SizeResult new_offset = align_arena_offset(arena, alignment); + if (!new_offset.is_valid) { + ArenaPointer err = { + .is_valid = false, + .err = new_offset.err, + }; + return err; + } + + if (new_offset.val + size >= arena->size) { ArenaPointer err = { .is_valid = false, .err = ARENA_OUT_OF_SPACE, @@ -64,7 +72,7 @@ ArenaPointer arena_alloc(Arena *arena, size_t size, size_t alignment) { return err; } - arena->offset = new_offset; + arena->offset = new_offset.val; ArenaPointer val = { .is_valid = true, @@ -81,13 +89,18 @@ ArenaErr arena_push(Arena *arena, void *data, size_t size, size_t alignment) { ArenaPointer pointer = arena_alloc(arena, size, alignment); if (!pointer.is_valid) { - size_t new_size = arena->size * 2; - ArenaErr err = arena_realloc(arena, new_size); + SizeResult new_size = arena_compute_necessary_capacity(arena->size, size); + if (!new_size.is_valid) { + return new_size.err; + } + + ArenaErr err = arena_realloc(arena, new_size.val); if (err != ARENA_OK) { return err; } - } + pointer = arena_alloc(arena, size, alignment); + } memcpy( pointer.address, @@ -111,3 +124,5 @@ ArenaErr arena_realloc(Arena *arena, size_t new_size) { arena->size = new_size; return ARENA_OK; } + +