Browse Source

Add `core:relative`

This will eventually replace the #relative types
gingerBill 1 year ago
parent
commit
7128bc4b34
1 changed files with 171 additions and 0 deletions
  1. 171 0
      core/relative/relative.odin

+ 171 - 0
core/relative/relative.odin

@@ -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,
+}