Skip to content

Instantly share code, notes, and snippets.

@mratsim
Created April 21, 2018 11:38
Show Gist options
  • Select an option

  • Save mratsim/51d45ed0adcbd411051b64d91f869d2e to your computer and use it in GitHub Desktop.

Select an option

Save mratsim/51d45ed0adcbd411051b64d91f869d2e to your computer and use it in GitHub Desktop.
# 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