From d9efa6c8b5cbaaf04c6468f465a6b402b4dc8e82 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 21 Jul 2021 09:06:28 +0200 Subject: [PATCH] big: More ZII refactoring. --- core/math/big/basic.odin | 46 +++++++++++++++++++++++++----------- core/math/big/example.odin | 4 ++-- core/math/big/helpers.odin | 48 ++++++++++++++++++++++++++------------ core/math/big/log.odin | 27 ++++++++++++--------- core/math/big/radix.odin | 5 ++-- 5 files changed, 87 insertions(+), 43 deletions(-) diff --git a/core/math/big/basic.odin b/core/math/big/basic.odin index 43f5a3715..8a50543ca 100644 --- a/core/math/big/basic.odin +++ b/core/math/big/basic.odin @@ -25,7 +25,11 @@ import "core:intrinsics" */ int_add :: proc(dest, a, b: ^Int) -> (err: Error) { dest := dest; x := a; y := b; - assert_initialized(dest); assert_initialized(a); assert_initialized(b); + if dest == nil || a == nil || b == nil { + return .Nil_Pointer_Passed; + } else if !is_initialized(a) || !is_initialized(b) { + return .Int_Not_Initialized; + } /* Handle both negative or both positive. @@ -56,8 +60,11 @@ int_add :: proc(dest, a, b: ^Int) -> (err: Error) { */ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) { dest := dest; digit := digit; - assert_initialized(dest); assert_initialized(a); - + if dest == nil || a == nil { + return .Nil_Pointer_Passed; + } else if !is_initialized(a) { + return .Int_Not_Initialized; + } /* Fast paths for destination and input Int being the same. */ @@ -81,8 +88,7 @@ int_add_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) { /* Grow destination as required. */ - err = grow(dest, a.used + 1); - if err != .OK { + if err = grow(dest, a.used + 1); err != .OK { return err; } @@ -170,7 +176,11 @@ 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; - assert_initialized(number); assert_initialized(decrease); assert_initialized(dest); + if dest == nil || number == nil || decrease == nil { + return .Nil_Pointer_Passed; + } else if !(is_initialized(number) && is_initialized(decrease)) { + return .Int_Not_Initialized; + } if x.sign != y.sign { /* @@ -210,7 +220,11 @@ int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) { */ int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error) { dest := dest; digit := digit; - assert_initialized(dest); assert_initialized(a); + if dest == nil || a == nil { + return .Nil_Pointer_Passed; + } else if !is_initialized(a) { + return .Int_Not_Initialized; + } /* Fast paths for destination and input Int being the same. @@ -306,7 +320,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; - assert_initialized(a); assert_initialized(b); assert_initialized(dest); + if dest == nil || a == nil || b == nil { + return .Nil_Pointer_Passed; + } else if !is_initialized(a) || !is_initialized(b) { + return .Int_Not_Initialized; + } old_used, min_used, max_used, i: int; @@ -318,8 +336,7 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) { max_used = y.used; old_used = dest.used; - err = grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)); - if err != .OK { + if err = grow(dest, max(max_used + 1, _DEFAULT_DIGIT_COUNT)); err != .OK { return err; } dest.used = max_used + 1; @@ -387,15 +404,18 @@ _int_add :: proc(dest, a, b: ^Int) -> (err: Error) { */ _int_sub :: proc(dest, number, decrease: ^Int) -> (err: Error) { dest := dest; x := number; y := decrease; - assert_initialized(number); assert_initialized(decrease); assert_initialized(dest); + if dest == nil || number == nil || decrease == nil { + return .Nil_Pointer_Passed; + } else if !is_initialized(number) || !is_initialized(decrease) { + return .Int_Not_Initialized; + } old_used := dest.used; min_used := y.used; max_used := x.used; i: int; - err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)); - if err != .OK { + if err = grow(dest, max(max_used, _DEFAULT_DIGIT_COUNT)); err != .OK { return err; } dest.used = max_used; diff --git a/core/math/big/example.odin b/core/math/big/example.odin index 9cb99b3e7..616cbc553 100644 --- a/core/math/big/example.odin +++ b/core/math/big/example.odin @@ -44,9 +44,9 @@ _SQR_TOOM_CUTOFF, print :: proc(name: string, a: ^Int, base := i8(16)) { as, err := itoa(a, base); defer delete(as); - if err == .OK { - fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, count_bits(a), as); + cb, _ := count_bits(a); + fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, cb, as); } else { fmt.printf("%v (error: %v): %v\n", name, err, a); } diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index a590967d8..5a2ea8962 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -328,7 +328,12 @@ minus_one :: proc { int_minus_one, }; power_of_two :: proc(a: ^Int, power: int) -> (err: Error) { - assert_initialized(a); + /* + Check that `a` is usable. + */ + if a == nil { + return .Nil_Pointer_Passed; + } if power < 0 || power > _MAX_BIT_COUNT { return .Invalid_Input; @@ -356,13 +361,17 @@ power_of_two :: proc(a: ^Int, power: int) -> (err: Error) { /* Count bits in an `Int`. */ -count_bits :: proc(a: ^Int) -> (count: int) { - assert_initialized(a); +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; + } /* Fast path for zero. */ if is_zero(a) { - return 0; + return 0, .OK; } /* Get the number of DIGITs and use it. @@ -384,7 +393,12 @@ assert_initialized :: proc(a: ^Int, loc := #caller_location) { } _zero_unused :: proc(a: ^Int) { - assert_initialized(a); + if a == nil { + return; + } else if !is_initialized(a) { + return; + } + if a.used < len(a.digit) { mem.zero_slice(a.digit[a.used:]); } @@ -397,15 +411,18 @@ _grow_if_uninitialized :: proc(dest: ^Int, minimize := false) -> (err: Error) { return .OK; } -clamp :: proc(a: ^Int) { - assert_initialized(a); - /* - Trim unused digits - This is used to ensure that leading zero digits are - trimmed and the leading "used" digit will be non-zero. - Typically very fast. Also fixes the sign if there - are no more leading digits. - */ +/* + Trim unused digits. + + This is used to ensure that leading zero digits are trimmed and the leading "used" digit will be non-zero. + 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; + } for a.used > 0 && a.digit[a.used - 1] == 0 { a.used -= 1; @@ -414,5 +431,6 @@ clamp :: proc(a: ^Int) { if is_zero(a) { a.sign = .Zero_or_Positive; } -} + return .OK; +} \ No newline at end of file diff --git a/core/math/big/log.odin b/core/math/big/log.odin index 1ce2437bf..9c4fc3a2a 100644 --- a/core/math/big/log.odin +++ b/core/math/big/log.odin @@ -10,7 +10,11 @@ package big */ log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) { - assert_initialized(a); + if a == nil { + return 0, .Nil_Pointer_Passed; + } 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; } @@ -19,14 +23,14 @@ log_n_int :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) { Fast path for bases that are a power of two. */ if is_power_of_two(int(base)) { - return _log_power_of_two(a, base), .OK; + return _log_power_of_two(a, base); } /* Fast path for `Int`s that fit within a single `DIGIT`. */ if a.used == 1 { - return log_n_digit(a.digit[0], DIGIT(base)), .OK; + return log_n_digit(a.digit[0], DIGIT(base)); } // if (MP_HAS(S_MP_LOG)) { @@ -42,14 +46,15 @@ log_n :: proc{log_n_int, log_n_digit}; Returns the log2 of an `Int`, provided `base` is a power of two. Don't call it if it isn't. */ -_log_power_of_two :: proc(a: ^Int, base: DIGIT) -> (log: int) { +_log_power_of_two :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error) { base := base; y: int; for y = 0; base & 1 == 0; { y += 1; base >>= 1; } - return (count_bits(a) - 1) / y; + log, err = count_bits(a); + return (log - 1) / y, err; } /* @@ -69,20 +74,20 @@ small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD) { return result; } -log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int) { +log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error) { /* If the number is smaller than the base, it fits within a fraction. Therefore, we return 0. */ if a < base { - return 0; + return 0, .OK; } /* If a number equals the base, the log is 1. */ if a == base { - return 1; + return 1, .OK; } N := _WORD(a); @@ -111,13 +116,13 @@ log_n_digit :: proc(a: DIGIT, base: DIGIT) -> (log: int) { bracket_low = bracket_mid; } if N == bracket_mid { - return mid; + return mid, .OK; } } if bracket_high == N { - return high; + return high, .OK; } else { - return low; + return low, .OK; } } \ No newline at end of file diff --git a/core/math/big/radix.odin b/core/math/big/radix.odin index 228104ff7..0dd07672c 100644 --- a/core/math/big/radix.odin +++ b/core/math/big/radix.odin @@ -198,9 +198,10 @@ itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size := int(-1), zero_termina buffer[available] = 0; } + shift, count: int; // mask := _WORD(radix - 1); - shift := int(log_n(DIGIT(radix), 2)); - count := int(count_bits(a)); + shift, err = log_n(DIGIT(radix), 2); + count, err = count_bits(a); // digit: _WORD; for offset := 0; offset < count; offset += 4 {