// Relative pointer package relptr import "base:intrinsics" Ptr :: struct($T: typeid) { offset: uintptr, } Slice :: struct($T: typeid) { offset: uintptr, len: int, } SOA_Slice :: struct($T: typeid) { // Offset for each field of SOA struct offsets: [len( T, ) when intrinsics.type_is_array(T) else intrinsics.type_struct_field_count(T)]uintptr, len: int, } from_rawptr :: #force_inline proc($T: typeid, addr: rawptr, base := context.user_ptr) -> Ptr(T) { offset := uintptr(addr) - uintptr(base) assert(offset >= 0, "ptr does not belong to this base") return Ptr(T){offset = offset} } from_ptr :: #force_inline proc(addr: ^$T, base := context.user_ptr) -> Ptr(T) { offset := uintptr(rawptr(addr)) - uintptr(base) assert(offset >= 0, "ptr does not belong to this base") return Ptr(T){offset = offset} } from_multi_ptr :: #force_inline proc(addr: [^]$T, base := context.user_ptr) -> Ptr(T) { offset := uintptr(rawptr(addr)) - uintptr(base) assert(offset >= 0, "ptr does not belong to this base") return Ptr(T){offset = offset} } from_slice :: #force_inline proc(slice: []$T, base := context.user_ptr) -> Slice(T) { offset := uintptr(rawptr(raw_data(slice))) - uintptr(base) assert(offset >= 0, "ptr does not belong to this base") return Slice(T){offset = offset, len = len(slice)} } from_soa_slice :: #force_inline proc(slice: #soa[]$T, base := context.user_ptr) -> SOA_Slice(T) { slice := slice result: SOA_Slice(T) FIELD_COUNT :: (len(T) when intrinsics.type_is_array(T) else intrinsics.type_struct_field_count(T)) // SOA slice is just an array of pointers to each member + a footer src_ptrs := (transmute([^]uintptr)(&slice))[:FIELD_COUNT] for i in 0 ..< len(result.offsets) { result.offsets[i] = src_ptrs[i] - uintptr(base) } result.len = len(slice) return result } deref_ptr :: #force_inline proc(ptr: Ptr($T), base := context.user_ptr) -> ^T { return transmute(^T)(uintptr(base) + ptr.offset) } deref_multi_ptr :: #force_inline proc(ptr: Ptr($T), base := context.user_ptr) -> [^]T { return transmute([^]T)(uintptr(base) + ptr.offset) } deref_slice :: #force_inline proc(slice: Slice($T), base := context.user_ptr) -> []T { return (transmute([^]T)(uintptr(base) + slice.offset))[:slice.len] } deref_soa_slice :: #force_inline proc(slice: SOA_Slice($T), base := context.user_ptr) -> #soa[]T { result: #soa[]T footer := raw_soa_footer_slice(&result) FIELD_COUNT :: (len(T) when intrinsics.type_is_array(T) else intrinsics.type_struct_field_count(T)) // Just in case SOA layout changes #assert(size_of(result) == (FIELD_COUNT * size_of(rawptr)) + size_of(footer)) // SOA slice is just an array of pointers to each member + a footer result_ptrs := (transmute([^]uintptr)(&result))[:FIELD_COUNT] for i in 0 ..< len(slice.offsets) { result_ptrs[i] = uintptr(base) + slice.offsets[i] } footer.len = slice.len return result }