mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-21 00:46:47 +00:00
#soa[dynamic]Type (Experimental)
This commit is contained in:
@@ -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};
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user