Browse Source

big: Finish big ZII refactor.

Jeroen van Rijn 4 years ago
parent
commit
7648f2e655

+ 106 - 72
core/math/big/basic.odin

@@ -25,11 +25,19 @@ import "core:intrinsics"
 */
 */
 int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 	dest := dest; x := a; y := b;
 	dest := dest; x := a; y := b;
-	if dest == nil || a == nil || b == nil {
-		return .Nil_Pointer_Passed;
-	} else if !is_initialized(a) || !is_initialized(b) {
-		return .Int_Not_Initialized;
+	if err = clear_if_uninitialized(a); err != .None {
+		return err;
+	}
+	if err = clear_if_uninitialized(b); err != .None {
+		return err;
+	}
+	if err = clear_if_uninitialized(dest); err != .None {
+		return err;
 	}
 	}
+	/*
+		All parameters have been initialized.
+		We can now safely ignore errors from comparison routines.
+	*/
 
 
 	/*
 	/*
 		Handle both negative or both positive.
 		Handle both negative or both positive.
@@ -44,7 +52,7 @@ int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 		Subtract the one with the greater magnitude from the other.
 		Subtract the one with the greater magnitude from the other.
 		The result gets the sign of the one with the greater magnitude.
 		The result gets the sign of the one with the greater magnitude.
 	*/
 	*/
-	if cmp_mag(x, y) == .Less_Than {
+	if c, _ := cmp_mag(a, b); c == -1 {
 		x, y = y, x;
 		x, y = y, x;
 	}
 	}
 
 
@@ -60,11 +68,22 @@ int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 */
 */
 int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 	dest := dest; digit := digit;
 	dest := dest; digit := digit;
-	if dest == nil || a == nil {
-		return .Nil_Pointer_Passed;
-	} else if !is_initialized(a) {
-		return .Int_Not_Initialized;
+	if err = clear_if_uninitialized(a); err != .None {
+		return err;
 	}
 	}
+	/*
+		Grow destination as required.
+	*/
+	if dest != a {
+		if err = grow(dest, a.used + 1); err != .None {
+			return err;
+		}
+	}
+	/*
+		All parameters have been initialized.
+		We can now safely ignore errors from comparison routines.
+	*/
+
 	/*
 	/*
 		Fast paths for destination and input Int being the same.
 		Fast paths for destination and input Int being the same.
 	*/
 	*/
@@ -72,46 +91,44 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 		/*
 		/*
 			Fast path for dest.digit[0] + digit fits in dest.digit[0] without overflow.
 			Fast path for dest.digit[0] + digit fits in dest.digit[0] without overflow.
 		*/
 		*/
-		if is_pos(dest) && (dest.digit[0] + digit < _DIGIT_MAX) {
+		if p, _ := is_pos(dest); p && (dest.digit[0] + digit < _DIGIT_MAX) {
 			dest.digit[0] += digit;
 			dest.digit[0] += digit;
-			return .OK;
+			return .None;
 		}
 		}
 		/*
 		/*
 			Can be subtracted from dest.digit[0] without underflow.
 			Can be subtracted from dest.digit[0] without underflow.
 		*/
 		*/
-		if is_neg(a) && (dest.digit[0] > digit) {
+		if n, _ := is_neg(a); n && (dest.digit[0] > digit) {
 			dest.digit[0] -= digit;
 			dest.digit[0] -= digit;
-			return .OK;
+			return .None;
 		}
 		}
 	}
 	}
 
 
-	/*
-		Grow destination as required.
-	*/
-	if err = grow(dest, a.used + 1); err != .OK {
-		return err;
-	}
-
 	/*
 	/*
 		If `a` is negative and `|a|` >= `digit`, call `dest = |a| - digit`
 		If `a` is negative and `|a|` >= `digit`, call `dest = |a| - digit`
 	*/
 	*/
-	if is_neg(a) && (a.used > 1 || a.digit[0] >= digit) {
+	if n, _ := is_neg(a); n && (a.used > 1 || a.digit[0] >= digit) {
 		/*
 		/*
 			Temporarily fix `a`'s sign.
 			Temporarily fix `a`'s sign.
 		*/
 		*/
-		t := a;
-		t.sign = .Zero_or_Positive;
+		a.sign = .Zero_or_Positive;
 		/*
 		/*
 			dest = |a| - digit
 			dest = |a| - digit
 		*/
 		*/
-		err = sub(dest, t, digit);
+		if err = sub(dest, a, digit); err != .None {
+			/*
+				Restore a's sign.
+			*/
+			a.sign = .Negative;
+			return err;
+		}
 		/*
 		/*
 			Restore sign and set `dest` sign.
 			Restore sign and set `dest` sign.
 		*/
 		*/
+		a.sign    = .Negative;
 		dest.sign = .Negative;
 		dest.sign = .Negative;
-		clamp(dest);
 
 
-		return err;
+		return clamp(dest);
 	}
 	}
 
 
 	/*
 	/*
@@ -122,7 +139,7 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 	/*
 	/*
 		If `a` is positive
 		If `a` is positive
 	*/
 	*/
-	if is_pos(a) {
+	if p, _ := is_pos(a); p {
 		/*
 		/*
 			Add digits, use `carry`.
 			Add digits, use `carry`.
 		*/
 		*/
@@ -166,9 +183,7 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 	/*
 	/*
 		Adjust dest.used based on leading zeroes.
 		Adjust dest.used based on leading zeroes.
 	*/
 	*/
-	clamp(dest);
-
-	return .OK;
+	return clamp(dest);
 }
 }
 
 
 /*
 /*
@@ -176,11 +191,19 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 */
 */
 int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 	dest := dest; x := number; y := decrease;
 	dest := dest; x := number; y := decrease;
-	if dest == nil || number == nil || decrease == nil {
-		return .Nil_Pointer_Passed;
-	} else if !(is_initialized(number) && is_initialized(decrease)) {
-		return .Int_Not_Initialized;
+	if err = clear_if_uninitialized(dest); err != .None {
+		return err;
+	}
+	if err = clear_if_uninitialized(x); err != .None {
+		return err;
 	}
 	}
+	if err = clear_if_uninitialized(y); err != .None {
+		return err;
+	}
+	/*
+		All parameters have been initialized.
+		We can now safely ignore errors from comparison routines.
+	*/
 
 
 	if x.sign != y.sign {
 	if x.sign != y.sign {
 		/*
 		/*
@@ -195,12 +218,16 @@ int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 		Subtract a positive from a positive, OR negative from a negative.
 		Subtract a positive from a positive, OR negative from a negative.
 		First, take the difference between their magnitudes, then...
 		First, take the difference between their magnitudes, then...
 	*/
 	*/
-	if cmp_mag(x, y) == .Less_Than {
+	if c, _ := cmp_mag(x, y); c == -1 {
 		/*
 		/*
 			The second has a larger magnitude.
 			The second has a larger magnitude.
 			The result has the *opposite* sign from the first number.
 			The result has the *opposite* sign from the first number.
 		*/
 		*/
-		dest.sign = .Negative if is_pos(x) else .Zero_or_Positive;
+		if p, _ := is_pos(x); p {
+			dest.sign = .Negative;
+		} else {
+			dest.sign = .Zero_or_Positive;
+		}
 		x, y = y, x;
 		x, y = y, x;
 	} else {
 	} else {
 		/*
 		/*
@@ -220,11 +247,21 @@ int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 */
 */
 int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 	dest := dest; digit := digit;
 	dest := dest; digit := digit;
-	if dest == nil || a == nil {
-		return .Nil_Pointer_Passed;
-	} else if !is_initialized(a) {
-		return .Int_Not_Initialized;
+	if err = clear_if_uninitialized(dest); err != .None {
+		return err;
+	}
+	/*
+		Grow destination as required.
+	*/
+	if dest != a {
+		if err = grow(dest, a.used + 1); err != .None {
+			return err;
+		}
 	}
 	}
+	/*
+		All parameters have been initialized.
+		We can now safely ignore errors from comparison routines.
+	*/
 
 
 	/*
 	/*
 		Fast paths for destination and input Int being the same.
 		Fast paths for destination and input Int being the same.
@@ -233,31 +270,23 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 		/*
 		/*
 			Fast path for `dest` is negative and unsigned addition doesn't overflow the lowest digit.
 			Fast path for `dest` is negative and unsigned addition doesn't overflow the lowest digit.
 		*/
 		*/
-		if is_neg(dest) && (dest.digit[0] + digit < _DIGIT_MAX) {
+		if n, _ := is_neg(dest); n && (dest.digit[0] + digit < _DIGIT_MAX) {
 			dest.digit[0] += digit;
 			dest.digit[0] += digit;
-			return .OK;
+			return .None;
 		}
 		}
 		/*
 		/*
 			Can be subtracted from dest.digit[0] without underflow.
 			Can be subtracted from dest.digit[0] without underflow.
 		*/
 		*/
-		if is_pos(a) && (dest.digit[0] > digit) {
+		if p, _ := is_pos(a); p && (dest.digit[0] > digit) {
 			dest.digit[0] -= digit;
 			dest.digit[0] -= digit;
-			return .OK;
+			return .None;
 		}
 		}
 	}
 	}
 
 
-	/*
-		Grow destination as required.
-	*/
-	err = grow(dest, a.used + 1);
-	if err != .OK {
-		return err;
-	}
-
 	/*
 	/*
 		If `a` is negative, just do an unsigned addition (with fudged signs).
 		If `a` is negative, just do an unsigned addition (with fudged signs).
 	*/
 	*/
-	if is_neg(a) {
+	if n, _ := is_neg(a); n {
 		t := a;
 		t := a;
 		t.sign = .Zero_or_Positive;
 		t.sign = .Zero_or_Positive;
 
 
@@ -273,7 +302,9 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 	/*
 	/*
 		if `a`<= digit, simply fix the single digit.
 		if `a`<= digit, simply fix the single digit.
 	*/
 	*/
-	if a.used == 1 && (a.digit[0] <= digit || is_zero(a)) {
+	z, _ := is_zero(a);
+
+	if a.used == 1 && (a.digit[0] <= digit) || z {
 		dest.digit[0] = digit - a.digit[0] if a.used == 1 else digit;
 		dest.digit[0] = digit - a.digit[0] if a.used == 1 else digit;
 		dest.sign = .Negative;
 		dest.sign = .Negative;
 		dest.used = 1;
 		dest.used = 1;
@@ -303,9 +334,7 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 	/*
 	/*
 		Adjust dest.used based on leading zeroes.
 		Adjust dest.used based on leading zeroes.
 	*/
 	*/
-	clamp(dest);
-
-	return .OK;
+	return clamp(dest);
 }
 }
 
 
 /*
 /*
@@ -320,10 +349,11 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 */
 */
 _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 	dest := dest; x := a; y := b;
 	dest := dest; x := a; y := b;
-	if dest == nil || a == nil || b == nil {
-		return .Nil_Pointer_Passed;
-	} else if !is_initialized(a) || !is_initialized(b) {
-		return .Int_Not_Initialized;
+	if err = clear_if_uninitialized(x); err != .None {
+		return err;
+	}
+	if err = clear_if_uninitialized(y); err != .None {
+		return err;
 	}
 	}
 
 
 	old_used, min_used, max_used, i: int;
 	old_used, min_used, max_used, i: int;
@@ -336,10 +366,13 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 	max_used = y.used;
 	max_used = y.used;
 	old_used = dest.used;
 	old_used = dest.used;
 
 
-	if err = grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)); err != .OK {
+	if err = grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)); err != .None {
 		return err;
 		return err;
 	}
 	}
 	dest.used = max_used + 1;
 	dest.used = max_used + 1;
+	/*
+		All parameters have been initialized.
+	*/
 
 
 	/* Zero the carry */
 	/* Zero the carry */
 	carry := DIGIT(0);
 	carry := DIGIT(0);
@@ -393,9 +426,7 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 	/*
 	/*
 		Adjust dest.used based on leading zeroes.
 		Adjust dest.used based on leading zeroes.
 	*/
 	*/
-	clamp(dest);
-
-	return .OK;
+	return clamp(dest);
 }
 }
 
 
 /*
 /*
@@ -404,10 +435,11 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 */
 */
 _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 	dest := dest; x := number; y := decrease;
 	dest := dest; x := number; y := decrease;
-	if dest == nil || number == nil || decrease == nil {
-		return .Nil_Pointer_Passed;
-	} else if !is_initialized(number) || !is_initialized(decrease) {
-		return .Int_Not_Initialized;
+	if err = clear_if_uninitialized(x); err != .None {
+		return err;
+	}
+	if err = clear_if_uninitialized(y); err != .None {
+		return err;
 	}
 	}
 
 
 	old_used := dest.used;
 	old_used := dest.used;
@@ -415,10 +447,13 @@ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 	max_used := x.used;
 	max_used := x.used;
 	i: int;
 	i: int;
 
 
-	if err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)); err != .OK {
+	if err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)); err != .None {
 		return err;
 		return err;
 	}
 	}
 	dest.used = max_used;
 	dest.used = max_used;
+	/*
+		All parameters have been initialized.
+	*/
 
 
 	borrow := DIGIT(0);
 	borrow := DIGIT(0);
 
 
@@ -465,6 +500,5 @@ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 	/*
 	/*
 		Adjust dest.used based on leading zeroes.
 		Adjust dest.used based on leading zeroes.
 	*/
 	*/
-	clamp(dest);
-	return .OK;
+	return clamp(dest);
 }
 }

+ 15 - 21
core/math/big/bigint.odin → core/math/big/common.odin

@@ -53,27 +53,21 @@ Int :: struct {
 	sign:      Sign,
 	sign:      Sign,
 };
 };
 
 
-Comparison_Flag :: enum i8 {
-	Less_Than     = -1,
-	Equal         =  0,
-	Greater_Than  =  1,
-
-	/* One of the numbers was uninitialized */
-	Uninitialized = -127,
-};
-
-Error :: enum i8 {
-	OK                     =  0,
-	Unknown_Error          = -1,
-	Out_of_Memory          = -2,
-	Invalid_Input          = -3,
-	Max_Iterations_Reached = -4,
-	Buffer_Overflow        = -5,
-	Integer_Overflow       = -6,
-	Nil_Pointer_Passed     = -7,
-	Int_Not_Initialized    = -8,
-
-	Unimplemented          = -127,
+/*
+	Errors are a strict superset of runtime.Allocation_Error.
+*/
+Error :: enum byte {
+	None                   = 0,
+	Out_Of_Memory          = 1,
+	Invalid_Pointer        = 2,
+	Invalid_Argument       = 3,
+
+	Unknown_Error          = 4,
+	Max_Iterations_Reached = 5,
+	Buffer_Overflow        = 6,
+	Integer_Overflow       = 7,
+
+	Unimplemented          = 127,
 };
 };
 
 
 Primality_Flag :: enum u8 {
 Primality_Flag :: enum u8 {

+ 96 - 46
core/math/big/compare.odin

@@ -22,61 +22,83 @@ int_is_initialized :: proc(a: ^Int) -> bool {
 	return raw.cap >= _MIN_DIGIT_COUNT;
 	return raw.cap >= _MIN_DIGIT_COUNT;
 }
 }
 
 
-int_is_zero :: proc(a: ^Int) -> bool {
-	return is_initialized(a) && a.used == 0;
+int_is_zero :: proc(a: ^Int) -> (res: bool, err: Error) {
+	if err = clear_if_uninitialized(a); err != .None {
+		return false, err;
+	}
+	return a.used == 0, .None;
 }
 }
 
 
-int_is_positive :: proc(a: ^Int) -> bool {
-	return is_initialized(a) && a.sign == .Zero_or_Positive;
+int_is_positive :: proc(a: ^Int) -> (res: bool, err: Error) {
+	if err = clear_if_uninitialized(a); err != .None {
+		return false, err;
+	}
+	return a.sign == .Zero_or_Positive, .None;
 }
 }
 
 
-int_is_negative :: proc(a: ^Int) -> bool {
-	return is_initialized(a) && a.sign == .Negative;
+int_is_negative :: proc(a: ^Int) -> (res: bool, err: Error) {
+	if err = clear_if_uninitialized(a); err != .None {
+		return false, err;
+	}
+	return a.sign == .Negative, .None;
 }
 }
 
 
-int_is_even :: proc(a: ^Int) -> bool {
-	if is_initialized(a) {
-		if is_zero(a) {
-			return true;
-		}
-		if a.used > 0 && a.digit[0] & 1 == 0 {
-			return true;
-		}
+int_is_even :: proc(a: ^Int) -> (res: bool, err: Error) {
+	if err = clear_if_uninitialized(a); err != .None {
+		return false, err;
+	}
+
+	res, err = is_zero(a);
+	if err != .None {
+		return false, err;
+	} else if res == true {
+		return true, .None;
+	}
+
+	res = false;
+	if a.used > 0 && a.digit[0] & 1 == 0 {
+		res = true;
 	}
 	}
-	return false;
+	return res, .None;
 }
 }
 
 
-int_is_odd :: proc(a: ^Int) -> bool {
-	if is_initialized(a) {
-		return !is_even(a);
+int_is_odd :: proc(a: ^Int) -> (res: bool, err: Error) {
+	if err = clear_if_uninitialized(a); err != .None {
+		return false, err;
 	}
 	}
-	return false;
+
+	res, err = is_even(a);
+	return !res, err;
 }
 }
 
 
 platform_int_is_power_of_two :: proc(a: int) -> bool {
 platform_int_is_power_of_two :: proc(a: int) -> bool {
 	return ((a) != 0) && (((a) & ((a) - 1)) == 0);
 	return ((a) != 0) && (((a) & ((a) - 1)) == 0);
 }
 }
 
 
-int_is_power_of_two :: proc(a: ^Int) -> (res: bool) {
+int_is_power_of_two :: proc(a: ^Int) -> (res: bool, err: Error) {
+	if err = clear_if_uninitialized(a); err != .None {
+		return false, err;
+	}
+
 	/*
 	/*
 		Early out for Int == 0.
 		Early out for Int == 0.
 	*/
 	*/
 	if a.used == 0 {
 	if a.used == 0 {
-		return false;
+		return false, .None;
 	}
 	}
 
 
 	/*
 	/*
 		For an `Int` to be a power of two, its top limb has to be a power of two.
 		For an `Int` to be a power of two, its top limb has to be a power of two.
 	*/
 	*/
 	if !platform_int_is_power_of_two(int(a.digit[a.used - 1])) {
 	if !platform_int_is_power_of_two(int(a.digit[a.used - 1])) {
-		return false;
+		return false, .None;
 	}
 	}
 
 
 	/*
 	/*
 		That was the only limb, so it's a power of two.
 		That was the only limb, so it's a power of two.
 	*/
 	*/
 	if a.used == 1 {
 	if a.used == 1 {
-		return true;
+		return true, .None;
 	}
 	}
 
 
 	/*
 	/*
@@ -84,74 +106,102 @@ int_is_power_of_two :: proc(a: ^Int) -> (res: bool) {
 	*/
 	*/
 	for i := 1; i < a.used; i += 1 {
 	for i := 1; i < a.used; i += 1 {
 		if a.digit[i - 1] != 0 {
 		if a.digit[i - 1] != 0 {
-			return false;
+			return false, .None;
 		}
 		}
 	}
 	}
-	return true;
+	return true, .None;
 }
 }
 
 
 /*
 /*
 	Compare two `Int`s, signed.
 	Compare two `Int`s, signed.
 */
 */
-int_compare :: proc(a, b: ^Int) -> Comparison_Flag {
-	if !is_initialized(a) { return .Uninitialized; }
-	if !is_initialized(b) { return .Uninitialized; }
+int_compare :: proc(a, b: ^Int) -> (res: int, err: Error) {
+	if err = clear_if_uninitialized(a); err != .None {
+		return 0, err;
+	}
+	if err = clear_if_uninitialized(b); err != .None {
+		return 0, err;
+	}
+
+	neg: bool;
+	if neg, err = is_negative(a); err != .None {
+		return 0, err;
+	}
 
 
 	/* Compare based on sign */
 	/* Compare based on sign */
 	if a.sign != b.sign {
 	if a.sign != b.sign {
-		return .Less_Than if is_negative(a) else .Greater_Than;
+		res = -1 if neg else +1;
+		return res, .None;
 	}
 	}
 
 
-	x, y := a, b;
 	/* If negative, compare in the opposite direction */
 	/* If negative, compare in the opposite direction */
-	if is_neg(a) {
-		x, y = b, a;
+	if neg {
+		return cmp_mag(b, a);
 	}
 	}
-	return cmp_mag(x, y);
+	return cmp_mag(a, b);
 }
 }
 
 
 /*
 /*
 	Compare an `Int` to an unsigned number upto the size of the backing type.
 	Compare an `Int` to an unsigned number upto the size of the backing type.
 */
 */
-int_compare_digit :: proc(a: ^Int, u: DIGIT) -> Comparison_Flag {
-	if !is_initialized(a) { return .Uninitialized; }
+int_compare_digit :: proc(a: ^Int, u: DIGIT) -> (res: int, err: Error) {
+	if err = clear_if_uninitialized(a); err != .None {
+		return 0, err;
+	}
 
 
 	/* Compare based on sign */
 	/* Compare based on sign */
-	if is_neg(a) {
-		return .Less_Than;
+	neg: bool;
+	if neg, err = is_neg(a); err != .None {
+		return 0, err;
+	}
+	if neg {
+		return -1, .None;
 	}
 	}
 
 
 	/* Compare based on magnitude */
 	/* Compare based on magnitude */
 	if a.used > 1 {
 	if a.used > 1 {
-		return .Greater_Than;
+		return +1, .None;
 	}
 	}
 
 
 	/* Compare the only digit in `a` to `u`. */
 	/* Compare the only digit in `a` to `u`. */
 	if a.digit[0] != u {
 	if a.digit[0] != u {
-		return .Greater_Than if a.digit[0] > u else .Less_Than;
+		if a.digit[0] > u {
+			return +1, .None;
+		}
+		return -1, .None;
 	}
 	}
 
 
-	return .Equal;
+	return 0, .None;
 }
 }
 
 
 /*
 /*
 	Compare the magnitude of two `Int`s, unsigned.
 	Compare the magnitude of two `Int`s, unsigned.
 */
 */
-int_compare_magnitude :: proc(a, b: ^Int) -> Comparison_Flag {
-	if !is_initialized(a) { return .Uninitialized; }
-	if !is_initialized(b) { return .Uninitialized; }
+int_compare_magnitude :: proc(a, b: ^Int) -> (res: int, err: Error) {
+	if err = clear_if_uninitialized(a); err != .None {
+		return 0, err;
+	}
+	if err = clear_if_uninitialized(b); err != .None {
+		return 0, err;
+	}
 
 
 	/* Compare based on used digits */
 	/* Compare based on used digits */
 	if a.used != b.used {
 	if a.used != b.used {
-		return .Greater_Than if a.used > b.used else .Less_Than;
+		if a.used > b.used {
+			return +1, .None;
+		}
+		return -1, .None;
 	}
 	}
 
 
 	/* Same number of used digits, compare based on their value */
 	/* Same number of used digits, compare based on their value */
 	for n := a.used - 1; n >= 0; n -= 1 {
 	for n := a.used - 1; n >= 0; n -= 1 {
 		if a.digit[n] != b.digit[n] {
 		if a.digit[n] != b.digit[n] {
-			return .Greater_Than if a.digit[n] > b.digit[n] else .Less_Than;
+			if a.digit[n] > b.digit[n] {
+				return +1, .None;
+			}
+			return -1, .None;
 		}
 		}
 	}
 	}
 
 
-   	return .Equal;
+   	return 0, .None;
 }
 }

+ 3 - 3
core/math/big/example.odin

@@ -44,7 +44,7 @@ _SQR_TOOM_CUTOFF,
 print :: proc(name: string, a: ^Int, base := i8(16)) {
 print :: proc(name: string, a: ^Int, base := i8(16)) {
 	as, err := itoa(a, base);
 	as, err := itoa(a, base);
 	defer delete(as);
 	defer delete(as);
-	if err == .OK {
+	if err == .None {
 		cb, _ := count_bits(a);
 		cb, _ := count_bits(a);
 		fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, cb, as);
 		fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, cb, as);
 	} else {
 	} else {
@@ -80,10 +80,10 @@ demo :: proc() {
 	print("c", c);
 	print("c", c);
 
 
 	fmt.println("\n\n=== Set a to (1 << 120) - 1 ===");
 	fmt.println("\n\n=== Set a to (1 << 120) - 1 ===");
-	if err = power_of_two(a, 120); err != .OK {
+	if err = power_of_two(a, 120); err != .None {
 		fmt.printf("Error %v while setting a to 1 << 120.\n", err);
 		fmt.printf("Error %v while setting a to 1 << 120.\n", err);
 	}
 	}
-	if err = sub(a, a, 1); err != .OK {
+	if err = sub(a, a, 1); err != .None {
 		fmt.printf("Error %v while subtracting 1 from a\n", err);	
 		fmt.printf("Error %v while subtracting 1 from a\n", err);	
 	}
 	}
 	print("a", a, 16);
 	print("a", a, 16);

+ 62 - 83
core/math/big/helpers.odin

@@ -30,15 +30,10 @@ int_destroy :: proc(integers: ..^Int) {
 int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator := context.allocator) -> (err: Error)
 int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator := context.allocator) -> (err: Error)
 	where intrinsics.type_is_integer(T) {
 	where intrinsics.type_is_integer(T) {
 	src := src;
 	src := src;
-	/*
-		Check that dest is usable.
-	*/
-	if dest == nil {
-		return .Nil_Pointer_Passed;
+	if err = clear_if_uninitialized(dest); err != .None {
+		return err;
 	}
 	}
 
 
-	if err = _grow_if_uninitialized(dest, minimize); err != .OK { return err; }
-
 	dest.used = 0;
 	dest.used = 0;
 	dest.sign = .Zero_or_Positive if src >= 0 else .Negative;
 	dest.sign = .Zero_or_Positive if src >= 0 else .Negative;
 	src = abs(src);
 	src = abs(src);
@@ -49,7 +44,7 @@ int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator :
 		src >>= _DIGIT_BITS;
 		src >>= _DIGIT_BITS;
 	}
 	}
 	_zero_unused(dest);
 	_zero_unused(dest);
-	return .OK;
+	return .None;
 }
 }
 
 
 set :: proc { int_set_from_integer, int_copy };
 set :: proc { int_set_from_integer, int_copy };
@@ -58,27 +53,20 @@ set :: proc { int_set_from_integer, int_copy };
 	Copy one `Int` to another.
 	Copy one `Int` to another.
 */
 */
 int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
-	/*
-		Check that src and dest are usable.
-	*/
-	if dest == nil || src == nil {
-		return .Nil_Pointer_Passed;
-	} else if !is_initialized(src) {
-		return .Int_Not_Initialized;
+	if err = clear_if_uninitialized(src); err != .None {
+		return err;
 	}
 	}
-
 	/*
 	/*
 		If dest == src, do nothing
 		If dest == src, do nothing
 	*/
 	*/
 	if (dest == src) {
 	if (dest == src) {
-		return .OK;
+		return .None;
 	}
 	}
-
 	/*
 	/*
 		Grow `dest` to fit `src`.
 		Grow `dest` to fit `src`.
 		If `dest` is not yet initialized, it will be using `allocator`.
 		If `dest` is not yet initialized, it will be using `allocator`.
 	*/
 	*/
-	if err = grow(dest, src.used, false, allocator); err != .OK {
+	if err = grow(dest, src.used, false, allocator); err != .None {
 		return err;
 		return err;
 	}
 	}
 
 
@@ -91,7 +79,7 @@ int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error
 	dest.used = src.used;
 	dest.used = src.used;
 	dest.sign = src.sign;
 	dest.sign = src.sign;
 	_zero_unused(dest);
 	_zero_unused(dest);
-	return .OK;
+	return .None;
 }
 }
 copy :: proc { int_copy, };
 copy :: proc { int_copy, };
 
 
@@ -100,26 +88,23 @@ copy :: proc { int_copy, };
 */
 */
 int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 	/*
 	/*
-		Check that src and dest are usable.
+		Check that src is usable.
 	*/
 	*/
-	if dest == nil || src == nil {
-		return .Nil_Pointer_Passed;
-	} else if !is_initialized(src) {
-		return .Int_Not_Initialized;
+	if err = clear_if_uninitialized(src); err != .None {
+		return err;
 	}
 	}
-
 	/*
 	/*
 		If `dest == src`, just fix `dest`'s sign.
 		If `dest == src`, just fix `dest`'s sign.
 	*/
 	*/
 	if (dest == src) {
 	if (dest == src) {
 		dest.sign = .Zero_or_Positive;
 		dest.sign = .Zero_or_Positive;
-		return .OK;
+		return .None;
 	}
 	}
 
 
 	/*
 	/*
 		Copy `src` to `dest`
 		Copy `src` to `dest`
 	*/
 	*/
-	if err = copy(dest, src, allocator); err != .OK {
+	if err = copy(dest, src, allocator); err != .None {
 		return err;
 		return err;
 	}
 	}
 
 
@@ -127,7 +112,7 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
 		Fix sign.
 		Fix sign.
 	*/
 	*/
 	dest.sign = .Zero_or_Positive;
 	dest.sign = .Zero_or_Positive;
-	return .OK;
+	return .None;
 }
 }
 
 
 platform_abs :: proc(n: $T) -> T where intrinsics.type_is_integer(T) {
 platform_abs :: proc(n: $T) -> T where intrinsics.type_is_integer(T) {
@@ -140,27 +125,29 @@ abs :: proc{int_abs, platform_abs};
 */
 */
 neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 	/*
 	/*
-		Check that src and dest are usable.
+		Check that src is usable.
 	*/
 	*/
-	if dest == nil || src == nil {
-		return .Nil_Pointer_Passed;
-	} else if !is_initialized(src) {
-		return .Int_Not_Initialized;
+	if err = clear_if_uninitialized(src); err != .None {
+		return err;
 	}
 	}
-
 	/*
 	/*
 		If `dest == src`, just fix `dest`'s sign.
 		If `dest == src`, just fix `dest`'s sign.
 	*/
 	*/
-	sign := Sign.Negative if !(is_zero(src) && is_neg(src)) else Sign.Zero_or_Positive;
-	if dest == src {
+	sign := Sign.Zero_or_Positive;
+	if z, _ := is_zero(src); z {
+		sign = .Negative;
+	}
+	if n, _ := is_neg(src); n {
+		sign = .Negative;
+	}
+	if (dest == src) {
 		dest.sign = sign;
 		dest.sign = sign;
-		return .OK;
+		return .None;
 	}
 	}
-
 	/*
 	/*
 		Copy `src` to `dest`
 		Copy `src` to `dest`
 	*/
 	*/
-	if err = copy(dest, src, allocator); err != .OK {
+	if err = copy(dest, src, allocator); err != .None {
 		return err;
 		return err;
 	}
 	}
 
 
@@ -168,7 +155,7 @@ neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 		Fix sign.
 		Fix sign.
 	*/
 	*/
 	dest.sign = sign;
 	dest.sign = sign;
-	return .OK;
+	return .None;
 }
 }
 
 
 /*
 /*
@@ -176,22 +163,20 @@ neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 */
 */
 extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
 extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
 	/*
 	/*
-		Check that `a` is usable.
+		Check that `a`is usable.
 	*/
 	*/
-	if a == nil {
-		return 0, .Nil_Pointer_Passed;
-	} else if !is_initialized(a) {
-		return 0, .Int_Not_Initialized;
+	if err = clear_if_uninitialized(a); err != .None {
+		return 0, err;
 	}
 	}
 
 
 	limb := bit_offset / _DIGIT_BITS;
 	limb := bit_offset / _DIGIT_BITS;
 	if limb < 0 || limb >= a.used {
 	if limb < 0 || limb >= a.used {
-		return 0, .Invalid_Input;
+		return 0, .Invalid_Argument;
 	}
 	}
 
 
 	i := DIGIT(1 << DIGIT((bit_offset % _DIGIT_BITS)));
 	i := DIGIT(1 << DIGIT((bit_offset % _DIGIT_BITS)));
 
 
-	return 1 if ((a.digit[limb] & i) != 0) else 0, .OK;
+	return 1 if ((a.digit[limb] & i) != 0) else 0, .None;
 }
 }
 
 
 /*
 /*
@@ -199,16 +184,14 @@ extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
 */
 */
 extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
 extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
 	/*
 	/*
-		Check that `a` is usable.
+		Check that `a`is usable.
 	*/
 	*/
-	if a == nil {
-		return 0, .Nil_Pointer_Passed;
-	} else if !is_initialized(a) {
-		return 0, .Int_Not_Initialized;
+	if err = clear_if_uninitialized(a); err != .None {
+		return 0, err;
 	}
 	}
 
 
 	if count > _WORD_BITS || count < 1 {
 	if count > _WORD_BITS || count < 1 {
-		return 0, .Invalid_Input;
+		return 0, .Invalid_Argument;
 	}
 	}
 
 
 	v: DIGIT;
 	v: DIGIT;
@@ -216,7 +199,7 @@ extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
 	for shift := 0; shift < count; shift += 1 {
 	for shift := 0; shift < count; shift += 1 {
 		o   := offset + shift;
 		o   := offset + shift;
 		v, e = extract_bit(a, o);
 		v, e = extract_bit(a, o);
-		if e != .OK {
+		if e != .None {
 			break;
 			break;
 		}
 		}
 		res = res + _WORD(v) << uint(shift);
 		res = res + _WORD(v) << uint(shift);
@@ -230,7 +213,7 @@ extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
 */
 */
 shrink :: proc(a: ^Int) -> (err: Error) {
 shrink :: proc(a: ^Int) -> (err: Error) {
 	if a == nil {
 	if a == nil {
-		return .Nil_Pointer_Passed;
+		return .Invalid_Pointer;
 	}
 	}
 
 
 	needed := max(_MIN_DIGIT_COUNT, a.used);
 	needed := max(_MIN_DIGIT_COUNT, a.used);
@@ -238,12 +221,12 @@ shrink :: proc(a: ^Int) -> (err: Error) {
 	if a.used != needed {
 	if a.used != needed {
 		return grow(a, needed);
 		return grow(a, needed);
 	}
 	}
-	return .OK;
+	return .None;
 }
 }
 
 
 int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) {
 int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) {
 	if a == nil {
 	if a == nil {
-		return .Nil_Pointer_Passed;
+		return .Invalid_Pointer;
 	}
 	}
 	raw := transmute(mem.Raw_Dynamic_Array)a.digit;
 	raw := transmute(mem.Raw_Dynamic_Array)a.digit;
 
 
@@ -269,9 +252,9 @@ int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := conte
 		Let's see if the allocation/resize worked as expected.
 		Let's see if the allocation/resize worked as expected.
 	*/
 	*/
 	if len(a.digit) != needed {
 	if len(a.digit) != needed {
-		return .Out_of_Memory;
+		return .Out_Of_Memory;
 	}
 	}
-	return .OK;
+	return .None;
 }
 }
 grow :: proc { int_grow, };
 grow :: proc { int_grow, };
 
 
@@ -280,7 +263,7 @@ grow :: proc { int_grow, };
 */
 */
 int_clear :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
 int_clear :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
 	if a == nil {
 	if a == nil {
-		return .Nil_Pointer_Passed;
+		return .Invalid_Pointer;
 	}
 	}
 
 
 	raw := transmute(mem.Raw_Dynamic_Array)a.digit;
 	raw := transmute(mem.Raw_Dynamic_Array)a.digit;
@@ -299,14 +282,14 @@ zero  :: clear;
 	Set the `Int` to 1 and optionally shrink it to the minimum backing size.
 	Set the `Int` to 1 and optionally shrink it to the minimum backing size.
 */
 */
 int_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
 int_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
-	if err = clear(a, minimize, allocator); err != .OK {
+	if err = clear(a, minimize, allocator); err != .None {
 		return err;
 		return err;
 	}
 	}
 
 
 	a.used     = 1;
 	a.used     = 1;
 	a.digit[0] = 1;
 	a.digit[0] = 1;
 	a.sign     = .Zero_or_Positive;
 	a.sign     = .Zero_or_Positive;
-	return .OK;
+	return .None;
 }
 }
 one :: proc { int_one, };
 one :: proc { int_one, };
 
 
@@ -314,14 +297,14 @@ one :: proc { int_one, };
 	Set the `Int` to -1 and optionally shrink it to the minimum backing size.
 	Set the `Int` to -1 and optionally shrink it to the minimum backing size.
 */
 */
 int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
 int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
-	if err = clear(a, minimize, allocator); err != .OK {
+	if err = clear(a, minimize, allocator); err != .None {
 		return err;
 		return err;
 	}
 	}
 
 
 	a.used     = 1;
 	a.used     = 1;
 	a.digit[0] = 1;
 	a.digit[0] = 1;
 	a.sign     = .Negative;
 	a.sign     = .Negative;
-	return .OK;
+	return .None;
 }
 }
 minus_one :: proc { int_minus_one, };
 minus_one :: proc { int_minus_one, };
 
 
@@ -332,18 +315,18 @@ power_of_two :: proc(a: ^Int, power: int) -> (err: Error) {
 		Check that `a` is usable.
 		Check that `a` is usable.
 	*/
 	*/
 	if a == nil {
 	if a == nil {
-		return .Nil_Pointer_Passed;
+		return .Invalid_Pointer;
 	}
 	}
 
 
 	if power < 0 || power > _MAX_BIT_COUNT {
 	if power < 0 || power > _MAX_BIT_COUNT {
-		return .Invalid_Input;
+		return .Invalid_Argument;
 	}
 	}
 
 
 	/*
 	/*
 		Grow to accomodate the single bit.
 		Grow to accomodate the single bit.
 	*/
 	*/
 	a.used = (power / _DIGIT_BITS) + 1;
 	a.used = (power / _DIGIT_BITS) + 1;
-	if err = grow(a, a.used); err != .OK {
+	if err = grow(a, a.used); err != .None {
 		return err;
 		return err;
 	}
 	}
 	/*
 	/*
@@ -355,23 +338,21 @@ power_of_two :: proc(a: ^Int, power: int) -> (err: Error) {
 		Set the bit.
 		Set the bit.
 	*/
 	*/
 	a.digit[power / _DIGIT_BITS] = 1 << uint((power % _DIGIT_BITS));
 	a.digit[power / _DIGIT_BITS] = 1 << uint((power % _DIGIT_BITS));
-   	return .OK;
+   	return .None;
 }
 }
 
 
 /*
 /*
 	Count bits in an `Int`.
 	Count bits in an `Int`.
 */
 */
 count_bits :: proc(a: ^Int) -> (count: int, err: Error) {
 count_bits :: proc(a: ^Int) -> (count: int, err: Error) {
-	if a == nil {
-		return 0, .Nil_Pointer_Passed;
-	} else if !is_initialized(a) {
-		return 0, .Int_Not_Initialized;
+	if err = clear_if_uninitialized(a); err != .None {
+		return 0, err;
 	}
 	}
 	/*
 	/*
 		Fast path for zero.
 		Fast path for zero.
 	*/
 	*/
-	if is_zero(a) {
-		return 0, .OK;
+	if z, _ := is_zero(a); z {
+		return 0, .None;
 	}
 	}
 	/*
 	/*
 		Get the number of DIGITs and use it.
 		Get the number of DIGITs and use it.
@@ -404,11 +385,11 @@ _zero_unused :: proc(a: ^Int) {
 	}
 	}
 }
 }
 
 
-_grow_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) {
+clear_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) {
 	if !is_initialized(dest) {
 	if !is_initialized(dest) {
 		return grow(dest, _MIN_DIGIT_COUNT if minimize else _DEFAULT_DIGIT_COUNT);
 		return grow(dest, _MIN_DIGIT_COUNT if minimize else _DEFAULT_DIGIT_COUNT);
 	}
 	}
-	return .OK;
+	return .None;
 }
 }
 
 
 /*
 /*
@@ -418,19 +399,17 @@ _grow_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) {
 	Typically very fast.  Also fixes the sign if there are no more leading digits.
 	Typically very fast.  Also fixes the sign if there are no more leading digits.
 */
 */
 clamp :: proc(a: ^Int) -> (err: Error) {
 clamp :: proc(a: ^Int) -> (err: Error) {
-	if a == nil {
-		return .Nil_Pointer_Passed;
-	} else if !is_initialized(a) {
-		return .Int_Not_Initialized;
+	if err = clear_if_uninitialized(a); err != .None {
+		return err;
 	}
 	}
 
 
 	for a.used > 0 && a.digit[a.used - 1] == 0 {
 	for a.used > 0 && a.digit[a.used - 1] == 0 {
 		a.used -= 1;
 		a.used -= 1;
 	}
 	}
 
 
-	if is_zero(a) {
+	if z, _ := is_zero(a); z {
 		a.sign = .Zero_or_Positive;
 		a.sign = .Zero_or_Positive;
 	}
 	}
 
 
-	return .OK;
+	return .None;
 }
 }

+ 16 - 11
core/math/big/log.odin

@@ -10,13 +10,18 @@ package big
 */
 */
 
 
 log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
 log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
-	if a == nil {
-		return 0, .Nil_Pointer_Passed;
-	} else if !is_initialized(a) {
-		return 0, .Int_Not_Initialized;
+	if base < 2 || DIGIT(base) > _DIGIT_MAX {
+		return -1, .Invalid_Argument;
 	}
 	}
-	if is_neg(a) || is_zero(a) || base < 2 || DIGIT(base) > _DIGIT_MAX {
-		return -1, .Invalid_Input;
+
+	if err = clear_if_uninitialized(a); err != .None {
+		return -1, err;
+	}
+	if n, _ := is_neg(a); n {
+		return -1, .Invalid_Argument;
+	}
+	if z, _ := is_zero(a); z {
+		return -1, .Invalid_Argument;
 	}
 	}
 
 
 	/*
 	/*
@@ -80,14 +85,14 @@ log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) {
 		Therefore, we return 0.
 		Therefore, we return 0.
 	*/
 	*/
 	if a < base {
 	if a < base {
-		return 0, .OK;
+		return 0, .None;
 	}
 	}
 
 
 	/*
 	/*
 		If a number equals the base, the log is 1.
 		If a number equals the base, the log is 1.
 	*/
 	*/
 	if a == base {
 	if a == base {
-		return 1, .OK;
+		return 1, .None;
 	}
 	}
 
 
 	N := _WORD(a);
 	N := _WORD(a);
@@ -116,13 +121,13 @@ log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) {
 			bracket_low = bracket_mid;
 			bracket_low = bracket_mid;
 		}
 		}
 		if N == bracket_mid {
 		if N == bracket_mid {
-			return mid, .OK;
+			return mid, .None;
 		}
 		}
    	}
    	}
 
 
    	if bracket_high == N {
    	if bracket_high == N {
-   		return high, .OK;
+   		return high, .None;
    	} else {
    	} else {
-   		return low, .OK;
+   		return low, .None;
    	}
    	}
 }
 }

+ 48 - 39
core/math/big/logical.odin

@@ -20,29 +20,33 @@ package big
 	2's complement `and`, returns `dest = a & b;`
 	2's complement `and`, returns `dest = a & b;`
 */
 */
 and :: proc(dest, a, b: ^Int) -> (err: Error) {
 and :: proc(dest, a, b: ^Int) -> (err: Error) {
-	assert_initialized(dest); assert_initialized(a); assert_initialized(b);
-
+	if err = clear_if_uninitialized(a); err != .None {
+		return err;
+	}
+	if err = clear_if_uninitialized(b); err != .None {
+		return err;
+	}
 	used := max(a.used, b.used) + 1;
 	used := max(a.used, b.used) + 1;
-	neg: bool;
-
-	neg  = is_neg(a) && is_neg(b);
-
-	ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
-
 	/*
 	/*
 		Grow the destination to accomodate the result.
 		Grow the destination to accomodate the result.
 	*/
 	*/
-	if err = grow(dest, used); err != .OK {
+	if err = grow(dest, used); err != .None {
 		return err;
 		return err;
 	}
 	}
 
 
+	neg_a, _ := is_neg(a);
+	neg_b, _ := is_neg(b);
+	neg      := neg_a && neg_b;
+
+	ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
+
 	for i := 0; i < used; i += 1 {
 	for i := 0; i < used; i += 1 {
 		x, y: DIGIT;
 		x, y: DIGIT;
 
 
 		/*
 		/*
 			Convert to 2's complement if negative.
 			Convert to 2's complement if negative.
 		*/
 		*/
-		if is_neg(a) {
+		if neg_a {
 			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
 			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
 			x = ac & _MASK;
 			x = ac & _MASK;
 			ac >>= _DIGIT_BITS;
 			ac >>= _DIGIT_BITS;
@@ -53,7 +57,7 @@ and :: proc(dest, a, b: ^Int) -> (err: Error) {
 		/*
 		/*
 			Convert to 2's complement if negative.
 			Convert to 2's complement if negative.
 		*/
 		*/
-		if is_neg(a) {
+		if neg_b {
 			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
 			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
 			y = bc & _MASK;
 			y = bc & _MASK;
 			bc >>= _DIGIT_BITS;
 			bc >>= _DIGIT_BITS;
@@ -75,37 +79,40 @@ and :: proc(dest, a, b: ^Int) -> (err: Error) {
 
 
 	dest.used = used;
 	dest.used = used;
 	dest.sign = .Negative if neg else .Zero_or_Positive;
 	dest.sign = .Negative if neg else .Zero_or_Positive;
-	clamp(dest);
-	return .OK;
+	return clamp(dest);
 }
 }
 
 
 /*
 /*
 	2's complement `or`, returns `dest = a | b;`
 	2's complement `or`, returns `dest = a | b;`
 */
 */
 or :: proc(dest, a, b: ^Int) -> (err: Error) {
 or :: proc(dest, a, b: ^Int) -> (err: Error) {
-	assert_initialized(dest); assert_initialized(a); assert_initialized(b);
-
+	if err = clear_if_uninitialized(a); err != .None {
+		return err;
+	}
+	if err = clear_if_uninitialized(b); err != .None {
+		return err;
+	}
 	used := max(a.used, b.used) + 1;
 	used := max(a.used, b.used) + 1;
-	neg: bool;
-
-	neg  = is_neg(a) || is_neg(b);
-
-	ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
-
 	/*
 	/*
 		Grow the destination to accomodate the result.
 		Grow the destination to accomodate the result.
 	*/
 	*/
-	if err = grow(dest, used); err != .OK {
+	if err = grow(dest, used); err != .None {
 		return err;
 		return err;
 	}
 	}
 
 
+	neg_a, _ := is_neg(a);
+	neg_b, _ := is_neg(b);
+	neg      := neg_a || neg_b;
+
+	ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
+
 	for i := 0; i < used; i += 1 {
 	for i := 0; i < used; i += 1 {
 		x, y: DIGIT;
 		x, y: DIGIT;
 
 
 		/*
 		/*
 			Convert to 2's complement if negative.
 			Convert to 2's complement if negative.
 		*/
 		*/
-		if is_neg(a) {
+		if neg_a {
 			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
 			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
 			x = ac & _MASK;
 			x = ac & _MASK;
 			ac >>= _DIGIT_BITS;
 			ac >>= _DIGIT_BITS;
@@ -116,7 +123,7 @@ or :: proc(dest, a, b: ^Int) -> (err: Error) {
 		/*
 		/*
 			Convert to 2's complement if negative.
 			Convert to 2's complement if negative.
 		*/
 		*/
-		if is_neg(a) {
+		if neg_b {
 			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
 			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
 			y = bc & _MASK;
 			y = bc & _MASK;
 			bc >>= _DIGIT_BITS;
 			bc >>= _DIGIT_BITS;
@@ -138,37 +145,40 @@ or :: proc(dest, a, b: ^Int) -> (err: Error) {
 
 
 	dest.used = used;
 	dest.used = used;
 	dest.sign = .Negative if neg else .Zero_or_Positive;
 	dest.sign = .Negative if neg else .Zero_or_Positive;
-	clamp(dest);
-	return .OK;
+	return clamp(dest);
 }
 }
 
 
 /*
 /*
 	2's complement `xor`, returns `dest = a ~ b;`
 	2's complement `xor`, returns `dest = a ~ b;`
 */
 */
 xor :: proc(dest, a, b: ^Int) -> (err: Error) {
 xor :: proc(dest, a, b: ^Int) -> (err: Error) {
-	assert_initialized(dest); assert_initialized(a); assert_initialized(b);
-
+	if err = clear_if_uninitialized(a); err != .None {
+		return err;
+	}
+	if err = clear_if_uninitialized(b); err != .None {
+		return err;
+	}
 	used := max(a.used, b.used) + 1;
 	used := max(a.used, b.used) + 1;
-	neg: bool;
-
-	neg  = is_neg(a) != is_neg(b);
-
-	ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
-
 	/*
 	/*
 		Grow the destination to accomodate the result.
 		Grow the destination to accomodate the result.
 	*/
 	*/
-	if err = grow(dest, used); err != .OK {
+	if err = grow(dest, used); err != .None {
 		return err;
 		return err;
 	}
 	}
 
 
+	neg_a, _ := is_neg(a);
+	neg_b, _ := is_neg(b);
+	neg      := neg_a != neg_b;
+
+	ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
+
 	for i := 0; i < used; i += 1 {
 	for i := 0; i < used; i += 1 {
 		x, y: DIGIT;
 		x, y: DIGIT;
 
 
 		/*
 		/*
 			Convert to 2's complement if negative.
 			Convert to 2's complement if negative.
 		*/
 		*/
-		if is_neg(a) {
+		if neg_a {
 			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
 			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
 			x = ac & _MASK;
 			x = ac & _MASK;
 			ac >>= _DIGIT_BITS;
 			ac >>= _DIGIT_BITS;
@@ -179,7 +189,7 @@ xor :: proc(dest, a, b: ^Int) -> (err: Error) {
 		/*
 		/*
 			Convert to 2's complement if negative.
 			Convert to 2's complement if negative.
 		*/
 		*/
-		if is_neg(a) {
+		if neg_b {
 			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
 			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
 			y = bc & _MASK;
 			y = bc & _MASK;
 			bc >>= _DIGIT_BITS;
 			bc >>= _DIGIT_BITS;
@@ -201,6 +211,5 @@ xor :: proc(dest, a, b: ^Int) -> (err: Error) {
 
 
 	dest.used = used;
 	dest.used = used;
 	dest.sign = .Negative if neg else .Zero_or_Positive;
 	dest.sign = .Negative if neg else .Zero_or_Positive;
-	clamp(dest);
-	return .OK;
+	return clamp(dest);
 }
 }

+ 54 - 44
core/math/big/radix.odin

@@ -19,8 +19,10 @@ import "core:strings"
 	This version of `itoa` allocates one behalf of the caller. The caller must free the string.
 	This version of `itoa` allocates one behalf of the caller. The caller must free the string.
 */
 */
 itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
 itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
-	radix := radix;
-	assert_initialized(a);
+	a := a; radix := radix;
+	if err = clear_if_uninitialized(a); err != .None {
+		return "", err;
+	}
 	/*
 	/*
 		Radix defaults to 10.
 		Radix defaults to 10.
 	*/
 	*/
@@ -32,14 +34,13 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator
 	*/
 	*/
 
 
 	/*
 	/*
-		Calculate the size of the buffer we need.
+		Calculate the size of the buffer we need, and 
 	*/
 	*/
 	size: int;
 	size: int;
-	size, err = radix_size(a, radix, zero_terminate);
 	/*
 	/*
 		Exit if calculating the size returned an error.
 		Exit if calculating the size returned an error.
 	*/
 	*/
-	if err != .OK {
+	if size, err = radix_size(a, radix, zero_terminate); err != .None {
 		f := strings.clone(fallback(a), allocator);
 		f := strings.clone(fallback(a), allocator);
 		if zero_terminate {
 		if zero_terminate {
 			c := strings.clone_to_cstring(f);
 			c := strings.clone_to_cstring(f);
@@ -57,14 +58,13 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator
 		Write the digits out into the buffer.
 		Write the digits out into the buffer.
 	*/
 	*/
 	written: int;
 	written: int;
-	written, err = itoa_raw(a, radix, buffer, size, zero_terminate);
+	if written, err = itoa_raw(a, radix, buffer, size, zero_terminate); err == .None {
+		return string(buffer[:written]), .None;
+	}
 
 
 	/*
 	/*
 		For now, delete the buffer and fall back to the below on failure.
 		For now, delete the buffer and fall back to the below on failure.
 	*/
 	*/
-	if err == .OK {
-		return string(buffer[:written]), .OK;
-	}
 	delete(buffer);
 	delete(buffer);
 
 
 	fallback :: proc(a: ^Int, print_raw := false) -> string {
 	fallback :: proc(a: ^Int, print_raw := false) -> string {
@@ -86,8 +86,10 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator
 	This version of `itoa` allocates one behalf of the caller. The caller must free the string.
 	This version of `itoa` allocates one behalf of the caller. The caller must free the string.
 */
 */
 itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
 itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
-	radix := radix;
-	assert_initialized(a);
+	a := a; radix := radix;
+	if err = clear_if_uninitialized(a); err != .None {
+		return "", err;
+	}
 	/*
 	/*
 		Radix defaults to 10.
 		Radix defaults to 10.
 	*/
 	*/
@@ -119,21 +121,25 @@ itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -
 	and having to perform a buffer overflow check each character.
 	and having to perform a buffer overflow check each character.
 */
 */
 itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
 itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
-	radix := radix;
-	assert_initialized(a); size := size;
+	a := a; radix := radix; size := size;
+	if err = clear_if_uninitialized(a); err != .None {
+		return 0, err;
+	}
 	/*
 	/*
 		Radix defaults to 10.
 		Radix defaults to 10.
 	*/
 	*/
 	radix = radix if radix > 0 else 10;
 	radix = radix if radix > 0 else 10;
 	if radix < 2 || radix > 64 {
 	if radix < 2 || radix > 64 {
-		return 0, .Invalid_Input;
+		return 0, .Invalid_Argument;
 	}
 	}
 
 
 	/*
 	/*
 		We weren't given a size. Let's compute it.
 		We weren't given a size. Let's compute it.
 	*/
 	*/
 	if size == -1 {
 	if size == -1 {
-		size, err = radix_size(a, radix, zero_terminate);
+		if size, err = radix_size(a, radix, zero_terminate); err != .None {
+			return 0, err;
+		}
 	}
 	}
 
 
 	/*
 	/*
@@ -146,7 +152,8 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
 	/*
 	/*
 		Fast path for when `Int` == 0 or the entire `Int` fits in a single radix digit.
 		Fast path for when `Int` == 0 or the entire `Int` fits in a single radix digit.
 	*/
 	*/
-	if is_zero(a) || (a.used == 1 && a.digit[0] < DIGIT(radix)) {
+	z, _ := is_zero(a);
+	if z || (a.used == 1 && a.digit[0] < DIGIT(radix)) {
 		if zero_terminate {
 		if zero_terminate {
 			available -= 1;
 			available -= 1;
 			buffer[available] = 0;
 			buffer[available] = 0;
@@ -154,12 +161,12 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
 		available -= 1;
 		available -= 1;
 		buffer[available] = RADIX_TABLE[a.digit[0]];
 		buffer[available] = RADIX_TABLE[a.digit[0]];
 
 
-		if is_neg(a) {
+		if n, _ := is_neg(a); n {
 			available -= 1;
 			available -= 1;
 			buffer[available] = '-';
 			buffer[available] = '-';
 		}
 		}
 
 
-		return len(buffer) - available, .OK;
+		return len(buffer) - available, .None;
 	}
 	}
 
 
 	/*
 	/*
@@ -179,11 +186,11 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
 
 
 			val = q;
 			val = q;
 		}
 		}
-		if is_neg(a) {
+		if n, _ := is_neg(a); n {
 			available -= 1;
 			available -= 1;
 			buffer[available] = '-';
 			buffer[available] = '-';
 		}
 		}
-		return len(buffer) - available, .OK;
+		return len(buffer) - available, .None;
 	}
 	}
 	/*
 	/*
 		At least 3 DIGITs are in use if we made it this far.
 		At least 3 DIGITs are in use if we made it this far.
@@ -202,24 +209,23 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
 		// mask  := _WORD(radix - 1);
 		// mask  := _WORD(radix - 1);
 		shift, err = log_n(DIGIT(radix), 2);
 		shift, err = log_n(DIGIT(radix), 2);
 		count, err = count_bits(a);
 		count, err = count_bits(a);
-		// digit: _WORD;
+		digit: _WORD;
 
 
 		for offset := 0; offset < count; offset += 4 {
 		for offset := 0; offset < count; offset += 4 {
 			bits_to_get := int(min(count - offset, shift));
 			bits_to_get := int(min(count - offset, shift));
-			digit, err  := extract_bits(a, offset, bits_to_get);
-			if err != .OK {
-				return len(buffer) - available, .Invalid_Input;
+			if digit, err = extract_bits(a, offset, bits_to_get); err != .None {
+				return len(buffer) - available, .Invalid_Argument;
 			}
 			}
 			available -= 1;
 			available -= 1;
 			buffer[available] = RADIX_TABLE[digit];
 			buffer[available] = RADIX_TABLE[digit];
 		}
 		}
 
 
-		if is_neg(a) {
+		if n, _ := is_neg(a); n {
 			available -= 1;
 			available -= 1;
 			buffer[available] = '-';
 			buffer[available] = '-';
 		}
 		}
 
 
-		return len(buffer) - available, .OK;
+		return len(buffer) - available, .None;
 	}
 	}
 
 
 	return -1, .Unimplemented;
 	return -1, .Unimplemented;
@@ -233,37 +239,41 @@ int_to_cstring :: itoa_cstring;
 	We size for `string`, not `cstring`.
 	We size for `string`, not `cstring`.
 */
 */
 radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false) -> (size: int, err: Error) {
 radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false) -> (size: int, err: Error) {
+	a := a;
 	if radix < 2 || radix > 64 {
 	if radix < 2 || radix > 64 {
-		return -1, .Invalid_Input;
+		return -1, .Invalid_Argument;
+	}
+	if err = clear_if_uninitialized(a); err != .None {
+		return 0, err;
 	}
 	}
 
 
- 	if is_zero(a) {
- 		if zero_terminate {
- 			return 2, .OK;
- 		}
- 		return 1, .OK;
- 	}
+	if z, _ := is_zero(a); z {
+		if zero_terminate {
+			return 2, .None;
+		}
+		return 1, .None;
+	}
 
 
- 	/*
+	/*
 		Calculate `log` on a temporary "copy" with its sign set to positive.
 		Calculate `log` on a temporary "copy" with its sign set to positive.
- 	*/
+	*/
 	t := &Int{
 	t := &Int{
 		used      = a.used,
 		used      = a.used,
 		sign      = .Zero_or_Positive,
 		sign      = .Zero_or_Positive,
 		digit     = a.digit,
 		digit     = a.digit,
 	};
 	};
 
 
- 	size, err = log_n(t, DIGIT(radix));
- 	if err != .OK {
- 		return;
- 	}
+	if size, err = log_n(t, DIGIT(radix)); err != .None {
+		return 0, err;
+	}
 
 
- 	/*
+	/*
 		log truncates to zero, so we need to add one more, and one for `-` if negative.
 		log truncates to zero, so we need to add one more, and one for `-` if negative.
- 	*/
- 	size += 2 if is_neg(a) else 1;
- 	size += 1 if zero_terminate else 0;
- 	return size, .OK;
+	*/
+	n, _ := is_neg(a);
+	size += 2 if n else 1;
+	size += 1 if zero_terminate else 0;
+	return size, .None;
 }
 }
 
 
 /*
 /*