Browse Source

Merge pull request #5617 from thetarnav/soa-resize-zero-memory

Zero existing memory when using resize_soa (fixes #5614)
gingerBill 2 weeks ago
parent
commit
ac71a0aed1
2 changed files with 58 additions and 1 deletions
  1. 24 1
      base/runtime/core_builtin_soa.odin
  2. 34 0
      tests/core/runtime/test_core_runtime.odin

+ 24 - 1
base/runtime/core_builtin_soa.odin

@@ -178,8 +178,31 @@ resize_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int length: int, loc := #cal
 	if array == nil {
 		return nil
 	}
-	reserve_soa(array, length, loc) or_return
+
 	footer := raw_soa_footer(array)
+
+	if length > footer.cap {
+		reserve_soa(array, length, loc) or_return
+	} else if size_of(E) > 0 && length > footer.len {
+		ti := type_info_base(type_info_of(typeid_of(T)))
+		si := &ti.variant.(Type_Info_Struct)
+
+		field_count := len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)
+
+		data := (^rawptr)(array)^
+
+		soa_offset := 0
+		for i in 0..<field_count {
+			type := si.types[i].variant.(Type_Info_Multi_Pointer).elem
+
+			soa_offset = align_forward_int(soa_offset, align_of(E))
+
+			mem_zero(rawptr(uintptr(data) + uintptr(soa_offset) + uintptr(type.size * footer.len)), type.size * (length - footer.len))
+
+			soa_offset += type.size * footer.cap
+		}
+	}
+
 	footer.len = length
 	return nil
 }

+ 34 - 0
tests/core/runtime/test_core_runtime.odin

@@ -179,6 +179,40 @@ test_map_get :: proc(t: ^testing.T) {
 	}
 }
 
+@(test)
+test_soa_array_resize :: proc(t: ^testing.T) {
+
+	V :: struct {x: int, y: u8}
+
+	array := make(#soa[dynamic]V, 0, 2)
+	defer delete(array)
+
+	append(&array, V{1, 2}, V{3, 4})
+
+	testing.expect_value(t, len(array), 2)
+	testing.expect_value(t, array[0], V{1, 2})
+	testing.expect_value(t, array[1], V{3, 4})
+
+	resize(&array, 1)
+
+	testing.expect_value(t, len(array), 1)
+	testing.expect_value(t, array[0], V{1, 2})
+
+	resize(&array, 2)
+
+	testing.expect_value(t, len(array), 2)
+	testing.expect_value(t, array[0], V{1, 2})
+	testing.expect_value(t, array[1], V{0, 0})
+
+	resize(&array, 0)
+	resize(&array, 3)
+
+	testing.expect_value(t, len(array), 3)
+	testing.expect_value(t, array[0], V{0, 0})
+	testing.expect_value(t, array[1], V{0, 0})
+	testing.expect_value(t, array[2], V{0, 0})
+}
+
 @(test)
 test_soa_make_len :: proc(t: ^testing.T) {