mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 22:58:46 +00:00
big: Finish big ZII refactor.
This commit is contained in:
+106
-72
@@ -25,11 +25,19 @@ import "core:intrinsics"
|
|||||||
*/
|
*/
|
||||||
int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||||
dest := dest; x := a; y := b;
|
dest := dest; x := a; y := b;
|
||||||
if dest == nil || a == nil || b == nil {
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
return .Nil_Pointer_Passed;
|
return err;
|
||||||
} else if !is_initialized(a) || !is_initialized(b) {
|
|
||||||
return .Int_Not_Initialized;
|
|
||||||
}
|
}
|
||||||
|
if err = clear_if_uninitialized(b); err != .None {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if err = clear_if_uninitialized(dest); err != .None {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
All parameters have been initialized.
|
||||||
|
We can now safely ignore errors from comparison routines.
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Handle both negative or both positive.
|
Handle both negative or both positive.
|
||||||
@@ -44,7 +52,7 @@ int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
Subtract the one with the greater magnitude from the other.
|
Subtract the one with the greater magnitude from the other.
|
||||||
The result gets the sign of the one with the greater magnitude.
|
The result gets the sign of the one with the greater magnitude.
|
||||||
*/
|
*/
|
||||||
if cmp_mag(x, y) == .Less_Than {
|
if c, _ := cmp_mag(a, b); c == -1 {
|
||||||
x, y = y, x;
|
x, y = y, x;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,11 +68,22 @@ int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
*/
|
*/
|
||||||
int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
||||||
dest := dest; digit := digit;
|
dest := dest; digit := digit;
|
||||||
if dest == nil || a == nil {
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
return .Nil_Pointer_Passed;
|
return err;
|
||||||
} else if !is_initialized(a) {
|
|
||||||
return .Int_Not_Initialized;
|
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
Grow destination as required.
|
||||||
|
*/
|
||||||
|
if dest != a {
|
||||||
|
if err = grow(dest, a.used + 1); err != .None {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
All parameters have been initialized.
|
||||||
|
We can now safely ignore errors from comparison routines.
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fast paths for destination and input Int being the same.
|
Fast paths for destination and input Int being the same.
|
||||||
*/
|
*/
|
||||||
@@ -72,46 +91,44 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Fast path for dest.digit[0] + digit fits in dest.digit[0] without overflow.
|
Fast path for dest.digit[0] + digit fits in dest.digit[0] without overflow.
|
||||||
*/
|
*/
|
||||||
if is_pos(dest) && (dest.digit[0] + digit < _DIGIT_MAX) {
|
if p, _ := is_pos(dest); p && (dest.digit[0] + digit < _DIGIT_MAX) {
|
||||||
dest.digit[0] += digit;
|
dest.digit[0] += digit;
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Can be subtracted from dest.digit[0] without underflow.
|
Can be subtracted from dest.digit[0] without underflow.
|
||||||
*/
|
*/
|
||||||
if is_neg(a) && (dest.digit[0] > digit) {
|
if n, _ := is_neg(a); n && (dest.digit[0] > digit) {
|
||||||
dest.digit[0] -= digit;
|
dest.digit[0] -= digit;
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Grow destination as required.
|
|
||||||
*/
|
|
||||||
if err = grow(dest, a.used + 1); err != .OK {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If `a` is negative and `|a|` >= `digit`, call `dest = |a| - digit`
|
If `a` is negative and `|a|` >= `digit`, call `dest = |a| - digit`
|
||||||
*/
|
*/
|
||||||
if is_neg(a) && (a.used > 1 || a.digit[0] >= digit) {
|
if n, _ := is_neg(a); n && (a.used > 1 || a.digit[0] >= digit) {
|
||||||
/*
|
/*
|
||||||
Temporarily fix `a`'s sign.
|
Temporarily fix `a`'s sign.
|
||||||
*/
|
*/
|
||||||
t := a;
|
a.sign = .Zero_or_Positive;
|
||||||
t.sign = .Zero_or_Positive;
|
|
||||||
/*
|
/*
|
||||||
dest = |a| - digit
|
dest = |a| - digit
|
||||||
*/
|
*/
|
||||||
err = sub(dest, t, digit);
|
if err = sub(dest, a, digit); err != .None {
|
||||||
|
/*
|
||||||
|
Restore a's sign.
|
||||||
|
*/
|
||||||
|
a.sign = .Negative;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
Restore sign and set `dest` sign.
|
Restore sign and set `dest` sign.
|
||||||
*/
|
*/
|
||||||
|
a.sign = .Negative;
|
||||||
dest.sign = .Negative;
|
dest.sign = .Negative;
|
||||||
clamp(dest);
|
|
||||||
|
|
||||||
return err;
|
return clamp(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -122,7 +139,7 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
If `a` is positive
|
If `a` is positive
|
||||||
*/
|
*/
|
||||||
if is_pos(a) {
|
if p, _ := is_pos(a); p {
|
||||||
/*
|
/*
|
||||||
Add digits, use `carry`.
|
Add digits, use `carry`.
|
||||||
*/
|
*/
|
||||||
@@ -166,9 +183,7 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Adjust dest.used based on leading zeroes.
|
Adjust dest.used based on leading zeroes.
|
||||||
*/
|
*/
|
||||||
clamp(dest);
|
return clamp(dest);
|
||||||
|
|
||||||
return .OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -176,11 +191,19 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
|||||||
*/
|
*/
|
||||||
int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
||||||
dest := dest; x := number; y := decrease;
|
dest := dest; x := number; y := decrease;
|
||||||
if dest == nil || number == nil || decrease == nil {
|
if err = clear_if_uninitialized(dest); err != .None {
|
||||||
return .Nil_Pointer_Passed;
|
return err;
|
||||||
} 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;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
All parameters have been initialized.
|
||||||
|
We can now safely ignore errors from comparison routines.
|
||||||
|
*/
|
||||||
|
|
||||||
if x.sign != y.sign {
|
if x.sign != y.sign {
|
||||||
/*
|
/*
|
||||||
@@ -195,12 +218,16 @@ int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
|||||||
Subtract a positive from a positive, OR negative from a negative.
|
Subtract a positive from a positive, OR negative from a negative.
|
||||||
First, take the difference between their magnitudes, then...
|
First, take the difference between their magnitudes, then...
|
||||||
*/
|
*/
|
||||||
if cmp_mag(x, y) == .Less_Than {
|
if c, _ := cmp_mag(x, y); c == -1 {
|
||||||
/*
|
/*
|
||||||
The second has a larger magnitude.
|
The second has a larger magnitude.
|
||||||
The result has the *opposite* sign from the first number.
|
The result has the *opposite* sign from the first number.
|
||||||
*/
|
*/
|
||||||
dest.sign = .Negative if is_pos(x) else .Zero_or_Positive;
|
if p, _ := is_pos(x); p {
|
||||||
|
dest.sign = .Negative;
|
||||||
|
} else {
|
||||||
|
dest.sign = .Zero_or_Positive;
|
||||||
|
}
|
||||||
x, y = y, x;
|
x, y = y, x;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
@@ -220,11 +247,21 @@ int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
|||||||
*/
|
*/
|
||||||
int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
||||||
dest := dest; digit := digit;
|
dest := dest; digit := digit;
|
||||||
if dest == nil || a == nil {
|
if err = clear_if_uninitialized(dest); err != .None {
|
||||||
return .Nil_Pointer_Passed;
|
return err;
|
||||||
} else if !is_initialized(a) {
|
|
||||||
return .Int_Not_Initialized;
|
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
Grow destination as required.
|
||||||
|
*/
|
||||||
|
if dest != a {
|
||||||
|
if err = grow(dest, a.used + 1); err != .None {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
All parameters have been initialized.
|
||||||
|
We can now safely ignore errors from comparison routines.
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fast paths for destination and input Int being the same.
|
Fast paths for destination and input Int being the same.
|
||||||
@@ -233,31 +270,23 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Fast path for `dest` is negative and unsigned addition doesn't overflow the lowest digit.
|
Fast path for `dest` is negative and unsigned addition doesn't overflow the lowest digit.
|
||||||
*/
|
*/
|
||||||
if is_neg(dest) && (dest.digit[0] + digit < _DIGIT_MAX) {
|
if n, _ := is_neg(dest); n && (dest.digit[0] + digit < _DIGIT_MAX) {
|
||||||
dest.digit[0] += digit;
|
dest.digit[0] += digit;
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Can be subtracted from dest.digit[0] without underflow.
|
Can be subtracted from dest.digit[0] without underflow.
|
||||||
*/
|
*/
|
||||||
if is_pos(a) && (dest.digit[0] > digit) {
|
if p, _ := is_pos(a); p && (dest.digit[0] > digit) {
|
||||||
dest.digit[0] -= digit;
|
dest.digit[0] -= digit;
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Grow destination as required.
|
|
||||||
*/
|
|
||||||
err = grow(dest, a.used + 1);
|
|
||||||
if err != .OK {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If `a` is negative, just do an unsigned addition (with fudged signs).
|
If `a` is negative, just do an unsigned addition (with fudged signs).
|
||||||
*/
|
*/
|
||||||
if is_neg(a) {
|
if n, _ := is_neg(a); n {
|
||||||
t := a;
|
t := a;
|
||||||
t.sign = .Zero_or_Positive;
|
t.sign = .Zero_or_Positive;
|
||||||
|
|
||||||
@@ -273,7 +302,9 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
if `a`<= digit, simply fix the single digit.
|
if `a`<= digit, simply fix the single digit.
|
||||||
*/
|
*/
|
||||||
if a.used == 1 && (a.digit[0] <= digit || is_zero(a)) {
|
z, _ := is_zero(a);
|
||||||
|
|
||||||
|
if a.used == 1 && (a.digit[0] <= digit) || z {
|
||||||
dest.digit[0] = digit - a.digit[0] if a.used == 1 else digit;
|
dest.digit[0] = digit - a.digit[0] if a.used == 1 else digit;
|
||||||
dest.sign = .Negative;
|
dest.sign = .Negative;
|
||||||
dest.used = 1;
|
dest.used = 1;
|
||||||
@@ -303,9 +334,7 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Adjust dest.used based on leading zeroes.
|
Adjust dest.used based on leading zeroes.
|
||||||
*/
|
*/
|
||||||
clamp(dest);
|
return clamp(dest);
|
||||||
|
|
||||||
return .OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -320,10 +349,11 @@ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) {
|
|||||||
*/
|
*/
|
||||||
_int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
_int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||||
dest := dest; x := a; y := b;
|
dest := dest; x := a; y := b;
|
||||||
if dest == nil || a == nil || b == nil {
|
if err = clear_if_uninitialized(x); err != .None {
|
||||||
return .Nil_Pointer_Passed;
|
return err;
|
||||||
} else if !is_initialized(a) || !is_initialized(b) {
|
}
|
||||||
return .Int_Not_Initialized;
|
if err = clear_if_uninitialized(y); err != .None {
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_used, min_used, max_used, i: int;
|
old_used, min_used, max_used, i: int;
|
||||||
@@ -336,10 +366,13 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
max_used = y.used;
|
max_used = y.used;
|
||||||
old_used = dest.used;
|
old_used = dest.used;
|
||||||
|
|
||||||
if err = grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)); err != .OK {
|
if err = grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)); err != .None {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
dest.used = max_used + 1;
|
dest.used = max_used + 1;
|
||||||
|
/*
|
||||||
|
All parameters have been initialized.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Zero the carry */
|
/* Zero the carry */
|
||||||
carry := DIGIT(0);
|
carry := DIGIT(0);
|
||||||
@@ -393,9 +426,7 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Adjust dest.used based on leading zeroes.
|
Adjust dest.used based on leading zeroes.
|
||||||
*/
|
*/
|
||||||
clamp(dest);
|
return clamp(dest);
|
||||||
|
|
||||||
return .OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -404,10 +435,11 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
*/
|
*/
|
||||||
_int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
_int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
||||||
dest := dest; x := number; y := decrease;
|
dest := dest; x := number; y := decrease;
|
||||||
if dest == nil || number == nil || decrease == nil {
|
if err = clear_if_uninitialized(x); err != .None {
|
||||||
return .Nil_Pointer_Passed;
|
return err;
|
||||||
} else if !is_initialized(number) || !is_initialized(decrease) {
|
}
|
||||||
return .Int_Not_Initialized;
|
if err = clear_if_uninitialized(y); err != .None {
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_used := dest.used;
|
old_used := dest.used;
|
||||||
@@ -415,10 +447,13 @@ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
|||||||
max_used := x.used;
|
max_used := x.used;
|
||||||
i: int;
|
i: int;
|
||||||
|
|
||||||
if err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)); err != .OK {
|
if err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)); err != .None {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
dest.used = max_used;
|
dest.used = max_used;
|
||||||
|
/*
|
||||||
|
All parameters have been initialized.
|
||||||
|
*/
|
||||||
|
|
||||||
borrow := DIGIT(0);
|
borrow := DIGIT(0);
|
||||||
|
|
||||||
@@ -465,6 +500,5 @@ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Adjust dest.used based on leading zeroes.
|
Adjust dest.used based on leading zeroes.
|
||||||
*/
|
*/
|
||||||
clamp(dest);
|
return clamp(dest);
|
||||||
return .OK;
|
|
||||||
}
|
}
|
||||||
@@ -53,27 +53,21 @@ Int :: struct {
|
|||||||
sign: Sign,
|
sign: Sign,
|
||||||
};
|
};
|
||||||
|
|
||||||
Comparison_Flag :: enum i8 {
|
/*
|
||||||
Less_Than = -1,
|
Errors are a strict superset of runtime.Allocation_Error.
|
||||||
Equal = 0,
|
*/
|
||||||
Greater_Than = 1,
|
Error :: enum byte {
|
||||||
|
None = 0,
|
||||||
|
Out_Of_Memory = 1,
|
||||||
|
Invalid_Pointer = 2,
|
||||||
|
Invalid_Argument = 3,
|
||||||
|
|
||||||
/* One of the numbers was uninitialized */
|
Unknown_Error = 4,
|
||||||
Uninitialized = -127,
|
Max_Iterations_Reached = 5,
|
||||||
};
|
Buffer_Overflow = 6,
|
||||||
|
Integer_Overflow = 7,
|
||||||
|
|
||||||
Error :: enum i8 {
|
Unimplemented = 127,
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Primality_Flag :: enum u8 {
|
Primality_Flag :: enum u8 {
|
||||||
+102
-52
@@ -22,61 +22,83 @@ int_is_initialized :: proc(a: ^Int) -> bool {
|
|||||||
return raw.cap >= _MIN_DIGIT_COUNT;
|
return raw.cap >= _MIN_DIGIT_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int_is_zero :: proc(a: ^Int) -> bool {
|
int_is_zero :: proc(a: ^Int) -> (res: bool, err: Error) {
|
||||||
return is_initialized(a) && a.used == 0;
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
}
|
return false, err;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return a.used == 0, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
int_is_odd :: proc(a: ^Int) -> bool {
|
int_is_positive :: proc(a: ^Int) -> (res: bool, err: Error) {
|
||||||
if is_initialized(a) {
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
return !is_even(a);
|
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 {
|
platform_int_is_power_of_two :: proc(a: int) -> bool {
|
||||||
return ((a) != 0) && (((a) & ((a) - 1)) == 0);
|
return ((a) != 0) && (((a) & ((a) - 1)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int_is_power_of_two :: proc(a: ^Int) -> (res: bool) {
|
int_is_power_of_two :: proc(a: ^Int) -> (res: bool, err: Error) {
|
||||||
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
|
return false, err;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Early out for Int == 0.
|
Early out for Int == 0.
|
||||||
*/
|
*/
|
||||||
if a.used == 0 {
|
if a.used == 0 {
|
||||||
return false;
|
return false, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
For an `Int` to be a power of two, its top limb has to be a power of two.
|
For an `Int` to be a power of two, its top limb has to be a power of two.
|
||||||
*/
|
*/
|
||||||
if !platform_int_is_power_of_two(int(a.digit[a.used - 1])) {
|
if !platform_int_is_power_of_two(int(a.digit[a.used - 1])) {
|
||||||
return false;
|
return false, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
That was the only limb, so it's a power of two.
|
That was the only limb, so it's a power of two.
|
||||||
*/
|
*/
|
||||||
if a.used == 1 {
|
if a.used == 1 {
|
||||||
return true;
|
return true, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -84,74 +106,102 @@ int_is_power_of_two :: proc(a: ^Int) -> (res: bool) {
|
|||||||
*/
|
*/
|
||||||
for i := 1; i < a.used; i += 1 {
|
for i := 1; i < a.used; i += 1 {
|
||||||
if a.digit[i - 1] != 0 {
|
if a.digit[i - 1] != 0 {
|
||||||
return false;
|
return false, .None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Compare two `Int`s, signed.
|
Compare two `Int`s, signed.
|
||||||
*/
|
*/
|
||||||
int_compare :: proc(a, b: ^Int) -> Comparison_Flag {
|
int_compare :: proc(a, b: ^Int) -> (res: int, err: Error) {
|
||||||
if !is_initialized(a) { return .Uninitialized; }
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
if !is_initialized(b) { return .Uninitialized; }
|
return 0, err;
|
||||||
|
}
|
||||||
|
if err = clear_if_uninitialized(b); err != .None {
|
||||||
|
return 0, err;
|
||||||
|
}
|
||||||
|
|
||||||
|
neg: bool;
|
||||||
|
if neg, err = is_negative(a); err != .None {
|
||||||
|
return 0, err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Compare based on sign */
|
/* Compare based on sign */
|
||||||
if a.sign != b.sign {
|
if a.sign != b.sign {
|
||||||
return .Less_Than if is_negative(a) else .Greater_Than;
|
res = -1 if neg else +1;
|
||||||
|
return res, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
x, y := a, b;
|
|
||||||
/* If negative, compare in the opposite direction */
|
/* If negative, compare in the opposite direction */
|
||||||
if is_neg(a) {
|
if neg {
|
||||||
x, y = b, a;
|
return cmp_mag(b, a);
|
||||||
}
|
}
|
||||||
return cmp_mag(x, y);
|
return cmp_mag(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Compare an `Int` to an unsigned number upto the size of the backing type.
|
Compare an `Int` to an unsigned number upto the size of the backing type.
|
||||||
*/
|
*/
|
||||||
int_compare_digit :: proc(a: ^Int, u: DIGIT) -> Comparison_Flag {
|
int_compare_digit :: proc(a: ^Int, u: DIGIT) -> (res: int, err: Error) {
|
||||||
if !is_initialized(a) { return .Uninitialized; }
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
|
return 0, err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Compare based on sign */
|
/* Compare based on sign */
|
||||||
if is_neg(a) {
|
neg: bool;
|
||||||
return .Less_Than;
|
if neg, err = is_neg(a); err != .None {
|
||||||
|
return 0, err;
|
||||||
|
}
|
||||||
|
if neg {
|
||||||
|
return -1, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compare based on magnitude */
|
/* Compare based on magnitude */
|
||||||
if a.used > 1 {
|
if a.used > 1 {
|
||||||
return .Greater_Than;
|
return +1, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compare the only digit in `a` to `u`. */
|
/* Compare the only digit in `a` to `u`. */
|
||||||
if a.digit[0] != u {
|
if a.digit[0] != u {
|
||||||
return .Greater_Than if a.digit[0] > u else .Less_Than;
|
if a.digit[0] > u {
|
||||||
|
return +1, .None;
|
||||||
|
}
|
||||||
|
return -1, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
return .Equal;
|
return 0, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Compare the magnitude of two `Int`s, unsigned.
|
Compare the magnitude of two `Int`s, unsigned.
|
||||||
*/
|
*/
|
||||||
int_compare_magnitude :: proc(a, b: ^Int) -> Comparison_Flag {
|
int_compare_magnitude :: proc(a, b: ^Int) -> (res: int, err: Error) {
|
||||||
if !is_initialized(a) { return .Uninitialized; }
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
if !is_initialized(b) { return .Uninitialized; }
|
return 0, err;
|
||||||
|
}
|
||||||
|
if err = clear_if_uninitialized(b); err != .None {
|
||||||
|
return 0, err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Compare based on used digits */
|
/* Compare based on used digits */
|
||||||
if a.used != b.used {
|
if a.used != b.used {
|
||||||
return .Greater_Than if a.used > b.used else .Less_Than;
|
if a.used > b.used {
|
||||||
|
return +1, .None;
|
||||||
|
}
|
||||||
|
return -1, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Same number of used digits, compare based on their value */
|
/* Same number of used digits, compare based on their value */
|
||||||
for n := a.used - 1; n >= 0; n -= 1 {
|
for n := a.used - 1; n >= 0; n -= 1 {
|
||||||
if a.digit[n] != b.digit[n] {
|
if a.digit[n] != b.digit[n] {
|
||||||
return .Greater_Than if a.digit[n] > b.digit[n] else .Less_Than;
|
if a.digit[n] > b.digit[n] {
|
||||||
|
return +1, .None;
|
||||||
|
}
|
||||||
|
return -1, .None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return .Equal;
|
return 0, .None;
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ _SQR_TOOM_CUTOFF,
|
|||||||
print :: proc(name: string, a: ^Int, base := i8(16)) {
|
print :: proc(name: string, a: ^Int, base := i8(16)) {
|
||||||
as, err := itoa(a, base);
|
as, err := itoa(a, base);
|
||||||
defer delete(as);
|
defer delete(as);
|
||||||
if err == .OK {
|
if err == .None {
|
||||||
cb, _ := count_bits(a);
|
cb, _ := count_bits(a);
|
||||||
fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, cb, as);
|
fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, cb, as);
|
||||||
} else {
|
} else {
|
||||||
@@ -80,10 +80,10 @@ demo :: proc() {
|
|||||||
print("c", c);
|
print("c", c);
|
||||||
|
|
||||||
fmt.println("\n\n=== Set a to (1 << 120) - 1 ===");
|
fmt.println("\n\n=== Set a to (1 << 120) - 1 ===");
|
||||||
if err = power_of_two(a, 120); err != .OK {
|
if err = power_of_two(a, 120); err != .None {
|
||||||
fmt.printf("Error %v while setting a to 1 << 120.\n", err);
|
fmt.printf("Error %v while setting a to 1 << 120.\n", err);
|
||||||
}
|
}
|
||||||
if err = sub(a, a, 1); err != .OK {
|
if err = sub(a, a, 1); err != .None {
|
||||||
fmt.printf("Error %v while subtracting 1 from a\n", err);
|
fmt.printf("Error %v while subtracting 1 from a\n", err);
|
||||||
}
|
}
|
||||||
print("a", a, 16);
|
print("a", a, 16);
|
||||||
|
|||||||
+62
-83
@@ -30,15 +30,10 @@ int_destroy :: proc(integers: ..^Int) {
|
|||||||
int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator := context.allocator) -> (err: Error)
|
int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator := context.allocator) -> (err: Error)
|
||||||
where intrinsics.type_is_integer(T) {
|
where intrinsics.type_is_integer(T) {
|
||||||
src := src;
|
src := src;
|
||||||
/*
|
if err = clear_if_uninitialized(dest); err != .None {
|
||||||
Check that dest is usable.
|
return err;
|
||||||
*/
|
|
||||||
if dest == nil {
|
|
||||||
return .Nil_Pointer_Passed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = _grow_if_uninitialized(dest, minimize); err != .OK { return err; }
|
|
||||||
|
|
||||||
dest.used = 0;
|
dest.used = 0;
|
||||||
dest.sign = .Zero_or_Positive if src >= 0 else .Negative;
|
dest.sign = .Zero_or_Positive if src >= 0 else .Negative;
|
||||||
src = abs(src);
|
src = abs(src);
|
||||||
@@ -49,7 +44,7 @@ int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator :
|
|||||||
src >>= _DIGIT_BITS;
|
src >>= _DIGIT_BITS;
|
||||||
}
|
}
|
||||||
_zero_unused(dest);
|
_zero_unused(dest);
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
set :: proc { int_set_from_integer, int_copy };
|
set :: proc { int_set_from_integer, int_copy };
|
||||||
@@ -58,27 +53,20 @@ set :: proc { int_set_from_integer, int_copy };
|
|||||||
Copy one `Int` to another.
|
Copy one `Int` to another.
|
||||||
*/
|
*/
|
||||||
int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
/*
|
if err = clear_if_uninitialized(src); err != .None {
|
||||||
Check that src and dest are usable.
|
return err;
|
||||||
*/
|
|
||||||
if dest == nil || src == nil {
|
|
||||||
return .Nil_Pointer_Passed;
|
|
||||||
} else if !is_initialized(src) {
|
|
||||||
return .Int_Not_Initialized;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If dest == src, do nothing
|
If dest == src, do nothing
|
||||||
*/
|
*/
|
||||||
if (dest == src) {
|
if (dest == src) {
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Grow `dest` to fit `src`.
|
Grow `dest` to fit `src`.
|
||||||
If `dest` is not yet initialized, it will be using `allocator`.
|
If `dest` is not yet initialized, it will be using `allocator`.
|
||||||
*/
|
*/
|
||||||
if err = grow(dest, src.used, false, allocator); err != .OK {
|
if err = grow(dest, src.used, false, allocator); err != .None {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +79,7 @@ int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error
|
|||||||
dest.used = src.used;
|
dest.used = src.used;
|
||||||
dest.sign = src.sign;
|
dest.sign = src.sign;
|
||||||
_zero_unused(dest);
|
_zero_unused(dest);
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
copy :: proc { int_copy, };
|
copy :: proc { int_copy, };
|
||||||
|
|
||||||
@@ -100,26 +88,23 @@ copy :: proc { int_copy, };
|
|||||||
*/
|
*/
|
||||||
int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
/*
|
/*
|
||||||
Check that src and dest are usable.
|
Check that src is usable.
|
||||||
*/
|
*/
|
||||||
if dest == nil || src == nil {
|
if err = clear_if_uninitialized(src); err != .None {
|
||||||
return .Nil_Pointer_Passed;
|
return err;
|
||||||
} else if !is_initialized(src) {
|
|
||||||
return .Int_Not_Initialized;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If `dest == src`, just fix `dest`'s sign.
|
If `dest == src`, just fix `dest`'s sign.
|
||||||
*/
|
*/
|
||||||
if (dest == src) {
|
if (dest == src) {
|
||||||
dest.sign = .Zero_or_Positive;
|
dest.sign = .Zero_or_Positive;
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copy `src` to `dest`
|
Copy `src` to `dest`
|
||||||
*/
|
*/
|
||||||
if err = copy(dest, src, allocator); err != .OK {
|
if err = copy(dest, src, allocator); err != .None {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +112,7 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
|
|||||||
Fix sign.
|
Fix sign.
|
||||||
*/
|
*/
|
||||||
dest.sign = .Zero_or_Positive;
|
dest.sign = .Zero_or_Positive;
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_abs :: proc(n: $T) -> T where intrinsics.type_is_integer(T) {
|
platform_abs :: proc(n: $T) -> T where intrinsics.type_is_integer(T) {
|
||||||
@@ -140,27 +125,29 @@ abs :: proc{int_abs, platform_abs};
|
|||||||
*/
|
*/
|
||||||
neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
/*
|
/*
|
||||||
Check that src and dest are usable.
|
Check that src is usable.
|
||||||
*/
|
*/
|
||||||
if dest == nil || src == nil {
|
if err = clear_if_uninitialized(src); err != .None {
|
||||||
return .Nil_Pointer_Passed;
|
return err;
|
||||||
} else if !is_initialized(src) {
|
|
||||||
return .Int_Not_Initialized;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If `dest == src`, just fix `dest`'s sign.
|
If `dest == src`, just fix `dest`'s sign.
|
||||||
*/
|
*/
|
||||||
sign := Sign.Negative if !(is_zero(src) && is_neg(src)) else Sign.Zero_or_Positive;
|
sign := Sign.Zero_or_Positive;
|
||||||
if dest == src {
|
if z, _ := is_zero(src); z {
|
||||||
|
sign = .Negative;
|
||||||
|
}
|
||||||
|
if n, _ := is_neg(src); n {
|
||||||
|
sign = .Negative;
|
||||||
|
}
|
||||||
|
if (dest == src) {
|
||||||
dest.sign = sign;
|
dest.sign = sign;
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copy `src` to `dest`
|
Copy `src` to `dest`
|
||||||
*/
|
*/
|
||||||
if err = copy(dest, src, allocator); err != .OK {
|
if err = copy(dest, src, allocator); err != .None {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +155,7 @@ neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
|||||||
Fix sign.
|
Fix sign.
|
||||||
*/
|
*/
|
||||||
dest.sign = sign;
|
dest.sign = sign;
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -176,22 +163,20 @@ neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) {
|
|||||||
*/
|
*/
|
||||||
extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
|
extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
|
||||||
/*
|
/*
|
||||||
Check that `a` is usable.
|
Check that `a`is usable.
|
||||||
*/
|
*/
|
||||||
if a == nil {
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
return 0, .Nil_Pointer_Passed;
|
return 0, err;
|
||||||
} else if !is_initialized(a) {
|
|
||||||
return 0, .Int_Not_Initialized;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
limb := bit_offset / _DIGIT_BITS;
|
limb := bit_offset / _DIGIT_BITS;
|
||||||
if limb < 0 || limb >= a.used {
|
if limb < 0 || limb >= a.used {
|
||||||
return 0, .Invalid_Input;
|
return 0, .Invalid_Argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
i := DIGIT(1 << DIGIT((bit_offset % _DIGIT_BITS)));
|
i := DIGIT(1 << DIGIT((bit_offset % _DIGIT_BITS)));
|
||||||
|
|
||||||
return 1 if ((a.digit[limb] & i) != 0) else 0, .OK;
|
return 1 if ((a.digit[limb] & i) != 0) else 0, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -199,16 +184,14 @@ extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) {
|
|||||||
*/
|
*/
|
||||||
extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
|
extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
|
||||||
/*
|
/*
|
||||||
Check that `a` is usable.
|
Check that `a`is usable.
|
||||||
*/
|
*/
|
||||||
if a == nil {
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
return 0, .Nil_Pointer_Passed;
|
return 0, err;
|
||||||
} else if !is_initialized(a) {
|
|
||||||
return 0, .Int_Not_Initialized;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if count > _WORD_BITS || count < 1 {
|
if count > _WORD_BITS || count < 1 {
|
||||||
return 0, .Invalid_Input;
|
return 0, .Invalid_Argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
v: DIGIT;
|
v: DIGIT;
|
||||||
@@ -216,7 +199,7 @@ extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
|
|||||||
for shift := 0; shift < count; shift += 1 {
|
for shift := 0; shift < count; shift += 1 {
|
||||||
o := offset + shift;
|
o := offset + shift;
|
||||||
v, e = extract_bit(a, o);
|
v, e = extract_bit(a, o);
|
||||||
if e != .OK {
|
if e != .None {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
res = res + _WORD(v) << uint(shift);
|
res = res + _WORD(v) << uint(shift);
|
||||||
@@ -230,7 +213,7 @@ extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) {
|
|||||||
*/
|
*/
|
||||||
shrink :: proc(a: ^Int) -> (err: Error) {
|
shrink :: proc(a: ^Int) -> (err: Error) {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
return .Nil_Pointer_Passed;
|
return .Invalid_Pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
needed := max(_MIN_DIGIT_COUNT, a.used);
|
needed := max(_MIN_DIGIT_COUNT, a.used);
|
||||||
@@ -238,12 +221,12 @@ shrink :: proc(a: ^Int) -> (err: Error) {
|
|||||||
if a.used != needed {
|
if a.used != needed {
|
||||||
return grow(a, needed);
|
return grow(a, needed);
|
||||||
}
|
}
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) {
|
int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
return .Nil_Pointer_Passed;
|
return .Invalid_Pointer;
|
||||||
}
|
}
|
||||||
raw := transmute(mem.Raw_Dynamic_Array)a.digit;
|
raw := transmute(mem.Raw_Dynamic_Array)a.digit;
|
||||||
|
|
||||||
@@ -269,9 +252,9 @@ int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := conte
|
|||||||
Let's see if the allocation/resize worked as expected.
|
Let's see if the allocation/resize worked as expected.
|
||||||
*/
|
*/
|
||||||
if len(a.digit) != needed {
|
if len(a.digit) != needed {
|
||||||
return .Out_of_Memory;
|
return .Out_Of_Memory;
|
||||||
}
|
}
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
grow :: proc { int_grow, };
|
grow :: proc { int_grow, };
|
||||||
|
|
||||||
@@ -280,7 +263,7 @@ grow :: proc { int_grow, };
|
|||||||
*/
|
*/
|
||||||
int_clear :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
int_clear :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
return .Nil_Pointer_Passed;
|
return .Invalid_Pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
raw := transmute(mem.Raw_Dynamic_Array)a.digit;
|
raw := transmute(mem.Raw_Dynamic_Array)a.digit;
|
||||||
@@ -299,14 +282,14 @@ zero :: clear;
|
|||||||
Set the `Int` to 1 and optionally shrink it to the minimum backing size.
|
Set the `Int` to 1 and optionally shrink it to the minimum backing size.
|
||||||
*/
|
*/
|
||||||
int_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
int_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
||||||
if err = clear(a, minimize, allocator); err != .OK {
|
if err = clear(a, minimize, allocator); err != .None {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.used = 1;
|
a.used = 1;
|
||||||
a.digit[0] = 1;
|
a.digit[0] = 1;
|
||||||
a.sign = .Zero_or_Positive;
|
a.sign = .Zero_or_Positive;
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
one :: proc { int_one, };
|
one :: proc { int_one, };
|
||||||
|
|
||||||
@@ -314,14 +297,14 @@ one :: proc { int_one, };
|
|||||||
Set the `Int` to -1 and optionally shrink it to the minimum backing size.
|
Set the `Int` to -1 and optionally shrink it to the minimum backing size.
|
||||||
*/
|
*/
|
||||||
int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) {
|
||||||
if err = clear(a, minimize, allocator); err != .OK {
|
if err = clear(a, minimize, allocator); err != .None {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.used = 1;
|
a.used = 1;
|
||||||
a.digit[0] = 1;
|
a.digit[0] = 1;
|
||||||
a.sign = .Negative;
|
a.sign = .Negative;
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
minus_one :: proc { int_minus_one, };
|
minus_one :: proc { int_minus_one, };
|
||||||
|
|
||||||
@@ -332,18 +315,18 @@ power_of_two :: proc(a: ^Int, power: int) -> (err: Error) {
|
|||||||
Check that `a` is usable.
|
Check that `a` is usable.
|
||||||
*/
|
*/
|
||||||
if a == nil {
|
if a == nil {
|
||||||
return .Nil_Pointer_Passed;
|
return .Invalid_Pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if power < 0 || power > _MAX_BIT_COUNT {
|
if power < 0 || power > _MAX_BIT_COUNT {
|
||||||
return .Invalid_Input;
|
return .Invalid_Argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Grow to accomodate the single bit.
|
Grow to accomodate the single bit.
|
||||||
*/
|
*/
|
||||||
a.used = (power / _DIGIT_BITS) + 1;
|
a.used = (power / _DIGIT_BITS) + 1;
|
||||||
if err = grow(a, a.used); err != .OK {
|
if err = grow(a, a.used); err != .None {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -355,23 +338,21 @@ power_of_two :: proc(a: ^Int, power: int) -> (err: Error) {
|
|||||||
Set the bit.
|
Set the bit.
|
||||||
*/
|
*/
|
||||||
a.digit[power / _DIGIT_BITS] = 1 << uint((power % _DIGIT_BITS));
|
a.digit[power / _DIGIT_BITS] = 1 << uint((power % _DIGIT_BITS));
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Count bits in an `Int`.
|
Count bits in an `Int`.
|
||||||
*/
|
*/
|
||||||
count_bits :: proc(a: ^Int) -> (count: int, err: Error) {
|
count_bits :: proc(a: ^Int) -> (count: int, err: Error) {
|
||||||
if a == nil {
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
return 0, .Nil_Pointer_Passed;
|
return 0, err;
|
||||||
} else if !is_initialized(a) {
|
|
||||||
return 0, .Int_Not_Initialized;
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Fast path for zero.
|
Fast path for zero.
|
||||||
*/
|
*/
|
||||||
if is_zero(a) {
|
if z, _ := is_zero(a); z {
|
||||||
return 0, .OK;
|
return 0, .None;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Get the number of DIGITs and use it.
|
Get the number of DIGITs and use it.
|
||||||
@@ -404,11 +385,11 @@ _zero_unused :: proc(a: ^Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_grow_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) {
|
clear_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) {
|
||||||
if !is_initialized(dest) {
|
if !is_initialized(dest) {
|
||||||
return grow(dest, _MIN_DIGIT_COUNT if minimize else _DEFAULT_DIGIT_COUNT);
|
return grow(dest, _MIN_DIGIT_COUNT if minimize else _DEFAULT_DIGIT_COUNT);
|
||||||
}
|
}
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -418,19 +399,17 @@ _grow_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) {
|
|||||||
Typically very fast. Also fixes the sign if there are no more leading digits.
|
Typically very fast. Also fixes the sign if there are no more leading digits.
|
||||||
*/
|
*/
|
||||||
clamp :: proc(a: ^Int) -> (err: Error) {
|
clamp :: proc(a: ^Int) -> (err: Error) {
|
||||||
if a == nil {
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
return .Nil_Pointer_Passed;
|
return err;
|
||||||
} else if !is_initialized(a) {
|
|
||||||
return .Int_Not_Initialized;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for a.used > 0 && a.digit[a.used - 1] == 0 {
|
for a.used > 0 && a.digit[a.used - 1] == 0 {
|
||||||
a.used -= 1;
|
a.used -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_zero(a) {
|
if z, _ := is_zero(a); z {
|
||||||
a.sign = .Zero_or_Positive;
|
a.sign = .Zero_or_Positive;
|
||||||
}
|
}
|
||||||
|
|
||||||
return .OK;
|
return .None;
|
||||||
}
|
}
|
||||||
+16
-11
@@ -10,13 +10,18 @@ package big
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
|
log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
|
||||||
if a == nil {
|
if base < 2 || DIGIT(base) > _DIGIT_MAX {
|
||||||
return 0, .Nil_Pointer_Passed;
|
return -1, .Invalid_Argument;
|
||||||
} else if !is_initialized(a) {
|
|
||||||
return 0, .Int_Not_Initialized;
|
|
||||||
}
|
}
|
||||||
if is_neg(a) || is_zero(a) || base < 2 || DIGIT(base) > _DIGIT_MAX {
|
|
||||||
return -1, .Invalid_Input;
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
|
return -1, err;
|
||||||
|
}
|
||||||
|
if n, _ := is_neg(a); n {
|
||||||
|
return -1, .Invalid_Argument;
|
||||||
|
}
|
||||||
|
if z, _ := is_zero(a); z {
|
||||||
|
return -1, .Invalid_Argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -80,14 +85,14 @@ log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) {
|
|||||||
Therefore, we return 0.
|
Therefore, we return 0.
|
||||||
*/
|
*/
|
||||||
if a < base {
|
if a < base {
|
||||||
return 0, .OK;
|
return 0, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If a number equals the base, the log is 1.
|
If a number equals the base, the log is 1.
|
||||||
*/
|
*/
|
||||||
if a == base {
|
if a == base {
|
||||||
return 1, .OK;
|
return 1, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
N := _WORD(a);
|
N := _WORD(a);
|
||||||
@@ -116,13 +121,13 @@ log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) {
|
|||||||
bracket_low = bracket_mid;
|
bracket_low = bracket_mid;
|
||||||
}
|
}
|
||||||
if N == bracket_mid {
|
if N == bracket_mid {
|
||||||
return mid, .OK;
|
return mid, .None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if bracket_high == N {
|
if bracket_high == N {
|
||||||
return high, .OK;
|
return high, .None;
|
||||||
} else {
|
} else {
|
||||||
return low, .OK;
|
return low, .None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+48
-39
@@ -20,29 +20,33 @@ package big
|
|||||||
2's complement `and`, returns `dest = a & b;`
|
2's complement `and`, returns `dest = a & b;`
|
||||||
*/
|
*/
|
||||||
and :: proc(dest, a, b: ^Int) -> (err: Error) {
|
and :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||||
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if err = clear_if_uninitialized(b); err != .None {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
used := max(a.used, b.used) + 1;
|
used := max(a.used, b.used) + 1;
|
||||||
neg: bool;
|
|
||||||
|
|
||||||
neg = is_neg(a) && is_neg(b);
|
|
||||||
|
|
||||||
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Grow the destination to accomodate the result.
|
Grow the destination to accomodate the result.
|
||||||
*/
|
*/
|
||||||
if err = grow(dest, used); err != .OK {
|
if err = grow(dest, used); err != .None {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
neg_a, _ := is_neg(a);
|
||||||
|
neg_b, _ := is_neg(b);
|
||||||
|
neg := neg_a && neg_b;
|
||||||
|
|
||||||
|
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||||
|
|
||||||
for i := 0; i < used; i += 1 {
|
for i := 0; i < used; i += 1 {
|
||||||
x, y: DIGIT;
|
x, y: DIGIT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Convert to 2's complement if negative.
|
Convert to 2's complement if negative.
|
||||||
*/
|
*/
|
||||||
if is_neg(a) {
|
if neg_a {
|
||||||
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
||||||
x = ac & _MASK;
|
x = ac & _MASK;
|
||||||
ac >>= _DIGIT_BITS;
|
ac >>= _DIGIT_BITS;
|
||||||
@@ -53,7 +57,7 @@ and :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Convert to 2's complement if negative.
|
Convert to 2's complement if negative.
|
||||||
*/
|
*/
|
||||||
if is_neg(a) {
|
if neg_b {
|
||||||
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
||||||
y = bc & _MASK;
|
y = bc & _MASK;
|
||||||
bc >>= _DIGIT_BITS;
|
bc >>= _DIGIT_BITS;
|
||||||
@@ -75,37 +79,40 @@ and :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
|
|
||||||
dest.used = used;
|
dest.used = used;
|
||||||
dest.sign = .Negative if neg else .Zero_or_Positive;
|
dest.sign = .Negative if neg else .Zero_or_Positive;
|
||||||
clamp(dest);
|
return clamp(dest);
|
||||||
return .OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
2's complement `or`, returns `dest = a | b;`
|
2's complement `or`, returns `dest = a | b;`
|
||||||
*/
|
*/
|
||||||
or :: proc(dest, a, b: ^Int) -> (err: Error) {
|
or :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||||
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if err = clear_if_uninitialized(b); err != .None {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
used := max(a.used, b.used) + 1;
|
used := max(a.used, b.used) + 1;
|
||||||
neg: bool;
|
|
||||||
|
|
||||||
neg = is_neg(a) || is_neg(b);
|
|
||||||
|
|
||||||
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Grow the destination to accomodate the result.
|
Grow the destination to accomodate the result.
|
||||||
*/
|
*/
|
||||||
if err = grow(dest, used); err != .OK {
|
if err = grow(dest, used); err != .None {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
neg_a, _ := is_neg(a);
|
||||||
|
neg_b, _ := is_neg(b);
|
||||||
|
neg := neg_a || neg_b;
|
||||||
|
|
||||||
|
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||||
|
|
||||||
for i := 0; i < used; i += 1 {
|
for i := 0; i < used; i += 1 {
|
||||||
x, y: DIGIT;
|
x, y: DIGIT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Convert to 2's complement if negative.
|
Convert to 2's complement if negative.
|
||||||
*/
|
*/
|
||||||
if is_neg(a) {
|
if neg_a {
|
||||||
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
||||||
x = ac & _MASK;
|
x = ac & _MASK;
|
||||||
ac >>= _DIGIT_BITS;
|
ac >>= _DIGIT_BITS;
|
||||||
@@ -116,7 +123,7 @@ or :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Convert to 2's complement if negative.
|
Convert to 2's complement if negative.
|
||||||
*/
|
*/
|
||||||
if is_neg(a) {
|
if neg_b {
|
||||||
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
||||||
y = bc & _MASK;
|
y = bc & _MASK;
|
||||||
bc >>= _DIGIT_BITS;
|
bc >>= _DIGIT_BITS;
|
||||||
@@ -138,37 +145,40 @@ or :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
|
|
||||||
dest.used = used;
|
dest.used = used;
|
||||||
dest.sign = .Negative if neg else .Zero_or_Positive;
|
dest.sign = .Negative if neg else .Zero_or_Positive;
|
||||||
clamp(dest);
|
return clamp(dest);
|
||||||
return .OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
2's complement `xor`, returns `dest = a ~ b;`
|
2's complement `xor`, returns `dest = a ~ b;`
|
||||||
*/
|
*/
|
||||||
xor :: proc(dest, a, b: ^Int) -> (err: Error) {
|
xor :: proc(dest, a, b: ^Int) -> (err: Error) {
|
||||||
assert_initialized(dest); assert_initialized(a); assert_initialized(b);
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if err = clear_if_uninitialized(b); err != .None {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
used := max(a.used, b.used) + 1;
|
used := max(a.used, b.used) + 1;
|
||||||
neg: bool;
|
|
||||||
|
|
||||||
neg = is_neg(a) != is_neg(b);
|
|
||||||
|
|
||||||
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Grow the destination to accomodate the result.
|
Grow the destination to accomodate the result.
|
||||||
*/
|
*/
|
||||||
if err = grow(dest, used); err != .OK {
|
if err = grow(dest, used); err != .None {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
neg_a, _ := is_neg(a);
|
||||||
|
neg_b, _ := is_neg(b);
|
||||||
|
neg := neg_a != neg_b;
|
||||||
|
|
||||||
|
ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1);
|
||||||
|
|
||||||
for i := 0; i < used; i += 1 {
|
for i := 0; i < used; i += 1 {
|
||||||
x, y: DIGIT;
|
x, y: DIGIT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Convert to 2's complement if negative.
|
Convert to 2's complement if negative.
|
||||||
*/
|
*/
|
||||||
if is_neg(a) {
|
if neg_a {
|
||||||
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
ac += _MASK if i >= a.used else (~a.digit[i] & _MASK);
|
||||||
x = ac & _MASK;
|
x = ac & _MASK;
|
||||||
ac >>= _DIGIT_BITS;
|
ac >>= _DIGIT_BITS;
|
||||||
@@ -179,7 +189,7 @@ xor :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
/*
|
/*
|
||||||
Convert to 2's complement if negative.
|
Convert to 2's complement if negative.
|
||||||
*/
|
*/
|
||||||
if is_neg(a) {
|
if neg_b {
|
||||||
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
bc += _MASK if i >= b.used else (~b.digit[i] & _MASK);
|
||||||
y = bc & _MASK;
|
y = bc & _MASK;
|
||||||
bc >>= _DIGIT_BITS;
|
bc >>= _DIGIT_BITS;
|
||||||
@@ -201,6 +211,5 @@ xor :: proc(dest, a, b: ^Int) -> (err: Error) {
|
|||||||
|
|
||||||
dest.used = used;
|
dest.used = used;
|
||||||
dest.sign = .Negative if neg else .Zero_or_Positive;
|
dest.sign = .Negative if neg else .Zero_or_Positive;
|
||||||
clamp(dest);
|
return clamp(dest);
|
||||||
return .OK;
|
|
||||||
}
|
}
|
||||||
+54
-44
@@ -19,8 +19,10 @@ import "core:strings"
|
|||||||
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
||||||
*/
|
*/
|
||||||
itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
|
itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) {
|
||||||
radix := radix;
|
a := a; radix := radix;
|
||||||
assert_initialized(a);
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
|
return "", err;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
Radix defaults to 10.
|
Radix defaults to 10.
|
||||||
*/
|
*/
|
||||||
@@ -32,14 +34,13 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate the size of the buffer we need.
|
Calculate the size of the buffer we need, and
|
||||||
*/
|
*/
|
||||||
size: int;
|
size: int;
|
||||||
size, err = radix_size(a, radix, zero_terminate);
|
|
||||||
/*
|
/*
|
||||||
Exit if calculating the size returned an error.
|
Exit if calculating the size returned an error.
|
||||||
*/
|
*/
|
||||||
if err != .OK {
|
if size, err = radix_size(a, radix, zero_terminate); err != .None {
|
||||||
f := strings.clone(fallback(a), allocator);
|
f := strings.clone(fallback(a), allocator);
|
||||||
if zero_terminate {
|
if zero_terminate {
|
||||||
c := strings.clone_to_cstring(f);
|
c := strings.clone_to_cstring(f);
|
||||||
@@ -57,14 +58,13 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator
|
|||||||
Write the digits out into the buffer.
|
Write the digits out into the buffer.
|
||||||
*/
|
*/
|
||||||
written: int;
|
written: int;
|
||||||
written, err = itoa_raw(a, radix, buffer, size, zero_terminate);
|
if written, err = itoa_raw(a, radix, buffer, size, zero_terminate); err == .None {
|
||||||
|
return string(buffer[:written]), .None;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
For now, delete the buffer and fall back to the below on failure.
|
For now, delete the buffer and fall back to the below on failure.
|
||||||
*/
|
*/
|
||||||
if err == .OK {
|
|
||||||
return string(buffer[:written]), .OK;
|
|
||||||
}
|
|
||||||
delete(buffer);
|
delete(buffer);
|
||||||
|
|
||||||
fallback :: proc(a: ^Int, print_raw := false) -> string {
|
fallback :: proc(a: ^Int, print_raw := false) -> string {
|
||||||
@@ -86,8 +86,10 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator
|
|||||||
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
This version of `itoa` allocates one behalf of the caller. The caller must free the string.
|
||||||
*/
|
*/
|
||||||
itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
|
itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) {
|
||||||
radix := radix;
|
a := a; radix := radix;
|
||||||
assert_initialized(a);
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
|
return "", err;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
Radix defaults to 10.
|
Radix defaults to 10.
|
||||||
*/
|
*/
|
||||||
@@ -119,21 +121,25 @@ itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -
|
|||||||
and having to perform a buffer overflow check each character.
|
and having to perform a buffer overflow check each character.
|
||||||
*/
|
*/
|
||||||
itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
|
itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) {
|
||||||
radix := radix;
|
a := a; radix := radix; size := size;
|
||||||
assert_initialized(a); size := size;
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
|
return 0, err;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
Radix defaults to 10.
|
Radix defaults to 10.
|
||||||
*/
|
*/
|
||||||
radix = radix if radix > 0 else 10;
|
radix = radix if radix > 0 else 10;
|
||||||
if radix < 2 || radix > 64 {
|
if radix < 2 || radix > 64 {
|
||||||
return 0, .Invalid_Input;
|
return 0, .Invalid_Argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We weren't given a size. Let's compute it.
|
We weren't given a size. Let's compute it.
|
||||||
*/
|
*/
|
||||||
if size == -1 {
|
if size == -1 {
|
||||||
size, err = radix_size(a, radix, zero_terminate);
|
if size, err = radix_size(a, radix, zero_terminate); err != .None {
|
||||||
|
return 0, err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -146,7 +152,8 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
|
|||||||
/*
|
/*
|
||||||
Fast path for when `Int` == 0 or the entire `Int` fits in a single radix digit.
|
Fast path for when `Int` == 0 or the entire `Int` fits in a single radix digit.
|
||||||
*/
|
*/
|
||||||
if is_zero(a) || (a.used == 1 && a.digit[0] < DIGIT(radix)) {
|
z, _ := is_zero(a);
|
||||||
|
if z || (a.used == 1 && a.digit[0] < DIGIT(radix)) {
|
||||||
if zero_terminate {
|
if zero_terminate {
|
||||||
available -= 1;
|
available -= 1;
|
||||||
buffer[available] = 0;
|
buffer[available] = 0;
|
||||||
@@ -154,12 +161,12 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
|
|||||||
available -= 1;
|
available -= 1;
|
||||||
buffer[available] = RADIX_TABLE[a.digit[0]];
|
buffer[available] = RADIX_TABLE[a.digit[0]];
|
||||||
|
|
||||||
if is_neg(a) {
|
if n, _ := is_neg(a); n {
|
||||||
available -= 1;
|
available -= 1;
|
||||||
buffer[available] = '-';
|
buffer[available] = '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
return len(buffer) - available, .OK;
|
return len(buffer) - available, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -179,11 +186,11 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
|
|||||||
|
|
||||||
val = q;
|
val = q;
|
||||||
}
|
}
|
||||||
if is_neg(a) {
|
if n, _ := is_neg(a); n {
|
||||||
available -= 1;
|
available -= 1;
|
||||||
buffer[available] = '-';
|
buffer[available] = '-';
|
||||||
}
|
}
|
||||||
return len(buffer) - available, .OK;
|
return len(buffer) - available, .None;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
At least 3 DIGITs are in use if we made it this far.
|
At least 3 DIGITs are in use if we made it this far.
|
||||||
@@ -202,24 +209,23 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina
|
|||||||
// mask := _WORD(radix - 1);
|
// mask := _WORD(radix - 1);
|
||||||
shift, err = log_n(DIGIT(radix), 2);
|
shift, err = log_n(DIGIT(radix), 2);
|
||||||
count, err = count_bits(a);
|
count, err = count_bits(a);
|
||||||
// digit: _WORD;
|
digit: _WORD;
|
||||||
|
|
||||||
for offset := 0; offset < count; offset += 4 {
|
for offset := 0; offset < count; offset += 4 {
|
||||||
bits_to_get := int(min(count - offset, shift));
|
bits_to_get := int(min(count - offset, shift));
|
||||||
digit, err := extract_bits(a, offset, bits_to_get);
|
if digit, err = extract_bits(a, offset, bits_to_get); err != .None {
|
||||||
if err != .OK {
|
return len(buffer) - available, .Invalid_Argument;
|
||||||
return len(buffer) - available, .Invalid_Input;
|
|
||||||
}
|
}
|
||||||
available -= 1;
|
available -= 1;
|
||||||
buffer[available] = RADIX_TABLE[digit];
|
buffer[available] = RADIX_TABLE[digit];
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_neg(a) {
|
if n, _ := is_neg(a); n {
|
||||||
available -= 1;
|
available -= 1;
|
||||||
buffer[available] = '-';
|
buffer[available] = '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
return len(buffer) - available, .OK;
|
return len(buffer) - available, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1, .Unimplemented;
|
return -1, .Unimplemented;
|
||||||
@@ -233,37 +239,41 @@ int_to_cstring :: itoa_cstring;
|
|||||||
We size for `string`, not `cstring`.
|
We size for `string`, not `cstring`.
|
||||||
*/
|
*/
|
||||||
radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false) -> (size: int, err: Error) {
|
radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false) -> (size: int, err: Error) {
|
||||||
|
a := a;
|
||||||
if radix < 2 || radix > 64 {
|
if radix < 2 || radix > 64 {
|
||||||
return -1, .Invalid_Input;
|
return -1, .Invalid_Argument;
|
||||||
|
}
|
||||||
|
if err = clear_if_uninitialized(a); err != .None {
|
||||||
|
return 0, err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_zero(a) {
|
if z, _ := is_zero(a); z {
|
||||||
if zero_terminate {
|
if zero_terminate {
|
||||||
return 2, .OK;
|
return 2, .None;
|
||||||
}
|
}
|
||||||
return 1, .OK;
|
return 1, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate `log` on a temporary "copy" with its sign set to positive.
|
Calculate `log` on a temporary "copy" with its sign set to positive.
|
||||||
*/
|
*/
|
||||||
t := &Int{
|
t := &Int{
|
||||||
used = a.used,
|
used = a.used,
|
||||||
sign = .Zero_or_Positive,
|
sign = .Zero_or_Positive,
|
||||||
digit = a.digit,
|
digit = a.digit,
|
||||||
};
|
};
|
||||||
|
|
||||||
size, err = log_n(t, DIGIT(radix));
|
if size, err = log_n(t, DIGIT(radix)); err != .None {
|
||||||
if err != .OK {
|
return 0, err;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
log truncates to zero, so we need to add one more, and one for `-` if negative.
|
log truncates to zero, so we need to add one more, and one for `-` if negative.
|
||||||
*/
|
*/
|
||||||
size += 2 if is_neg(a) else 1;
|
n, _ := is_neg(a);
|
||||||
size += 1 if zero_terminate else 0;
|
size += 2 if n else 1;
|
||||||
return size, .OK;
|
size += 1 if zero_terminate else 0;
|
||||||
|
return size, .None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user