aboutsummaryrefslogtreecommitdiff
path: root/core/runtime
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2019-11-21 19:36:07 +0000
committergingerBill <bill@gingerbill.org>2019-11-21 19:36:07 +0000
commit9b58781122aaed23f3952eff6ba749e62a04a2ae (patch)
tree823b1cc1d758c1ad93e2497f40cf490b7da3efdd /core/runtime
parentb74f8f204776c7cacc22fcbb44898ea496e02645 (diff)
#soa[dynamic]Type (Experimental)
Diffstat (limited to 'core/runtime')
-rw-r--r--core/runtime/core.odin196
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};