commit 127f2ed3dcebf899067b15a4de248860f99ae72d
parent a1c5abf4e635079f49a468f4a7bf4b49390cfdbb
Author: Sebastian <sebastian@sebsite.pw>
Date: Sun, 1 Dec 2024 20:25:15 -0500
math::checked: add functions for int, uint, and size
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
2 files changed, 140 insertions(+), 0 deletions(-)
diff --git a/math/checked/checked.ha b/math/checked/checked.ha
@@ -69,6 +69,13 @@ export fn addi64(a: i64, b: i64) (i64, bool) = {
};
// Adds 'a' and 'b', returning the result and whether overflow occurred.
+export fn addi(a: int, b: int) (int, bool) = {
+ const res = a + b;
+ const overflow = a < 0 == b < 0 && a < 0 != res < 0;
+ return (res, overflow);
+};
+
+// Adds 'a' and 'b', returning the result and whether overflow occurred.
export fn addu8(a: u8, b: u8) (u8, bool) = {
const res = a + b;
const overflow = res < a;
@@ -132,6 +139,20 @@ export fn addu64(a: u64, b: u64) (u64, bool) = {
assert(overflow);
};
+// Adds 'a' and 'b', returning the result and whether overflow occurred.
+export fn addu(a: uint, b: uint) (uint, bool) = {
+ const res = a + b;
+ const overflow = res < a;
+ return (res, overflow);
+};
+
+// Adds 'a' and 'b', returning the result and whether overflow occurred.
+export fn addz(a: size, b: size) (size, bool) = {
+ const res = a + b;
+ const overflow = res < a;
+ return (res, overflow);
+};
+
// Subtracts 'b' from 'a', returning the result and whether overflow occurred.
export fn subi8(a: i8, b: i8) (i8, bool) = {
const res = a - b;
@@ -209,6 +230,13 @@ export fn subi64(a: i64, b: i64) (i64, bool) = {
};
// Subtracts 'b' from 'a', returning the result and whether overflow occurred.
+export fn subi(a: int, b: int) (int, bool) = {
+ const res = a - b;
+ const overflow = a < 0 != b < 0 && a < 0 != res < 0;
+ return (res, overflow);
+};
+
+// Subtracts 'b' from 'a', returning the result and whether overflow occurred.
export fn subu8(a: u8, b: u8) (u8, bool) = {
const res = a - b;
const overflow = res > a;
@@ -272,6 +300,20 @@ export fn subu64(a: u64, b: u64) (u64, bool) = {
assert(overflow);
};
+// Subtracts 'b' from 'a', returning the result and whether overflow occurred.
+export fn subu(a: uint, b: uint) (uint, bool) = {
+ const res = a - b;
+ const overflow = res > a;
+ return (res, overflow);
+};
+
+// Subtracts 'b' from 'a', returning the result and whether overflow occurred.
+export fn subz(a: size, b: size) (size, bool) = {
+ const res = a - b;
+ const overflow = res > a;
+ return (res, overflow);
+};
+
// Multiplies 'a' and 'b' returning the result and whether overflow occurred.
export fn muli8(a: i8, b: i8) (i8, bool) = {
const fullres = a: int * b: int;
@@ -341,6 +383,17 @@ export fn muli64(a: i64, b: i64) (i64, bool) = {
};
// Multiplies 'a' and 'b' returning the result and whether overflow occurred.
+export fn muli(a: int, b: int) (int, bool) = {
+ if (size(int) == 4) {
+ const ret = muli32(a: i32, b: i32);
+ return (ret.0, ret.1);
+ } else {
+ const ret = muli64(a, b);
+ return (ret.0: int, ret.1);
+ };
+};
+
+// Multiplies 'a' and 'b' returning the result and whether overflow occurred.
export fn mulu8(a: u8, b: u8) (u8, bool) = {
const fullres = a: uint * b: uint;
const res = fullres: u8;
@@ -407,3 +460,25 @@ export fn mulu64(a: u64, b: u64) (u64, bool) = {
assert(res == 0);
assert(overflow);
};
+
+// Multiplies 'a' and 'b' returning the result and whether overflow occurred.
+export fn mulu(a: uint, b: uint) (uint, bool) = {
+ if (size(uint) == 4) {
+ const ret = mulu32(a: u32, b: u32);
+ return (ret.0, ret.1);
+ } else {
+ const ret = mulu64(a, b);
+ return (ret.0: uint, ret.1);
+ };
+};
+
+// Multiplies 'a' and 'b' returning the result and whether overflow occurred.
+export fn mulz(a: size, b: size) (size, bool) = {
+ if (size(size) == 4) {
+ const ret = mulu32(a: u32, b: u32);
+ return (ret.0, ret.1);
+ } else {
+ const ret = mulu64(a, b);
+ return (ret.0: size, ret.1);
+ };
+};
diff --git a/math/checked/saturating.ha b/math/checked/saturating.ha
@@ -65,6 +65,15 @@ export fn sat_addi64(a: i64, b: i64) i64 = {
};
// Computes the saturating addition of 'a' and 'b'.
+export fn sat_addi(a: int, b: int) int = {
+ const res = a + b;
+ if (a < 0 == b < 0 && a < 0 != res < 0) {
+ return if (res < 0) types::INT_MAX else types::INT_MIN;
+ };
+ return res;
+};
+
+// Computes the saturating addition of 'a' and 'b'.
export fn sat_addu8(a: u8, b: u8) u8 = {
return if (a + b < a) types::U8_MAX else a + b;
};
@@ -104,6 +113,16 @@ export fn sat_addu64(a: u64, b: u64) u64 = {
assert(sat_addu64(18446744073709551600, 50) == types::U64_MAX);
};
+// Computes the saturating addition of 'a' and 'b'.
+export fn sat_addu(a: uint, b: uint) uint = {
+ return if (a + b < a) types::UINT_MAX else a + b;
+};
+
+// Computes the saturating addition of 'a' and 'b'.
+export fn sat_addz(a: size, b: size) size = {
+ return if (a + b < a) types::SIZE_MAX else a + b;
+};
+
// Computes the saturating subtraction of 'b' from 'a'.
export fn sat_subi8(a: i8, b: i8) i8 = {
const res = a - b;
@@ -165,6 +184,15 @@ export fn sat_subi64(a: i64, b: i64) i64 = {
};
// Computes the saturating subtraction of 'b' from 'a'.
+export fn sat_subi(a: int, b: int) int = {
+ const res = a - b;
+ if (a < 0 != b < 0 && a < 0 != res < 0) {
+ return if (res < 0) types::INT_MAX else types::INT_MIN;
+ };
+ return res;
+};
+
+// Computes the saturating subtraction of 'b' from 'a'.
export fn sat_subu8(a: u8, b: u8) u8 = {
return if (a - b > a) types::U8_MIN else a - b;
};
@@ -204,6 +232,16 @@ export fn sat_subu64(a: u64, b: u64) u64 = {
assert(sat_subu64(44, 50) == types::U64_MIN);
};
+// Computes the saturating subtraction of 'b' from 'a'.
+export fn sat_subu(a: uint, b: uint) uint = {
+ return if (a - b > a) types::UINT_MIN else a - b;
+};
+
+// Computes the saturating subtraction of 'b' from 'a'.
+export fn sat_subz(a: size, b: size) size = {
+ return if (a - b > a) types::SIZE_MIN else a - b;
+};
+
// Computes the saturating multiplication of 'a' and 'b'.
export fn sat_muli8(a: i8, b: i8) i8 = {
const fullres = a: int * b: int;
@@ -276,6 +314,15 @@ export fn sat_muli64(a: i64, b: i64) i64 = {
};
// Computes the saturating multiplication of 'a' and 'b'.
+export fn sat_muli(a: int, b: int) int = {
+ if (size(int) == 4) {
+ return sat_muli32(a: i32, b: i32);
+ } else {
+ return sat_muli64(a, b): int;
+ };
+};
+
+// Computes the saturating multiplication of 'a' and 'b'.
export fn sat_mulu8(a: u8, b: u8) u8 = {
const res = a: uint * b: uint;
return if (res > types::U8_MAX) types::U8_MAX else res: u8;
@@ -318,3 +365,21 @@ export fn sat_mulu64(a: u64, b: u64) u64 = {
assert(sat_mulu64(4294967295, 4294967295) == 18446744065119617025);
assert(sat_mulu64(4294967296, 4294967296) == types::U64_MAX);
};
+
+// Computes the saturating multiplication of 'a' and 'b'.
+export fn sat_mulu(a: uint, b: uint) uint = {
+ if (size(uint) == 4) {
+ return sat_mulu32(a: u32, b: u32);
+ } else {
+ return sat_mulu64(a, b): uint;
+ };
+};
+
+// Computes the saturating multiplication of 'a' and 'b'.
+export fn sat_mulz(a: size, b: size) size = {
+ if (size(size) == 4) {
+ return sat_mulu32(a: u32, b: u32);
+ } else {
+ return sat_mulu64(a, b): size;
+ };
+};