Merge pull request #2571 from jakubtomsu/builtin-soa-procs-improvements

Update SOA dynamic array procs to match non-SOA
This commit is contained in:
gingerBill
2023-06-06 22:40:27 +01:00
committed by GitHub
+41 -46
View File
@@ -145,26 +145,25 @@ make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.al
} }
@(builtin, require_results) @(builtin, require_results)
make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T) { make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
context.allocator = allocator context.allocator = allocator
reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc) reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc) or_return
return return array, nil
} }
@(builtin, require_results) @(builtin, require_results)
make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) { make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
context.allocator = allocator context.allocator = allocator
resize_soa(&array, length, loc) resize_soa(&array, length, loc) or_return
return return array, nil
} }
@(builtin, require_results) @(builtin, require_results)
make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) { make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
context.allocator = allocator context.allocator = allocator
if reserve_soa(&array, capacity, loc) { reserve_soa(&array, capacity, loc) or_return
resize_soa(&array, length, loc) resize_soa(&array, length, loc) or_return
} return array, nil
return
} }
@@ -178,27 +177,25 @@ make_soa :: proc{
@builtin @builtin
resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> bool { resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
if array == nil { if array == nil {
return false return nil
}
if !reserve_soa(array, length, loc) {
return false
} }
reserve_soa(array, length, loc) or_return
footer := raw_soa_footer(array) footer := raw_soa_footer(array)
footer.len = length footer.len = length
return true return nil
} }
@builtin @builtin
reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> bool { reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
if array == nil { if array == nil {
return false return nil
} }
old_cap := cap(array) old_cap := cap(array)
if capacity <= old_cap { if capacity <= old_cap {
return true return nil
} }
if array.allocator.procedure == nil { if array.allocator.procedure == nil {
@@ -209,7 +206,7 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
footer := raw_soa_footer(array) footer := raw_soa_footer(array)
if size_of(E) == 0 { if size_of(E) == 0 {
footer.cap = capacity footer.cap = capacity
return true return nil
} }
ti := type_info_of(typeid_of(T)) ti := type_info_of(typeid_of(T))
@@ -240,13 +237,10 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
old_data := (^rawptr)(array)^ old_data := (^rawptr)(array)^
new_bytes, err := array.allocator.procedure( new_bytes := array.allocator.procedure(
array.allocator.data, .Alloc, new_size, max_align, array.allocator.data, .Alloc, new_size, max_align,
nil, old_size, loc, nil, old_size, loc,
) ) or_return
if new_bytes == nil || err != nil {
return false
}
new_data := raw_data(new_bytes) new_data := raw_data(new_bytes)
@@ -271,31 +265,28 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
new_offset += type.size * capacity new_offset += type.size * capacity
} }
_, err = array.allocator.procedure( array.allocator.procedure(
array.allocator.data, .Free, 0, max_align, array.allocator.data, .Free, 0, max_align,
old_data, old_size, loc, old_data, old_size, loc,
) ) or_return
return true return nil
} }
@builtin @builtin
append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) { append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil { if array == nil {
return return 0, nil
} }
arg_len := 1 if cap(array) <= len(array) + 1 {
cap := 2 * cap(array) + 8
if cap(array) <= len(array)+arg_len { err = reserve_soa(array, cap, loc) // do not 'or_return' here as it could be a partial success
cap := 2 * cap(array) + max(8, arg_len)
_ = reserve_soa(array, cap, loc)
} }
arg_len = min(cap(array)-len(array), arg_len)
footer := raw_soa_footer(array) footer := raw_soa_footer(array)
if size_of(E) > 0 && arg_len > 0 { if size_of(E) > 0 && cap(array)-len(array) > 0 {
ti := type_info_of(typeid_of(T)) ti := type_info_of(typeid_of(T))
ti = type_info_base(ti) ti = type_info_base(ti)
si := &ti.variant.(Type_Info_Struct) si := &ti.variant.(Type_Info_Struct)
@@ -328,12 +319,14 @@ append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_locat
soa_offset += type.size * cap(array) soa_offset += type.size * cap(array)
item_offset += type.size item_offset += type.size
} }
footer.len += 1
return 1, err
} }
footer.len += arg_len return 0, err
} }
@builtin @builtin
append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) { append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil { if array == nil {
return return
} }
@@ -345,7 +338,7 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l
if cap(array) <= len(array)+arg_len { if cap(array) <= len(array)+arg_len {
cap := 2 * cap(array) + max(8, arg_len) cap := 2 * cap(array) + max(8, arg_len)
_ = reserve_soa(array, cap, loc) err = reserve_soa(array, cap, loc) // do not 'or_return' here as it could be a partial success
} }
arg_len = min(cap(array)-len(array), arg_len) arg_len = min(cap(array)-len(array), arg_len)
@@ -382,8 +375,8 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l
item_offset += type.size item_offset += type.size
} }
} }
footer.len += arg_len footer.len += arg_len
return arg_len, err
} }
@@ -395,21 +388,23 @@ append_soa :: proc{
} }
delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) { delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
when intrinsics.type_struct_field_count(E) != 0 { when intrinsics.type_struct_field_count(E) != 0 {
array := array array := array
ptr := (^rawptr)(&array)^ ptr := (^rawptr)(&array)^
free(ptr, allocator, loc) free(ptr, allocator, loc) or_return
} }
return nil
} }
delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) { delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) -> Allocator_Error {
when intrinsics.type_struct_field_count(E) != 0 { when intrinsics.type_struct_field_count(E) != 0 {
array := array array := array
ptr := (^rawptr)(&array)^ ptr := (^rawptr)(&array)^
footer := raw_soa_footer(&array) footer := raw_soa_footer(&array)
free(ptr, footer.allocator, loc) free(ptr, footer.allocator, loc) or_return
} }
return nil
} }