diff --git a/src/mini_arena.h b/src/mini_arena.h new file mode 100644 index 0000000..c844aa1 --- /dev/null +++ b/src/mini_arena.h @@ -0,0 +1,96 @@ +#pragma once +#include "base_core.h" + +typedef struct MiniArena MiniArena; +struct MiniArena { + U8 *start; // start of user buffer + U8 *curr; // next alloc point + U8 *end; // one past end of user buffer + int checkpoint_level; // level of miniarenatmp_begin stacks +}; + +typedef struct MiniArenaCheckpoint MiniArenaCheckpoint; +struct MiniArenaCheckpoint { + U8 *alloc_point; + MiniArena *arena; +}; + +#define LARENA_STATIC_INITIALIZER(data) LARENA_INITIALIZER((data), sizeof(data)) +#define LARENA_INITIALIZER(data, sz) {.start = (data), .curr = (data), .end = (data) + sz, .checkpoint_level = 0} +#define LARENA_DEFINE(var_name, size_, alignment_) \ + struct { \ + _Alignas(alignment_) U8 memory[size_]; \ + } var_name##_arena_memory; \ + MiniArena var_name = LARENA_STATIC_INITIALIZER(var_name##_arena_memory.memory) +#define LARENA_ALLOC_TYPE(allocator, type_) miniarenaalloc_aligned((allocator), sizeof(type_), _Alignof(type_)) +#define LARENA_ALLOC_ARRAY(allocator, type_, nr_elements_) miniarenaalloc_aligned((allocator), (nr_elements_) * sizeof(type_), _Alignof(type_)) +static INLINE size_t miniarena_size(const MiniArena *arena) +{ + return (size_t)(arena->end - arena->start); +} + +static INLINE size_t miniarena_used(const MiniArena *arena) +{ + return (size_t)(arena->curr - arena->start); +} +static INLINE size_t miniarena_available(const MiniArena *arena) +{ + return miniarena_size(arena) - miniarena_used(arena); +} + +static INLINE void miniarena_init(MiniArena *arena, void *memory, size_t sz) +{ + arena->start = arena->curr = (U8 *)memory; + arena->end = arena->start + sz; +} + +static INLINE MiniArenaCheckpoint miniarenatmp_begin(MiniArena *arena) +{ + MiniArenaCheckpoint checkpoint = {}; + + checkpoint.arena = arena; + checkpoint.alloc_point = arena->curr; + arena->checkpoint_level++; + + return checkpoint; +} + +static INLINE void miniarenatmp_end(MiniArenaCheckpoint *state) +{ + MiniArena *arena = state->arena; + Assert(arena->checkpoint_level > 0); + arena->curr = state->alloc_point; + arena->checkpoint_level--; +} +static INLINE void *miniarena_push(MiniArena *arena, size_t sz) +{ + if (sz > miniarena_available(arena)) { + return NULL; + } + void *start = arena->curr; + arena->curr += sz; + return start; +} + +[[gnu::alloc_align(3)]] +static INLINE void *miniaren_push_aligned(MiniArena *arena, size_t sz, unsigned int align) +{ + Assert(IsPow2(align)); + + uintptr_t curr = (uintptr_t)arena->curr; + uintptr_t aligned = AlignUp(curr, align); + U8 *start = (U8 *)aligned; + + if (sz > (size_t)(arena->end - start)) { + return NULL; + } + + arena->curr = start + sz; + + return start; +} + +static INLINE void miniarena_reset(MiniArena *arena) +{ + arena->curr = arena->start; +}