package runtime import "intrinsics" _ :: intrinsics; /* SOA types are implemented with this sort of layout: SOA Fixed Array struct { f0: [N]T0, f1: [N]T1, f2: [N]T2, } SOA Slice struct { f0: ^T0, f1: ^T1, f2: ^T2, len: int, } SOA Dynamic Array struct { f0: ^T0, f1: ^T1, f2: ^T2, len: int, cap: int, allocator: Allocator, } A footer is used rather than a header purely to simplify access to the fields internally i.e. field index of the AOS == SOA */ Raw_SOA_Footer_Slice :: struct { len: int, } Raw_SOA_Footer_Dynamic_Array :: struct { len: int, cap: int, allocator: Allocator, } raw_soa_footer_slice :: proc(array: ^$T/#soa[]$E) -> (footer: ^Raw_SOA_Footer_Slice) { if array == nil { return nil; } field_count := uintptr(intrinsics.type_struct_field_count(E)); footer = (^Raw_SOA_Footer_Slice)(uintptr(array) + field_count*size_of(rawptr)); return; } raw_soa_footer_dynamic_array :: proc(array: ^$T/#soa[dynamic]$E) -> (footer: ^Raw_SOA_Footer_Dynamic_Array) { if array == nil { return nil; } field_count := uintptr(intrinsics.type_struct_field_count(E)); footer = (^Raw_SOA_Footer_Dynamic_Array)(uintptr(array) + field_count*size_of(rawptr)); return; } raw_soa_footer :: proc{ raw_soa_footer_slice, raw_soa_footer_dynamic_array, }; @builtin make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second { if length <= 0 { return; } footer := raw_soa_footer(&array); if size_of(E) == 0 { footer.len = length; return; } max_align := max(alignment, align_of(E)); ti := type_info_of(typeid_of(T)); ti = type_info_base(ti); si := &ti.variant.(Type_Info_Struct); field_count := uintptr(intrinsics.type_struct_field_count(E)); total_size := 0; for i in 0.. (array: T, err: Allocator_Error) #optional_second { return make_soa_aligned(T, length, align_of(E), allocator, loc); } @builtin make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T) { context.allocator = allocator; reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc); return; } @builtin make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, auto_cast length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) { context.allocator = allocator; resize_soa(&array, length, loc); return; } @builtin make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, auto_cast length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) { context.allocator = allocator; if reserve_soa(&array, capacity, loc) { resize_soa(&array, length, loc); } return; } @builtin make_soa :: proc{ make_soa_slice, make_soa_dynamic_array, make_soa_dynamic_array_len, make_soa_dynamic_array_len_cap, }; @builtin resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> bool { if array == nil { return false; } if !reserve_soa(array, length, loc) { return false; } footer := raw_soa_footer(array); footer.len = length; return true; } @builtin reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> bool { if array == nil { return false; } old_cap := cap(array); if capacity <= old_cap { return true; } if array.allocator.procedure == nil { array.allocator = context.allocator; } assert(array.allocator.procedure != nil); footer := raw_soa_footer(array); if size_of(E) == 0 { footer.cap = capacity; return true; } ti := type_info_of(typeid_of(T)); ti = type_info_base(ti); si := &ti.variant.(Type_Info_Struct); field_count := uintptr(intrinsics.type_struct_field_count(E)); assert(footer.cap == old_cap); old_size := 0; new_size := 0; max_align :: align_of(E); for i in 0.. 0 && arg_len > 0 { ti := type_info_of(typeid_of(T)); ti = type_info_base(ti); si := &ti.variant.(Type_Info_Struct); field_count := uintptr(intrinsics.type_struct_field_count(E)); data := (^rawptr)(array)^; soa_offset := 0; item_offset := 0; arg_copy := arg; arg_ptr := &arg_copy; max_align :: align_of(E); for i in 0.. 0 && arg_len > 0 { ti := type_info_of(typeid_of(T)); ti = type_info_base(ti); si := &ti.variant.(Type_Info_Struct); field_count := uintptr(intrinsics.type_struct_field_count(E)); data := (^rawptr)(array)^; soa_offset := 0; item_offset := 0; args_ptr := &args[0]; max_align :: align_of(E); for i in 0..