#pragma once #include "base_core.h" // Mini Arena for arena allocations from a supplied buffer typedef struct MArena MArena; struct MArena { U8 *base; // start of buffer U32 first_free; U32 size; S32 temp_level; // level of marena_temp_begin nesting }; typedef struct MTemp MTemp; struct MTemp { U32 offset; MArena *arena; }; #define MARENA_STATIC_INITIALIZER(data) MARENA_INITIALIZER((data), sizeof(data)) #define MARENA_INITIALIZER(data, size_) {.base = (data), .first_free = 0, .size = (U32)size_, .temp_level = 0} #define MARENA_DEFINE(var_name, size, alignment_) \ struct { \ _Alignas(alignment_) U8 memory[size];\ } var_name##_marena_memory; \ MArena var_name = MARENA_STATIC_INITIALIZER(var_name##_marena_memory.memory) static INLINE void marena_init(MArena *arena, void *memory, U32 size) { Assert(memory != NULL); arena->base = (U8 *)memory; arena->first_free = 0; arena->size = size; } static INLINE MTemp marena_temp_begin(MArena *arena) { MTemp checkpoint = {}; checkpoint.arena = arena; checkpoint.offset = arena->first_free; arena->temp_level++; return checkpoint; } static INLINE void marena_temp_end(MTemp *state) { MArena *arena = state->arena; Assert(arena->temp_level > 0); arena->first_free = state->offset; arena->temp_level--; } static INLINE void *marena_push(MArena *arena, U32 size) { if (size > arena->size - arena->first_free) { return NULL; } void *base = &arena->base[arena->first_free]; arena->first_free += size; return base; } [[gnu::alloc_align(3)]] static INLINE void *marena_push_aligned(MArena *arena, U32 size, U32 align) { Assert(IsPow2(align)); U32 aligned = AlignUp(arena->first_free, align); if (aligned < arena->first_free) { // aligned wrapped around return NULL; } if (aligned > arena->size || size > arena->size - aligned) { return NULL; } void *base = &arena->base[aligned]; arena->first_free = aligned + size; return base; } #define marena_push_type(arena, type_)\ marena_push_aligned((arena), sizeof(type_), _Alignof(type_)) #define marena_push_array(arena, type_, nr_elements_)\ marena_push_aligned((arena), (nr_elements_) * (U32)sizeof(type_), _Alignof(type_)) static INLINE void marena_reset(MArena *arena) { arena->first_free = 0; } static INLINE void *marena_allocator_func(Allocator *allocator, AllocOperation operation , void *memory, U32 size, U32 align) { switch (operation) { case Alloc_Op_Aligned: return marena_push_aligned(allocator->data, size, align); case Alloc_Op_Free: // can't free/Free_all from an marena return NULL; case Alloc_Op_Free_All: return NULL; } Assert(false); } static INLINE Allocator marena_allocator(MArena *arena) { Allocator allocator = {}; allocator.op_func_ptr = marena_allocator_func; allocator.data = arena; return allocator; }