mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-03 11:42:28 +00:00
big: Finish big ZII refactor.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -53,27 +53,21 @@ Int :: struct {
|
||||
sign: Sign,
|
||||
};
|
||||
|
||||
Comparison_Flag :: enum i8 {
|
||||
Less_Than = -1,
|
||||
Equal = 0,
|
||||
Greater_Than = 1,
|
||||
/*
|
||||
Errors are a strict superset of runtime.Allocation_Error.
|
||||
*/
|
||||
Error :: enum byte {
|
||||
None = 0,
|
||||
Out_Of_Memory = 1,
|
||||
Invalid_Pointer = 2,
|
||||
Invalid_Argument = 3,
|
||||
|
||||
/* One of the numbers was uninitialized */
|
||||
Uninitialized = -127,
|
||||
};
|
||||
Unknown_Error = 4,
|
||||
Max_Iterations_Reached = 5,
|
||||
Buffer_Overflow = 6,
|
||||
Integer_Overflow = 7,
|
||||
|
||||
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,
|
||||
Unimplemented = 127,
|
||||
};
|
||||
|
||||
Primality_Flag :: enum u8 {
|
||||
@@ -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_positive :: proc(a: ^Int) -> bool {
|
||||
return is_initialized(a) && a.sign == .Zero_or_Positive;
|
||||
}
|
||||
|
||||
int_is_negative :: proc(a: ^Int) -> bool {
|
||||
return is_initialized(a) && a.sign == .Negative;
|
||||
}
|
||||
|
||||
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_zero :: proc(a: ^Int) -> (res: bool, err: Error) {
|
||||
if err = clear_if_uninitialized(a); err != .None {
|
||||
return false, err;
|
||||
}
|
||||
return false;
|
||||
return a.used == 0, .None;
|
||||
}
|
||||
|
||||
int_is_odd :: proc(a: ^Int) -> bool {
|
||||
if is_initialized(a) {
|
||||
return !is_even(a);
|
||||
int_is_positive :: proc(a: ^Int) -> (res: bool, err: Error) {
|
||||
if err = clear_if_uninitialized(a); err != .None {
|
||||
return false, err;
|
||||
}
|
||||
return false;
|
||||
return a.sign == .Zero_or_Positive, .None;
|
||||
}
|
||||
|
||||
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) -> (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 res, .None;
|
||||
}
|
||||
|
||||
int_is_odd :: proc(a: ^Int) -> (res: bool, err: Error) {
|
||||
if err = clear_if_uninitialized(a); err != .None {
|
||||
return false, err;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
dest.sign = sign;
|
||||
return .OK;
|
||||
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 .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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user