mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-13 14:53:34 +00:00
Add core:relative
This will eventually replace the #relative types
This commit is contained in:
171
core/relative/relative.odin
Normal file
171
core/relative/relative.odin
Normal file
@@ -0,0 +1,171 @@
|
||||
package relative_types
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
Pointer :: struct($Type: typeid, $Backing: typeid)
|
||||
where
|
||||
intrinsics.type_is_pointer(Type) || intrinsics.type_is_multi_pointer(Type),
|
||||
intrinsics.type_is_integer(Backing) {
|
||||
offset: Backing,
|
||||
}
|
||||
|
||||
Slice :: struct($Type: typeid, $Backing: typeid)
|
||||
where
|
||||
intrinsics.type_is_slice(Type),
|
||||
intrinsics.type_is_integer(Backing) {
|
||||
offset: Backing,
|
||||
len: Backing,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
pointer_get :: proc "contextless" (p: ^$P/Pointer($T, $B)) -> T {
|
||||
if p.offset == 0 {
|
||||
return nil
|
||||
}
|
||||
ptr := ([^]byte)(p)[p.offset:]
|
||||
return (T)(ptr)
|
||||
}
|
||||
|
||||
pointer_set :: proc "contextless" (p: ^$P/Pointer($T, $B), ptr: T) {
|
||||
if ptr == nil {
|
||||
p.offset = 0
|
||||
} else {
|
||||
p.offset = B(int(uintptr(ptr)) - int(uintptr(p)))
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
slice_get :: proc "contextless" (p: ^$S/Slice($T/[]$E, $B)) -> (slice: T) {
|
||||
if p.offset == 0 {
|
||||
when size_of(E) == 0 {
|
||||
slice = T(([^]E)(nil)[:p.len])
|
||||
}
|
||||
} else {
|
||||
ptr := ([^]E)(([^]byte)(p)[p.offset:])
|
||||
slice = T(ptr[:p.len])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
slice_set :: proc "contextless" (p: ^$S/Slice($T, $B), slice: T) {
|
||||
if slice == nil {
|
||||
p.offset, p.len = 0, 0
|
||||
} else {
|
||||
ptr := raw_data(slice)
|
||||
p.offset = B(int(uintptr(ptr)) - int(uintptr(p)))
|
||||
p.len = B(len(slice))
|
||||
}
|
||||
}
|
||||
|
||||
get :: proc{
|
||||
pointer_get,
|
||||
slice_get,
|
||||
}
|
||||
|
||||
set :: proc{
|
||||
pointer_set,
|
||||
slice_set,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Set_Safe_Error :: enum {
|
||||
None,
|
||||
Memory_Too_Far_Apart,
|
||||
Length_Out_Of_Bounds,
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
pointer_set_safe :: proc "contextless" (p: ^$P/Pointer($T, $B), ptr: T) -> Set_Safe_Error {
|
||||
if ptr == nil {
|
||||
p.offset = 0
|
||||
} else {
|
||||
when intrinsics.type_is_unsigned(B) {
|
||||
diff := uint(uintptr(ptr) - uintptr(p))
|
||||
when size_of(B) < size_of(uint) {
|
||||
if diff > uint(max(B)) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
} else {
|
||||
if B(diff) > max(B) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
}
|
||||
} else {
|
||||
diff := int(uintptr(ptr)) - int(uintptr(p))
|
||||
when size_of(B) < size_of(int) {
|
||||
if diff > int(max(B)) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
} else {
|
||||
if B(diff) > max(B) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
}
|
||||
}
|
||||
p.offset = B(diff)
|
||||
}
|
||||
return .None
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
slice_set_safe :: proc "contextless" (p: ^$S/Slice($T, $B), slice: T) -> Set_Safe_Error {
|
||||
if slice == nil {
|
||||
p.offset, p.len = 0, 0
|
||||
} else {
|
||||
ptr := raw_data(slice)
|
||||
when intrinsics.type_is_unsigned(B) {
|
||||
diff := uint(uintptr(ptr) - uintptr(p))
|
||||
when size_of(B) < size_of(uint) {
|
||||
if diff > uint(max(B)) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
|
||||
if uint(len(slice)) > uint(max(B)) {
|
||||
return .Length_Out_Of_Bounds
|
||||
}
|
||||
} else {
|
||||
if B(diff) > max(B) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
if B(len(slice)) > max(B) {
|
||||
return .Length_Out_Of_Bounds
|
||||
}
|
||||
}
|
||||
p.offset = B(diff)
|
||||
p.len = B(len(slice))
|
||||
} else {
|
||||
diff := int(uintptr(ptr)) - int(uintptr(p))
|
||||
when size_of(B) < size_of(int) {
|
||||
if diff > int(max(B)) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
if len(slice) > int(max(B)) || len(slice) < int(min(B)) {
|
||||
return .Length_Out_Of_Bounds
|
||||
}
|
||||
} else {
|
||||
if B(diff) > max(B) {
|
||||
return .Memory_Too_Far_Apart
|
||||
}
|
||||
if B(len(slice)) > max(B) {
|
||||
return .Length_Out_Of_Bounds
|
||||
}
|
||||
if B(len(slice)) > max(B) || B(len(slice)) < min(B) {
|
||||
return .Length_Out_Of_Bounds
|
||||
}
|
||||
}
|
||||
}
|
||||
p.offset = B(diff)
|
||||
p.len = B(len(slice))
|
||||
}
|
||||
return .None
|
||||
}
|
||||
|
||||
|
||||
set_safe :: proc{
|
||||
pointer_set_safe,
|
||||
slice_set_safe,
|
||||
}
|
||||
Reference in New Issue
Block a user