diff --git a/src/private/as_words.nim b/src/private/as_words.nim new file mode 100644 index 0000000..16ba777 --- /dev/null +++ b/src/private/as_words.nim @@ -0,0 +1,107 @@ +# Mpint +# Copyright 2018 Status Research & Development GmbH +# Licensed under either of +# +# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +# +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +import ./uint_type, macros + +macro optim(x: typed): untyped = + let size = getSize(x) + + if size > 64: + result = quote do: + array[`size` div 64, uint64] + elif size == 64: + result = quote do: + uint64 + elif size == 32: + result = quote do: + uint32 + elif size == 16: + result = quote do: + uint16 + elif size == 8: + result = quote do: + uint8 + else: + error "Unreachable path reached" + +# The following iterators allow efficient iteration on multiprecision integers internal representation. +# Note: in case the size in one, hopefully the compiler optimizes it. +# using a template is not more efficient due to having to allocate the injection variable. +# This can be rewritten using macros though +# +# template asWordsRawZip*(x, y: MpUintImpl, xw, yw: untyped, body: untyped): untyped = +# when optim(x) is array: +# let +# x_ptr = cast[ptr optim(x)](x.unsafeaddr) +# y_ptr = cast[ptr optim(y)](y.unsafeaddr) + +# for i in 0.. 64: - result = quote do: - array[`size` div 64, uint64] - elif size == 64: - result = quote do: - uint64 - elif size == 32: - result = quote do: - uint32 - elif size == 16: - result = quote do: - uint16 - elif size == 8: - result = quote do: - uint8 - else: - error "Unreachable path reached" +import ./uint_type, ./as_words func isZero*(n: SomeUnsignedInt): bool {.inline.} = n == 0 func isZero*(n: MpUintImpl): bool {.inline.} = + for val in asWordsRaw(n): + if val != 0: + return false + return true - when optim(`n`) is array: - for val in cast[optim(n)](n): - if val != 0: - return false - return true - else: - cast[optim(n)](n) == 0 +func `<`*(x, y: MpUintImpl): bool {.inline.}= + # Lower comparison for multi-precision integers + for xw, yw in asWordsZip(x, y): + if xw != yw: + return xw < yw + return false # they're equal -func `<`*(x, y: MpUintImpl): bool {.noInit, inline.}= - - when optim(x) is array: - let - x_ptr = cast[ptr optim(x)](x.unsafeaddr) - y_ptr = cast[ptr optim(y)](y.unsafeaddr) - - when system.cpuEndian == bigEndian: - for i in 0..