rebase and try to make it works with clients
This commit is contained in:
parent
bff69b3f98
commit
63a32129c8
14
stint.nim
14
stint.nim
|
@ -1,5 +1,5 @@
|
||||||
# Stint
|
# Stint
|
||||||
# Copyright 2018 Status Research & Development GmbH
|
# Copyright 2018-2023 Status Research & Development GmbH
|
||||||
# Licensed under either of
|
# Licensed under either of
|
||||||
#
|
#
|
||||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
@ -10,12 +10,12 @@
|
||||||
# import stint/[bitops2, endians2, intops, io, modular_arithmetic, literals_stint]
|
# import stint/[bitops2, endians2, intops, io, modular_arithmetic, literals_stint]
|
||||||
# export bitops2, endians2, intops, io, modular_arithmetic, literals_stint
|
# export bitops2, endians2, intops, io, modular_arithmetic, literals_stint
|
||||||
|
|
||||||
import stint/[io, uintops]
|
import stint/[io, uintops, intops, literals_stint, modular_arithmetic]
|
||||||
export io, uintops
|
export io, uintops, intops, literals_stint, modular_arithmetic
|
||||||
|
|
||||||
type
|
type
|
||||||
# Int128* = Stint[128]
|
Int128* = Stint[128]
|
||||||
# Int256* = Stint[256]
|
Int256* = Stint[256]
|
||||||
UInt128* = StUint[128]
|
UInt128* = StUint[128]
|
||||||
UInt256* = StUint[256]
|
UInt256* = StUint[256]
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ func u128*(s: string): UInt128 {.inline.} = s.parse(UInt128)
|
||||||
func u256*(n: SomeInteger): UInt256 {.inline.} = n.stuint(256)
|
func u256*(n: SomeInteger): UInt256 {.inline.} = n.stuint(256)
|
||||||
func u256*(s: string): UInt256 {.inline.} = s.parse(UInt256)
|
func u256*(s: string): UInt256 {.inline.} = s.parse(UInt256)
|
||||||
|
|
||||||
# func i128*(n: SomeInteger): Int128 {.inline.} = n.stint(128)
|
func i128*(n: SomeInteger): Int128 {.inline.} = n.stint(128)
|
||||||
# func i128*(s: string): Int128 {.inline.} = s.parse(Int128)
|
# func i128*(s: string): Int128 {.inline.} = s.parse(Int128)
|
||||||
|
|
||||||
# func i256*(n: SomeInteger): Int256 {.inline.} = n.stint(256)
|
func i256*(n: SomeInteger): Int256 {.inline.} = n.stint(256)
|
||||||
# func i256*(s: string): Int256 {.inline.} = s.parse(Int256)
|
# func i256*(s: string): Int256 {.inline.} = s.parse(Int256)
|
||||||
|
|
|
@ -7,10 +7,10 @@ skipDirs = @["tests", "benchmarks"]
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|
||||||
# TODO test only requirements don't work: https://github.com/nim-lang/nimble/issues/482
|
# TODO test only requirements don't work: https://github.com/nim-lang/nimble/issues/482
|
||||||
requires "nim >= 1.6.0",
|
requires "nim >= 1.6.12",
|
||||||
"stew"
|
"stew"
|
||||||
|
|
||||||
proc test(args, path: string) =
|
proc test(name: string, lang: string = "c") =
|
||||||
if not dirExists "build":
|
if not dirExists "build":
|
||||||
mkDir "build"
|
mkDir "build"
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
import private/datatypes
|
import private/datatypes
|
||||||
|
|
||||||
{.push raises: [IndexError], noInit, gcsafe.}
|
{.push raises: [IndexDefect], noInit, gcsafe.}
|
||||||
|
|
||||||
# Serialization
|
# Serialization
|
||||||
# ------------------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------------------
|
||||||
|
@ -138,7 +138,7 @@ func toBytes*[bits: static int](x: StUint[bits], endian: Endianness = bigEndian)
|
||||||
|
|
||||||
func fromBytesBE*[bits: static int](
|
func fromBytesBE*[bits: static int](
|
||||||
T: typedesc[StUint[bits]],
|
T: typedesc[StUint[bits]],
|
||||||
x: openArray[byte]): T =
|
x: openArray[byte]): T {.raises: [], noInit, gcsafe.} =
|
||||||
## Read big endian bytes and convert to an integer. At runtime, v must contain
|
## Read big endian bytes and convert to an integer. At runtime, v must contain
|
||||||
## at least sizeof(T) bytes. Native endianess is used which is not
|
## at least sizeof(T) bytes. Native endianess is used which is not
|
||||||
## portable! (i.e. use fixed-endian byte array or hex for serialization)
|
## portable! (i.e. use fixed-endian byte array or hex for serialization)
|
||||||
|
|
|
@ -7,19 +7,18 @@
|
||||||
#
|
#
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import ./private/[bitops2_priv, datatypes]
|
import ./private/[datatypes]
|
||||||
|
|
||||||
export StInt, StUint
|
export StInt
|
||||||
export IntImpl, intImpl, UintImpl, uintImpl, bitsof # TODO: remove the need to export those
|
#export IntImpl, intImpl, UintImpl, uintImpl, bitsof # TODO: remove the need to export those
|
||||||
|
|
||||||
type SomeBigInteger = StUint|StInt
|
#import ./private/initialization
|
||||||
|
|
||||||
import ./private/initialization
|
func zero*[bits: static[int]](T: typedesc[StInt[bits]]): T {.inline.} =
|
||||||
|
|
||||||
func zero*[bits: static[int]](T: typedesc[StUint[bits] or StInt[bits]]): T {.inline.} =
|
|
||||||
## Returns the zero of the input type
|
## Returns the zero of the input type
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
#[
|
||||||
func one*[bits: static[int]](T: typedesc[StUint[bits]]): T {.inline.} =
|
func one*[bits: static[int]](T: typedesc[StUint[bits]]): T {.inline.} =
|
||||||
## Returns the one of the input type
|
## Returns the one of the input type
|
||||||
result.data = one(type result.data)
|
result.data = one(type result.data)
|
||||||
|
@ -159,3 +158,4 @@ func pow*(x: StUint, y: StUint): StUint {.inline.} =
|
||||||
result.data = x.data.pow(y.data)
|
result.data = x.data.pow(y.data)
|
||||||
else:
|
else:
|
||||||
result.data = x.data ^ y.data
|
result.data = x.data ^ y.data
|
||||||
|
]#
|
132
stint/io.nim
132
stint/io.nim
|
@ -1,5 +1,5 @@
|
||||||
# Stint
|
# Stint
|
||||||
# Copyright 2018 Status Research & Development GmbH
|
# Copyright 2018-2023 Status Research & Development GmbH
|
||||||
# Licensed under either of
|
# Licensed under either of
|
||||||
#
|
#
|
||||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
@ -21,6 +21,18 @@ import
|
||||||
|
|
||||||
from stew/byteutils import toHex # Why are we exporting readHexChar in byteutils?
|
from stew/byteutils import toHex # Why are we exporting readHexChar in byteutils?
|
||||||
|
|
||||||
|
template leastSignificantWord*(a: SomeBigInteger): Word =
|
||||||
|
a.limbs[0]
|
||||||
|
|
||||||
|
template mostSignificantWord*(a: SomeBigInteger): Word =
|
||||||
|
a.limbs[^1]
|
||||||
|
|
||||||
|
template signedWordType*(_: type SomeBigInteger): type =
|
||||||
|
SignedWord
|
||||||
|
|
||||||
|
template wordType*(_: type SomeBigInteger): type =
|
||||||
|
Word
|
||||||
|
|
||||||
template static_check_size(T: typedesc[SomeInteger], bits: static[int]) =
|
template static_check_size(T: typedesc[SomeInteger], bits: static[int]) =
|
||||||
# To avoid a costly runtime check, we refuse storing into StUint types smaller
|
# To avoid a costly runtime check, we refuse storing into StUint types smaller
|
||||||
# than the input type.
|
# than the input type.
|
||||||
|
@ -62,14 +74,14 @@ func stuint*[T: SomeInteger](n: T, bits: static[int]): StUint[bits] {.inline.}=
|
||||||
func to*(a: SomeUnsignedInt, T: typedesc[StUint]): T =
|
func to*(a: SomeUnsignedInt, T: typedesc[StUint]): T =
|
||||||
stuint(a, result.bits)
|
stuint(a, result.bits)
|
||||||
|
|
||||||
func truncate*(num: StInt or StUint, T: typedesc[SomeInteger]): T {.inline.}=
|
func truncate*(num: Stint or StUint, T: typedesc[SomeInteger]): T {.inline.}=
|
||||||
## Extract the int, uint, int8-int64 or uint8-uint64 portion of a multi-precision integer.
|
## Extract the int, uint, int8-int64 or uint8-uint64 portion of a multi-precision integer.
|
||||||
## Note that int and uint are 32-bit on 32-bit platform.
|
## Note that int and uint are 32-bit on 32-bit platform.
|
||||||
## For unsigned result type, result is modulo 2^(sizeof T in bit)
|
## For unsigned result type, result is modulo 2^(sizeof T in bit)
|
||||||
## For signed result type, result is undefined if input does not fit in the target type.
|
## For signed result type, result is undefined if input does not fit in the target type.
|
||||||
result = T(num.leastSignificantWord())
|
result = T(num.leastSignificantWord())
|
||||||
|
|
||||||
func toInt*(num: StInt or StUint): int {.inline, deprecated:"Use num.truncate(int) instead".}=
|
func toInt*(num: Stint or StUint): int {.inline, deprecated:"Use num.truncate(int) instead".}=
|
||||||
num.truncate(int)
|
num.truncate(int)
|
||||||
|
|
||||||
func stuint*(a: StUint, bits: static[int]): StUint[bits] {.inline.} =
|
func stuint*(a: StUint, bits: static[int]): StUint[bits] {.inline.} =
|
||||||
|
@ -79,7 +91,7 @@ func stuint*(a: StUint, bits: static[int]): StUint[bits] {.inline.} =
|
||||||
for i in 0 ..< result.len:
|
for i in 0 ..< result.len:
|
||||||
result[i] = a[i]
|
result[i] = a[i]
|
||||||
|
|
||||||
# func stuint*(a: StInt, bits: static[int]): StUint[bits] {.inline.} =
|
# func StUint*(a: StInt, bits: static[int]): StUint[bits] {.inline.} =
|
||||||
# ## signed int to unsigned int conversion
|
# ## signed int to unsigned int conversion
|
||||||
# ## current behavior is cast-like, copying bit pattern
|
# ## current behavior is cast-like, copying bit pattern
|
||||||
# ## or truncating if input does not fit into destination
|
# ## or truncating if input does not fit into destination
|
||||||
|
@ -87,12 +99,12 @@ func stuint*(a: StUint, bits: static[int]): StUint[bits] {.inline.} =
|
||||||
# when N < bits:
|
# when N < bits:
|
||||||
# when N <= 64:
|
# when N <= 64:
|
||||||
# type T = StUint[N]
|
# type T = StUint[N]
|
||||||
# result = stuint(convert[T](a).data, bits)
|
# result = StUint(convert[T](a).data, bits)
|
||||||
# else:
|
# else:
|
||||||
# smallToBig(result.data, a.data)
|
# smallToBig(result.data, a.data)
|
||||||
# elif N > bits:
|
# elif N > bits:
|
||||||
# when bits <= 64:
|
# when bits <= 64:
|
||||||
# result = stuint(x.truncate(type(result.data)), bits)
|
# result = StUint(x.truncate(type(result.data)), bits)
|
||||||
# else:
|
# else:
|
||||||
# bigToSmall(result.data, a.data)
|
# bigToSmall(result.data, a.data)
|
||||||
# else:
|
# else:
|
||||||
|
@ -143,7 +155,7 @@ func stuint*(a: StUint, bits: static[int]): StUint[bits] {.inline.} =
|
||||||
|
|
||||||
# func stint*(a: StUint, bits: static[int]): StInt[bits] {.inline.} =
|
# func stint*(a: StUint, bits: static[int]): StInt[bits] {.inline.} =
|
||||||
# const N = bitsof(a.data)
|
# const N = bitsof(a.data)
|
||||||
# const dmax = stuint((type result).high, N)
|
# const dmax = StUint((type result).high, N)
|
||||||
# if a > dmax: raise newException(RangeError, "value out of range")
|
# if a > dmax: raise newException(RangeError, "value out of range")
|
||||||
# when N < bits:
|
# when N < bits:
|
||||||
# when N <= 64:
|
# when N <= 64:
|
||||||
|
@ -170,8 +182,6 @@ func readHexChar(c: char): int8 {.inline.}=
|
||||||
func skipPrefixes(current_idx: var int, str: string, radix: range[2..16]) {.inline.} =
|
func skipPrefixes(current_idx: var int, str: string, radix: range[2..16]) {.inline.} =
|
||||||
## Returns the index of the first meaningful char in `hexStr` by skipping
|
## Returns the index of the first meaningful char in `hexStr` by skipping
|
||||||
## "0x" prefix
|
## "0x" prefix
|
||||||
# Always called from a context where radix is known at compile-time
|
|
||||||
# and checked within 2..16 and so cannot throw a RangeDefect at runtime
|
|
||||||
|
|
||||||
if str.len < 2:
|
if str.len < 2:
|
||||||
return
|
return
|
||||||
|
@ -179,20 +189,14 @@ func skipPrefixes(current_idx: var int, str: string, radix: range[2..16]) {.inli
|
||||||
doAssert current_idx == 0, "skipPrefixes only works for prefixes (position 0 and 1 of the string)"
|
doAssert current_idx == 0, "skipPrefixes only works for prefixes (position 0 and 1 of the string)"
|
||||||
if str[0] == '0':
|
if str[0] == '0':
|
||||||
if str[1] in {'x', 'X'}:
|
if str[1] in {'x', 'X'}:
|
||||||
if radix == 16:
|
doAssert radix == 16, "Parsing mismatch, 0x prefix is only valid for a hexadecimal number (base 16)"
|
||||||
current_idx = 2
|
current_idx = 2
|
||||||
else:
|
|
||||||
raise newException(ValueError,"Parsing mismatch, 0x prefix is only valid for a hexadecimal number (base 16)")
|
|
||||||
elif str[1] in {'o', 'O'}:
|
elif str[1] in {'o', 'O'}:
|
||||||
if radix == 8:
|
doAssert radix == 8, "Parsing mismatch, 0o prefix is only valid for an octal number (base 8)"
|
||||||
current_idx = 2
|
current_idx = 2
|
||||||
else:
|
|
||||||
raise newException(ValueError, "Parsing mismatch, 0o prefix is only valid for an octal number (base 8)")
|
|
||||||
elif str[1] in {'b', 'B'}:
|
elif str[1] in {'b', 'B'}:
|
||||||
if radix == 2:
|
doAssert radix == 2, "Parsing mismatch, 0b prefix is only valid for a binary number (base 2)"
|
||||||
current_idx = 2
|
current_idx = 2
|
||||||
elif radix != 16:
|
|
||||||
raise newException(ValueError, "Parsing mismatch, 0b prefix is only valid for a binary number (base 2) or as first byte of a hexadecimal number (base 16)")
|
|
||||||
|
|
||||||
func nextNonBlank(current_idx: var int, s: string) {.inline.} =
|
func nextNonBlank(current_idx: var int, s: string) {.inline.} =
|
||||||
## Move the current index, skipping white spaces and "_" characters.
|
## Move the current index, skipping white spaces and "_" characters.
|
||||||
|
@ -203,15 +207,13 @@ func nextNonBlank(current_idx: var int, s: string) {.inline.} =
|
||||||
while current_idx < s.len and s[current_idx] in blanks:
|
while current_idx < s.len and s[current_idx] in blanks:
|
||||||
inc current_idx
|
inc current_idx
|
||||||
|
|
||||||
func readDecChar(c: char): int {.inline.}=
|
func readDecChar(c: range['0'..'9']): int {.inline.}=
|
||||||
## Converts a decimal char to an int
|
## Converts a decimal char to an int
|
||||||
# specialization without branching for base <= 10.
|
# specialization without branching for base <= 10.
|
||||||
if c notin {'0'..'9'}:
|
|
||||||
raise newException(ValueError, "Character out of '0'..'9' range")
|
|
||||||
ord(c) - ord('0')
|
ord(c) - ord('0')
|
||||||
|
|
||||||
func parse*[bits: static[int]](input: string, T: typedesc[StUint[bits]], radix: static[uint8] = 10): T =
|
func parse*[bits: static[int]](input: string, T: typedesc[StUint[bits]], radix: static[uint8] = 10): T =
|
||||||
## Parse a string and store the result in a StInt[bits] or StUint[bits].
|
## Parse a string and store the result in a Stint[bits] or StUint[bits].
|
||||||
|
|
||||||
static: doAssert (radix >= 2) and radix <= 16, "Only base from 2..16 are supported"
|
static: doAssert (radix >= 2) and radix <= 16, "Only base from 2..16 are supported"
|
||||||
# TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
|
# TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
|
||||||
|
@ -232,7 +234,7 @@ func parse*[bits: static[int]](input: string, T: typedesc[StUint[bits]], radix:
|
||||||
nextNonBlank(curr, input)
|
nextNonBlank(curr, input)
|
||||||
|
|
||||||
# func parse*[bits: static[int]](input: string, T: typedesc[Stint[bits]], radix: static[int8] = 10): T =
|
# func parse*[bits: static[int]](input: string, T: typedesc[Stint[bits]], radix: static[int8] = 10): T =
|
||||||
# ## Parse a string and store the result in a Stint[bits] or Stuint[bits].
|
# ## Parse a string and store the result in a Stint[bits] or StUint[bits].
|
||||||
|
|
||||||
# static: doAssert (radix >= 2) and radix <= 16, "Only base from 2..16 are supported"
|
# static: doAssert (radix >= 2) and radix <= 16, "Only base from 2..16 are supported"
|
||||||
# # TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
|
# # TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
|
||||||
|
@ -241,12 +243,12 @@ func parse*[bits: static[int]](input: string, T: typedesc[StUint[bits]], radix:
|
||||||
# # and be much faster
|
# # and be much faster
|
||||||
|
|
||||||
# # For conversion we require overflowing operations (for example for negative hex numbers)
|
# # For conversion we require overflowing operations (for example for negative hex numbers)
|
||||||
# const base = radix.int8.stuint(bits)
|
# const base = radix.int8.StUint(bits)
|
||||||
|
|
||||||
# var
|
# var
|
||||||
# curr = 0 # Current index in the string
|
# curr = 0 # Current index in the string
|
||||||
# isNeg = false
|
# isNeg = false
|
||||||
# no_overflow: Stuint[bits]
|
# no_overflow: StUint[bits]
|
||||||
|
|
||||||
# if input[curr] == '-':
|
# if input[curr] == '-':
|
||||||
# doAssert radix == 10, "Negative numbers are only supported with base 10 input."
|
# doAssert radix == 10, "Negative numbers are only supported with base 10 input."
|
||||||
|
@ -258,9 +260,9 @@ func parse*[bits: static[int]](input: string, T: typedesc[StUint[bits]], radix:
|
||||||
# while curr < input.len:
|
# while curr < input.len:
|
||||||
# # TODO: overflow detection
|
# # TODO: overflow detection
|
||||||
# when radix <= 10:
|
# when radix <= 10:
|
||||||
# no_overflow = no_overflow * base + input[curr].readDecChar.stuint(bits)
|
# no_overflow = no_overflow * base + input[curr].readDecChar.StUint(bits)
|
||||||
# else:
|
# else:
|
||||||
# no_overflow = no_overflow * base + input[curr].readHexChar.stuint(bits)
|
# no_overflow = no_overflow * base + input[curr].readHexChar.StUint(bits)
|
||||||
# nextNonBlank(curr, input)
|
# nextNonBlank(curr, input)
|
||||||
|
|
||||||
# # TODO: we can't create the lowest int this way
|
# # TODO: we can't create the lowest int this way
|
||||||
|
@ -269,7 +271,7 @@ func parse*[bits: static[int]](input: string, T: typedesc[StUint[bits]], radix:
|
||||||
# else:
|
# else:
|
||||||
# result = convert[T](no_overflow)
|
# result = convert[T](no_overflow)
|
||||||
|
|
||||||
func fromHex*(T: typedesc[StUint|StInt], s: string): T {.inline.} =
|
func fromHex*(T: typedesc[StUint|Stint], s: string): T {.inline.} =
|
||||||
## Convert an hex string to the corresponding unsigned integer
|
## Convert an hex string to the corresponding unsigned integer
|
||||||
parse(s, type result, radix = 16)
|
parse(s, type result, radix = 16)
|
||||||
|
|
||||||
|
@ -277,34 +279,34 @@ func hexToUint*[bits: static[int]](hexString: string): StUint[bits] {.inline.} =
|
||||||
## Convert an hex string to the corresponding unsigned integer
|
## Convert an hex string to the corresponding unsigned integer
|
||||||
parse(hexString, type result, radix = 16)
|
parse(hexString, type result, radix = 16)
|
||||||
|
|
||||||
# func toString*[bits: static[int]](num: StUint[bits], radix: static[uint8] = 10): string =
|
func toString*[bits: static[int]](num: StUint[bits], radix: static[uint8] = 10): string =
|
||||||
# ## Convert a Stint or Stuint to string.
|
## Convert a Stint or StUint to string.
|
||||||
# ## In case of negative numbers:
|
## In case of negative numbers:
|
||||||
# ## - they are prefixed with "-" for base 10.
|
## - they are prefixed with "-" for base 10.
|
||||||
# ## - if not base 10, they are returned raw in two-complement form.
|
## - if not base 10, they are returned raw in two-complement form.
|
||||||
|
|
||||||
# static: doAssert (radix >= 2) and radix <= 16, "Only base from 2..16 are supported"
|
static: doAssert (radix >= 2) and radix <= 16, "Only base from 2..16 are supported"
|
||||||
# # TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
|
# TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
|
||||||
|
|
||||||
# const hexChars = "0123456789abcdef"
|
const hexChars = "0123456789abcdef"
|
||||||
# const base = radix.uint8.stuint(bits)
|
const base = radix.uint8.stuint(bits)
|
||||||
|
|
||||||
# result = ""
|
result = ""
|
||||||
# var (q, r) = divmod(num, base)
|
var (q, r) = divmod(num, base)
|
||||||
|
|
||||||
# while true:
|
while true:
|
||||||
# when bitsof(r.data) <= 64:
|
when bits <= 64:
|
||||||
# result.add hexChars[r.data.int]
|
result.add hexChars[r.leastSignificantWord()]
|
||||||
# else:
|
else:
|
||||||
# result.add hexChars[r.truncate(int)]
|
result.add hexChars[r.truncate(int)]
|
||||||
# if q.isZero:
|
if q.isZero:
|
||||||
# break
|
break
|
||||||
# (q, r) = divmod(q, base)
|
(q, r) = divmod(q, base)
|
||||||
|
|
||||||
# reverse(result)
|
reverse(result)
|
||||||
|
|
||||||
# func toString*[bits: static[int]](num: Stint[bits], radix: static[int8] = 10): string =
|
# func toString*[bits: static[int]](num: Stint[bits], radix: static[int8] = 10): string =
|
||||||
# ## Convert a Stint or Stuint to string.
|
# ## Convert a Stint or StUint to string.
|
||||||
# ## In case of negative numbers:
|
# ## In case of negative numbers:
|
||||||
# ## - they are prefixed with "-" for base 10.
|
# ## - they are prefixed with "-" for base 10.
|
||||||
# ## - if not base 10, they are returned raw in two-complement form.
|
# ## - if not base 10, they are returned raw in two-complement form.
|
||||||
|
@ -313,11 +315,11 @@ func hexToUint*[bits: static[int]](hexString: string): StUint[bits] {.inline.} =
|
||||||
# # TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
|
# # TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
|
||||||
|
|
||||||
# const hexChars = "0123456789abcdef"
|
# const hexChars = "0123456789abcdef"
|
||||||
# const base = radix.int8.stuint(bits)
|
# const base = radix.int8.StUint(bits)
|
||||||
|
|
||||||
# result = ""
|
# result = ""
|
||||||
|
|
||||||
# type T = Stuint[bits]
|
# type T = StUint[bits]
|
||||||
# let isNeg = num.isNegative
|
# let isNeg = num.isNegative
|
||||||
# let num = convert[T](if radix == 10 and isNeg: -num
|
# let num = convert[T](if radix == 10 and isNeg: -num
|
||||||
# else: num)
|
# else: num)
|
||||||
|
@ -344,11 +346,11 @@ func hexToUint*[bits: static[int]](hexString: string): StUint[bits] {.inline.} =
|
||||||
# else:
|
# else:
|
||||||
# toString(num, 10)
|
# toString(num, 10)
|
||||||
|
|
||||||
# func toHex*[bits: static[int]](num: Stint[bits] or StUint[bits]): string {.inline.}=
|
func toHex*[bits: static[int]](num: Stint[bits] or StUint[bits]): string {.inline.}=
|
||||||
# ## Convert to a hex string.
|
## Convert to a hex string.
|
||||||
# ## Output is considered a big-endian base 16 string.
|
## Output is considered a big-endian base 16 string.
|
||||||
# ## Leading zeros are stripped. Use dumpHex instead if you need the in-memory representation
|
## Leading zeros are stripped. Use dumpHex instead if you need the in-memory representation
|
||||||
# toString(num, 16)
|
toString(num, 16)
|
||||||
|
|
||||||
func dumpHex*(a: Stint or StUint, order: static[Endianness] = bigEndian): string =
|
func dumpHex*(a: Stint or StUint, order: static[Endianness] = bigEndian): string =
|
||||||
## Stringify an int to hex.
|
## Stringify an int to hex.
|
||||||
|
@ -365,7 +367,9 @@ func dumpHex*(a: Stint or StUint, order: static[Endianness] = bigEndian): string
|
||||||
let bytes = a.toBytes(order)
|
let bytes = a.toBytes(order)
|
||||||
result = bytes.toHex()
|
result = bytes.toHex()
|
||||||
|
|
||||||
func readUintBE*[bits: static[int]](ba: openarray[byte]): Stuint[bits] {.noInit, inline.}=
|
export fromBytes, toBytes
|
||||||
|
|
||||||
|
func readUintBE*[bits: static[int]](ba: openArray[byte]): StUint[bits] {.noInit, inline.}=
|
||||||
## Convert a big-endian array of (bits div 8) Bytes to an UInt[bits] (in native host endianness)
|
## Convert a big-endian array of (bits div 8) Bytes to an UInt[bits] (in native host endianness)
|
||||||
## Input:
|
## Input:
|
||||||
## - a big-endian openArray of size (bits div 8) at least
|
## - a big-endian openArray of size (bits div 8) at least
|
||||||
|
@ -386,3 +390,11 @@ template hash*(num: StUint|StInt): Hash =
|
||||||
# `hashData` is not particularly efficient.
|
# `hashData` is not particularly efficient.
|
||||||
# Explore better hashing solutions in nim-stew.
|
# Explore better hashing solutions in nim-stew.
|
||||||
hashData(unsafeAddr num, sizeof num)
|
hashData(unsafeAddr num, sizeof num)
|
||||||
|
|
||||||
|
func fromBytesBE*(T: type StUint, ba: openArray[byte], allowPadding: static[bool] = true): T {.noInit, inline.}=
|
||||||
|
result = readUintBE[T.bits](ba)
|
||||||
|
when allowPadding:
|
||||||
|
result = result shl ((sizeof(T) - ba.len) * 8)
|
||||||
|
|
||||||
|
template initFromBytesBE*(x: var StUint, ba: openArray[byte], allowPadding: static[bool] = true) =
|
||||||
|
x = fromBytesBE(type x, ba, allowPadding)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
## This file provides syntactic sugar to work with literals
|
## This file provides syntactic sugar to work with literals
|
||||||
|
|
||||||
import ./intops, macros
|
import ./intops, ./uintops, macros
|
||||||
|
|
||||||
type Signedness = enum
|
type Signedness = enum
|
||||||
BothSigned, IntOnly, UintOnly
|
BothSigned, IntOnly, UintOnly
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#
|
#
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import ./intops, private/datatypes
|
import ./uintops, private/datatypes
|
||||||
|
|
||||||
func addmod_internal(a, b, m: StUint): StUint {.inline.}=
|
func addmod_internal(a, b, m: StUint): StUint {.inline.}=
|
||||||
## Modular addition
|
## Modular addition
|
||||||
|
|
|
@ -12,9 +12,13 @@ import
|
||||||
stew/bitops2
|
stew/bitops2
|
||||||
|
|
||||||
when sizeof(int) == 8 and not defined(Stint32):
|
when sizeof(int) == 8 and not defined(Stint32):
|
||||||
type Word* = uint64
|
type
|
||||||
|
Word* = uint64
|
||||||
|
SignedWord* = int64
|
||||||
else:
|
else:
|
||||||
type Word* = uint32
|
type
|
||||||
|
Word* = uint32
|
||||||
|
SignedWord* = int32
|
||||||
|
|
||||||
const WordBitWidth* = sizeof(Word) * 8
|
const WordBitWidth* = sizeof(Word) * 8
|
||||||
|
|
||||||
|
@ -33,10 +37,19 @@ type
|
||||||
limbs*: array[bits.wordsRequired, Word]
|
limbs*: array[bits.wordsRequired, Word]
|
||||||
# Limbs-Endianess is little-endian
|
# Limbs-Endianess is little-endian
|
||||||
|
|
||||||
StInt*[bits: static[int]] {.borrow: `.`.} = distinct StUint[bits]
|
when (NimMajor, NimMinor) < (1,9):
|
||||||
## Stack-based integer
|
type
|
||||||
## Signed
|
StInt*[bits: static[int]] = object
|
||||||
|
## Stack-based integer
|
||||||
|
## Signed
|
||||||
|
limbs*: array[bits.wordsRequired, Word]
|
||||||
|
else:
|
||||||
|
type
|
||||||
|
StInt*[bits: static[int]] {.borrow: `.`.} = distinct StUint[bits]
|
||||||
|
## Stack-based integer
|
||||||
|
## Signed
|
||||||
|
|
||||||
|
type
|
||||||
Carry* = uint8 # distinct range[0'u8 .. 1]
|
Carry* = uint8 # distinct range[0'u8 .. 1]
|
||||||
Borrow* = uint8 # distinct range[0'u8 .. 1]
|
Borrow* = uint8 # distinct range[0'u8 .. 1]
|
||||||
|
|
||||||
|
@ -136,4 +149,4 @@ func copyWords*(
|
||||||
for i in countdown(numWords-1, 0):
|
for i in countdown(numWords-1, 0):
|
||||||
a[startA+i] = b[startB+i]
|
a[startA+i] = b[startB+i]
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import
|
||||||
func bitnot*(r: var StUint, a: Stuint) =
|
func bitnot*(r: var StUint, a: Stuint) =
|
||||||
## Bitwise complement of unsigned integer a
|
## Bitwise complement of unsigned integer a
|
||||||
## i.e. flips all bits of the input
|
## i.e. flips all bits of the input
|
||||||
for i in 0 ..< r.len:
|
for i in 0 ..< r.limbs.len:
|
||||||
r[i] = not a[i]
|
r[i] = not a[i]
|
||||||
r.clearExtraBitsOverMSB()
|
r.clearExtraBitsOverMSB()
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ func leadingZeros*(a: Stuint): int =
|
||||||
# Adjust when we use only part of the word size
|
# Adjust when we use only part of the word size
|
||||||
var extraBits = WordBitWidth * a.limbs.len - a.bits
|
var extraBits = WordBitWidth * a.limbs.len - a.bits
|
||||||
|
|
||||||
for i in countdown(a.len-1, 0):
|
for i in countdown(a.limbs.len-1, 0):
|
||||||
let zeroCount = a.limbs[i].leadingZeros()
|
let zeroCount = a.limbs[i].leadingZeros()
|
||||||
if extraBits > 0:
|
if extraBits > 0:
|
||||||
result += zeroCount - min(extraBits, WordBitWidth)
|
result += zeroCount - min(extraBits, WordBitWidth)
|
||||||
|
|
|
@ -54,146 +54,6 @@ func shlAddMod_multi(a: var openArray[Word], c: Word,
|
||||||
## Does a <- a * W + c (mod M)
|
## Does a <- a * W + c (mod M)
|
||||||
## and returns q = (a * W + c ) / M
|
## and returns q = (a * W + c ) / M
|
||||||
##
|
##
|
||||||
<<<<<<< HEAD
|
|
||||||
## For now only LittleEndian is implemented
|
|
||||||
#
|
|
||||||
# Resources at the bottom of the file
|
|
||||||
|
|
||||||
const
|
|
||||||
qLen = q.limbs.len
|
|
||||||
rLen = r.limbs.len
|
|
||||||
uLen = u.limbs.len
|
|
||||||
vLen = v.limbs.len
|
|
||||||
|
|
||||||
template `[]`(a: Stuint, i: int): Word = a.limbs[i]
|
|
||||||
template `[]=`(a: Stuint, i: int, val: Word) = a.limbs[i] = val
|
|
||||||
|
|
||||||
# Find the most significant word with actual set bits
|
|
||||||
# and get the leading zero count there
|
|
||||||
var divisorLen = vLen
|
|
||||||
var clz: int
|
|
||||||
for w in mostToLeastSig(v):
|
|
||||||
if w != 0:
|
|
||||||
clz = leadingZeros(w)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
divisorLen -= 1
|
|
||||||
|
|
||||||
doAssert divisorLen != 0, "Division by zero. Abandon ship!"
|
|
||||||
|
|
||||||
# Divisor is a single word.
|
|
||||||
if divisorLen == 1:
|
|
||||||
q.copyFrom(u)
|
|
||||||
r.leastSignificantWord() = q.limbs.shortDiv(v.leastSignificantWord())
|
|
||||||
# zero all but the least significant word
|
|
||||||
var lsw = true
|
|
||||||
for w in leastToMostSig(r):
|
|
||||||
if lsw:
|
|
||||||
lsw = false
|
|
||||||
else:
|
|
||||||
w = 0
|
|
||||||
return
|
|
||||||
|
|
||||||
var un {.noInit.}: Limbs[uLen+1]
|
|
||||||
var vn {.noInit.}: Limbs[vLen] # [mswLen .. vLen] range is unused
|
|
||||||
|
|
||||||
# Normalize so that the divisor MSB is set,
|
|
||||||
# vn cannot overflow, un can overflowed by 1 word at most, hence uLen+1
|
|
||||||
un.shlSmallOverflowing(u.limbs, clz)
|
|
||||||
vn.shlSmall(v.limbs, clz)
|
|
||||||
|
|
||||||
static: doAssert cpuEndian == littleEndian, "Currently the division algorithm requires little endian ordering of the limbs"
|
|
||||||
# TODO: is it worth it to have the uint be the exact same extended precision representation
|
|
||||||
# as a wide int (say uint128 or uint256)?
|
|
||||||
# in big-endian, the following loop must go the other way and the -1 must be +1
|
|
||||||
|
|
||||||
let vhi = vn[divisorLen-1]
|
|
||||||
let vlo = vn[divisorLen-2]
|
|
||||||
|
|
||||||
for j in countdown(uLen - divisorLen, 0, 1):
|
|
||||||
# Compute qhat estimate of q[j] (off by 0, 1 and rarely 2)
|
|
||||||
var qhat, rhat: Word
|
|
||||||
let uhi = un[j+divisorLen]
|
|
||||||
let ulo = un[j+divisorLen-1]
|
|
||||||
div2n1n(qhat, rhat, uhi, ulo, vhi)
|
|
||||||
var mhi, mlo: Word
|
|
||||||
var rhi, rlo: Word
|
|
||||||
mul(mhi, mlo, qhat, vlo)
|
|
||||||
rhi = rhat
|
|
||||||
rlo = ulo
|
|
||||||
|
|
||||||
# if r < m, adjust approximation, up to twice
|
|
||||||
while rhi < mhi or (rhi == mhi and rlo < mlo):
|
|
||||||
qhat -= 1
|
|
||||||
rhi += vhi
|
|
||||||
|
|
||||||
# Found the quotient
|
|
||||||
q[j] = qhat
|
|
||||||
|
|
||||||
# un -= qhat * v
|
|
||||||
var borrow = Borrow(0)
|
|
||||||
var qvhi, qvlo: Word
|
|
||||||
for i in 0 ..< divisorLen-1:
|
|
||||||
mul(qvhi, qvlo, qhat, v[i])
|
|
||||||
subB(borrow, un[j+i], un[j+i], qvlo, borrow)
|
|
||||||
subB(borrow, un[j+i+1], un[j+i+1], qvhi, borrow)
|
|
||||||
# Last step
|
|
||||||
mul(qvhi, qvlo, qhat, v[divisorLen-1])
|
|
||||||
subB(borrow, un[j+divisorLen-1], un[j+divisorLen-1], qvlo, borrow)
|
|
||||||
qvhi += Word(borrow)
|
|
||||||
let isNeg = un[j+divisorLen] < qvhi
|
|
||||||
un[j+divisorLen] -= qvhi
|
|
||||||
|
|
||||||
if isNeg:
|
|
||||||
# oops, too big by one, add back
|
|
||||||
q[j] -= 1
|
|
||||||
var carry = Carry(0)
|
|
||||||
for i in 0 ..< divisorLen:
|
|
||||||
addC(carry, un[j+i], un[j+i], v[i], carry)
|
|
||||||
|
|
||||||
# Quotient is found, if remainder is needed we need to un-normalize un
|
|
||||||
if needRemainder:
|
|
||||||
# r.limbs.shrSmall(un, clz) - TODO
|
|
||||||
when cpuEndian == littleEndian:
|
|
||||||
# rLen+1 == un.len
|
|
||||||
for i in 0 ..< rLen:
|
|
||||||
r[i] = (un[i] shr clz) or (un[i+1] shl (WordBitWidth - clz))
|
|
||||||
else:
|
|
||||||
{.error: "Not Implemented for bigEndian".}
|
|
||||||
|
|
||||||
|
|
||||||
const BinaryShiftThreshold = 8 # If the difference in bit-length is below 8
|
|
||||||
# binary shift is probably faster
|
|
||||||
|
|
||||||
func divmod(q, r: var Stuint,
|
|
||||||
x, y: Stuint, needRemainder: bool) =
|
|
||||||
|
|
||||||
let x_clz = x.leadingZeros()
|
|
||||||
let y_clz = y.leadingZeros()
|
|
||||||
|
|
||||||
# We short-circuit division depending on special-cases.
|
|
||||||
if unlikely(y.isZero()):
|
|
||||||
raise newException(DivByZeroError, "You attempted to divide by zero")
|
|
||||||
elif y_clz == (y.bits - 1):
|
|
||||||
# y is one
|
|
||||||
q = x
|
|
||||||
# elif (x.hi or y.hi).isZero:
|
|
||||||
# # If computing just on the low part is enough
|
|
||||||
# (result.quot.lo, result.rem.lo) = divmod(x.lo, y.lo, needRemainder)
|
|
||||||
# elif (y and (y - one(type y))).isZero:
|
|
||||||
# # y is a power of 2. (this also matches 0 but it was eliminated earlier)
|
|
||||||
# # TODO. Would it be faster to use countTrailingZero (ctz) + clz == size(y) - 1?
|
|
||||||
# # Especially because we shift by ctz after.
|
|
||||||
# let y_ctz = bitsof(y) - y_clz - 1
|
|
||||||
# result.quot = x shr y_ctz
|
|
||||||
# if needRemainder:
|
|
||||||
# result.rem = x and (y - one(type y))
|
|
||||||
elif x == y:
|
|
||||||
q.setOne()
|
|
||||||
elif x < y:
|
|
||||||
r = x
|
|
||||||
# elif (y_clz - x_clz) < BinaryShiftThreshold:
|
|
||||||
# binaryShiftDiv(x, y, result.quot, result.rem)
|
|
||||||
## The modulus `M` most-significant bit at `mBits` MUST be set.
|
## The modulus `M` most-significant bit at `mBits` MUST be set.
|
||||||
|
|
||||||
# Assuming 64-bit words
|
# Assuming 64-bit words
|
||||||
|
@ -369,7 +229,7 @@ func divRem*(
|
||||||
# - An Efficient Multiple-Precision Division Algorithm,
|
# - An Efficient Multiple-Precision Division Algorithm,
|
||||||
# Liusheng Huang, Hong Zhong, Hong Shen, Yonglong Luo, 2005
|
# Liusheng Huang, Hong Zhong, Hong Shen, Yonglong Luo, 2005
|
||||||
# https://ieeexplore.ieee.org/document/1579076
|
# https://ieeexplore.ieee.org/document/1579076
|
||||||
#
|
#
|
||||||
# - Efficient multiple-precision integer division algorithm
|
# - Efficient multiple-precision integer division algorithm
|
||||||
# Debapriyay Mukhopadhyaya, Subhas C.Nandy, 2014
|
# Debapriyay Mukhopadhyaya, Subhas C.Nandy, 2014
|
||||||
# https://www.sciencedirect.com/science/article/abs/pii/S0020019013002627
|
# https://www.sciencedirect.com/science/article/abs/pii/S0020019013002627
|
||||||
|
|
|
@ -46,7 +46,7 @@ func one*[bits: static[int]](T: typedesc[Stuint[bits]]): T {.inline.} =
|
||||||
result.setOne()
|
result.setOne()
|
||||||
|
|
||||||
func high*[bits](_: typedesc[Stuint[bits]]): Stuint[bits] {.inline.} =
|
func high*[bits](_: typedesc[Stuint[bits]]): Stuint[bits] {.inline.} =
|
||||||
for i in 0 ..< result.len:
|
for i in 0 ..< result.limbs.len:
|
||||||
result[i] = high(Word)
|
result[i] = high(Word)
|
||||||
|
|
||||||
func low*[bits](_: typedesc[Stuint[bits]]): Stuint[bits] {.inline.} =
|
func low*[bits](_: typedesc[Stuint[bits]]): Stuint[bits] {.inline.} =
|
||||||
|
|
Loading…
Reference in New Issue