constexpr size_t ARENA_BLOCK_SIZE = mib(4); constexpr size_t ARENA_ALIGNMENT = 8; struct CRT_Heap : Allocator {}; static void *crt_allocate(Allocator *allocator, size_t size) { return malloc(size); } static void crt_deallocate(Allocator *allocator, void *p) { return free(p); } static CRT_Heap make_crt_heap() { CRT_Heap result = {}; result.allocate = crt_allocate; result.deallocate = crt_deallocate; return result; } //----------------------------------------------------------------------------- // Memory OS //----------------------------------------------------------------------------- struct OS_Memory { size_t commit, reserve; U8 *data; }; CORE_Static OS_Memory os_reserve(size_t size); CORE_Static B32 os_commit(OS_Memory *m, size_t size); CORE_Static void os_release(OS_Memory *m); CORE_Static B32 os_decommit_pos(OS_Memory *m, size_t pos); //----------------------------------------------------------------------------- // Memory arenas //----------------------------------------------------------------------------- global const size_t default_reserve_size = gib(4); global const size_t default_alignment = 8; global const size_t additional_commit_size = mib(1); struct Arena : Allocator { OS_Memory memory; size_t alignment; size_t len; String debug_string; }; CORE_Static void arena_pop_pos(Arena *arena, size_t pos) { pos = clamp_top(pos, arena->len); arena->len = pos; } CORE_Static void * arena_pop(Arena *arena, size_t size) { size = clamp_top(size, arena->len); arena->len -= size; return arena->memory.data + arena->len; } CORE_Static void arena_release(Arena *arena) { os_release(&arena->memory); } CORE_Static void arena_clear(Arena *arena) { arena_pop_pos(arena, 0); } CORE_Static void * arena_push_size(Arena *a, size_t size) { size_t generous_size = size + a->alignment; if (a->len + generous_size > a->memory.commit) { assert(a->memory.reserve > 0); B32 result = os_commit(&a->memory, generous_size + additional_commit_size); assert(result); } a->len = align_up(a->len, a->alignment); assert(a->memory.reserve > a->len + size); void *result = (U8 *)a->memory.data + a->len; a->len += size; return result; } #define push_struct_copy(a, T, p) (T *)push_copy(a, p, sizeof(T)) CORE_Static void * push_copy(Arena *a, void *p, size_t size) { if (p == 0) return 0; void *result = arena_push_size(a, size); memory_copy(result, p, size); return result; } CORE_Static Arena push_arena(Allocator *allocator, size_t size, String debug_name) { Arena result = {}; result.memory.data = (U8 *)allocate_size(allocator, size); result.memory.reserve = size; result.alignment = default_alignment; result.debug_string = debug_name; result.allocate = (Allocator::Allocate *)arena_push_size; result.deallocate = (Allocator::Deallocate *)deallocate_stub; return result; } CORE_Static void arena_init(Arena *a, String debug_name) { a->memory = os_reserve(default_reserve_size); a->alignment = default_alignment; a->debug_string = debug_name; a->allocate = (Allocator::Allocate *)arena_push_size; a->deallocate = (Allocator::Deallocate *)deallocate_stub; } CORE_Static Arena arena_sub(Arena *base, size_t size, String debug_name) { Arena result = {}; result.memory.data = (U8 *)arena_push_size(base, size); result.memory.commit = size; result.memory.reserve = size; result.alignment = default_alignment; result.allocate = (Allocator::Allocate *)arena_push_size; result.deallocate = (Allocator::Deallocate *)deallocate_stub; return result; } CORE_Static Arena arena_from_buffer(void *buffer, size_t size) { Arena result = {}; result.memory.data = (U8 *)buffer; result.memory.commit = size; result.memory.reserve = size; result.alignment = default_alignment; result.allocate = (Allocator::Allocate *)arena_push_size; result.deallocate = (Allocator::Deallocate *)deallocate_stub; return result; } struct Scratch_Scope { Arena *arena; int pos; Scratch_Scope(Arena *arena) { this->arena = arena; this->pos = arena->len; } ~Scratch_Scope() { this->arena->len = this->pos; } };