diff options
| author | 2026-01-06 03:27:12 -0600 | |
|---|---|---|
| committer | 2026-01-06 03:27:12 -0600 | |
| commit | 4cf8b35097a131abcfc8e0d04d35294be13943ac (patch) | |
| tree | bb384a58c53d7b4ab9faf45e84677ae5cdb42ac1 /lib/arena.c | |
initial commit
Diffstat (limited to 'lib/arena.c')
| -rw-r--r-- | lib/arena.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/lib/arena.c b/lib/arena.c new file mode 100644 index 0000000..bea98ef --- /dev/null +++ b/lib/arena.c @@ -0,0 +1,107 @@ +#include "arena.h" +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <stdio.h> + +#ifdef ARENA_ASAN_INSTRUMENT +#include <sanitizer/asan_interface.h> + +#define ASAN_POISON(...) __asan_poison_memory_region(__VA_ARGS__) +#define ASAN_UNPOISON(...) __asan_unpoison_memory_region(__VA_ARGS__) +#else +#define ASAN_POISON(...) +#define ASAN_UNPOISON(...) +#endif + +struct vl__arena_tag { + size_t cap; /* number of bytes after the end of this struct we can use */ + size_t cur; +}; + +#define ARENA_ALIGN (size_t)((1 << 6) - 1) +#define ROUND_UP(_am) (((_am) + ARENA_ALIGN) & ~ARENA_ALIGN) + +static void *arena_addr(void *a, size_t len) +{ + return (void *)((uintptr_t)a + ROUND_UP(sizeof(vl_arena)) + len); +} + +/* returns NULL if an arena could not be allocated */ +vl_arena *vl_arena_new(size_t cap) +{ + cap = ROUND_UP(cap); + + vl_arena *arena = calloc(1, ROUND_UP(sizeof(vl_arena)) + cap); + if (!arena) return NULL; + + arena->cap = cap; + arena->cur = 0; + + ASAN_POISON(arena + 1, cap + (ROUND_UP(sizeof(vl_arena)) - sizeof(vl_arena))); + + return arena; +} + +/* aborts if the arena is overflowing */ +void *vl_arena_push(vl_arena *parena, size_t len) +{ + size_t rlen = ROUND_UP(len); + if (parena->cur + rlen > parena->cap) abort(); + + void *ret = arena_addr(parena, parena->cur); + parena->cur += rlen; + + ASAN_UNPOISON(ret, len); + return ret; +} + +/* resets the arena (but does not free it) */ +void vl_arena_reset(vl_arena *parena) +{ + parena->cur = 0; + ASAN_POISON(arena_addr(parena, 0), parena->cap); +} + +/* frees the arena */ +void vl_arena_free(vl_arena *parena) +{ + free(parena); +} + +char *vl_arena_strdup(vl_arena *parena, const char *str) +{ + size_t len = strlen(str); + void *out = vl_arena_push(parena, len + 1); + memcpy(out, str, len + 1); + return out; +} + +char *vl_arena_sprintf(vl_arena *parena, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + char *ret = vl_arena_vsprintf(parena, fmt, ap); + + va_end(ap); + return ret; +} + +char *vl_arena_vsprintf(vl_arena *parena, const char *fmt, va_list ap) +{ + va_list copy; + va_copy(copy, ap); + + int desire = vsnprintf(NULL, 0, fmt, copy); + va_end(copy); + + if (desire < 0) { + abort(); /* vsnprintf should never fail */ + } + + char *str = vl_arena_push(parena, (unsigned)desire + 1); + vsnprintf(str, (unsigned)desire + 1, fmt, ap); + + return str; +} |
