package runtime import "core: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 when intrinsics.type_is_array(E) { field_count = len(E) } else { 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 when intrinsics.type_is_array(E) { field_count = len(E) } else { 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 when intrinsics.type_is_array(E) { field_count = len(E) } else { 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..