diff options
| author | gingerBill <bill@gingerbill.org> | 2019-11-21 19:36:07 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2019-11-21 19:36:07 +0000 |
| commit | 9b58781122aaed23f3952eff6ba749e62a04a2ae (patch) | |
| tree | 823b1cc1d758c1ad93e2497f40cf490b7da3efdd /core/runtime | |
| parent | b74f8f204776c7cacc22fcbb44898ea496e02645 (diff) | |
#soa[dynamic]Type (Experimental)
Diffstat (limited to 'core/runtime')
| -rw-r--r-- | core/runtime/core.odin | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 7fdadbaa1..6944be60d 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -559,7 +559,203 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) a.len += arg_len; } } + +@builtin +reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> bool { + if array == nil do return false; + + old_cap := cap(array); + if capacity <= old_cap do return true; + + if array.allocator.procedure == nil { + array.allocator = context.allocator; + } + assert(array.allocator.procedure != nil); + + + ti := type_info_of(typeid_of(T)); + ti = type_info_base(ti); + si := &ti.variant.(Type_Info_Struct); + + field_count := uintptr(len(si.offsets) - 3); + + if field_count == 0 { + return true; + } + + cap_ptr := cast(^int)rawptr(uintptr(array) + (field_count + 1)*size_of(rawptr)); + assert(cap_ptr^ == old_cap); + + + old_size := 0; + new_size := 0; + + max_align := 0; + for i in 0..<field_count { + type := si.types[i].variant.(Type_Info_Pointer).elem; + max_align = max(max_align, type.align); + + old_size = mem.align_forward_int(old_size, type.align); + new_size = mem.align_forward_int(new_size, type.align); + + old_size += type.size * old_cap; + new_size += type.size * capacity; + } + + old_size = mem.align_forward_int(old_size, max_align); + new_size = mem.align_forward_int(new_size, max_align); + + old_data := (^rawptr)(array)^; + + new_data := array.allocator.procedure( + array.allocator.data, mem.Allocator_Mode.Alloc, new_size, max_align, + nil, old_size, 0, loc, + ); + if new_data == nil do return false; + + + cap_ptr^ = capacity; + + old_offset := 0; + new_offset := 0; + for i in 0..<field_count { + type := si.types[i].variant.(Type_Info_Pointer).elem; + max_align = max(max_align, type.align); + + old_offset = mem.align_forward_int(old_offset, type.align); + new_offset = mem.align_forward_int(new_offset, type.align); + + new_data_elem := rawptr(uintptr(new_data) + uintptr(new_offset)); + old_data_elem := rawptr(uintptr(old_data) + uintptr(old_offset)); + + mem_copy(new_data_elem, old_data_elem, type.size * old_cap); + + (^rawptr)(uintptr(array) + i*size_of(rawptr))^ = new_data_elem; + + old_offset += type.size * old_cap; + new_offset += type.size * capacity; + } + + array.allocator.procedure( + array.allocator.data, mem.Allocator_Mode.Free, 0, max_align, + old_data, old_size, 0, loc, + ); + + return true; +} + +@builtin +append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) { + if array == nil do return; + + arg_len := 1; + + if cap(array) <= len(array)+arg_len { + cap := 2 * cap(array) + max(8, arg_len); + _ = reserve_soa(array, cap, loc); + } + arg_len = min(cap(array)-len(array), arg_len); + if arg_len > 0 { + ti := type_info_of(typeid_of(T)); + ti = type_info_base(ti); + si := &ti.variant.(Type_Info_Struct); + field_count := uintptr(len(si.offsets) - 3); + + if field_count == 0 { + return; + } + + data := (^rawptr)(array)^; + + len_ptr := cast(^int)rawptr(uintptr(array) + (field_count + 0)*size_of(rawptr)); + + + soa_offset := 0; + item_offset := 0; + + arg_copy := arg; + arg_ptr := &arg_copy; + + max_align := 0; + for i in 0..<field_count { + type := si.types[i].variant.(Type_Info_Pointer).elem; + max_align = max(max_align, type.align); + + soa_offset = mem.align_forward_int(soa_offset, type.align); + item_offset = mem.align_forward_int(item_offset, type.align); + + dst := rawptr(uintptr(data) + uintptr(soa_offset) + uintptr(type.size * len_ptr^)); + src := rawptr(uintptr(arg_ptr) + uintptr(item_offset)); + mem_copy(dst, src, type.size); + + soa_offset += type.size * cap(array); + item_offset += type.size; + } + + len_ptr^ += arg_len; + } +} + +@builtin +append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) { + if array == nil do return; + + arg_len := len(args); + if arg_len == 0 { + return; + } + + if cap(array) <= len(array)+arg_len { + cap := 2 * cap(array) + max(8, arg_len); + _ = reserve_soa(array, cap, loc); + } + arg_len = min(cap(array)-len(array), arg_len); + if arg_len > 0 { + ti := type_info_of(typeid_of(T)); + ti = type_info_base(ti); + si := &ti.variant.(Type_Info_Struct); + field_count := uintptr(len(si.offsets) - 3); + + if field_count == 0 { + return; + } + + data := (^rawptr)(array)^; + + len_ptr := cast(^int)rawptr(uintptr(array) + (field_count + 0)*size_of(rawptr)); + + + soa_offset := 0; + item_offset := 0; + + args_ptr := &args[0]; + + max_align := 0; + for i in 0..<field_count { + type := si.types[i].variant.(Type_Info_Pointer).elem; + max_align = max(max_align, type.align); + + soa_offset = mem.align_forward_int(soa_offset, type.align); + item_offset = mem.align_forward_int(item_offset, type.align); + + dst := uintptr(data) + uintptr(soa_offset) + uintptr(type.size * len_ptr^); + src := uintptr(args_ptr) + uintptr(item_offset); + for j in 0..<arg_len { + d := rawptr(dst + uintptr(j*type.size)); + s := rawptr(src + uintptr(j*size_of(E))); + mem_copy(d, s, type.size); + } + + soa_offset += type.size * cap(array); + item_offset += type.size; + } + + len_ptr^ += arg_len; + } +} + @builtin append :: proc{append_elem, append_elems}; +@builtin append_soa :: proc{append_soa_elem, append_soa_elems}; |