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) {
 	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.
@@ -44,7 +52,7 @@ int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 		Subtract the one with the greater magnitude from the other.
 		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;
 	}
 
@@ -60,11 +68,22 @@ int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 */
 int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 	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.
 	*/
@@ -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.
 		*/
-		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;
-			return .OK;
+			return .None;
 		}
 		/*
 			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;
-			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 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.
 		*/
-		t := a;
-		t.sign = .Zero_or_Positive;
+		a.sign = .Zero_or_Positive;
 		/*
 			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.
 		*/
+		a.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 is_pos(a) {
+	if p, _ := is_pos(a); p {
 		/*
 			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.
 	*/
-	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) {
 	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 {
 		/*
@@ -195,12 +218,16 @@ int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 		Subtract a positive from a positive, OR negative from a negative.
 		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 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;
 	} 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) {
 	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.
@@ -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.
 		*/
-		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;
-			return .OK;
+			return .None;
 		}
 		/*
 			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;
-			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 is_neg(a) {
+	if n, _ := is_neg(a); n {
 		t := a;
 		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.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.sign = .Negative;
 		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.
 	*/
-	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) {
 	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;
@@ -336,10 +366,13 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 	max_used = y.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;
 	}
 	dest.used = max_used + 1;
+	/*
+		All parameters have been initialized.
+	*/
 
 	/* Zero the carry */
 	carry := DIGIT(0);
@@ -393,9 +426,7 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
 	/*
 		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) {
 	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;
@@ -415,10 +447,13 @@ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 	max_used := x.used;
 	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;
 	}
 	dest.used = max_used;
+	/*
+		All parameters have been initialized.
+	*/
 
 	borrow := DIGIT(0);
 
@@ -465,6 +500,5 @@ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
 	/*
 		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,
 };
 
-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 {

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

@@ -22,61 +22,83 @@ int_is_initialized :: proc(a: ^Int) -> bool {
 	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 {
 	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.
 	*/
 	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.
 	*/
 	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.
 	*/
 	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 {
 		if a.digit[i - 1] != 0 {
-			return false;
+			return false, .None;
 		}
 	}
-	return true;
+	return true, .None;
 }
 
 /*
 	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 */
 	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 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.
 */
-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 */
-	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 */
 	if a.used > 1 {
-		return .Greater_Than;
+		return +1, .None;
 	}
 
 	/* Compare the only digit in `a` to `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.
 */
-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 */
 	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 */
 	for n := a.used - 1; n >= 0; n -= 1 {
 		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)) {
 	as, err := itoa(a, base);
 	defer delete(as);
-	if err == .OK {
+	if err == .None {
 		cb, _ := count_bits(a);
 		fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, cb, as);
 	} else {
@@ -80,10 +80,10 @@ demo :: proc() {
 	print("c", c);
 
 	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);
 	}
-	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);	
 	}
 	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)
 	where intrinsics.type_is_integer(T) {
 	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.sign = .Zero_or_Positive if src >= 0 else .Negative;
 	src = abs(src);
@@ -49,7 +44,7 @@ int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator :
 		src >>= _DIGIT_BITS;
 	}
 	_zero_unused(dest);
-	return .OK;
+	return .None;
 }
 
 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.
 */
 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) {
-		return .OK;
+		return .None;
 	}
-
 	/*
 		Grow `dest` to fit `src`.
 		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;
 	}
 
@@ -91,7 +79,7 @@ int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error
 	dest.used = src.used;
 	dest.sign = src.sign;
 	_zero_unused(dest);
-	return .OK;
+	return .None;
 }
 copy :: proc { int_copy, };
 
@@ -100,26 +88,23 @@ copy :: proc { int_copy, };
 */
 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) {
 		dest.sign = .Zero_or_Positive;
-		return .OK;
+		return .None;
 	}
 
 	/*
 		Copy `src` to `dest`
 	*/
-	if err = copy(dest, src, allocator); err != .OK {
+	if err = copy(dest, src, allocator); err != .None {
 		return err;
 	}
 
@@ -127,7 +112,7 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
 		Fix sign.
 	*/
 	dest.sign = .Zero_or_Positive;
-	return .OK;
+	return .None;
 }
 
 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) {
 	/*
-		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.
 	*/
-	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;
-		return .OK;
+		return .None;
 	}
-
 	/*
 		Copy `src` to `dest`
 	*/
-	if err = copy(dest, src, allocator); err != .OK {
+	if err = copy(dest, src, allocator); err != .None {
 		return err;
 	}
 
@@ -168,7 +155,7 @@ neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 		Fix 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) {
 	/*
-		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;
 	if limb < 0 || limb >= a.used {
-		return 0, .Invalid_Input;
+		return 0, .Invalid_Argument;
 	}
 
 	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) {
 	/*
-		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 {
-		return 0, .Invalid_Input;
+		return 0, .Invalid_Argument;
 	}
 
 	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 {
 		o   := offset + shift;
 		v, e = extract_bit(a, o);
-		if e != .OK {
+		if e != .None {
 			break;
 		}
 		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) {
 	if a == nil {
-		return .Nil_Pointer_Passed;
+		return .Invalid_Pointer;
 	}
 
 	needed := max(_MIN_DIGIT_COUNT, a.used);
@@ -238,12 +221,12 @@ shrink :: proc(a: ^Int) -> (err: Error) {
 	if a.used != needed {
 		return grow(a, needed);
 	}
-	return .OK;
+	return .None;
 }
 
 int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) {
 	if a == nil {
-		return .Nil_Pointer_Passed;
+		return .Invalid_Pointer;
 	}
 	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.
 	*/
 	if len(a.digit) != needed {
-		return .Out_of_Memory;
+		return .Out_Of_Memory;
 	}
-	return .OK;
+	return .None;
 }
 grow :: proc { int_grow, };
 
@@ -280,7 +263,7 @@ grow :: proc { int_grow, };
 */
 int_clear :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
 	if a == nil {
-		return .Nil_Pointer_Passed;
+		return .Invalid_Pointer;
 	}
 
 	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.
 */
 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;
 	}
 
 	a.used     = 1;
 	a.digit[0] = 1;
 	a.sign     = .Zero_or_Positive;
-	return .OK;
+	return .None;
 }
 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.
 */
 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;
 	}
 
 	a.used     = 1;
 	a.digit[0] = 1;
 	a.sign     = .Negative;
-	return .OK;
+	return .None;
 }
 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.
 	*/
 	if a == nil {
-		return .Nil_Pointer_Passed;
+		return .Invalid_Pointer;
 	}
 
 	if power < 0 || power > _MAX_BIT_COUNT {
-		return .Invalid_Input;
+		return .Invalid_Argument;
 	}
 
 	/*
 		Grow to accomodate the single bit.
 	*/
 	a.used = (power / _DIGIT_BITS) + 1;
-	if err = grow(a, a.used); err != .OK {
+	if err = grow(a, a.used); err != .None {
 		return err;
 	}
 	/*
@@ -355,23 +338,21 @@ power_of_two :: proc(a: ^Int, power: int) -> (err: Error) {
 		Set the bit.
 	*/
 	a.digit[power / _DIGIT_BITS] = 1 << uint((power % _DIGIT_BITS));
-   	return .OK;
+   	return .None;
 }
 
 /*
 	Count bits in an `Int`.
 */
 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.
 	*/
-	if is_zero(a) {
-		return 0, .OK;
+	if z, _ := is_zero(a); z {
+		return 0, .None;
 	}
 	/*
 		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) {
 		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.
 */
 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 {
 		a.used -= 1;
 	}
 
-	if is_zero(a) {
+	if z, _ := is_zero(a); z {
 		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) {
-	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.
 	*/
 	if a < base {
-		return 0, .OK;
+		return 0, .None;
 	}
 
 	/*
 		If a number equals the base, the log is 1.
 	*/
 	if a == base {
-		return 1, .OK;
+		return 1, .None;
 	}
 
 	N := _WORD(a);
@@ -116,13 +121,13 @@ log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) {
 			bracket_low = bracket_mid;
 		}
 		if N == bracket_mid {
-			return mid, .OK;
+			return mid, .None;
 		}
    	}
 
    	if bracket_high == N {
-   		return high, .OK;
+   		return high, .None;
    	} 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;`
 */
 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;
-	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.
 	*/
-	if err = grow(dest, used); err != .OK {
+	if err = grow(dest, used); err != .None {
 		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 {
 		x, y: DIGIT;
 
 		/*
 			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);
 			x = ac & _MASK;
 			ac >>= _DIGIT_BITS;
@@ -53,7 +57,7 @@ and :: proc(dest, a, b: ^Int) -> (err: Error) {
 		/*
 			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);
 			y = bc & _MASK;
 			bc >>= _DIGIT_BITS;
@@ -75,37 +79,40 @@ and :: proc(dest, a, b: ^Int) -> (err: Error) {
 
 	dest.used = used;
 	dest.sign = .Negative if neg else .Zero_or_Positive;
-	clamp(dest);
-	return .OK;
+	return clamp(dest);
 }
 
 /*
 	2's complement `or`, returns `dest = a | b;`
 */
 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;
-	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.
 	*/
-	if err = grow(dest, used); err != .OK {
+	if err = grow(dest, used); err != .None {
 		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 {
 		x, y: DIGIT;
 
 		/*
 			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);
 			x = ac & _MASK;
 			ac >>= _DIGIT_BITS;
@@ -116,7 +123,7 @@ or :: proc(dest, a, b: ^Int) -> (err: Error) {
 		/*
 			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);
 			y = bc & _MASK;
 			bc >>= _DIGIT_BITS;
@@ -138,37 +145,40 @@ or :: proc(dest, a, b: ^Int) -> (err: Error) {
 
 	dest.used = used;
 	dest.sign = .Negative if neg else .Zero_or_Positive;
-	clamp(dest);
-	return .OK;
+	return clamp(dest);
 }
 
 /*
 	2's complement `xor`, returns `dest = a ~ b;`
 */
 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;
-	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.
 	*/
-	if err = grow(dest, used); err != .OK {
+	if err = grow(dest, used); err != .None {
 		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 {
 		x, y: DIGIT;
 
 		/*
 			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);
 			x = ac & _MASK;
 			ac >>= _DIGIT_BITS;
@@ -179,7 +189,7 @@ xor :: proc(dest, a, b: ^Int) -> (err: Error) {
 		/*
 			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);
 			y = bc & _MASK;
 			bc >>= _DIGIT_BITS;
@@ -201,6 +211,5 @@ xor :: proc(dest, a, b: ^Int) -> (err: Error) {
 
 	dest.used = used;
 	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.
 */
 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.
 	*/
@@ -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, err = radix_size(a, radix, zero_terminate);
 	/*
 		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);
 		if zero_terminate {
 			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.
 	*/
 	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.
 	*/
-	if err == .OK {
-		return string(buffer[:written]), .OK;
-	}
 	delete(buffer);
 
 	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.
 */
 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.
 	*/
@@ -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.
 */
 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 = radix if radix > 0 else 10;
 	if radix < 2 || radix > 64 {
-		return 0, .Invalid_Input;
+		return 0, .Invalid_Argument;
 	}
 
 	/*
 		We weren't given a size. Let's compute it.
 	*/
 	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.
 	*/
-	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 {
 			available -= 1;
 			buffer[available] = 0;
@@ -154,12 +161,12 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
 		available -= 1;
 		buffer[available] = RADIX_TABLE[a.digit[0]];
 
-		if is_neg(a) {
+		if n, _ := is_neg(a); n {
 			available -= 1;
 			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;
 		}
-		if is_neg(a) {
+		if n, _ := is_neg(a); n {
 			available -= 1;
 			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.
@@ -202,24 +209,23 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
 		// mask  := _WORD(radix - 1);
 		shift, err = log_n(DIGIT(radix), 2);
 		count, err = count_bits(a);
-		// digit: _WORD;
+		digit: _WORD;
 
 		for offset := 0; offset < count; offset += 4 {
 			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;
 			buffer[available] = RADIX_TABLE[digit];
 		}
 
-		if is_neg(a) {
+		if n, _ := is_neg(a); n {
 			available -= 1;
 			buffer[available] = '-';
 		}
 
-		return len(buffer) - available, .OK;
+		return len(buffer) - available, .None;
 	}
 
 	return -1, .Unimplemented;
@@ -233,37 +239,41 @@ int_to_cstring :: itoa_cstring;
 	We size for `string`, not `cstring`.
 */
 radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false) -> (size: int, err: Error) {
+	a := a;
 	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.
- 	*/
+	*/
 	t := &Int{
 		used      = a.used,
 		sign      = .Zero_or_Positive,
 		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.
- 	*/
- 	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;
 }
 
 /*