浏览代码

Add virtual.Static_Arena

gingerBill 3 年之前
父节点
当前提交
bc2b8b597c
共有 1 个文件被更改,包括 134 次插入0 次删除
  1. 134 0
      core/mem/virtual/static_arena.odin

+ 134 - 0
core/mem/virtual/static_arena.odin

@@ -0,0 +1,134 @@
+package mem_virtual
+
+import "core:mem"
+
+Static_Arena :: struct {
+	block: ^Memory_Block,
+	minimum_reserve_size: uint,
+	
+	temp_count: int,
+}
+
+STATIC_ARENA_DEFAULT_COMMIT_SIZE  :: 1<<20
+STATIC_ARENA_DEFAULT_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<26
+
+static_arena_init :: proc(arena: ^Static_Arena, reserved: uint, commit_size: uint = STATIC_ARENA_DEFAULT_COMMIT_SIZE) -> (err: Allocator_Error) {
+	reserved := reserved
+	reserved = max(reserved, STATIC_ARENA_DEFAULT_COMMIT_SIZE)
+	data := reserve(uint(reserved)) or_return
+	committed := max(commit_size, STATIC_ARENA_DEFAULT_COMMIT_SIZE)
+	committed = min(committed, reserved)
+	
+	ptr := raw_data(data)
+	commit(ptr, uint(committed))
+	
+	arena.block = memory_block_alloc(commit_size, reserved, {}) or_return
+	return
+} 
+
+static_arena_destroy :: proc(arena: ^Static_Arena) {
+	memory_block_dealloc(arena.block)
+	arena^ = {}
+} 
+
+
+static_arena_alloc :: proc(arena: ^Static_Arena, size: int, alignment: int) -> (data: []byte, err: Allocator_Error) {
+	align_forward :: #force_inline proc "contextless" (ptr: uint, align: uint) -> uint {
+		mask := align-1
+		return (ptr + mask) &~ mask
+	}
+	
+	if arena.block == nil {
+		reserve_size := max(arena.minimum_reserve_size, STATIC_ARENA_DEFAULT_RESERVE_SIZE)
+		static_arena_init(arena, reserve_size, STATIC_ARENA_DEFAULT_COMMIT_SIZE) or_return
+	}
+	
+	MINIMUM_ALIGN :: 2*align_of(uintptr)
+	
+	align := max(MINIMUM_ALIGN, alignment)
+	
+	return alloc_from_memory_block(arena.block, size, align)
+}
+
+static_arena_reset_to :: proc(arena: ^Static_Arena, pos: uint) -> bool {
+	if arena.block != nil {
+		prev_pos := arena.block.used
+		arena.block.used = clamp(pos, 0, arena.block.reserved)
+		
+		if prev_pos < pos {
+			mem.zero_slice(arena.block.base[arena.block.used:][:pos-prev_pos])
+		}
+		return true
+	} else if pos == 0 {
+		return true
+	}
+	return false
+}
+
+static_arena_free_all :: proc(arena: ^Static_Arena) {
+	static_arena_reset_to(arena, 0)
+}
+
+static_arena_allocator :: proc(arena: ^Static_Arena) -> mem.Allocator {
+	return mem.Allocator{static_arena_allocator_proc, arena}
+}
+
+static_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
+                             size, alignment: int,
+                             old_memory: rawptr, old_size: int,
+                             location := #caller_location) -> (data: []byte, err: Allocator_Error) {
+	arena := (^Static_Arena)(allocator_data)
+	
+	switch mode {
+	case .Alloc:
+		return static_arena_alloc(arena, size, alignment)
+	case .Free:
+		err = .Mode_Not_Implemented
+		return
+	case .Free_All:
+		static_arena_free_all(arena)
+		return
+	case .Resize:
+		return mem.default_resize_bytes_align(mem.byte_slice(old_memory, old_size), size, alignment, static_arena_allocator(arena), location)
+		
+	case .Query_Features, .Query_Info:
+		err = .Mode_Not_Implemented
+		return	
+	}	
+	
+	err = .Mode_Not_Implemented
+	return 
+}
+
+
+Static_Arena_Temp :: struct {
+	arena: ^Static_Arena,
+	used:  uint,
+}
+
+
+static_arena_temp_begin :: proc(arena: ^Static_Arena) -> (temp: Static_Arena_Temp) {
+	temp.arena = arena
+	temp.used = arena.block.used if arena.block != nil else 0
+	arena.temp_count += 1
+	return
+}
+
+static_arena_temp_end :: proc(temp: Static_Arena_Temp, loc := #caller_location) {
+	assert(temp.arena != nil, "nil arena", loc)
+	arena := temp.arena
+	
+	used := arena.block.used if arena.block != nil else 0
+	
+	assert(temp.used >= used, "invalid Static_Arena_Temp", loc)
+	
+	static_arena_reset_to(arena, temp.used)
+	
+	assert(arena.temp_count > 0, "double-use of growing_arena_temp_end", loc)
+	arena.temp_count -= 1
+}
+
+
+static_arena_check_temp :: proc(arena: ^Static_Arena, loc := #caller_location) {
+	assert(arena.temp_count == 0, "Static_Arena_Temp not been ended", loc)
+}