From dbe1af7125d09c2184a387a6a4573ea935ab9ff9 Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Mon, 19 May 2025 14:09:07 +0200 Subject: [PATCH] Scratch arena, in-place temporary gebs_fmt() macro --- example/arena.c | 26 +++++++ gebs.c | 4 +- gebs.h | 190 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 207 insertions(+), 13 deletions(-) create mode 100644 example/arena.c diff --git a/example/arena.c b/example/arena.c new file mode 100644 index 0000000..13e1609 --- /dev/null +++ b/example/arena.c @@ -0,0 +1,26 @@ +#define GEBS_IMPLEMENTATION +#include "../gebs.h" + +typedef struct { + int *items; + size_t count, capacity; +} Ints; + +int main(void) +{ + Gebs_Arena *arena = gebs_arena_make(1024); + defer { gebs_arena_destroy(arena); } + + Ints ints = {0}; + defer { gebs_list_free_alloc(arena, &ints); } + for (size_t i = 0; i < 1000; i++) { + gebs_list_append_alloc(arena, &ints, i); + } + for (size_t i = 0; i < ints.count; i++) { + printf("%zu\n", i); + } + + printf("%s\n", gebs_fmt("Hello formatting %d", 124)); + + return 0; +} diff --git a/gebs.c b/gebs.c index 509859f..765fb4b 100644 --- a/gebs.c +++ b/gebs.c @@ -9,7 +9,9 @@ int main(int argc, char ** argv) gebs_mkdir("build"); } - if (GEBS_CMD("gcc", "-o", "build/self_rebuild", "example/self_rebuild.c") != 0) + if (GEBS_CMD("gcc", "-ggdb", "-o", "build/self_rebuild", "example/self_rebuild.c") != 0) + return 1; + if (GEBS_CMD("gcc", "-ggdb", "-o", "build/arena", "example/arena.c") != 0) return 1; return 0; diff --git a/gebs.h b/gebs.h index 82c8a7d..ec1bf91 100644 --- a/gebs.h +++ b/gebs.h @@ -62,22 +62,48 @@ // ---------------------------------------------------------------------------- typedef struct { - void *(*malloc)(size_t size); - void (*free)(void *memory); - void *(*realloc)(void *memory, size_t prev_size, size_t new_size); + void *(*malloc)(void *self, size_t size); + void (*free)(void *self, void *memory); + void *(*realloc)(void *self, void *memory, size_t prev_size, size_t new_size); } Gebs_Allocator; // Wrapper macros -#define gebs_malloc(alloc, size) ((alloc)->malloc((size))) -#define gebs_free(alloc, memory) ((alloc)->free((memory))) +#define gebs_malloc(alloc, size) ((alloc)->malloc((void *)(alloc), (size))) +#define gebs_free(alloc, memory) ((alloc)->free((void *)(alloc), (memory))) #define gebs_realloc(alloc, memory, prev_size, new_size) \ - ((alloc)->realloc((memory), (prev_size), (new_size))) + ((alloc)->realloc((void *)(alloc), (memory), (prev_size), (new_size))) extern Gebs_Allocator gebs_default_allocator; -void *gebs_default_allocator_malloc(size_t size); -void gebs_default_allocator_free(void *memory); -void *gebs_default_allocator_realloc(void *memory, size_t prev_size, size_t new_size); +void *gebs_default_allocator_malloc(void *self, size_t size); +void gebs_default_allocator_free(void *self, void *memory); +void *gebs_default_allocator_realloc(void *self, void *memory, + size_t prev_size, size_t new_size); + +typedef struct Gebs_Arena_Allocation { + size_t index; + size_t size; + char *ptr; + struct Gebs_Arena_Allocation *next; +} Gebs_Arena_Allocation; + +typedef struct { + void *(*malloc)(void *self, size_t size); + void (*free)(void *self, void *memory); + void *(*realloc)(void *self, void *memory, size_t prev_size, size_t new_size); + + char *region; + size_t index; + size_t size; +} Gebs_Arena; + +void gebs_arena_reset(Gebs_Arena *a); +void gebs_arena_destroy(Gebs_Arena *a); +Gebs_Arena *gebs_arena_make(size_t size); +Gebs_Arena *gebs_arena_expand(Gebs_Arena *a, size_t new_size); +void *gebs_arena_malloc(void *self, size_t size); +void gebs_arena_free(void *self, void *memory); +void *gebs_arena_realloc(void *self, void *memory, size_t prev_size, size_t new_size); // ---------------------------------------------------------------------------- // Dynamic list @@ -210,6 +236,24 @@ void gebs_rebuild_self1_alloc(Gebs_Allocator *alloc, int argc, char ** argv, sizeof(__argv)/sizeof(__argv[0]), (char**)__argv, __FILE__); \ } while(0) +// ---------------------------------------------------------------------------- +// Scratch arena +// ---------------------------------------------------------------------------- + +#ifndef GEBS_SCRATCH_ARENA_SIZE +# define GEBS_SCRATCH_ARENA_SIZE 4096 +#endif + +extern Gebs_Arena *gebs_scratch_arena; + +#define gebs_fmt(fmt, ...) \ +({ \ + size_t __size = snprintf(NULL, 0, (fmt), ##__VA_ARGS__); \ + char *__buf = gebs_malloc(gebs_scratch_arena, __size+1); \ + sprintf(__buf, (fmt), ##__VA_ARGS__); \ + __buf; \ +}) + #ifdef GEBS_IMPLEMENTATION // ---------------------------------------------------------------------------- @@ -273,22 +317,144 @@ Gebs_Allocator gebs_default_allocator = { .realloc = &gebs_default_allocator_realloc, }; -void *gebs_default_allocator_malloc(size_t size) +void *gebs_default_allocator_malloc(void *self, size_t size) { + (void)self; return malloc(size); } -void gebs_default_allocator_free(void *memory) +void gebs_default_allocator_free(void *self, void *memory) { + (void)self; free(memory); } -void *gebs_default_allocator_realloc(void *memory, size_t prev_size, size_t new_size) +void *gebs_default_allocator_realloc(void *self, void *memory, + size_t prev_size, size_t new_size) { + (void)self; void *p = realloc(memory, new_size); return p; } +Gebs_Arena *gebs_arena_make(size_t size) +{ + Gebs_Arena *a; + if (size == 0) { + return NULL; + } + + a = malloc(sizeof(*a)); + if (a == NULL) { + return NULL; + } + + a->malloc = &gebs_arena_malloc; + a->free = &gebs_arena_free; + a->realloc = &gebs_arena_realloc; + + a->region = malloc(size); + if (a->region == NULL) { + free(a); + return NULL; + } + + a->index = 0; + a->size = size; + return a; +} + +Gebs_Arena *gebs_arena_expand(Gebs_Arena *a, size_t new_size) +{ + if (a == NULL || new_size <= a->size) { + return NULL; + } + + a->region = realloc(a->region, new_size); + if (a->region == NULL) { + return NULL; + } + + a->size = new_size; + return a; +} + +void *gebs_arena_malloc(void *self, size_t size) +{ + Gebs_Arena *a = (Gebs_Arena *)self; + unsigned int offset; + + if (size == 0) { + return NULL; + } + + if (a == NULL || a->region == NULL) { + return NULL; + } + + offset = 0; + if (a->size - (a->index + offset) < size) { + return NULL; + } + + a->index += size; + return a->region + (a->index - size); +} + +void gebs_arena_free(void *self, void *memory) +{ + (void)self; + (void)memory; +} + +void *gebs_arena_realloc(void *self, void *memory, size_t prev_size, size_t new_size) +{ + (void)prev_size; + (void)memory; + gebs_arena_expand((Gebs_Arena *)self, new_size); + return memory; +} + +void gebs_arena_reset(Gebs_Arena *a) +{ + if (a == NULL) { + return; + } + + a->index = 0; +} + +void gebs_arena_destroy(Gebs_Arena *a) +{ + if (a == NULL) { + return; + } + + if (a->region != NULL) { + free(a->region); + } + + free(a); +} + +// ---------------------------------------------------------------------------- +// Scratch arena +// ---------------------------------------------------------------------------- + +Gebs_Arena *gebs_scratch_arena; + +__attribute__((constructor)) +void gebs_scratch_areana_init(void) +{ + gebs_scratch_arena = gebs_arena_make(GEBS_SCRATCH_ARENA_SIZE); +} + +__attribute__((destructor)) +void gebs_scratch_areana_free(void) +{ + gebs_arena_destroy(gebs_scratch_arena); +} + // ---------------------------------------------------------------------------- // Filesystem operations // ----------------------------------------------------------------------------