Browse Source

Add `Arena_Kind.Buffer` to `core:mem/virtual`

gingerBill 2 years ago
parent
commit
7d217269b5
2 changed files with 45 additions and 10 deletions
  1. 41 10
      core/mem/virtual/arena.odin
  2. 4 0
      core/mem/virtual/virtual.odin

+ 41 - 10
core/mem/virtual/arena.odin

@@ -3,8 +3,9 @@ package mem_virtual
 import "core:mem"
 import "core:mem"
 
 
 Arena_Kind :: enum uint {
 Arena_Kind :: enum uint {
-	Growing = 0, // chained memory blocks (singly linked list)
-	Static  = 1, // fixed reservation sized
+	Growing = 0, // Chained memory blocks (singly linked list).
+	Static  = 1, // Fixed reservation sized.
+	Buffer  = 2, // Uses a fixed sized buffer.
 }
 }
 
 
 Arena :: struct {
 Arena :: struct {
@@ -28,9 +29,9 @@ DEFAULT_ARENA_STATIC_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<27
 
 
 @(require_results)
 @(require_results)
 arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
 arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
-	arena.kind = .Growing
-	arena.curr_block = memory_block_alloc(0, reserved, {}) or_return
-	arena.total_used = 0
+	arena.kind           = .Growing
+	arena.curr_block     = memory_block_alloc(0, reserved, {}) or_return
+	arena.total_used     = 0
 	arena.total_reserved = arena.curr_block.reserved
 	arena.total_reserved = arena.curr_block.reserved
 	return
 	return
 }
 }
@@ -38,8 +39,31 @@ arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING
 
 
 @(require_results)
 @(require_results)
 arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = DEFAULT_ARENA_STATIC_COMMIT_SIZE) -> (err: Allocator_Error) {
 arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = DEFAULT_ARENA_STATIC_COMMIT_SIZE) -> (err: Allocator_Error) {
-	arena.kind = .Static
-	arena.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return
+	arena.kind           = .Static
+	arena.curr_block     = memory_block_alloc(commit_size, reserved, {}) or_return
+	arena.total_used     = 0
+	arena.total_reserved = arena.curr_block.reserved
+	return
+}
+
+@(require_results)
+arena_init_buffer :: proc(arena: ^Arena, buffer: []byte) -> (err: Allocator_Error) {
+	if len(buffer) < size_of(Memory_Block) {
+		return .Out_Of_Memory
+	}
+
+	arena.kind = .Buffer
+
+	mem.zero_slice(buffer)
+
+	block_base := raw_data(buffer)
+	block := (^Memory_Block)(block_base)
+	block.base      = block_base[size_of(Memory_Block):]
+	block.reserved  = len(buffer) - size_of(Memory_Block)
+	block.committed = block.reserved
+	block.used      = 0
+
+	arena.curr_block = block
 	arena.total_used = 0
 	arena.total_used = 0
 	arena.total_reserved = arena.curr_block.reserved
 	arena.total_reserved = arena.curr_block.reserved
 	return
 	return
@@ -80,6 +104,11 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
 			}
 			}
 			arena_init_static(arena=arena, reserved=arena.minimum_block_size, commit_size=DEFAULT_ARENA_STATIC_COMMIT_SIZE) or_return
 			arena_init_static(arena=arena, reserved=arena.minimum_block_size, commit_size=DEFAULT_ARENA_STATIC_COMMIT_SIZE) or_return
 		}
 		}
+		fallthrough
+	case .Buffer:
+		if arena.curr_block == nil {
+			return nil, .Out_Of_Memory
+		}
 		data, err = alloc_from_memory_block(arena.curr_block, size, alignment)
 		data, err = alloc_from_memory_block(arena.curr_block, size, alignment)
 		arena.total_used = arena.curr_block.used
 		arena.total_used = arena.curr_block.used
 	}
 	}
@@ -88,7 +117,7 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
 
 
 arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
 arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
 	if arena.curr_block != nil {
 	if arena.curr_block != nil {
-		assert(arena.kind == .Static, "expected a .Static arena", loc)
+		assert(arena.kind != .Growing, "expected a non .Growing arena", loc)
 
 
 		prev_pos := arena.curr_block.used
 		prev_pos := arena.curr_block.used
 		arena.curr_block.used = clamp(pos, 0, arena.curr_block.reserved)
 		arena.curr_block.used = clamp(pos, 0, arena.curr_block.reserved)
@@ -120,7 +149,7 @@ arena_free_all :: proc(arena: ^Arena) {
 			arena_growing_free_last_memory_block(arena)
 			arena_growing_free_last_memory_block(arena)
 		}
 		}
 		arena.total_reserved = 0
 		arena.total_reserved = 0
-	case .Static:
+	case .Static, .Buffer:
 		arena_static_reset_to(arena, 0)
 		arena_static_reset_to(arena, 0)
 	}
 	}
 	arena.total_used = 0
 	arena.total_used = 0
@@ -128,7 +157,9 @@ arena_free_all :: proc(arena: ^Arena) {
 
 
 arena_destroy :: proc(arena: ^Arena) {
 arena_destroy :: proc(arena: ^Arena) {
 	arena_free_all(arena)
 	arena_free_all(arena)
-	memory_block_dealloc(arena.curr_block)
+	if arena.kind != .Buffer {
+		memory_block_dealloc(arena.curr_block)
+	}
 	arena.curr_block = nil
 	arena.curr_block = nil
 	arena.total_used     = 0
 	arena.total_used     = 0
 	arena.total_reserved = 0
 	arena.total_reserved = 0

+ 4 - 0
core/mem/virtual/virtual.odin

@@ -128,6 +128,10 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint)
 		return nil
 		return nil
 	}
 	}
 
 
+	if block == nil {
+		return nil, .Out_Of_Memory
+	}
+
 	alignment_offset := calc_alignment_offset(block, uintptr(alignment))
 	alignment_offset := calc_alignment_offset(block, uintptr(alignment))
 	size, size_ok := safe_add(min_size, alignment_offset)
 	size, size_ok := safe_add(min_size, alignment_offset)
 	if !size_ok {
 	if !size_ok {