From 648504907c9f62adc72628ae73a8c668ec1276c8 Mon Sep 17 00:00:00 2001 From: iamcheeseman Date: Fri, 29 May 2026 22:28:43 -0400 Subject: Generic arena allocator Also replaces the temp allocator behind the scenes --- teensy/teensy_mem.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++------- teensy/teensy_mem.h | 28 ++++++++++++++++- 2 files changed, 103 insertions(+), 11 deletions(-) (limited to 'teensy') diff --git a/teensy/teensy_mem.c b/teensy/teensy_mem.c index d32cabf..cea24cb 100644 --- a/teensy/teensy_mem.c +++ b/teensy/teensy_mem.c @@ -1,26 +1,92 @@ #include "teensy_mem.h" +#include + #include "teensy_common.h" #include "teensy_list.h" -#define TEMP_ALLOC_ARENA_SIZE (1024*1024) +#define ARENA_DEFAULT_HUNK_SIZE (1<<16) // ~65KB -uint8_t temp_arena[TEMP_ALLOC_ARENA_SIZE]; -uint8_t *next_temp_alloc = temp_arena; +Arena temp_arena; -void *ty_talloc(size_t size) +static +Arena_Hunk *create_new_hunk(size_t hunk_size) +{ + Arena_Hunk *hunk = ty_new(Arena_Hunk); + memset(hunk, 0, sizeof(Arena_Hunk)); + + hunk->start = ty_alloc(hunk_size); + hunk->end = hunk->start + hunk_size; + hunk->head = hunk->start; + + return hunk; +} + +void *ty_arena_alloc(Arena *arena, size_t size) { - if (next_temp_alloc > temp_arena + TEMP_ALLOC_ARENA_SIZE) - ty_log_fatal(TY_ERR_MEM, "bump up the temp alloc arena size"); + Arena_Hunk *hunk = arena->hunks; + while (hunk) { + if (hunk->head + size < hunk->end) + break; + hunk = hunk->next; + } + + if (!hunk) { + // I like these lines + arena->hunk_size = arena->hunk_size + ? arena->hunk_size : ARENA_DEFAULT_HUNK_SIZE; + + hunk = create_new_hunk(arena->hunk_size); + hunk = create_new_hunk(arena->hunk_size); + hunk->next = arena->hunks; + arena->hunks = hunk; + } + + void *ptr = hunk->head; + memset(ptr, 0, size); + + hunk->head += size; + arena->alloced_size += size; - void *ptr = next_temp_alloc; - next_temp_alloc += size; return ptr; } -void ty_free_temp_allocs(void) +void ty_arena_clear(Arena *arena) +{ + Arena_Hunk *hunk = arena->hunks; + while (hunk) { + hunk->head = hunk->start; + hunk = hunk->next; + } + + arena->alloced_size = 0; +} + +void ty_arena_free(Arena *arena) +{ + Arena_Hunk *hunk = arena->hunks; + while (hunk) { + Arena_Hunk *next = hunk->next; + + ty_free(hunk->start); + ty_free(hunk); + + hunk = next; + } + + arena->hunks = NULL; + arena->alloced_size = 0; +} + +void *ty_talloc(size_t size) +{ + return ty_arena_alloc(&temp_arena, size); +} + +void ty_clear_temp_allocs(void) { - next_temp_alloc = temp_arena; + ty_log_debug("%zu/%zu", temp_arena.alloced_size, temp_arena.hunk_size); + ty_arena_clear(&temp_arena); } void *ty_alloc(size_t size) diff --git a/teensy/teensy_mem.h b/teensy/teensy_mem.h index 133869f..b4cdc62 100644 --- a/teensy/teensy_mem.h +++ b/teensy/teensy_mem.h @@ -1,11 +1,37 @@ #ifndef TEENSY_MEM_H_ #define TEENSY_MEM_H_ +#include #include #define ty_new(T) (ty_alloc(sizeof(T))) -void ty_free_temp_allocs(void); +// A specific section of memory allocated for an arena. +typedef struct Arena_Hunk Arena_Hunk; +struct Arena_Hunk { + Arena_Hunk *next; + uint8_t *start; + uint8_t *end; + uint8_t *head; +}; + +// Memory arena. It allows the user of this API to allocate lots of memory and +// free it all at once. Arenas do not support reallocation. +typedef struct { + Arena_Hunk *hunks; + size_t hunk_size; + size_t alloced_size; +} Arena; + +// Makes an allocation with the speicified arena. +void *ty_arena_alloc(Arena *arena, size_t size); +// Frees all allocations made with this arena. +void ty_arena_clear(Arena *arena); +// Frees the arena itself. Do NOT call to free allocations made with the arena. +// Use `ty_arena_clear()` for that. +void ty_arena_free(Arena *arena); + +void ty_clear_temp_allocs(void); // Temp allocation. Freed at the end of every frame. Do NOT realloc. void *ty_talloc(size_t size); -- cgit v1.3-2-g0d8e