Os :: #import "os.kl" SizeU :: #strict U64 arena_di: U64 ALLOCATOR_ACTION :: enum ALLOCATE RESIZE FREE_ALL Allocator :: struct proc: (a: *Allocator, action: ALLOCATOR_ACTION, size: SizeU, old_pointer: *void): *void Arena :: struct allocator: Allocator di: U64 // @debug_id memory: Os.Memory alignment: U64 len: U64 ADDITIONAL_COMMIT_SIZE :: 1024*1024 DEFAULT_RESERVE_SIZE :: 1024*1024*1024 DEFAULT_ALIGNMENT :: 8 clamp_top_sizeu :: (val: SizeU, max: SizeU): SizeU if val > max return max return val get_align_offset :: (size: SizeU, align: SizeU): SizeU mask := align - 1 val := size & mask if val != 0 val = align - val return val align_up :: (size: SizeU, align: SizeU): SizeU result := size + get_align_offset(size, align) return result arena_init :: (a: *Arena) a.memory = Os.reserve(a.DEFAULT_RESERVE_SIZE) a.alignment = a.DEFAULT_ALIGNMENT a.di = arena_di++ a.allocator.proc = arena_allocator_proc arena_push_size :: (a: *Arena, size: SizeU): *void generous_size := size + a.alignment if a.len + generous_size > a.memory.commit if a.memory.reserve == 0 arena_init(a) result := Os.commit(&a.memory, generous_size + a.ADDITIONAL_COMMIT_SIZE) assert(result == true) a.len = align_up(a.len, a.alignment) assert(a.memory.reserve > a.len + a.memory.commit) result: *void = a.memory.data + a.len a.len += size return result arena_release :: (a: *Arena) Os.release(&a.memory) arena_allocator_proc :: (a: *Allocator, action: ALLOCATOR_ACTION, size: SizeU, old_pointer: *void): *void arena: *Arena = a->*Arena if action == ALLOCATOR_ACTION.ALLOCATE return arena_push_size(arena, size) elif action == ALLOCATOR_ACTION.RESIZE pass elif action == ALLOCATOR_ACTION.FREE_ALL pass else;; assert(false, "Invalid codepath") return 0 allocate :: (a: *Allocator, size: SizeU): *void return a.proc(a, ALLOCATOR_ACTION.ALLOCATE, size, 0)