Przeglądaj źródła

Inline resize logic for `virtual.Arena`

gingerBill 2 lat temu
rodzic
commit
5c62211f00
2 zmienionych plików z 44 dodań i 16 usunięć
  1. 8 7
      core/mem/alloc.odin
  2. 36 9
      core/mem/virtual/arena.odin

+ 8 - 7
core/mem/alloc.odin

@@ -243,13 +243,11 @@ default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, a
 		return alloc_bytes(new_size, alignment, allocator, loc)
 	}
 
-	if new_size == 0 {
-		err := free_bytes(old_data, allocator, loc)
-		return nil, err
-	}
-
 	if new_size == old_size {
-		return old_data, .None
+		return old_data, nil
+	}
+	if new_size == 0 {
+		return nil, free_bytes(old_data, allocator, loc)
 	}
 
 	new_memory, err := alloc_bytes(new_size, alignment, allocator, loc)
@@ -258,6 +256,9 @@ default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, a
 	}
 
 	runtime.copy(new_memory, old_data)
-	free_bytes(old_data, allocator, loc)
+	err1 := free_bytes(old_data, allocator, loc)
+	if err == nil {
+		err = err1
+	}
 	return new_memory, err
 }

+ 36 - 9
core/mem/virtual/arena.odin

@@ -46,6 +46,10 @@ arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = STA
 arena_alloc :: proc(arena: ^Arena, min_size: int, alignment: int, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
 	assert(mem.is_power_of_two(uintptr(alignment)), "non-power of two alignment", loc)
 
+	if min_size == 0 {
+		return nil, nil
+	}
+
 	switch arena.kind {
 	case .Growing:
 		size := uint(min_size)
@@ -186,9 +190,9 @@ arena_allocator :: proc(arena: ^Arena) -> mem.Allocator {
 }
 
 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) {
+                             size, alignment: int,
+                             old_memory: rawptr, old_size: int,
+                             location := #caller_location) -> (data: []byte, err: Allocator_Error) {
 	arena := (^Arena)(allocator_data)
 
 	switch mode {
@@ -196,19 +200,42 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
 		return arena_alloc(arena, size, alignment)
 	case .Free:
 		err = .Mode_Not_Implemented
-		return
 	case .Free_All:
 		arena_free_all(arena)
-		return
 	case .Resize:
-		return mem.default_resize_bytes_align(mem.byte_slice(old_memory, old_size), size, alignment, arena_allocator(arena), location)
+		old_data := ([^]byte)(old_memory)
+
+		switch {
+		case old_data == nil:
+			return arena_alloc(arena, size, alignment)
+		case size == old_size:
+			// return old memory
+			data = old_data[:size]
+			return
+		case size == 0:
+			err = .Mode_Not_Implemented
+			return
+		case (uintptr(old_data) & uintptr(alignment-1) == 0) && size < old_size:
+			// shrink data in-place
+			data = old_data[:size]
+			return
+		}
 
-	case .Query_Features, .Query_Info:
+		new_memory := arena_alloc(arena, size, alignment) or_return
+		if new_memory == nil {
+			return
+		}
+		copy(new_memory, old_data[:old_size])
+		return new_memory, nil
+	case .Query_Features:
+		set := (^mem.Allocator_Mode_Set)(old_memory)
+		if set != nil {
+			set^ = {.Alloc, .Free_All, .Resize, .Query_Features}
+		}
+	case .Query_Info:
 		err = .Mode_Not_Implemented
-		return
 	}
 
-	err = .Mode_Not_Implemented
 	return
 }