aboutsummaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
authorthetarnav <gthetarnav@gmail.com>2025-11-02 12:13:11 +0100
committerthetarnav <gthetarnav@gmail.com>2025-11-02 12:13:11 +0100
commite364e76f7f8978ffef78321f962324a4fc4dcaae (patch)
treee7de4d1fd0989659414342f65337b552735f2dd6 /base
parent91d923bd8f89dd11208d7d67783e5085955377fc (diff)
Add `inject_at_soa` and `append_nothing_soa` procedures
Diffstat (limited to 'base')
-rw-r--r--base/runtime/core_builtin_soa.odin111
1 files changed, 111 insertions, 0 deletions
diff --git a/base/runtime/core_builtin_soa.odin b/base/runtime/core_builtin_soa.odin
index 331254ac7..5c3253f97 100644
--- a/base/runtime/core_builtin_soa.odin
+++ b/base/runtime/core_builtin_soa.odin
@@ -501,6 +501,117 @@ append_soa :: proc{
}
+// `append_nothing_soa` appends an empty value to a dynamic SOA array. It returns `1, nil` if successful, and `0, err` when it was not possible,
+// whatever `err` happens to be.
+@builtin
+append_nothing_soa :: proc(array: ^$T/#soa[dynamic]$E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
+ if array == nil {
+ return 0, nil
+ }
+ prev_len := len(array)
+ resize(array, len(array)+1, loc) or_return
+ return len(array)-prev_len, nil
+}
+
+
+// `inject_at_elem_soa` injects an element in a dynamic SOA array at a specified index and moves the previous elements after that index "across"
+@builtin
+inject_at_elem_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int index: int, #no_broadcast arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
+ when !ODIN_NO_BOUNDS_CHECK {
+ ensure(index >= 0, "Index must be positive.", loc)
+ }
+ if array == nil {
+ return
+ }
+ n := max(len(array), index)
+ m :: 1
+ new_len := n + m
+
+ resize(array, new_len, loc) or_return
+ when size_of(E) != 0 {
+ 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)
+
+ item_offset := 0
+
+ arg_copy := arg
+ arg_ptr := &arg_copy
+
+ for i in 0..<field_count {
+ data := (^uintptr)(uintptr(array) + uintptr(si.offsets[i]))^
+ type := si.types[i].variant.(Type_Info_Multi_Pointer).elem
+ item_offset = align_forward_int(item_offset, type.align)
+
+ src := data + uintptr(index * type.size)
+ dst := data + uintptr((index + m) * type.size)
+ mem_copy(rawptr(dst), rawptr(src), (n - index) * type.size)
+
+ mem_copy(rawptr(src), rawptr(uintptr(arg_ptr) + uintptr(item_offset)), type.size)
+
+ item_offset += type.size
+ }
+ }
+ ok = true
+ return
+}
+
+// `inject_at_elems_soa` injects multiple elements in a dynamic SOA array at a specified index and moves the previous elements after that index "across"
+@builtin
+inject_at_elems_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
+ when !ODIN_NO_BOUNDS_CHECK {
+ ensure(index >= 0, "Index must be positive.", loc)
+ }
+ if array == nil {
+ return
+ }
+ if len(args) == 0 {
+ ok = true
+ return
+ }
+
+ n := max(len(array), index)
+ m := len(args)
+ new_len := n + m
+
+ resize(array, new_len, loc) or_return
+ when size_of(E) != 0 {
+ 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)
+
+ item_offset := 0
+
+ args_ptr := &args[0]
+
+ for i in 0..<field_count {
+ data := (^uintptr)(uintptr(array) + uintptr(si.offsets[i]))^
+ type := si.types[i].variant.(Type_Info_Multi_Pointer).elem
+ item_offset = align_forward_int(item_offset, type.align)
+
+ src := data + uintptr(index * type.size)
+ dst := data + uintptr((index + m) * type.size)
+ mem_copy(rawptr(dst), rawptr(src), (n - index) * type.size)
+
+ for j in 0..<len(args) {
+ d := rawptr(src + uintptr(j*type.size))
+ s := rawptr(uintptr(args_ptr) + uintptr(item_offset) + uintptr(j*size_of(E)))
+ mem_copy(d, s, type.size)
+ }
+
+ item_offset += type.size
+ }
+ }
+ ok = true
+ return
+}
+
+// `inject_at_soa` injects something into a dynamic SOA array at a specified index and moves the previous elements after that index "across"
+@builtin inject_at_soa :: proc{inject_at_elem_soa, inject_at_elems_soa}
+
+
delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
field_count :: len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)
when field_count != 0 {