Created
April 21, 2018 11:38
-
-
Save mratsim/51d45ed0adcbd411051b64d91f869d2e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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 templates allow efficient iteration on multiprecision integers internal representation. | |
| # A template is preferred to inline iterators because inline iterator would still generate a while loop | |
| # even when the size of the array is one | |
| template asWordsRaw*(n: MpUintImpl, nw: untyped, body: untyped): untyped = | |
| ## Iterates over n, as an array of words. | |
| ## Input: | |
| ## - n: The Multiprecision int | |
| ## - nw: A word of the multi-precision int | |
| ## - body: the operation you want to do | |
| ## Iteration is done from low to high, not taking endianness in account | |
| when optim(`n`) is array: | |
| for nw{.inject.} in cast[optim(n)](n): | |
| body | |
| else: | |
| let nw{.inject.} = cast[optim(n)](n) | |
| body | |
| template asWordsRawZip*(x, y: MpUintImpl, xw, yw: untyped, body: untyped): untyped = | |
| ## Iterates over n, as an array of words. | |
| ## Input: | |
| ## - x, y: The multiprecision ints | |
| ## - xw, yw: a pair of word of the multi-precision ints | |
| ## - body: the operation you want to do | |
| ## Iteration is done from low to high, not taking endianness in account | |
| 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..<x_ptr[].len: | |
| let | |
| xw{.inject.} = x_ptr[i] | |
| yw{.inject.} = y_ptr[i] | |
| body | |
| else: | |
| let | |
| xw{.inject.} = cast[optim(x)](x) | |
| yw{.inject.} = cast[optim(y)](y) | |
| body | |
| template asWordsZip*(x, y: MpUintImpl, xw, yw: untyped, body: untyped): untyped = | |
| ## Iterates over n, as an array of words. | |
| ## Input: | |
| ## - x, y: The multiprecision ints | |
| ## - xw, yw: a pair of word of the multi-precision ints | |
| ## - body: the operation you want to do | |
| ## Iteration is done from Most significant byte to Least significant byte | |
| ## i.e. memory order for BigEndian, reverse for little endian | |
| 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..<x_ptr[].len: | |
| let | |
| xw{.inject.} = x_ptr[i] | |
| yw{.inject.} = y_ptr[i] | |
| body | |
| else: # littleEndian, the most significant bytes are on the right | |
| doAssert x_ptr[].len != 1 | |
| for i in countdown(x_ptr[].len - 1, 0): | |
| let | |
| xw{.inject.} = x_ptr[i] | |
| yw{.inject.} = y_ptr[i] | |
| body | |
| else: | |
| let | |
| xw{.inject.} = cast[optim(x)](x) | |
| yw{.inject.} = cast[optim(y)](y) | |
| body |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment