diff options
| author | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2021-07-21 13:46:37 +0200 |
|---|---|---|
| committer | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2021-08-11 20:59:50 +0200 |
| commit | 7648f2e655b0e280bfb049eb02634d0f5cd136ac (patch) | |
| tree | 2b245d2766e67503f807550997bfe264313a2666 /core/math | |
| parent | d9efa6c8b5cbaaf04c6468f465a6b402b4dc8e82 (diff) | |
big: Finish big ZII refactor.
Diffstat (limited to 'core/math')
| -rw-r--r-- | core/math/big/basic.odin | 178 | ||||
| -rw-r--r-- | core/math/big/common.odin (renamed from core/math/big/bigint.odin) | 36 | ||||
| -rw-r--r-- | core/math/big/compare.odin | 142 | ||||
| -rw-r--r-- | core/math/big/example.odin | 6 | ||||
| -rw-r--r-- | core/math/big/helpers.odin | 145 | ||||
| -rw-r--r-- | core/math/big/log.odin | 27 | ||||
| -rw-r--r-- | core/math/big/logical.odin | 87 | ||||
| -rw-r--r-- | core/math/big/radix.odin | 98 |
8 files changed, 400 insertions, 319 deletions
diff --git a/core/math/big/basic.odin b/core/math/big/basic.odin index 8a50543ca..4e923526a 100644 --- a/core/math/big/basic.odin +++ b/core/math/big/basic.odin @@ -25,11 +25,19 @@ import "core:intrinsics" */
int_add :: proc(dest, a, b: ^Int) -> (err: Error) {
dest := dest; x := a; y := b;
- if dest == nil || a == nil || b == nil {
- return .Nil_Pointer_Passed;
- } else if !is_initialized(a) || !is_initialized(b) {
- return .Int_Not_Initialized;
+ if err = clear_if_uninitialized(a); err != .None {
+ return err;
+ }
+ if err = clear_if_uninitialized(b); err != .None {
+ return err;
+ }
+ if err = clear_if_uninitialized(dest); err != .None {
+ return err;
}
+ /*
+ All parameters have been initialized.
+ We can now safely ignore errors from comparison routines.
+ */
/*
Handle both negative or both positive.
@@ -44,7 +52,7 @@ int_add :: proc(dest, a, b: ^Int) -> (err: Error) { Subtract the one with the greater magnitude from the other.
The result gets the sign of the one with the greater magnitude.
*/
- if cmp_mag(x, y) == .Less_Than {
+ if c, _ := cmp_mag(a, b); c == -1 {
x, y = y, x;
}
@@ -60,58 +68,67 @@ 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.
*/
if dest == a {
/*
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);
}
\ No newline at end of file diff --git a/core/math/big/bigint.odin b/core/math/big/common.odin index f2c9366ad..bcbfafaef 100644 --- a/core/math/big/bigint.odin +++ b/core/math/big/common.odin @@ -53,27 +53,21 @@ Int :: struct { sign: Sign, }; -Comparison_Flag :: enum i8 { - Less_Than = -1, - Equal = 0, - Greater_Than = 1, - - /* One of the numbers was uninitialized */ - Uninitialized = -127, -}; - -Error :: enum i8 { - OK = 0, - Unknown_Error = -1, - Out_of_Memory = -2, - Invalid_Input = -3, - Max_Iterations_Reached = -4, - Buffer_Overflow = -5, - Integer_Overflow = -6, - Nil_Pointer_Passed = -7, - Int_Not_Initialized = -8, - - Unimplemented = -127, +/* + Errors are a strict superset of runtime.Allocation_Error. +*/ +Error :: enum byte { + None = 0, + Out_Of_Memory = 1, + Invalid_Pointer = 2, + Invalid_Argument = 3, + + Unknown_Error = 4, + Max_Iterations_Reached = 5, + Buffer_Overflow = 6, + Integer_Overflow = 7, + + Unimplemented = 127, }; Primality_Flag :: enum u8 { diff --git a/core/math/big/compare.odin b/core/math/big/compare.odin index 142a3bfe3..43e872ce1 100644 --- a/core/math/big/compare.odin +++ b/core/math/big/compare.odin @@ -22,61 +22,83 @@ int_is_initialized :: proc(a: ^Int) -> bool { return raw.cap >= _MIN_DIGIT_COUNT; } -int_is_zero :: proc(a: ^Int) -> bool { - return is_initialized(a) && a.used == 0; +int_is_zero :: proc(a: ^Int) -> (res: bool, err: Error) { + if err = clear_if_uninitialized(a); err != .None { + return false, err; + } + return a.used == 0, .None; } -int_is_positive :: proc(a: ^Int) -> bool { - return is_initialized(a) && a.sign == .Zero_or_Positive; +int_is_positive :: proc(a: ^Int) -> (res: bool, err: Error) { + if err = clear_if_uninitialized(a); err != .None { + return false, err; + } + return a.sign == .Zero_or_Positive, .None; } -int_is_negative :: proc(a: ^Int) -> bool { - return is_initialized(a) && a.sign == .Negative; +int_is_negative :: proc(a: ^Int) -> (res: bool, err: Error) { + if err = clear_if_uninitialized(a); err != .None { + return false, err; + } + return a.sign == .Negative, .None; } -int_is_even :: proc(a: ^Int) -> bool { - if is_initialized(a) { - if is_zero(a) { - return true; - } - if a.used > 0 && a.digit[0] & 1 == 0 { - return true; - } +int_is_even :: proc(a: ^Int) -> (res: bool, err: Error) { + if err = clear_if_uninitialized(a); err != .None { + return false, err; + } + + res, err = is_zero(a); + if err != .None { + return false, err; + } else if res == true { + return true, .None; + } + + res = false; + if a.used > 0 && a.digit[0] & 1 == 0 { + res = true; } - return false; + return res, .None; } -int_is_odd :: proc(a: ^Int) -> bool { - if is_initialized(a) { - return !is_even(a); +int_is_odd :: proc(a: ^Int) -> (res: bool, err: Error) { + if err = clear_if_uninitialized(a); err != .None { + return false, err; } - return false; + + res, err = is_even(a); + return !res, err; } platform_int_is_power_of_two :: proc(a: int) -> bool { return ((a) != 0) && (((a) & ((a) - 1)) == 0); } -int_is_power_of_two :: proc(a: ^Int) -> (res: bool) { +int_is_power_of_two :: proc(a: ^Int) -> (res: bool, err: Error) { + if err = clear_if_uninitialized(a); err != .None { + return false, err; + } + /* Early out for Int == 0. */ if a.used == 0 { - return false; + return false, .None; } /* For an `Int` to be a power of two, its top limb has to be a power of two. */ if !platform_int_is_power_of_two(int(a.digit[a.used - 1])) { - return false; + return false, .None; } /* That was the only limb, so it's a power of two. */ if a.used == 1 { - return true; + return true, .None; } /* @@ -84,74 +106,102 @@ int_is_power_of_two :: proc(a: ^Int) -> (res: bool) { */ for i := 1; i < a.used; i += 1 { if a.digit[i - 1] != 0 { - return false; + return false, .None; } } - return true; + return true, .None; } /* Compare two `Int`s, signed. */ -int_compare :: proc(a, b: ^Int) -> Comparison_Flag { - if !is_initialized(a) { return .Uninitialized; } - if !is_initialized(b) { return .Uninitialized; } +int_compare :: proc(a, b: ^Int) -> (res: int, err: Error) { + if err = clear_if_uninitialized(a); err != .None { + return 0, err; + } + if err = clear_if_uninitialized(b); err != .None { + return 0, err; + } + + neg: bool; + if neg, err = is_negative(a); err != .None { + return 0, err; + } /* Compare based on sign */ if a.sign != b.sign { - return .Less_Than if is_negative(a) else .Greater_Than; + res = -1 if neg else +1; + return res, .None; } - x, y := a, b; /* If negative, compare in the opposite direction */ - if is_neg(a) { - x, y = b, a; + if neg { + return cmp_mag(b, a); } - return cmp_mag(x, y); + return cmp_mag(a, b); } /* Compare an `Int` to an unsigned number upto the size of the backing type. */ -int_compare_digit :: proc(a: ^Int, u: DIGIT) -> Comparison_Flag { - if !is_initialized(a) { return .Uninitialized; } +int_compare_digit :: proc(a: ^Int, u: DIGIT) -> (res: int, err: Error) { + if err = clear_if_uninitialized(a); err != .None { + return 0, err; + } /* Compare based on sign */ - if is_neg(a) { - return .Less_Than; + neg: bool; + if neg, err = is_neg(a); err != .None { + return 0, err; + } + if neg { + return -1, .None; } /* Compare based on magnitude */ if a.used > 1 { - return .Greater_Than; + return +1, .None; } /* Compare the only digit in `a` to `u`. */ if a.digit[0] != u { - return .Greater_Than if a.digit[0] > u else .Less_Than; + if a.digit[0] > u { + return +1, .None; + } + return -1, .None; } - return .Equal; + return 0, .None; } /* Compare the magnitude of two `Int`s, unsigned. */ -int_compare_magnitude :: proc(a, b: ^Int) -> Comparison_Flag { - if !is_initialized(a) { return .Uninitialized; } - if !is_initialized(b) { return .Uninitialized; } +int_compare_magnitude :: proc(a, b: ^Int) -> (res: int, err: Error) { + if err = clear_if_uninitialized(a); err != .None { + return 0, err; + } + if err = clear_if_uninitialized(b); err != .None { + return 0, err; + } /* Compare based on used digits */ if a.used != b.used { - return .Greater_Than if a.used > b.used else .Less_Than; + if a.used > b.used { + return +1, .None; + } + return -1, .None; } /* Same number of used digits, compare based on their value */ for n := a.used - 1; n >= 0; n -= 1 { if a.digit[n] != b.digit[n] { - return .Greater_Than if a.digit[n] > b.digit[n] else .Less_Than; + if a.digit[n] > b.digit[n] { + return +1, .None; + } + return -1, .None; } } - return .Equal; + return 0, .None; }
\ No newline at end of file diff --git a/core/math/big/example.odin b/core/math/big/example.odin index 616cbc553..3c90719f1 100644 --- a/core/math/big/example.odin +++ b/core/math/big/example.odin @@ -44,7 +44,7 @@ _SQR_TOOM_CUTOFF, print :: proc(name: string, a: ^Int, base := i8(16)) { as, err := itoa(a, base); defer delete(as); - if err == .OK { + if err == .None { cb, _ := count_bits(a); fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, cb, as); } else { @@ -80,10 +80,10 @@ demo :: proc() { print("c", c); fmt.println("\n\n=== Set a to (1 << 120) - 1 ==="); - if err = power_of_two(a, 120); err != .OK { + if err = power_of_two(a, 120); err != .None { fmt.printf("Error %v while setting a to 1 << 120.\n", err); } - if err = sub(a, a, 1); err != .OK { + if err = sub(a, a, 1); err != .None { fmt.printf("Error %v while subtracting 1 from a\n", err); } print("a", a, 16); diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index 5a2ea8962..af3d27e0f 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -30,15 +30,10 @@ int_destroy :: proc(integers: ..^Int) { int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator := context.allocator) -> (err: Error) where intrinsics.type_is_integer(T) { src := src; - /* - Check that dest is usable. - */ - if dest == nil { - return .Nil_Pointer_Passed; + if err = clear_if_uninitialized(dest); err != .None { + return err; } - if err = _grow_if_uninitialized(dest, minimize); err != .OK { return err; } - dest.used = 0; dest.sign = .Zero_or_Positive if src >= 0 else .Negative; src = abs(src); @@ -49,7 +44,7 @@ int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator : src >>= _DIGIT_BITS; } _zero_unused(dest); - return .OK; + return .None; } set :: proc { int_set_from_integer, int_copy }; @@ -58,27 +53,20 @@ set :: proc { int_set_from_integer, int_copy }; Copy one `Int` to another. */ int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) { - /* - Check that src and dest are usable. - */ - if dest == nil || src == nil { - return .Nil_Pointer_Passed; - } else if !is_initialized(src) { - return .Int_Not_Initialized; + if err = clear_if_uninitialized(src); err != .None { + return err; } - /* If dest == src, do nothing */ if (dest == src) { - return .OK; + return .None; } - /* Grow `dest` to fit `src`. If `dest` is not yet initialized, it will be using `allocator`. */ - if err = grow(dest, src.used, false, allocator); err != .OK { + if err = grow(dest, src.used, false, allocator); err != .None { return err; } @@ -91,7 +79,7 @@ int_copy :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error dest.used = src.used; dest.sign = src.sign; _zero_unused(dest); - return .OK; + return .None; } copy :: proc { int_copy, }; @@ -100,26 +88,23 @@ copy :: proc { int_copy, }; */ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) { /* - Check that src and dest are usable. + Check that src is usable. */ - if dest == nil || src == nil { - return .Nil_Pointer_Passed; - } else if !is_initialized(src) { - return .Int_Not_Initialized; + if err = clear_if_uninitialized(src); err != .None { + return err; } - /* If `dest == src`, just fix `dest`'s sign. */ if (dest == src) { dest.sign = .Zero_or_Positive; - return .OK; + return .None; } /* Copy `src` to `dest` */ - if err = copy(dest, src, allocator); err != .OK { + if err = copy(dest, src, allocator); err != .None { return err; } @@ -127,7 +112,7 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) Fix sign. */ dest.sign = .Zero_or_Positive; - return .OK; + return .None; } platform_abs :: proc(n: $T) -> T where intrinsics.type_is_integer(T) { @@ -140,27 +125,29 @@ abs :: proc{int_abs, platform_abs}; */ neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) { /* - Check that src and dest are usable. + Check that src is usable. */ - if dest == nil || src == nil { - return .Nil_Pointer_Passed; - } else if !is_initialized(src) { - return .Int_Not_Initialized; + if err = clear_if_uninitialized(src); err != .None { + return err; } - /* If `dest == src`, just fix `dest`'s sign. */ - sign := Sign.Negative if !(is_zero(src) && is_neg(src)) else Sign.Zero_or_Positive; - if dest == src { + sign := Sign.Zero_or_Positive; + if z, _ := is_zero(src); z { + sign = .Negative; + } + if n, _ := is_neg(src); n { + sign = .Negative; + } + if (dest == src) { dest.sign = sign; - return .OK; + return .None; } - /* Copy `src` to `dest` */ - if err = copy(dest, src, allocator); err != .OK { + if err = copy(dest, src, allocator); err != .None { return err; } @@ -168,7 +155,7 @@ neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) { Fix sign. */ dest.sign = sign; - return .OK; + return .None; } /* @@ -176,22 +163,20 @@ neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error) { */ extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) { /* - Check that `a` is usable. + Check that `a`is usable. */ - if a == nil { - return 0, .Nil_Pointer_Passed; - } else if !is_initialized(a) { - return 0, .Int_Not_Initialized; + if err = clear_if_uninitialized(a); err != .None { + return 0, err; } limb := bit_offset / _DIGIT_BITS; if limb < 0 || limb >= a.used { - return 0, .Invalid_Input; + return 0, .Invalid_Argument; } i := DIGIT(1 << DIGIT((bit_offset % _DIGIT_BITS))); - return 1 if ((a.digit[limb] & i) != 0) else 0, .OK; + return 1 if ((a.digit[limb] & i) != 0) else 0, .None; } /* @@ -199,16 +184,14 @@ extract_bit :: proc(a: ^Int, bit_offset: int) -> (bit: DIGIT, err: Error) { */ extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) { /* - Check that `a` is usable. + Check that `a`is usable. */ - if a == nil { - return 0, .Nil_Pointer_Passed; - } else if !is_initialized(a) { - return 0, .Int_Not_Initialized; + if err = clear_if_uninitialized(a); err != .None { + return 0, err; } if count > _WORD_BITS || count < 1 { - return 0, .Invalid_Input; + return 0, .Invalid_Argument; } v: DIGIT; @@ -216,7 +199,7 @@ extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) { for shift := 0; shift < count; shift += 1 { o := offset + shift; v, e = extract_bit(a, o); - if e != .OK { + if e != .None { break; } res = res + _WORD(v) << uint(shift); @@ -230,7 +213,7 @@ extract_bits :: proc(a: ^Int, offset, count: int) -> (res: _WORD, err: Error) { */ shrink :: proc(a: ^Int) -> (err: Error) { if a == nil { - return .Nil_Pointer_Passed; + return .Invalid_Pointer; } needed := max(_MIN_DIGIT_COUNT, a.used); @@ -238,12 +221,12 @@ shrink :: proc(a: ^Int) -> (err: Error) { if a.used != needed { return grow(a, needed); } - return .OK; + return .None; } int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := context.allocator) -> (err: Error) { if a == nil { - return .Nil_Pointer_Passed; + return .Invalid_Pointer; } raw := transmute(mem.Raw_Dynamic_Array)a.digit; @@ -269,9 +252,9 @@ int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator := conte Let's see if the allocation/resize worked as expected. */ if len(a.digit) != needed { - return .Out_of_Memory; + return .Out_Of_Memory; } - return .OK; + return .None; } grow :: proc { int_grow, }; @@ -280,7 +263,7 @@ grow :: proc { int_grow, }; */ int_clear :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) { if a == nil { - return .Nil_Pointer_Passed; + return .Invalid_Pointer; } raw := transmute(mem.Raw_Dynamic_Array)a.digit; @@ -299,14 +282,14 @@ zero :: clear; Set the `Int` to 1 and optionally shrink it to the minimum backing size. */ int_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) { - if err = clear(a, minimize, allocator); err != .OK { + if err = clear(a, minimize, allocator); err != .None { return err; } a.used = 1; a.digit[0] = 1; a.sign = .Zero_or_Positive; - return .OK; + return .None; } one :: proc { int_one, }; @@ -314,14 +297,14 @@ one :: proc { int_one, }; Set the `Int` to -1 and optionally shrink it to the minimum backing size. */ int_minus_one :: proc(a: ^Int, minimize := false, allocator := context.allocator) -> (err: Error) { - if err = clear(a, minimize, allocator); err != .OK { + if err = clear(a, minimize, allocator); err != .None { return err; } a.used = 1; a.digit[0] = 1; a.sign = .Negative; - return .OK; + return .None; } minus_one :: proc { int_minus_one, }; @@ -332,18 +315,18 @@ power_of_two :: proc(a: ^Int, power: int) -> (err: Error) { Check that `a` is usable. */ if a == nil { - return .Nil_Pointer_Passed; + return .Invalid_Pointer; } if power < 0 || power > _MAX_BIT_COUNT { - return .Invalid_Input; + return .Invalid_Argument; } /* Grow to accomodate the single bit. */ a.used = (power / _DIGIT_BITS) + 1; - if err = grow(a, a.used); err != .OK { + if err = grow(a, a.used); err != .None { return err; } /* @@ -355,23 +338,21 @@ power_of_two :: proc(a: ^Int, power: int) -> (err: Error) { Set the bit. */ a.digit[power / _DIGIT_BITS] = 1 << uint((power % _DIGIT_BITS)); - return .OK; + return .None; } /* Count bits in an `Int`. */ count_bits :: proc(a: ^Int) -> (count: int, err: Error) { - if a == nil { - return 0, .Nil_Pointer_Passed; - } else if !is_initialized(a) { - return 0, .Int_Not_Initialized; + if err = clear_if_uninitialized(a); err != .None { + return 0, err; } /* Fast path for zero. */ - if is_zero(a) { - return 0, .OK; + if z, _ := is_zero(a); z { + return 0, .None; } /* Get the number of DIGITs and use it. @@ -404,11 +385,11 @@ _zero_unused :: proc(a: ^Int) { } } -_grow_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) { +clear_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) { if !is_initialized(dest) { return grow(dest, _MIN_DIGIT_COUNT if minimize else _DEFAULT_DIGIT_COUNT); } - return .OK; + return .None; } /* @@ -418,19 +399,17 @@ _grow_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) { Typically very fast. Also fixes the sign if there are no more leading digits. */ clamp :: proc(a: ^Int) -> (err: Error) { - if a == nil { - return .Nil_Pointer_Passed; - } else if !is_initialized(a) { - return .Int_Not_Initialized; + if err = clear_if_uninitialized(a); err != .None { + return err; } for a.used > 0 && a.digit[a.used - 1] == 0 { a.used -= 1; } - if is_zero(a) { + if z, _ := is_zero(a); z { a.sign = .Zero_or_Positive; } - return .OK; + return .None; }
\ No newline at end of file diff --git a/core/math/big/log.odin b/core/math/big/log.odin index 9c4fc3a2a..bb918f690 100644 --- a/core/math/big/log.odin +++ b/core/math/big/log.odin @@ -10,13 +10,18 @@ package big */
log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) {
- if a == nil {
- return 0, .Nil_Pointer_Passed;
- } else if !is_initialized(a) {
- return 0, .Int_Not_Initialized;
+ if base < 2 || DIGIT(base) > _DIGIT_MAX {
+ return -1, .Invalid_Argument;
}
- if is_neg(a) || is_zero(a) || base < 2 || DIGIT(base) > _DIGIT_MAX {
- return -1, .Invalid_Input;
+
+ if err = clear_if_uninitialized(a); err != .None {
+ return -1, err;
+ }
+ if n, _ := is_neg(a); n {
+ return -1, .Invalid_Argument;
+ }
+ if z, _ := is_zero(a); z {
+ return -1, .Invalid_Argument;
}
/*
@@ -80,14 +85,14 @@ log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) { Therefore, we return 0.
*/
if a < base {
- return 0, .OK;
+ return 0, .None;
}
/*
If a number equals the base, the log is 1.
*/
if a == base {
- return 1, .OK;
+ return 1, .None;
}
N := _WORD(a);
@@ -116,13 +121,13 @@ log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) { bracket_low = bracket_mid;
}
if N == bracket_mid {
- return mid, .OK;
+ return mid, .None;
}
}
if bracket_high == N {
- return high, .OK;
+ return high, .None;
} else {
- return low, .OK;
+ return low, .None;
}
}
\ No newline at end of file diff --git a/core/math/big/logical.odin b/core/math/big/logical.odin index 6c857a2f2..47537d092 100644 --- a/core/math/big/logical.odin +++ b/core/math/big/logical.odin @@ -20,29 +20,33 @@ package big 2's complement `and`, returns `dest = a & b;` */ and :: proc(dest, a, b: ^Int) -> (err: Error) { - assert_initialized(dest); assert_initialized(a); assert_initialized(b); - + if err = clear_if_uninitialized(a); err != .None { + return err; + } + if err = clear_if_uninitialized(b); err != .None { + return err; + } used := max(a.used, b.used) + 1; - neg: bool; - - neg = is_neg(a) && is_neg(b); - - ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1); - /* Grow the destination to accomodate the result. */ - if err = grow(dest, used); err != .OK { + if err = grow(dest, used); err != .None { return err; } + neg_a, _ := is_neg(a); + neg_b, _ := is_neg(b); + neg := neg_a && neg_b; + + ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1); + for i := 0; i < used; i += 1 { x, y: DIGIT; /* Convert to 2's complement if negative. */ - if is_neg(a) { + if neg_a { ac += _MASK if i >= a.used else (~a.digit[i] & _MASK); x = ac & _MASK; ac >>= _DIGIT_BITS; @@ -53,7 +57,7 @@ and :: proc(dest, a, b: ^Int) -> (err: Error) { /* Convert to 2's complement if negative. */ - if is_neg(a) { + if neg_b { bc += _MASK if i >= b.used else (~b.digit[i] & _MASK); y = bc & _MASK; bc >>= _DIGIT_BITS; @@ -75,37 +79,40 @@ and :: proc(dest, a, b: ^Int) -> (err: Error) { dest.used = used; dest.sign = .Negative if neg else .Zero_or_Positive; - clamp(dest); - return .OK; + return clamp(dest); } /* 2's complement `or`, returns `dest = a | b;` */ or :: proc(dest, a, b: ^Int) -> (err: Error) { - assert_initialized(dest); assert_initialized(a); assert_initialized(b); - + if err = clear_if_uninitialized(a); err != .None { + return err; + } + if err = clear_if_uninitialized(b); err != .None { + return err; + } used := max(a.used, b.used) + 1; - neg: bool; - - neg = is_neg(a) || is_neg(b); - - ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1); - /* Grow the destination to accomodate the result. */ - if err = grow(dest, used); err != .OK { + if err = grow(dest, used); err != .None { return err; } + neg_a, _ := is_neg(a); + neg_b, _ := is_neg(b); + neg := neg_a || neg_b; + + ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1); + for i := 0; i < used; i += 1 { x, y: DIGIT; /* Convert to 2's complement if negative. */ - if is_neg(a) { + if neg_a { ac += _MASK if i >= a.used else (~a.digit[i] & _MASK); x = ac & _MASK; ac >>= _DIGIT_BITS; @@ -116,7 +123,7 @@ or :: proc(dest, a, b: ^Int) -> (err: Error) { /* Convert to 2's complement if negative. */ - if is_neg(a) { + if neg_b { bc += _MASK if i >= b.used else (~b.digit[i] & _MASK); y = bc & _MASK; bc >>= _DIGIT_BITS; @@ -138,37 +145,40 @@ or :: proc(dest, a, b: ^Int) -> (err: Error) { dest.used = used; dest.sign = .Negative if neg else .Zero_or_Positive; - clamp(dest); - return .OK; + return clamp(dest); } /* 2's complement `xor`, returns `dest = a ~ b;` */ xor :: proc(dest, a, b: ^Int) -> (err: Error) { - assert_initialized(dest); assert_initialized(a); assert_initialized(b); - + if err = clear_if_uninitialized(a); err != .None { + return err; + } + if err = clear_if_uninitialized(b); err != .None { + return err; + } used := max(a.used, b.used) + 1; - neg: bool; - - neg = is_neg(a) != is_neg(b); - - ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1); - /* Grow the destination to accomodate the result. */ - if err = grow(dest, used); err != .OK { + if err = grow(dest, used); err != .None { return err; } + neg_a, _ := is_neg(a); + neg_b, _ := is_neg(b); + neg := neg_a != neg_b; + + ac, bc, cc := DIGIT(1), DIGIT(1), DIGIT(1); + for i := 0; i < used; i += 1 { x, y: DIGIT; /* Convert to 2's complement if negative. */ - if is_neg(a) { + if neg_a { ac += _MASK if i >= a.used else (~a.digit[i] & _MASK); x = ac & _MASK; ac >>= _DIGIT_BITS; @@ -179,7 +189,7 @@ xor :: proc(dest, a, b: ^Int) -> (err: Error) { /* Convert to 2's complement if negative. */ - if is_neg(a) { + if neg_b { bc += _MASK if i >= b.used else (~b.digit[i] & _MASK); y = bc & _MASK; bc >>= _DIGIT_BITS; @@ -201,6 +211,5 @@ xor :: proc(dest, a, b: ^Int) -> (err: Error) { dest.used = used; dest.sign = .Negative if neg else .Zero_or_Positive; - clamp(dest); - return .OK; + return clamp(dest); }
\ No newline at end of file diff --git a/core/math/big/radix.odin b/core/math/big/radix.odin index 0dd07672c..8b4abc76d 100644 --- a/core/math/big/radix.odin +++ b/core/math/big/radix.odin @@ -19,8 +19,10 @@ import "core:strings" This version of `itoa` allocates one behalf of the caller. The caller must free the string. */ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator := context.allocator) -> (res: string, err: Error) { - radix := radix; - assert_initialized(a); + a := a; radix := radix; + if err = clear_if_uninitialized(a); err != .None { + return "", err; + } /* Radix defaults to 10. */ @@ -32,14 +34,13 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator */ /* - Calculate the size of the buffer we need. + Calculate the size of the buffer we need, and */ size: int; - size, err = radix_size(a, radix, zero_terminate); /* Exit if calculating the size returned an error. */ - if err != .OK { + if size, err = radix_size(a, radix, zero_terminate); err != .None { f := strings.clone(fallback(a), allocator); if zero_terminate { c := strings.clone_to_cstring(f); @@ -57,14 +58,13 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator Write the digits out into the buffer. */ written: int; - written, err = itoa_raw(a, radix, buffer, size, zero_terminate); + if written, err = itoa_raw(a, radix, buffer, size, zero_terminate); err == .None { + return string(buffer[:written]), .None; + } /* For now, delete the buffer and fall back to the below on failure. */ - if err == .OK { - return string(buffer[:written]), .OK; - } delete(buffer); fallback :: proc(a: ^Int, print_raw := false) -> string { @@ -86,8 +86,10 @@ itoa_string :: proc(a: ^Int, radix := i8(-1), zero_terminate := false, allocator This version of `itoa` allocates one behalf of the caller. The caller must free the string. */ itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) -> (res: cstring, err: Error) { - radix := radix; - assert_initialized(a); + a := a; radix := radix; + if err = clear_if_uninitialized(a); err != .None { + return "", err; + } /* Radix defaults to 10. */ @@ -119,21 +121,25 @@ itoa_cstring :: proc(a: ^Int, radix := i8(-1), allocator := context.allocator) - and having to perform a buffer overflow check each character. */ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_terminate := false) -> (written: int, err: Error) { - radix := radix; - assert_initialized(a); size := size; + a := a; radix := radix; size := size; + if err = clear_if_uninitialized(a); err != .None { + return 0, err; + } /* Radix defaults to 10. */ radix = radix if radix > 0 else 10; if radix < 2 || radix > 64 { - return 0, .Invalid_Input; + return 0, .Invalid_Argument; } /* We weren't given a size. Let's compute it. */ if size == -1 { - size, err = radix_size(a, radix, zero_terminate); + if size, err = radix_size(a, radix, zero_terminate); err != .None { + return 0, err; + } } /* @@ -146,7 +152,8 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina /* Fast path for when `Int` == 0 or the entire `Int` fits in a single radix digit. */ - if is_zero(a) || (a.used == 1 && a.digit[0] < DIGIT(radix)) { + z, _ := is_zero(a); + if z || (a.used == 1 && a.digit[0] < DIGIT(radix)) { if zero_terminate { available -= 1; buffer[available] = 0; @@ -154,12 +161,12 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina available -= 1; buffer[available] = RADIX_TABLE[a.digit[0]]; - if is_neg(a) { + if n, _ := is_neg(a); n { available -= 1; buffer[available] = '-'; } - return len(buffer) - available, .OK; + return len(buffer) - available, .None; } /* @@ -179,11 +186,11 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina val = q; } - if is_neg(a) { + if n, _ := is_neg(a); n { available -= 1; buffer[available] = '-'; } - return len(buffer) - available, .OK; + return len(buffer) - available, .None; } /* At least 3 DIGITs are in use if we made it this far. @@ -202,24 +209,23 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina // mask := _WORD(radix - 1); shift, err = log_n(DIGIT(radix), 2); count, err = count_bits(a); - // digit: _WORD; + digit: _WORD; for offset := 0; offset < count; offset += 4 { bits_to_get := int(min(count - offset, shift)); - digit, err := extract_bits(a, offset, bits_to_get); - if err != .OK { - return len(buffer) - available, .Invalid_Input; + if digit, err = extract_bits(a, offset, bits_to_get); err != .None { + return len(buffer) - available, .Invalid_Argument; } available -= 1; buffer[available] = RADIX_TABLE[digit]; } - if is_neg(a) { + if n, _ := is_neg(a); n { available -= 1; buffer[available] = '-'; } - return len(buffer) - available, .OK; + return len(buffer) - available, .None; } return -1, .Unimplemented; @@ -233,37 +239,41 @@ int_to_cstring :: itoa_cstring; We size for `string`, not `cstring`. */ radix_size :: proc(a: ^Int, radix: i8, zero_terminate := false) -> (size: int, err: Error) { + a := a; if radix < 2 || radix > 64 { - return -1, .Invalid_Input; + return -1, .Invalid_Argument; + } + if err = clear_if_uninitialized(a); err != .None { + return 0, err; } - if is_zero(a) { - if zero_terminate { - return 2, .OK; - } - return 1, .OK; - } + if z, _ := is_zero(a); z { + if zero_terminate { + return 2, .None; + } + return 1, .None; + } - /* + /* Calculate `log` on a temporary "copy" with its sign set to positive. - */ + */ t := &Int{ used = a.used, sign = .Zero_or_Positive, digit = a.digit, }; - size, err = log_n(t, DIGIT(radix)); - if err != .OK { - return; - } + if size, err = log_n(t, DIGIT(radix)); err != .None { + return 0, err; + } - /* + /* log truncates to zero, so we need to add one more, and one for `-` if negative. - */ - size += 2 if is_neg(a) else 1; - size += 1 if zero_terminate else 0; - return size, .OK; + */ + n, _ := is_neg(a); + size += 2 if n else 1; + size += 1 if zero_terminate else 0; + return size, .None; } /* |