Browse Source

big: More refactoring.

Jeroen van Rijn 4 years ago
parent
commit
1ebb0bd9d6

+ 418 - 16
core/math/big/internal.odin

@@ -149,7 +149,8 @@ internal_add_signed :: proc { internal_int_add_signed, };
 		`dest` and `a` != `nil` and have been initalized.
 		`dest` and `a` != `nil` and have been initalized.
 		`dest` is large enough (a.used + 1) to fit result.
 		`dest` is large enough (a.used + 1) to fit result.
 */
 */
-internal_int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
+internal_int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
+	if err = internal_grow(dest, a.used + 1, false, allocator); err != nil { return err; }
 	/*
 	/*
 		Fast paths for destination and input Int being the same.
 		Fast paths for destination and input Int being the same.
 	*/
 	*/
@@ -183,7 +184,7 @@ internal_int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
 		/*
 		/*
 			dest = |a| - digit
 			dest = |a| - digit
 		*/
 		*/
-		if err =  #force_inline internal_int_add_digit(dest, a, digit); err != nil {
+		if err =  #force_inline internal_int_add_digit(dest, a, digit, allocator); err != nil {
 			/*
 			/*
 				Restore a's sign.
 				Restore a's sign.
 			*/
 			*/
@@ -367,7 +368,9 @@ internal_int_sub_signed :: proc(dest, number, decrease: ^Int, allocator := conte
 		`dest`, `number` != `nil` and have been initalized.
 		`dest`, `number` != `nil` and have been initalized.
 		`dest` is large enough (number.used + 1) to fit result.
 		`dest` is large enough (number.used + 1) to fit result.
 */
 */
-internal_int_sub_digit :: proc(dest, number: ^Int, digit: DIGIT) -> (err: Error) {
+internal_int_sub_digit :: proc(dest, number: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
+	if err = internal_grow(dest, number.used + 1, false, allocator); err != nil { return err; }
+
 	dest := dest; digit := digit;
 	dest := dest; digit := digit;
 	/*
 	/*
 		All parameters have been initialized.
 		All parameters have been initialized.
@@ -1630,7 +1633,7 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al
 	src := src;
 	src := src;
 
 
 	if err = error_if_immutable(dest); err != nil { return err; }
 	if err = error_if_immutable(dest); err != nil { return err; }
-	if err = clear_if_uninitialized(dest); err != nil { return err; }
+	if err = internal_clear_if_uninitialized_single(dest); err != nil { return err; }
 
 
 	dest.flags = {}; // We're not -Inf, Inf, NaN or Immutable.
 	dest.flags = {}; // We're not -Inf, Inf, NaN or Immutable.
 
 
@@ -1659,7 +1662,7 @@ internal_int_copy :: proc(dest, src: ^Int, minimize := false, allocator := conte
 	if (dest == src) { return nil; }
 	if (dest == src) { return nil; }
 
 
 	if err = error_if_immutable(dest);    err != nil { return err; }
 	if err = error_if_immutable(dest);    err != nil { return err; }
-	if err = clear_if_uninitialized(src); err != nil { return err; }
+	if err = internal_clear_if_uninitialized_single(src); err != nil { return err; }
 
 
 	/*
 	/*
 		Grow `dest` to fit `src`.
 		Grow `dest` to fit `src`.
@@ -1707,7 +1710,7 @@ internal_int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (er
 	/*
 	/*
 		Check that src is usable.
 		Check that src is usable.
 	*/
 	*/
-	if err = clear_if_uninitialized(src); err != nil {
+	if err = internal_clear_if_uninitialized_single(src); err != nil {
 		return err;
 		return err;
 	}
 	}
 	/*
 	/*
@@ -1744,7 +1747,7 @@ internal_int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (er
 	/*
 	/*
 		Check that src is usable.
 		Check that src is usable.
 	*/
 	*/
-	if err = clear_if_uninitialized(src); err != nil {
+	if err = internal_clear_if_uninitialized_single(src); err != nil {
 		return err;
 		return err;
 	}
 	}
 	/*
 	/*
@@ -1788,7 +1791,7 @@ internal_int_bitfield_extract :: proc(a: ^Int, offset, count: int) -> (res: _WOR
 	/*
 	/*
 		Check that `a` is usable.
 		Check that `a` is usable.
 	*/
 	*/
-	if err = clear_if_uninitialized(a); err != nil { return 0, err; }
+	if err = internal_clear_if_uninitialized_single(a); err != nil { return 0, err; }
 	/*
 	/*
 		Early out for single bit.
 		Early out for single bit.
 	*/
 	*/
@@ -2046,7 +2049,7 @@ internal_int_get :: proc(a: ^Int, $T: typeid) -> (res: T, err: Error) where intr
 internal_get :: proc { internal_int_get, };
 internal_get :: proc { internal_int_get, };
 
 
 internal_int_get_float :: proc(a: ^Int) -> (res: f64, err: Error) {
 internal_int_get_float :: proc(a: ^Int) -> (res: f64, err: Error) {
-	if err = clear_if_uninitialized(a); err != nil {
+	if err = internal_clear_if_uninitialized_single(a); err != nil {
 		return 0, err;
 		return 0, err;
 	}	
 	}	
 
 
@@ -2062,11 +2065,410 @@ internal_int_get_float :: proc(a: ^Int) -> (res: f64, err: Error) {
 	return;
 	return;
 }
 }
 
 
+/*
+	The `and`, `or` and `xor` binops differ in two lines only.
+	We could handle those with a switch, but that adds overhead.
+
+	TODO: Implement versions that take a DIGIT immediate.
+*/
+
+/*
+	2's complement `and`, returns `dest = a & b;`
+*/
+internal_int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
+	used := max(a.used, b.used) + 1;
+	/*
+		Grow the destination to accomodate the result.
+	*/
+	if err = internal_grow(dest, used, false, allocator); err != nil { 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 neg_a {
+			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
+			x = ac & _MASK;
+			ac >>= _DIGIT_BITS;
+		} else {
+			x = 0 if i >= a.used else a.digit[i];
+		}
+
+		/*
+			Convert to 2's complement if negative.
+		*/
+		if neg_b {
+			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
+			y = bc & _MASK;
+			bc >>= _DIGIT_BITS;
+		} else {
+			y = 0 if i >= b.used else b.digit[i];
+		}
+
+		dest.digit[i] = x & y;
+
+		/*
+			Convert to to sign-magnitude if negative.
+		*/
+		if neg {
+			cc += ~dest.digit[i] & _MASK;
+			dest.digit[i] = cc & _MASK;
+			cc >>= _DIGIT_BITS;
+		}
+	}
+
+	dest.used = used;
+	dest.sign = .Negative if neg else .Zero_or_Positive;
+	return clamp(dest);
+}
+internal_and :: proc { internal_int_and, };
+
+/*
+	2's complement `or`, returns `dest = a | b;`
+*/
+internal_int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
+	used := max(a.used, b.used) + 1;
+	/*
+		Grow the destination to accomodate the result.
+	*/
+	if err = grow(dest, used, false, allocator); err != nil { 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 neg_a {
+			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
+			x = ac & _MASK;
+			ac >>= _DIGIT_BITS;
+		} else {
+			x = 0 if i >= a.used else a.digit[i];
+		}
+
+		/*
+			Convert to 2's complement if negative.
+		*/
+		if neg_b {
+			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
+			y = bc & _MASK;
+			bc >>= _DIGIT_BITS;
+		} else {
+			y = 0 if i >= b.used else b.digit[i];
+		}
+
+		dest.digit[i] = x | y;
+
+		/*
+			Convert to to sign-magnitude if negative.
+		*/
+		if neg {
+			cc += ~dest.digit[i] & _MASK;
+			dest.digit[i] = cc & _MASK;
+			cc >>= _DIGIT_BITS;
+		}
+	}
+
+	dest.used = used;
+	dest.sign = .Negative if neg else .Zero_or_Positive;
+	return clamp(dest);
+}
+internal_or :: proc { internal_int_or, };
+
+/*
+	2's complement `xor`, returns `dest = a ~ b;`
+*/
+internal_int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
+	used := max(a.used, b.used) + 1;
+	/*
+		Grow the destination to accomodate the result.
+	*/
+	if err = grow(dest, used, false, allocator); err != nil { 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 neg_a {
+			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
+			x = ac & _MASK;
+			ac >>= _DIGIT_BITS;
+		} else {
+			x = 0 if i >= a.used else a.digit[i];
+		}
+
+		/*
+			Convert to 2's complement if negative.
+		*/
+		if neg_b {
+			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
+			y = bc & _MASK;
+			bc >>= _DIGIT_BITS;
+		} else {
+			y = 0 if i >= b.used else b.digit[i];
+		}
+
+		dest.digit[i] = x ~ y;
+
+		/*
+			Convert to to sign-magnitude if negative.
+		*/
+		if neg {
+			cc += ~dest.digit[i] & _MASK;
+			dest.digit[i] = cc & _MASK;
+			cc >>= _DIGIT_BITS;
+		}
+	}
+
+	dest.used = used;
+	dest.sign = .Negative if neg else .Zero_or_Positive;
+	return clamp(dest);
+}
+internal_xor :: proc { internal_int_xor, };
+
+/*
+	dest = ~src
+*/
+internal_int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
+	/*
+		Temporarily fix sign.
+	*/
+	old_sign := src.sign;
+	z, _ := is_zero(src);
+
+	src.sign = .Negative if (src.sign == .Zero_or_Positive || z) else .Zero_or_Positive;
+
+	err = internal_sub(dest, src, 1);
+	/*
+		Restore sign.
+	*/
+	src.sign = old_sign;
+
+	return err;
+}
+internal_complement :: proc { internal_int_complement, };
+
+/*
+	quotient, remainder := numerator >> bits;
+	`remainder` is allowed to be passed a `nil`, in which case `mod` won't be computed.
+*/
+internal_int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
+	bits := bits;
+	if bits < 0 { return .Invalid_Argument; }
+
+	if err = internal_copy(quotient, numerator, true, allocator); err != nil { return err; }
+
+	/*
+		Shift right by a certain bit count (store quotient and optional remainder.)
+	   `numerator` should not be used after this.
+	*/
+	if remainder != nil {
+		if err = mod_bits(remainder, numerator, bits); err != nil { return err; }
+	}
+
+	/*
+		Shift by as many digits in the bit count.
+	*/
+	if bits >= _DIGIT_BITS {
+		if err = shr_digit(quotient, bits / _DIGIT_BITS); err != nil { return err; }
+	}
+
+	/*
+		Shift any bit count < _DIGIT_BITS.
+	*/
+	bits %= _DIGIT_BITS;
+	if bits != 0 {
+		mask  := DIGIT(1 << uint(bits)) - 1;
+		shift := DIGIT(_DIGIT_BITS - bits);
+		carry := DIGIT(0);
+
+		for x := quotient.used - 1; x >= 0; x -= 1 {
+			/*
+				Get the lower bits of this word in a temp.
+			*/
+			fwd_carry := quotient.digit[x] & mask;
+
+			/*
+				Shift the current word and mix in the carry bits from the previous word.
+			*/
+	        quotient.digit[x] = (quotient.digit[x] >> uint(bits)) | (carry << shift);
+
+	        /*
+	        	Update carry from forward carry.
+	        */
+	        carry = fwd_carry;
+		}
+
+	}
+	return clamp(numerator);
+}
+internal_shrmod :: proc { internal_int_shrmod, };
+
+internal_int_shr :: proc(dest, source: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
+	return internal_shrmod(dest, nil, source, bits, allocator);
+}
+internal_shr :: proc { internal_int_shr, };
+
+/*
+	Shift right by `digits` * _DIGIT_BITS bits.
+*/
+internal_int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
+	if digits <= 0 { return nil; }
+
+	/*
+		If digits > used simply zero and return.
+	*/
+	if digits > quotient.used {
+		return internal_zero(quotient, true, allocator);
+	}
+
+   	/*
+		Much like `int_shl_digit`, this is implemented using a sliding window,
+		except the window goes the other way around.
+
+		b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
+		            /\                   |      ---->
+		             \-------------------/      ---->
+    */
+
+	for x := 0; x < (quotient.used - digits); x += 1 {
+    	quotient.digit[x] = quotient.digit[x + digits];
+	}
+	quotient.used -= digits;
+	zero_unused(quotient);
+	return clamp(quotient);
+}
+internal_shr_digit :: proc { internal_int_shr_digit, };
+
+/*
+	Shift right by a certain bit count with sign extension.
+*/
+internal_int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
+	if src.sign == .Zero_or_Positive {
+		return internal_shr(dest, src, bits, allocator);
+	}
+	if err = internal_int_add_digit(dest, src, DIGIT(1), allocator);		err != nil { return err; }
+
+	if err = internal_shr(dest, dest, bits, allocator);			err != nil { return err; }
+	return internal_sub(dest, src, DIGIT(1), allocator);
+}
+
+internal_shr_signed :: proc { internal_int_shr_signed, };
+
+/*
+	Shift left by a certain bit count.
+*/
+internal_int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
+	bits := bits;
+
+	if bits < 0 { return .Invalid_Argument; }
+
+	if err = copy(dest, src, false, allocator); err != nil { return err; }
+
+	/*
+		Grow `dest` to accommodate the additional bits.
+	*/
+	digits_needed := dest.used + (bits / _DIGIT_BITS) + 1;
+	if err = grow(dest, digits_needed); err != nil { return err; }
+	dest.used = digits_needed;
+	/*
+		Shift by as many digits in the bit count as we have.
+	*/
+	if bits >= _DIGIT_BITS {
+		if err = shl_digit(dest, bits / _DIGIT_BITS); err != nil { return err; }
+	}
+
+	/*
+		Shift any remaining bit count < _DIGIT_BITS
+	*/
+	bits %= _DIGIT_BITS;
+	if bits != 0 {
+		mask  := (DIGIT(1) << uint(bits)) - DIGIT(1);
+		shift := DIGIT(_DIGIT_BITS - bits);
+		carry := DIGIT(0);
+
+		for x:= 0; x < dest.used; x+= 1 {		
+			fwd_carry := (dest.digit[x] >> shift) & mask;
+			dest.digit[x] = (dest.digit[x] << uint(bits) | carry) & _MASK;
+			carry = fwd_carry;
+		}
+
+		/*
+			Use final carry.
+		*/
+		if carry != 0 {
+			dest.digit[dest.used] = carry;
+			dest.used += 1;
+		}
+	}
+	return clamp(dest);
+}
+internal_shl :: proc { internal_int_shl, };
+
+
+/*
+	Shift left by `digits` * _DIGIT_BITS bits.
+*/
+internal_int_shl_digit :: proc(quotient: ^Int, digits: int) -> (err: Error) {
+	if digits <= 0 { return nil; }
+
+	/*
+		No need to shift a zero.
+	*/
+	z: bool;
+	if z, err = is_zero(quotient); z || err != nil { return err; }
+
+	/*
+		Resize `quotient` to accomodate extra digits.
+	*/
+	if err = grow(quotient, quotient.used + digits); err != nil { return err; }
+
+	/*
+		Increment the used by the shift amount then copy upwards.
+	*/
+
+	/*
+		Much like `int_shr_digit`, this is implemented using a sliding window,
+		except the window goes the other way around.
+    */
+    for x := quotient.used; x > 0; x -= 1 {
+    	quotient.digit[x+digits-1] = quotient.digit[x-1];
+    }
+
+   	quotient.used += digits;
+    mem.zero_slice(quotient.digit[:digits]);
+    return nil;
+}
+internal_shl_digit :: proc { internal_int_shl_digit, };
+
 /*
 /*
 	Count bits in an `Int`.
 	Count bits in an `Int`.
 */
 */
 internal_count_bits :: proc(a: ^Int) -> (count: int, err: Error) {
 internal_count_bits :: proc(a: ^Int) -> (count: int, err: Error) {
-	if err = clear_if_uninitialized(a); err != nil {
+	if err = internal_clear_if_uninitialized_single(a); err != nil {
 		return 0, err;
 		return 0, err;
 	}
 	}
 	/*
 	/*
@@ -2092,7 +2494,7 @@ internal_count_bits :: proc(a: ^Int) -> (count: int, err: Error) {
 	Differs from regular `ctz` in that 0 returns 0.
 	Differs from regular `ctz` in that 0 returns 0.
 */
 */
 internal_int_count_lsb :: proc(a: ^Int) -> (count: int, err: Error) {
 internal_int_count_lsb :: proc(a: ^Int) -> (count: int, err: Error) {
-	if err = clear_if_uninitialized(a); err != nil { return -1, err; }
+	if err = internal_clear_if_uninitialized_single(a); err != nil { return -1, err; }
 
 
 	_ctz :: intrinsics.count_trailing_zeros;
 	_ctz :: intrinsics.count_trailing_zeros;
 	/*
 	/*
@@ -2163,7 +2565,7 @@ internal_assert_initialized :: proc(a: ^Int, loc := #caller_location) {
 }
 }
 
 
 internal_clear_if_uninitialized_single :: proc(arg: ^Int, allocator := context.allocator) -> (err: Error) {
 internal_clear_if_uninitialized_single :: proc(arg: ^Int, allocator := context.allocator) -> (err: Error) {
-	if !internal_is_initialized(arg) {
+	if ! #force_inline internal_is_initialized(arg) {
 		return #force_inline internal_grow(arg, _DEFAULT_DIGIT_COUNT, true, allocator);
 		return #force_inline internal_grow(arg, _DEFAULT_DIGIT_COUNT, true, allocator);
 	}
 	}
 	return err;
 	return err;
@@ -2171,7 +2573,7 @@ internal_clear_if_uninitialized_single :: proc(arg: ^Int, allocator := context.a
 
 
 internal_clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context.allocator) -> (err: Error) {
 internal_clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context.allocator) -> (err: Error) {
 	for i in args {
 	for i in args {
-		if !internal_is_initialized(i) {
+		if ! #force_inline internal_is_initialized(i) {
 			e := #force_inline internal_grow(i, _DEFAULT_DIGIT_COUNT, true, allocator);
 			e := #force_inline internal_grow(i, _DEFAULT_DIGIT_COUNT, true, allocator);
 			if e != nil { err = e; }
 			if e != nil { err = e; }
 		}
 		}
@@ -2208,8 +2610,8 @@ internal_init_multi :: proc { internal_int_init_multi, };
 
 
 _private_copy_digits :: proc(dest, src: ^Int, digits: int) -> (err: Error) {
 _private_copy_digits :: proc(dest, src: ^Int, digits: int) -> (err: Error) {
 	digits := digits;
 	digits := digits;
-	if err = clear_if_uninitialized(src);  err != nil { return err; }
-	if err = clear_if_uninitialized(dest); err != nil { return err; }
+	if err = internal_clear_if_uninitialized_single(src);  err != nil { return err; }
+	if err = internal_clear_if_uninitialized_single(dest); err != nil { return err; }
 	/*
 	/*
 		If dest == src, do nothing
 		If dest == src, do nothing
 	*/
 	*/
@@ -2229,7 +2631,7 @@ _private_copy_digits :: proc(dest, src: ^Int, digits: int) -> (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.
 */
 */
 internal_clamp :: proc(a: ^Int) -> (err: Error) {
 internal_clamp :: proc(a: ^Int) -> (err: Error) {
-	if err = internal_clear_if_uninitialized(a); err != nil {
+	if err = internal_clear_if_uninitialized_single(a); err != nil {
 		return err;
 		return err;
 	}
 	}
 	for a.used > 0 && a.digit[a.used - 1] == 0 {
 	for a.used > 0 && a.digit[a.used - 1] == 0 {

+ 42 - 343
core/math/big/logical.odin

@@ -23,210 +23,48 @@ import "core:mem"
 /*
 /*
 	2's complement `and`, returns `dest = a & b;`
 	2's complement `and`, returns `dest = a & b;`
 */
 */
-int_and :: proc(dest, a, b: ^Int) -> (err: Error) {
+int_and :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(dest, a, b);
 	assert_if_nil(dest, a, b);
-	if err = clear_if_uninitialized(a, b); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
 
 
-	used := max(a.used, b.used) + 1;
-	/*
-		Grow the destination to accomodate the result.
-	*/
-	if err = grow(dest, used); err != nil { 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 neg_a {
-			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
-			x = ac & _MASK;
-			ac >>= _DIGIT_BITS;
-		} else {
-			x = 0 if i >= a.used else a.digit[i];
-		}
-
-		/*
-			Convert to 2's complement if negative.
-		*/
-		if neg_b {
-			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
-			y = bc & _MASK;
-			bc >>= _DIGIT_BITS;
-		} else {
-			y = 0 if i >= b.used else b.digit[i];
-		}
-
-		dest.digit[i] = x & y;
-
-		/*
-			Convert to to sign-magnitude if negative.
-		*/
-		if neg {
-			cc += ~dest.digit[i] & _MASK;
-			dest.digit[i] = cc & _MASK;
-			cc >>= _DIGIT_BITS;
-		}
-	}
-
-	dest.used = used;
-	dest.sign = .Negative if neg else .Zero_or_Positive;
-	return clamp(dest);
+	return #force_inline internal_int_and(dest, a, b, allocator);
 }
 }
-and :: proc { int_add, };
+and :: proc { int_and, };
 
 
 /*
 /*
 	2's complement `or`, returns `dest = a | b;`
 	2's complement `or`, returns `dest = a | b;`
 */
 */
-int_or :: proc(dest, a, b: ^Int) -> (err: Error) {
-	if err = clear_if_uninitialized(a, b); err != nil { return err; }
-	used := max(a.used, b.used) + 1;
-	/*
-		Grow the destination to accomodate the result.
-	*/
-	if err = grow(dest, used); err != nil { 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 neg_a {
-			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
-			x = ac & _MASK;
-			ac >>= _DIGIT_BITS;
-		} else {
-			x = 0 if i >= a.used else a.digit[i];
-		}
-
-		/*
-			Convert to 2's complement if negative.
-		*/
-		if neg_b {
-			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
-			y = bc & _MASK;
-			bc >>= _DIGIT_BITS;
-		} else {
-			y = 0 if i >= b.used else b.digit[i];
-		}
-
-		dest.digit[i] = x | y;
-
-		/*
-			Convert to to sign-magnitude if negative.
-		*/
-		if neg {
-			cc += ~dest.digit[i] & _MASK;
-			dest.digit[i] = cc & _MASK;
-			cc >>= _DIGIT_BITS;
-		}
-	}
+int_or :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
+	assert_if_nil(dest, a, b);
+	if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
 
 
-	dest.used = used;
-	dest.sign = .Negative if neg else .Zero_or_Positive;
-	return clamp(dest);
+	return #force_inline internal_int_or(dest, a, b, allocator);
 }
 }
 or :: proc { int_or, };
 or :: proc { int_or, };
 
 
 /*
 /*
-	2's complement `xor`, returns `dest = a ~ b;`
+	2's complement `xor`, returns `dest = a ^ b;`
 */
 */
-int_xor :: proc(dest, a, b: ^Int) -> (err: Error) {
-	if err = clear_if_uninitialized(a, b); err != nil { return err; }
-
-	used := max(a.used, b.used) + 1;
-	/*
-		Grow the destination to accomodate the result.
-	*/
-	if err = grow(dest, used); err != nil { 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 neg_a {
-			ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
-			x = ac & _MASK;
-			ac >>= _DIGIT_BITS;
-		} else {
-			x = 0 if i >= a.used else a.digit[i];
-		}
-
-		/*
-			Convert to 2's complement if negative.
-		*/
-		if neg_b {
-			bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
-			y = bc & _MASK;
-			bc >>= _DIGIT_BITS;
-		} else {
-			y = 0 if i >= b.used else b.digit[i];
-		}
-
-		dest.digit[i] = x ~ y;
-
-		/*
-			Convert to to sign-magnitude if negative.
-		*/
-		if neg {
-			cc += ~dest.digit[i] & _MASK;
-			dest.digit[i] = cc & _MASK;
-			cc >>= _DIGIT_BITS;
-		}
-	}
+int_xor :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
+	assert_if_nil(dest, a, b);
+	if err = internal_clear_if_uninitialized(a, b); err != nil { return err; }
 
 
-	dest.used = used;
-	dest.sign = .Negative if neg else .Zero_or_Positive;
-	return clamp(dest);
+	return #force_inline internal_int_xor(dest, a, b, allocator);
 }
 }
 xor :: proc { int_xor, };
 xor :: proc { int_xor, };
 
 
 /*
 /*
 	dest = ~src
 	dest = ~src
 */
 */
-int_complement :: proc(dest, src: ^Int) -> (err: Error) {
+int_complement :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
 	/*
 	/*
-		Check that src is usable. Dest will get checked by `sub`.
+		Check that `src` and `dest` are usable.
 	*/
 	*/
-	if err = clear_if_uninitialized(src); err != nil { return err; }
+	assert_if_nil(dest, src);
+	if err = internal_clear_if_uninitialized(dest, allocator); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(src, allocator);  err != nil { return err; }
 
 
-	/*
-		Temporarily fix sign.
-	*/
-	old_sign := src.sign;
-	z, _ := is_zero(src);
-
-	src.sign = .Negative if (src.sign == .Zero_or_Positive || z) else .Zero_or_Positive;
-
-	err = sub(dest, src, 1);
-	/*
-		Restore sign.
-	*/
-	src.sign = old_sign;
-
-	return err;
+	return #force_inline internal_int_complement(dest, src);
 }
 }
 complement :: proc { int_complement, };
 complement :: proc { int_complement, };
 
 
@@ -234,115 +72,43 @@ complement :: proc { int_complement, };
 	quotient, remainder := numerator >> bits;
 	quotient, remainder := numerator >> bits;
 	`remainder` is allowed to be passed a `nil`, in which case `mod` won't be computed.
 	`remainder` is allowed to be passed a `nil`, in which case `mod` won't be computed.
 */
 */
-int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int) -> (err: Error) {
-	bits := bits;
-	if err = clear_if_uninitialized(quotient, numerator);  err != nil { return err; }
-
-	if bits < 0 { return .Invalid_Argument; }
-
-	if err = copy(quotient, numerator); err != nil { return err; }
-
-	/*
-		Shift right by a certain bit count (store quotient and optional remainder.)
-	   `numerator` should not be used after this.
-	*/
-	if remainder != nil {
-		if err = mod_bits(remainder, numerator, bits); err != nil { return err; }
-	}
-
-	/*
-		Shift by as many digits in the bit count.
-	*/
-	if bits >= _DIGIT_BITS {
-		if err = shr_digit(quotient, bits / _DIGIT_BITS); err != nil { return err; }
-	}
-
-	/*
-		Shift any bit count < _DIGIT_BITS.
-	*/
-	bits %= _DIGIT_BITS;
-	if bits != 0 {
-		mask  := DIGIT(1 << uint(bits)) - 1;
-		shift := DIGIT(_DIGIT_BITS - bits);
-		carry := DIGIT(0);
-
-		for x := quotient.used - 1; x >= 0; x -= 1 {
-			/*
-				Get the lower bits of this word in a temp.
-			*/
-			fwd_carry := quotient.digit[x] & mask;
-
-			/*
-				Shift the current word and mix in the carry bits from the previous word.
-			*/
-	        quotient.digit[x] = (quotient.digit[x] >> uint(bits)) | (carry << shift);
-
-	        /*
-	        	Update carry from forward carry.
-	        */
-	        carry = fwd_carry;
-		}
+int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
+	assert_if_nil(quotient, numerator);
+	if err = internal_clear_if_uninitialized(quotient, allocator);  err != nil { return err; }
+	if err = internal_clear_if_uninitialized(numerator, allocator); err != nil { return err; }
 
 
-	}
-	return clamp(numerator);
+	return #force_inline internal_int_shrmod(quotient, remainder, numerator, bits, allocator);
 }
 }
 shrmod :: proc { int_shrmod, };
 shrmod :: proc { int_shrmod, };
 
 
 int_shr :: proc(dest, source: ^Int, bits: int) -> (err: Error) {
 int_shr :: proc(dest, source: ^Int, bits: int) -> (err: Error) {
-	return shrmod(dest, nil, source, bits);
+	return #force_inline shrmod(dest, nil, source, bits);
 }
 }
 shr :: proc { int_shr, };
 shr :: proc { int_shr, };
 
 
 /*
 /*
 	Shift right by `digits` * _DIGIT_BITS bits.
 	Shift right by `digits` * _DIGIT_BITS bits.
 */
 */
-int_shr_digit :: proc(quotient: ^Int, digits: int) -> (err: Error) {
+int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
 	/*
 	/*
 		Check that `quotient` is usable.
 		Check that `quotient` is usable.
 	*/
 	*/
-	if err = clear_if_uninitialized(quotient); err != nil { return err; }
+	assert_if_nil(quotient);
+	if err = internal_clear_if_uninitialized(quotient, allocator); err != nil { return err; }
 
 
-	if digits <= 0 { return nil; }
-
-	/*
-		If digits > used simply zero and return.
-	*/
-	if digits > quotient.used {
-		return zero(quotient);
-	}
-
-   	/*
-		Much like `int_shl_digit`, this is implemented using a sliding window,
-		except the window goes the other way around.
-
-		b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
-		            /\                   |      ---->
-		             \-------------------/      ---->
-    */
-
-	for x := 0; x < (quotient.used - digits); x += 1 {
-    	quotient.digit[x] = quotient.digit[x + digits];
-	}
-	quotient.used -= digits;
-	zero_unused(quotient);
-	return clamp(quotient);
+	return #force_inline internal_int_shr_digit(quotient, digits, allocator);
 }
 }
 shr_digit :: proc { int_shr_digit, };
 shr_digit :: proc { int_shr_digit, };
 
 
 /*
 /*
 	Shift right by a certain bit count with sign extension.
 	Shift right by a certain bit count with sign extension.
 */
 */
-int_shr_signed :: proc(dest, src: ^Int, bits: int) -> (err: Error) {
-	if err = clear_if_uninitialized(src);	err != nil { return err; }
-	if err = clear_if_uninitialized(dest);	err != nil { return err; }
-
-	if src.sign == .Zero_or_Positive {
-		return shr(dest, src, bits);
-	}
-	if err = add(dest, src, DIGIT(1));		err != nil { return err; }
+int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
+	assert_if_nil(dest, src);
+	if err = internal_clear_if_uninitialized(dest, allocator); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(src, allocator);  err != nil { return err; }
 
 
-	if err = shr(dest, dest, bits);			err != nil { return err; }
-	return sub(dest, src, DIGIT(1));
+	return #force_inline internal_int_shr_signed(dest, src, bits);
 }
 }
 
 
 shr_signed :: proc { int_shr_signed, };
 shr_signed :: proc { int_shr_signed, };
@@ -350,53 +116,12 @@ shr_signed :: proc { int_shr_signed, };
 /*
 /*
 	Shift left by a certain bit count.
 	Shift left by a certain bit count.
 */
 */
-int_shl :: proc(dest, src: ^Int, bits: int) -> (err: Error) {
-	bits := bits;
-	if err = clear_if_uninitialized(src, dest);  err != nil { return err; }
-
-	if bits < 0 {
-		return .Invalid_Argument;
-	}
+int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
+	assert_if_nil(dest, src);
+	if err = internal_clear_if_uninitialized(dest, allocator); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(src, allocator);  err != nil { return err; }
 
 
-	if err = copy(dest, src); err != nil { return err; }
-
-	/*
-		Grow `dest` to accommodate the additional bits.
-	*/
-	digits_needed := dest.used + (bits / _DIGIT_BITS) + 1;
-	if err = grow(dest, digits_needed); err != nil { return err; }
-	dest.used = digits_needed;
-	/*
-		Shift by as many digits in the bit count as we have.
-	*/
-	if bits >= _DIGIT_BITS {
-		if err = shl_digit(dest, bits / _DIGIT_BITS); err != nil { return err; }
-	}
-
-	/*
-		Shift any remaining bit count < _DIGIT_BITS
-	*/
-	bits %= _DIGIT_BITS;
-	if bits != 0 {
-		mask  := (DIGIT(1) << uint(bits)) - DIGIT(1);
-		shift := DIGIT(_DIGIT_BITS - bits);
-		carry := DIGIT(0);
-
-		for x:= 0; x < dest.used; x+= 1 {		
-			fwd_carry := (dest.digit[x] >> shift) & mask;
-			dest.digit[x] = (dest.digit[x] << uint(bits) | carry) & _MASK;
-			carry = fwd_carry;
-		}
-
-		/*
-			Use final carry.
-		*/
-		if carry != 0 {
-			dest.digit[dest.used] = carry;
-			dest.used += 1;
-		}
-	}
-	return clamp(dest);
+	return #force_inline internal_int_shl(dest, src, bits);
 }
 }
 shl :: proc { int_shl, };
 shl :: proc { int_shl, };
 
 
@@ -408,35 +133,9 @@ int_shl_digit :: proc(quotient: ^Int, digits: int) -> (err: Error) {
 	/*
 	/*
 		Check that `quotient` is usable.
 		Check that `quotient` is usable.
 	*/
 	*/
-	if err = clear_if_uninitialized(quotient); err != nil { return err; }
-
-	if digits <= 0 { return nil; }
-
-	/*
-		No need to shift a zero.
-	*/
-	z: bool;
-	if z, err = is_zero(quotient); z || err != nil { return err; }
-
-	/*
-		Resize `quotient` to accomodate extra digits.
-	*/
-	if err = grow(quotient, quotient.used + digits); err != nil { return err; }
-
-	/*
-		Increment the used by the shift amount then copy upwards.
-	*/
-
-	/*
-		Much like `int_shr_digit`, this is implemented using a sliding window,
-		except the window goes the other way around.
-    */
-    for x := quotient.used; x > 0; x -= 1 {
-    	quotient.digit[x+digits-1] = quotient.digit[x-1];
-    }
+	assert_if_nil(quotient);
+	if err = internal_clear_if_uninitialized(quotient); err != nil { return err; }
 
 
-   	quotient.used += digits;
-    mem.zero_slice(quotient.digit[:digits]);
-    return nil;
+	return #force_inline internal_int_shl_digit(quotient, digits);
 }
 }
 shl_digit :: proc { int_shl_digit, };
 shl_digit :: proc { int_shl_digit, };

+ 4 - 2
core/math/big/prime.odin

@@ -15,11 +15,13 @@ package big
 	Determines if an Integer is divisible by one of the _PRIME_TABLE primes.
 	Determines if an Integer is divisible by one of the _PRIME_TABLE primes.
 	Returns true if it is, false if not. 
 	Returns true if it is, false if not. 
 */
 */
-int_prime_is_divisible :: proc(a: ^Int) -> (res: bool, err: Error) {
+int_prime_is_divisible :: proc(a: ^Int, allocator := context.allocator) -> (res: bool, err: Error) {
+	assert_if_nil(a);
+	if err = internal_clear_if_uninitialized(a, allocator); err != nil { return {}, err; }
 
 
 	rem: DIGIT;
 	rem: DIGIT;
 	for prime in _private_prime_table {
 	for prime in _private_prime_table {
-		if rem, err = mod(a, prime); err != nil { return false, err; }
+		if rem, err = #force_inline int_mod_digit(a, prime); err != nil { return false, err; }
 		if rem == 0 { return true, nil; }
 		if rem == 0 { return true, nil; }
 	}
 	}
 	/*
 	/*

+ 33 - 33
core/math/big/public.odin

@@ -22,7 +22,7 @@ package big
 */
 */
 int_add :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
 int_add :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(dest, a, b);
 	assert_if_nil(dest, a, b);
-	if err = clear_if_uninitialized(dest, a, b); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(dest, a, b); err != nil { return err; }
 	/*
 	/*
 		All parameters have been initialized.
 		All parameters have been initialized.
 	*/
 	*/
@@ -37,7 +37,7 @@ int_add :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error
 */
 */
 int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
 int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(dest, a);
 	assert_if_nil(dest, a);
-	if err = clear_if_uninitialized(a); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(a); err != nil { return err; }
 	/*
 	/*
 		Grow destination as required.
 		Grow destination as required.
 	*/
 	*/
@@ -54,7 +54,7 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocato
 */
 */
 int_sub :: proc(dest, number, decrease: ^Int, allocator := context.allocator) -> (err: Error) {
 int_sub :: proc(dest, number, decrease: ^Int, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(dest, number, decrease);
 	assert_if_nil(dest, number, decrease);
-	if err = clear_if_uninitialized(dest, number, decrease); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(dest, number, decrease); err != nil { return err; }
 	/*
 	/*
 		All parameters have been initialized.
 		All parameters have been initialized.
 	*/
 	*/
@@ -69,7 +69,7 @@ int_sub :: proc(dest, number, decrease: ^Int, allocator := context.allocator) ->
 */
 */
 int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
 int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(dest, a);
 	assert_if_nil(dest, a);
-	if err = clear_if_uninitialized(a); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(a); err != nil { return err; }
 	/*
 	/*
 		Grow destination as required.
 		Grow destination as required.
 	*/
 	*/
@@ -87,7 +87,7 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocato
 */
 */
 int_halve :: proc(dest, src: ^Int) -> (err: Error) {
 int_halve :: proc(dest, src: ^Int) -> (err: Error) {
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
-	if err = clear_if_uninitialized(dest, src); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
 	/*
 	/*
 		Grow destination as required.
 		Grow destination as required.
 	*/
 	*/
@@ -104,7 +104,7 @@ shr1  :: halve;
 */
 */
 int_double :: proc(dest, src: ^Int) -> (err: Error) {
 int_double :: proc(dest, src: ^Int) -> (err: Error) {
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
-	if err = clear_if_uninitialized(dest, src); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(dest, src); err != nil { return err; }
 	/*
 	/*
 		Grow destination as required.
 		Grow destination as required.
 	*/
 	*/
@@ -120,7 +120,7 @@ shl1   :: double;
 */
 */
 int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator := context.allocator) -> (err: Error) {
 int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
-	if err = clear_if_uninitialized(src, dest); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(src, dest); err != nil { return err; }
 
 
 	return #force_inline internal_int_mul_digit(dest, src, multiplier, allocator);
 	return #force_inline internal_int_mul_digit(dest, src, multiplier, allocator);
 }
 }
@@ -130,7 +130,7 @@ int_mul_digit :: proc(dest, src: ^Int, multiplier: DIGIT, allocator := context.a
 */
 */
 int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.allocator) -> (err: Error) {
 int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.allocator) -> (err: Error) {
 	assert_if_nil(dest, src, multiplier);
 	assert_if_nil(dest, src, multiplier);
-	if err = clear_if_uninitialized(dest, src, multiplier); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(dest, src, multiplier); err != nil { return err; }
 
 
 	return #force_inline internal_int_mul(dest, src, multiplier, allocator);
 	return #force_inline internal_int_mul(dest, src, multiplier, allocator);
 }
 }
@@ -148,14 +148,14 @@ int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: E
 		Early out if neither of the results is wanted.
 		Early out if neither of the results is wanted.
 	*/
 	*/
 	if quotient == nil && remainder == nil { return nil; }
 	if quotient == nil && remainder == nil { return nil; }
-	if err = clear_if_uninitialized(numerator, denominator); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(numerator, denominator); err != nil { return err; }
 
 
 	return #force_inline internal_divmod(quotient, remainder, numerator, denominator);
 	return #force_inline internal_divmod(quotient, remainder, numerator, denominator);
 }
 }
 
 
 int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT) -> (remainder: DIGIT, err: Error) {
 int_divmod_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT) -> (remainder: DIGIT, err: Error) {
 	assert_if_nil(quotient, numerator);
 	assert_if_nil(quotient, numerator);
-	if err = clear_if_uninitialized(numerator); err != nil { return 0, err; }
+	if err = internal_clear_if_uninitialized(numerator); err != nil { return 0, err; }
 
 
 	return #force_inline internal_divmod(quotient, numerator, denominator);
 	return #force_inline internal_divmod(quotient, numerator, denominator);
 }
 }
@@ -163,14 +163,14 @@ divmod :: proc{ int_divmod, int_divmod_digit, };
 
 
 int_div :: proc(quotient, numerator, denominator: ^Int) -> (err: Error) {
 int_div :: proc(quotient, numerator, denominator: ^Int) -> (err: Error) {
 	assert_if_nil(quotient, numerator, denominator);
 	assert_if_nil(quotient, numerator, denominator);
-	if err = clear_if_uninitialized(numerator, denominator); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(numerator, denominator); err != nil { return err; }
 
 
 	return #force_inline internal_divmod(quotient, nil, numerator, denominator);
 	return #force_inline internal_divmod(quotient, nil, numerator, denominator);
 }
 }
 
 
 int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT) -> (err: Error) {
 int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT) -> (err: Error) {
 	assert_if_nil(quotient, numerator);
 	assert_if_nil(quotient, numerator);
-	if err = clear_if_uninitialized(numerator); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(numerator); err != nil { return err; }
 
 
 	remainder: DIGIT;
 	remainder: DIGIT;
 	remainder, err = #force_inline internal_divmod(quotient, numerator, denominator);
 	remainder, err = #force_inline internal_divmod(quotient, numerator, denominator);
@@ -185,7 +185,7 @@ div :: proc { int_div, int_div_digit, };
 */
 */
 int_mod :: proc(remainder, numerator, denominator: ^Int) -> (err: Error) {
 int_mod :: proc(remainder, numerator, denominator: ^Int) -> (err: Error) {
 	assert_if_nil(remainder, numerator, denominator);
 	assert_if_nil(remainder, numerator, denominator);
-	if err = clear_if_uninitialized(numerator, denominator); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(numerator, denominator); err != nil { return err; }
 
 
 	return #force_inline internal_int_mod(remainder, numerator, denominator);
 	return #force_inline internal_int_mod(remainder, numerator, denominator);
 }
 }
@@ -201,7 +201,7 @@ mod :: proc { int_mod, int_mod_digit, };
 */
 */
 int_addmod :: proc(remainder, number, addend, modulus: ^Int) -> (err: Error) {
 int_addmod :: proc(remainder, number, addend, modulus: ^Int) -> (err: Error) {
 	assert_if_nil(remainder, number, addend);
 	assert_if_nil(remainder, number, addend);
-	if err = clear_if_uninitialized(number, addend, modulus); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(number, addend, modulus); err != nil { return err; }
 
 
 	return #force_inline internal_addmod(remainder, number, addend, modulus);
 	return #force_inline internal_addmod(remainder, number, addend, modulus);
 }
 }
@@ -212,7 +212,7 @@ addmod :: proc { int_addmod, };
 */
 */
 int_submod :: proc(remainder, number, decrease, modulus: ^Int) -> (err: Error) {
 int_submod :: proc(remainder, number, decrease, modulus: ^Int) -> (err: Error) {
 	assert_if_nil(remainder, number, decrease);
 	assert_if_nil(remainder, number, decrease);
-	if err = clear_if_uninitialized(number, decrease, modulus); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(number, decrease, modulus); err != nil { return err; }
 
 
 	return #force_inline internal_submod(remainder, number, decrease, modulus);
 	return #force_inline internal_submod(remainder, number, decrease, modulus);
 }
 }
@@ -223,7 +223,7 @@ submod :: proc { int_submod, };
 */
 */
 int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int) -> (err: Error) {
 int_mulmod :: proc(remainder, number, multiplicand, modulus: ^Int) -> (err: Error) {
 	assert_if_nil(remainder, number, multiplicand);
 	assert_if_nil(remainder, number, multiplicand);
-	if err = clear_if_uninitialized(number, multiplicand, modulus); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(number, multiplicand, modulus); err != nil { return err; }
 
 
 	return #force_inline internal_mulmod(remainder, number, multiplicand, modulus);
 	return #force_inline internal_mulmod(remainder, number, multiplicand, modulus);
 }
 }
@@ -234,7 +234,7 @@ mulmod :: proc { int_mulmod, };
 */
 */
 int_sqrmod :: proc(remainder, number, modulus: ^Int) -> (err: Error) {
 int_sqrmod :: proc(remainder, number, modulus: ^Int) -> (err: Error) {
 	assert_if_nil(remainder, number, modulus);
 	assert_if_nil(remainder, number, modulus);
-	if err = clear_if_uninitialized(number, modulus); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(number, modulus); err != nil { return err; }
 
 
 	return #force_inline internal_sqrmod(remainder, number, modulus);
 	return #force_inline internal_sqrmod(remainder, number, modulus);
 }
 }
@@ -295,8 +295,8 @@ int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context.allocator
 	if res_gcd == nil && res_lcm == nil { return nil; }
 	if res_gcd == nil && res_lcm == nil { return nil; }
 	assert_if_nil(a, b);
 	assert_if_nil(a, b);
 
 
-	if err = clear_if_uninitialized(a, allocator); err != nil { return err; }
-	if err = clear_if_uninitialized(b, allocator); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(a, allocator); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(b, allocator); err != nil { return err; }
 	return #force_inline internal_int_gcd_lcm(res_gcd, res_lcm, a, b);
 	return #force_inline internal_int_gcd_lcm(res_gcd, res_lcm, a, b);
 }
 }
 gcd_lcm :: proc { int_gcd_lcm, };
 gcd_lcm :: proc { int_gcd_lcm, };
@@ -323,7 +323,7 @@ lcm :: proc { int_lcm, };
 int_mod_bits :: proc(remainder, numerator: ^Int, bits: int) -> (err: Error) {
 int_mod_bits :: proc(remainder, numerator: ^Int, bits: int) -> (err: Error) {
 	assert_if_nil(remainder, numerator);
 	assert_if_nil(remainder, numerator);
 
 
-	if err = clear_if_uninitialized(remainder, numerator); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(remainder, numerator); err != nil { return err; }
 	if bits  < 0 { return .Invalid_Argument; }
 	if bits  < 0 { return .Invalid_Argument; }
 
 
 	return #force_inline internal_int_mod_bits(remainder, numerator, bits);
 	return #force_inline internal_int_mod_bits(remainder, numerator, bits);
@@ -337,7 +337,7 @@ mod_bits :: proc { int_mod_bits, };
 */
 */
 int_log :: proc(a: ^Int, base: DIGIT) -> (res: int, err: Error) {
 int_log :: proc(a: ^Int, base: DIGIT) -> (res: int, err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = clear_if_uninitialized(a); err != nil { return 0, err; }
+	if err = internal_clear_if_uninitialized(a); err != nil { return 0, err; }
 
 
 	return #force_inline internal_int_log(a, base);
 	return #force_inline internal_int_log(a, base);
 }
 }
@@ -352,7 +352,7 @@ log :: proc { int_log, digit_log, };
 */
 */
 int_pow :: proc(dest, base: ^Int, power: int) -> (err: Error) {
 int_pow :: proc(dest, base: ^Int, power: int) -> (err: Error) {
 	assert_if_nil(dest, base);
 	assert_if_nil(dest, base);
-	if err = clear_if_uninitialized(dest, base); err != nil { return err; }
+	if err = internal_clear_if_uninitialized(dest, base); err != nil { return err; }
 
 
 	return #force_inline internal_int_pow(dest, base, power);
 	return #force_inline internal_int_pow(dest, base, power);
 }
 }
@@ -378,7 +378,7 @@ small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) {
 */
 */
 int_sqrt :: proc(dest, src: ^Int) -> (err: Error) {
 int_sqrt :: proc(dest, src: ^Int) -> (err: Error) {
 	assert_if_nil(dest, src);
 	assert_if_nil(dest, src);
-	if err = clear_if_uninitialized(dest, src);	err != nil { return err; }
+	if err = internal_clear_if_uninitialized(dest, src);	err != nil { return err; }
 
 
 	return #force_inline internal_int_sqrt(dest, src);
 	return #force_inline internal_int_sqrt(dest, src);
 }
 }
@@ -402,7 +402,7 @@ int_root_n :: proc(dest, src: ^Int, n: int) -> (err: Error) {
 	/*
 	/*
 		Initialize dest + src if needed.
 		Initialize dest + src if needed.
 	*/
 	*/
-	if err = clear_if_uninitialized(dest, src);	err != nil { return err; }
+	if err = internal_clear_if_uninitialized(dest, src);	err != nil { return err; }
 
 
 	return #force_inline internal_int_root_n(dest, src, n);
 	return #force_inline internal_int_root_n(dest, src, n);
 }
 }
@@ -420,35 +420,35 @@ int_is_initialized :: proc(a: ^Int) -> bool {
 
 
 int_is_zero :: proc(a: ^Int) -> (zero: bool, err: Error) {
 int_is_zero :: proc(a: ^Int) -> (zero: bool, err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = clear_if_uninitialized(a); err != nil { return false, err; }
+	if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
 
 
 	return #force_inline internal_is_zero(a), nil;
 	return #force_inline internal_is_zero(a), nil;
 }
 }
 
 
 int_is_positive :: proc(a: ^Int) -> (positive: bool, err: Error) {
 int_is_positive :: proc(a: ^Int) -> (positive: bool, err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = clear_if_uninitialized(a); err != nil { return false, err; }
+	if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
 
 
 	return #force_inline internal_is_positive(a), nil;
 	return #force_inline internal_is_positive(a), nil;
 }
 }
 
 
 int_is_negative :: proc(a: ^Int) -> (negative: bool, err: Error) {
 int_is_negative :: proc(a: ^Int) -> (negative: bool, err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = clear_if_uninitialized(a); err != nil { return false, err; }
+	if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
 
 
 	return #force_inline internal_is_negative(a), nil;
 	return #force_inline internal_is_negative(a), nil;
 }
 }
 
 
 int_is_even :: proc(a: ^Int) -> (even: bool, err: Error) {
 int_is_even :: proc(a: ^Int) -> (even: bool, err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = clear_if_uninitialized(a); err != nil { return false, err; }
+	if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
 
 
 	return #force_inline internal_is_even(a), nil;
 	return #force_inline internal_is_even(a), nil;
 }
 }
 
 
 int_is_odd :: proc(a: ^Int) -> (odd: bool, err: Error) {
 int_is_odd :: proc(a: ^Int) -> (odd: bool, err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = clear_if_uninitialized(a); err != nil { return false, err; }
+	if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
 
 
 	return #force_inline internal_is_odd(a), nil;
 	return #force_inline internal_is_odd(a), nil;
 }
 }
@@ -459,7 +459,7 @@ platform_int_is_power_of_two :: #force_inline proc(a: int) -> bool {
 
 
 int_is_power_of_two :: proc(a: ^Int) -> (res: bool, err: Error) {
 int_is_power_of_two :: proc(a: ^Int) -> (res: bool, err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = clear_if_uninitialized(a); err != nil { return false, err; }
+	if err = internal_clear_if_uninitialized(a); err != nil { return false, err; }
 
 
 	return #force_inline internal_is_power_of_two(a), nil;
 	return #force_inline internal_is_power_of_two(a), nil;
 }
 }
@@ -469,7 +469,7 @@ int_is_power_of_two :: proc(a: ^Int) -> (res: bool, err: Error) {
 */
 */
 int_compare :: proc(a, b: ^Int) -> (comparison: int, err: Error) {
 int_compare :: proc(a, b: ^Int) -> (comparison: int, err: Error) {
 	assert_if_nil(a, b);
 	assert_if_nil(a, b);
-	if err = clear_if_uninitialized(a, b); err != nil {	return 0, err; }
+	if err = internal_clear_if_uninitialized(a, b); err != nil {	return 0, err; }
 
 
 	return #force_inline internal_cmp(a, b), nil;
 	return #force_inline internal_cmp(a, b), nil;
 }
 }
@@ -480,7 +480,7 @@ int_cmp :: int_compare;
 */
 */
 int_compare_digit :: proc(a: ^Int, b: DIGIT) -> (comparison: int, err: Error) {
 int_compare_digit :: proc(a: ^Int, b: DIGIT) -> (comparison: int, err: Error) {
 	assert_if_nil(a);
 	assert_if_nil(a);
-	if err = clear_if_uninitialized(a); err != nil { return 0, err; }
+	if err = internal_clear_if_uninitialized(a); err != nil { return 0, err; }
 
 
 	return #force_inline internal_cmp_digit(a, b), nil;
 	return #force_inline internal_cmp_digit(a, b), nil;
 }
 }
@@ -491,7 +491,7 @@ int_cmp_digit :: int_compare_digit;
 */
 */
 int_compare_magnitude :: proc(a, b: ^Int) -> (res: int, err: Error) {
 int_compare_magnitude :: proc(a, b: ^Int) -> (res: int, err: Error) {
 	assert_if_nil(a, b);
 	assert_if_nil(a, b);
-	if err = clear_if_uninitialized(a, b); err != nil { return 0, err; }
+	if err = internal_clear_if_uninitialized(a, b); err != nil { return 0, err; }
 
 
 	return #force_inline internal_cmp_mag(a, b), nil;
 	return #force_inline internal_cmp_mag(a, b), nil;
 }
 }

+ 14 - 19
core/math/big/radix.odin

@@ -18,10 +18,10 @@ import "core:mem"
 	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.
 */
 */
 int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
 int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
+	assert_if_nil(a);
+
 	a := a; radix := radix;
 	a := a; radix := radix;
-	if err = clear_if_uninitialized(a); err != nil {
-		return "", err;
-	}
+	if err = clear_if_uninitialized(a, allocator); err != nil { return "", err; }
 	/*
 	/*
 		Radix defaults to 10.
 		Radix defaults to 10.
 	*/
 	*/
@@ -61,10 +61,10 @@ int_itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, alloc
 	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.
 */
 */
 int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
 int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
+	assert_if_nil(a);
+
 	a := a; radix := radix;
 	a := a; radix := radix;
-	if err = clear_if_uninitialized(a); err != nil {
-		return "", err;
-	}
+	if err = clear_if_uninitialized(a, allocator); err != nil { return "", err; }
 	/*
 	/*
 		Radix defaults to 10.
 		Radix defaults to 10.
 	*/
 	*/
@@ -96,10 +96,9 @@ int_itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocato
 	and having to perform a buffer overflow check each character.
 	and having to perform a buffer overflow check each character.
 */
 */
 int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
 int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
+	assert_if_nil(a);
 	a := a; radix := radix; size := size;
 	a := a; radix := radix; size := size;
-	if err = clear_if_uninitialized(a); err != nil {
-		return 0, err;
-	}
+	if err = clear_if_uninitialized(a); err != nil { return 0, err; }
 	/*
 	/*
 		Radix defaults to 10.
 		Radix defaults to 10.
 	*/
 	*/
@@ -237,27 +236,23 @@ int_to_cstring :: int_itoa_cstring;
 /*
 /*
 	Read a string [ASCII] in a given radix.
 	Read a string [ASCII] in a given radix.
 */
 */
-int_atoi :: proc(res: ^Int, input: string, radix: i8) -> (err: Error) {
+int_atoi :: proc(res: ^Int, input: string, radix: i8, allocator := context.allocator) -> (err: Error) {
 	input := input;
 	input := input;
 	/*
 	/*
 		Make sure the radix is ok.
 		Make sure the radix is ok.
 	*/
 	*/
 
 
-	if radix < 2 || radix > 64 {
-		return .Invalid_Argument;
-	}
+	if radix < 2 || radix > 64 { return .Invalid_Argument; }
 
 
 	/*
 	/*
 		Set the integer to the default of zero.
 		Set the integer to the default of zero.
 	*/
 	*/
-	if err = zero(res); err != nil { return err; }
+	if err = zero(res, false, allocator); err != nil { return err; }
 
 
 	/*
 	/*
 		We'll interpret an empty string as zero.
 		We'll interpret an empty string as zero.
 	*/
 	*/
-	if len(input) == 0 {
-		return nil;
-	}
+	if len(input) == 0 { return nil; }
 
 
 	/*
 	/*
 		If the leading digit is a minus set the sign to negative.
 		If the leading digit is a minus set the sign to negative.
@@ -297,8 +292,8 @@ int_atoi :: proc(res: ^Int, input: string, radix: i8) -> (err: Error) {
 			break;
 			break;
 		}
 		}
 
 
-		if err = mul(res, res, DIGIT(radix)); err != nil { return err; }
-		if err = add(res, res, DIGIT(y));     err != nil { return err; }
+		if err = internal_mul(res, res, DIGIT(radix)); err != nil { return err; }
+		if err = internal_add(res, res, DIGIT(y));     err != nil { return err; }
 
 
 		input = input[1:];
 		input = input[1:];
 	}
 	}

+ 19 - 19
core/math/big/test.odin

@@ -45,9 +45,9 @@ PyRes :: struct {
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":add:atoi(a):", err=err}; }
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":add:atoi(a):", err=err}; }
 	if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":add:atoi(b):", err=err}; }
 	if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":add:atoi(b):", err=err}; }
 	if bb.used == 1 {
 	if bb.used == 1 {
-		if err = add(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }	
+		if err = #force_inline internal_add(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }	
 	} else {
 	} else {
-		if err = add(sum, aa, bb);          err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }
+		if err = #force_inline internal_add(sum, aa, bb);          err != nil { return PyRes{res=":add:add(sum,a,b):", err=err}; }
 	}
 	}
 
 
 	r: cstring;
 	r: cstring;
@@ -66,9 +66,9 @@ PyRes :: struct {
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":sub:atoi(a):", err=err}; }
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":sub:atoi(a):", err=err}; }
 	if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":sub:atoi(b):", err=err}; }
 	if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":sub:atoi(b):", err=err}; }
 	if bb.used == 1 {
 	if bb.used == 1 {
-		if err = sub(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
+		if err = #force_inline internal_sub(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
 	} else {
 	} else {
-		if err = sub(sum, aa, bb);          err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
+		if err = #force_inline internal_sub(sum, aa, bb);          err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err}; }
 	}
 	}
 
 
 	r: cstring;
 	r: cstring;
@@ -86,7 +86,7 @@ PyRes :: struct {
 
 
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":mul:atoi(a):", err=err}; }
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":mul:atoi(a):", err=err}; }
 	if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err}; }
 	if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err}; }
-	if err = mul(product, aa, bb);    err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err}; }
+	if err = #force_inline internal_mul(product, aa, bb);    err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(product, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(product, 16, context.temp_allocator);
@@ -106,7 +106,7 @@ PyRes :: struct {
 
 
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":div:atoi(a):", err=err}; }
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":div:atoi(a):", err=err}; }
 	if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err}; }
 	if err = atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err}; }
-	if err = div(quotient, aa, bb);   err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err}; }
+	if err = #force_inline internal_div(quotient, aa, bb);   err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(quotient, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(quotient, 16, context.temp_allocator);
@@ -127,9 +127,9 @@ PyRes :: struct {
 	defer destroy(aa);
 	defer destroy(aa);
 
 
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":log:atoi(a):", err=err}; }
 	if err = atoi(aa, string(a), 16); err != nil { return PyRes{res=":log:atoi(a):", err=err}; }
-	if l, err = log(aa, base);        err != nil { return PyRes{res=":log:log(a, base):", err=err}; }
+	if l, err = #force_inline internal_log(aa, base);        err != nil { return PyRes{res=":log:log(a, base):", err=err}; }
 
 
-	zero(aa);
+	#force_inline internal_zero(aa);
 	aa.digit[0] = DIGIT(l)  & _MASK;
 	aa.digit[0] = DIGIT(l)  & _MASK;
 	aa.digit[1] = DIGIT(l) >> _DIGIT_BITS;
 	aa.digit[1] = DIGIT(l) >> _DIGIT_BITS;
 	aa.used = 2;
 	aa.used = 2;
@@ -152,7 +152,7 @@ PyRes :: struct {
 	defer destroy(dest, bb);
 	defer destroy(dest, bb);
 
 
 	if err = atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err}; }
 	if err = atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err}; }
-	if err = pow(dest, bb, power);       err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err}; }
+	if err = #force_inline internal_pow(dest, bb, power);       err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
@@ -171,7 +171,7 @@ PyRes :: struct {
 	defer destroy(src);
 	defer destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err}; }
-	if err = sqrt(src, src);                err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err}; }
+	if err = #force_inline internal_sqrt(src, src);                err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -190,7 +190,7 @@ PyRes :: struct {
 	defer destroy(src);
 	defer destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err}; }
-	if err = root_n(src, src, power);       err != nil { return PyRes{res=":root_n:root_n(src):", err=err}; }
+	if err = #force_inline internal_root_n(src, src, power);       err != nil { return PyRes{res=":root_n:root_n(src):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -209,7 +209,7 @@ PyRes :: struct {
 	defer destroy(src);
 	defer destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err}; }
-	if err = shr_digit(src, digits);        err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err}; }
+	if err = #force_inline internal_shr_digit(src, digits);        err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -228,7 +228,7 @@ PyRes :: struct {
 	defer destroy(src);
 	defer destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err}; }
-	if err = shl_digit(src, digits);        err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err}; }
+	if err = #force_inline internal_shl_digit(src, digits);        err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -247,7 +247,7 @@ PyRes :: struct {
 	defer destroy(src);
 	defer destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err}; }
-	if err = shr(src, src, bits);           err != nil { return PyRes{res=":shr:shr(src, bits):", err=err}; }
+	if err = #force_inline internal_shr(src, src, bits);           err != nil { return PyRes{res=":shr:shr(src, bits):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -266,7 +266,7 @@ PyRes :: struct {
 	defer destroy(src);
 	defer destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err}; }
-	if err = shr_signed(src, src, bits);    err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err}; }
+	if err = #force_inline internal_shr_signed(src, src, bits);    err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -285,7 +285,7 @@ PyRes :: struct {
 	defer destroy(src);
 	defer destroy(src);
 
 
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err}; }
 	if err = atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err}; }
-	if err = shl(src, src, bits);           err != nil { return PyRes{res=":shl:shl(src, bits):", err=err}; }
+	if err = #force_inline internal_shl(src, src, bits);           err != nil { return PyRes{res=":shl:shl(src, bits):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(src, 16, context.temp_allocator);
@@ -303,7 +303,7 @@ PyRes :: struct {
 	dest := &Int{};
 	dest := &Int{};
 	defer destroy(dest);
 	defer destroy(dest);
 
 
-	if err = factorial(dest, n); err != nil { return PyRes{res=":factorial:factorial(n):", err=err}; }
+	if err = #force_inline factorial(dest, n); err != nil { return PyRes{res=":factorial:factorial(n):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
@@ -323,7 +323,7 @@ PyRes :: struct {
 
 
 	if err = atoi(ai, string(a), 16); err != nil { return PyRes{res=":gcd:atoi(a):", err=err}; }
 	if err = atoi(ai, string(a), 16); err != nil { return PyRes{res=":gcd:atoi(a):", err=err}; }
 	if err = atoi(bi, string(b), 16); err != nil { return PyRes{res=":gcd:atoi(b):", err=err}; }
 	if err = atoi(bi, string(b), 16); err != nil { return PyRes{res=":gcd:atoi(b):", err=err}; }
-	if err = gcd(dest, ai, bi); err != nil { return PyRes{res=":gcd:gcd(a, b):", err=err}; }	
+	if err = #force_inline gcd(dest, ai, bi); err != nil { return PyRes{res=":gcd:gcd(a, b):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
@@ -343,7 +343,7 @@ PyRes :: struct {
 
 
 	if err = atoi(ai, string(a), 16); err != nil { return PyRes{res=":lcm:atoi(a):", err=err}; }
 	if err = atoi(ai, string(a), 16); err != nil { return PyRes{res=":lcm:atoi(a):", err=err}; }
 	if err = atoi(bi, string(b), 16); err != nil { return PyRes{res=":lcm:atoi(b):", err=err}; }
 	if err = atoi(bi, string(b), 16); err != nil { return PyRes{res=":lcm:atoi(b):", err=err}; }
-	if err = lcm(dest, ai, bi); err != nil { return PyRes{res=":lcm:lcm(a, b):", err=err}; }	
+	if err = #force_inline lcm(dest, ai, bi); err != nil { return PyRes{res=":lcm:lcm(a, b):", err=err}; }
 
 
 	r: cstring;
 	r: cstring;
 	r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
 	r, err = int_itoa_cstring(dest, 16, context.temp_allocator);