From 494612827a992ca7e8614358788e9db1ca25ba5c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 10 Feb 2023 14:30:41 +0000 Subject: [PATCH] Add `Arena_Temp` --- core/runtime/default_allocators_arena.odin | 81 ++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/core/runtime/default_allocators_arena.odin b/core/runtime/default_allocators_arena.odin index 58b1cc679..4c3ba555e 100644 --- a/core/runtime/default_allocators_arena.odin +++ b/core/runtime/default_allocators_arena.odin @@ -18,6 +18,7 @@ Arena :: struct { total_used: uint, total_capacity: uint, minimum_block_size: uint, + temp_count: uint, } @(private, require_results) @@ -140,15 +141,20 @@ arena_init :: proc(arena: ^Arena, size: uint, backing_allocator: Allocator, loc } -// `arena_free_all` will free all but the first memory block, and then reset the memory block -arena_free_all :: proc(arena: ^Arena, loc := #caller_location) { - for arena.curr_block != nil && arena.curr_block.prev != nil { - free_block := arena.curr_block +arena_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) { + if free_block := arena.curr_block; free_block != nil { arena.curr_block = free_block.prev arena.total_capacity -= free_block.capacity memory_block_dealloc(free_block, loc) } +} + +// `arena_free_all` will free all but the first memory block, and then reset the memory block +arena_free_all :: proc(arena: ^Arena, loc := #caller_location) { + for arena.curr_block != nil && arena.curr_block.prev != nil { + arena_free_last_memory_block(arena, loc) + } if arena.curr_block != nil { intrinsics.mem_zero(arena.curr_block.base, arena.curr_block.used) @@ -225,3 +231,70 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, return } + + + + +Arena_Temp :: struct { + arena: ^Arena, + block: ^Memory_Block, + used: uint, +} + +@(require_results) +arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) { + assert(arena != nil, "nil arena", loc) + + temp.arena = arena + temp.block = arena.curr_block + if arena.curr_block != nil { + temp.used = arena.curr_block.used + } + arena.temp_count += 1 + return +} + +arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) { + assert(temp.arena != nil, "nil arena", loc) + arena := temp.arena + + if temp.block != nil { + memory_block_found := false + for block := arena.curr_block; block != nil; block = block.prev { + if block == temp.block { + memory_block_found = true + break + } + } + if !memory_block_found { + assert(arena.curr_block == temp.block, "memory block stored within Arena_Temp not owned by Arena", loc) + } + + for arena.curr_block != temp.block { + arena_free_last_memory_block(arena) + } + + if block := arena.curr_block; block != nil { + assert(block.used >= temp.used, "out of order use of arena_temp_end", loc) + amount_to_zero := min(block.used-temp.used, block.capacity-block.used) + intrinsics.mem_zero(block.base[temp.used:], amount_to_zero) + block.used = temp.used + } + } + + assert(arena.temp_count > 0, "double-use of arena_temp_end", loc) + arena.temp_count -= 1 +} + +// Ignore the use of a `arena_temp_begin` entirely +arena_temp_ignore :: proc(temp: Arena_Temp, loc := #caller_location) { + assert(temp.arena != nil, "nil arena", loc) + arena := temp.arena + + assert(arena.temp_count > 0, "double-use of arena_temp_end", loc) + arena.temp_count -= 1 +} + +arena_check_temp :: proc(arena: ^Arena, loc := #caller_location) { + assert(arena.temp_count == 0, "Arena_Temp not been ended", loc) +}