2018-04-30 11:38:55 +00:00
# Stint
# 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.
2018-05-06 20:29:08 +00:00
2018-04-30 11:38:55 +00:00
import
. / private / datatypes ,
. / private / int_negabs ,
2019-10-09 01:51:53 +00:00
. / private / compiletime_helpers ,
2019-07-22 07:53:58 +00:00
. / intops ,
2019-12-18 13:02:16 +00:00
typetraits , algorithm , hashes
2018-04-30 11:38:55 +00:00
template static_check_size ( T : typedesc [ SomeInteger ] , bits : static [ int ] ) =
# To avoid a costly runtime check, we refuse storing into StUint types smaller
# than the input type.
2019-03-14 02:43:51 +00:00
static : doAssert sizeof ( T ) * 8 < = bits , " Input type ( " & $ T &
2018-04-30 11:38:55 +00:00
" ) cannot be stored in a multi-precision " &
$ bits & " -bit integer. " &
" \n Use a smaller input type instead. This is a compile-time check " &
" to avoid a costly run-time bit_length check at each StUint initialization. "
2018-10-25 10:58:40 +00:00
func assignLo ( result : var ( UintImpl | IntImpl ) , n : SomeInteger ) {. inline . } =
when result . lo is UintImpl :
assignLo ( result . lo , n )
else :
result . lo = ( type result . lo ) ( n )
2018-06-16 16:54:40 +00:00
2018-04-30 11:38:55 +00:00
func stuint * [ T : SomeInteger ] ( n : T , bits : static [ int ] ) : StUint [ bits ] {. inline . } =
2018-06-16 16:54:40 +00:00
## Converts an integer to an arbitrary precision integer.
2019-03-14 02:43:51 +00:00
doAssert n > = 0 . T
2018-04-30 11:38:55 +00:00
when result . data is UintImpl :
static_check_size ( T , bits )
2018-10-25 10:58:40 +00:00
assignLo ( result . data , n )
2018-04-30 11:38:55 +00:00
else :
result . data = ( type result . data ) ( n )
func stint * [ T : SomeInteger ] ( n : T , bits : static [ int ] ) : StInt [ bits ] {. inline . } =
2018-06-16 16:54:40 +00:00
## Converts an integer to an arbitrary precision signed integer.
2018-04-30 11:38:55 +00:00
when result . data is IntImpl :
static_check_size ( T , bits )
2018-06-27 10:18:48 +00:00
when T is SomeSignedInt :
if n < 0 :
2019-10-16 11:37:02 +00:00
# TODO: when bits >= 128, cannot create from
# low(int8-64)
# see: status-im/nim-stint/issues/92
2018-10-25 10:58:40 +00:00
assignLo ( result . data , - n )
2018-06-27 10:18:48 +00:00
result = - result
else :
2018-10-25 10:58:40 +00:00
assignLo ( result . data , n )
2018-04-30 11:38:55 +00:00
else :
2018-10-25 10:58:40 +00:00
assignLo ( result . data , n )
2018-04-30 11:38:55 +00:00
else :
result . data = ( type result . data ) ( n )
2022-02-24 19:09:53 +00:00
func to * ( x : SomeInteger , T : typedesc [ StInt ] ) : T =
2018-06-27 10:18:48 +00:00
stint ( x , result . bits )
func to * ( x : SomeUnsignedInt , T : typedesc [ StUint ] ) : T =
stuint ( x , result . bits )
2022-02-24 19:09:53 +00:00
func truncate * ( num : StInt or StUint , T : typedesc [ SomeInteger ] ) : T {. inline . } =
2019-10-08 13:11:08 +00:00
## Extract the int, uint, int8-int64 or uint8-uint64 portion of a multi-precision integer.
2018-10-08 19:04:00 +00:00
## 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 signed result type, result is undefined if input does not fit in the target type.
2019-10-08 13:11:08 +00:00
static :
doAssert bitsof ( T ) < = bitsof ( num . data . leastSignificantWord )
when nimvm :
let data = num . data . leastSignificantWord
2019-10-16 11:37:02 +00:00
vmIntCast [ T ] ( data )
2019-10-08 13:11:08 +00:00
else :
cast [ T ] ( num . data . leastSignificantWord )
2018-10-08 19:04:00 +00:00
2022-02-24 19:09:53 +00:00
func toInt * ( num : StInt or StUint ) : int {. inline , deprecated : " Use num.truncate(int) instead " . } =
2018-10-08 19:04:00 +00:00
num . truncate ( int )
2018-10-06 09:28:15 +00:00
2019-12-10 08:57:19 +00:00
func bigToSmall ( result : var ( UintImpl | IntImpl ) , x : auto ) {. inline . } =
when bitsof ( x ) = = bitsof ( result ) :
when type ( result ) is type ( x ) :
result = x
else :
result = convert [ type ( result ) ] ( x )
else :
bigToSmall ( result , x . lo )
func smallToBig ( result : var ( UintImpl | IntImpl ) , x : auto ) {. inline . } =
when bitsof ( x ) = = bitsof ( result ) :
when type ( result ) is type ( x ) :
result = x
else :
result = convert [ type ( result ) ] ( x )
else :
smallToBig ( result . lo , x )
func stuint * ( x : StUint , bits : static [ int ] ) : StUint [ bits ] {. inline . } =
## unsigned int to unsigned int conversion
## smaller to bigger bits conversion will have the same value
## bigger to smaller bits conversion, the result is truncated
const N = bitsof ( x . data )
when N < bits :
when N < = 64 :
result = stuint ( x . data , bits )
else :
smallToBig ( result . data , x . data )
elif N > bits :
when bits < = 64 :
result = stuint ( x . truncate ( type ( result . data ) ) , bits )
else :
bigToSmall ( result . data , x . data )
else :
result = x
func stuint * ( x : StInt , bits : static [ int ] ) : StUint [ bits ] {. inline . } =
## signed int to unsigned int conversion
## current behavior is cast-like, copying bit pattern
## or truncating if input does not fit into destination
const N = bitsof ( x . data )
when N < bits :
when N < = 64 :
type T = StUint [ N ]
result = stuint ( convert [ T ] ( x ) . data , bits )
else :
smallToBig ( result . data , x . data )
elif N > bits :
when bits < = 64 :
result = stuint ( x . truncate ( type ( result . data ) ) , bits )
else :
bigToSmall ( result . data , x . data )
else :
result = convert [ type ( result ) ] ( x )
func stint * ( x : StInt , bits : static [ int ] ) : StInt [ bits ] {. inline . } =
## signed int to signed int conversion
## will raise exception if input does not fit into destination
const N = bitsof ( x . data )
when N < bits :
when N < = 64 :
result = stint ( x . data , bits )
else :
if x . isNegative :
smallToBig ( result . data , ( - x ) . data )
result = - result
else :
smallToBig ( result . data , x . data )
elif N > bits :
2019-12-12 03:52:57 +00:00
template checkNegativeRange ( ) =
# due to bug #92, we skip negative range check
when false :
const dmin = stint ( ( type result ) . low , N )
2021-10-08 08:08:56 +00:00
if x < dmin : raise newException ( ValueError , " value out of range " )
2019-12-12 03:52:57 +00:00
2019-12-10 08:57:19 +00:00
template checkPositiveRange ( ) =
2019-12-12 03:52:57 +00:00
const dmax = stint ( ( type result ) . high , N )
2021-10-08 08:08:56 +00:00
if x > dmax : raise newException ( ValueError , " value out of range " )
2019-12-12 03:52:57 +00:00
2019-12-10 08:57:19 +00:00
when bits < = 64 :
if x . isNegative :
2019-12-12 03:52:57 +00:00
checkNegativeRange ( )
2019-12-10 08:57:19 +00:00
result = stint ( ( - x ) . truncate ( type ( result . data ) ) , bits )
result = - result
else :
checkPositiveRange ( )
result = stint ( x . truncate ( type ( result . data ) ) , bits )
else :
if x . isNegative :
2019-12-12 03:52:57 +00:00
checkNegativeRange ( )
2019-12-10 08:57:19 +00:00
bigToSmall ( result . data , ( - x ) . data )
result = - result
else :
checkPositiveRange ( )
bigToSmall ( result . data , x . data )
else :
result = x
func stint * ( x : StUint , bits : static [ int ] ) : StInt [ bits ] {. inline . } =
const N = bitsof ( x . data )
const dmax = stuint ( ( type result ) . high , N )
2021-10-08 08:08:56 +00:00
if x > dmax : raise newException ( ValueError , " value out of range " )
2019-12-10 08:57:19 +00:00
when N < bits :
when N < = 64 :
result = stint ( x . data , bits )
else :
smallToBig ( result . data , x . data )
elif N > bits :
when bits < = 64 :
result = stint ( x . truncate ( type ( result . data ) ) , bits )
else :
bigToSmall ( result . data , x . data )
else :
result = convert [ type ( result ) ] ( x )
2018-04-30 11:38:55 +00:00
func readHexChar ( c : char ) : int8 {. inline . } =
## Converts an hex char to an int
case c
of ' 0 ' .. ' 9 ' : result = int8 ord ( c ) - ord ( ' 0 ' )
of ' a ' .. ' f ' : result = int8 ord ( c ) - ord ( ' a ' ) + 10
of ' A ' .. ' F ' : result = int8 ord ( c ) - ord ( ' A ' ) + 10
else :
raise newException ( ValueError , $ c & " is not a hexadecimal character " )
2018-10-08 18:17:39 +00:00
func skipPrefixes ( current_idx : var int , str : string , radix : range [ 2 .. 16 ] ) {. inline . } =
2018-04-30 11:38:55 +00:00
## Returns the index of the first meaningful char in `hexStr` by skipping
## "0x" prefix
2021-10-08 08:08:56 +00:00
# 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
2018-04-30 11:38:55 +00:00
2018-08-05 21:47:05 +00:00
if str . len < 2 :
return
2019-03-14 02:43:51 +00:00
doAssert current_idx = = 0 , " skipPrefixes only works for prefixes (position 0 and 1 of the string) "
2018-04-30 11:38:55 +00:00
if str [ 0 ] = = ' 0 ' :
if str [ 1 ] in { ' x ' , ' X ' } :
2022-10-03 10:15:45 +00:00
if radix = = 16 :
current_idx = 2
else :
2021-10-06 16:53:52 +00:00
raise newException ( ValueError , " Parsing mismatch, 0x prefix is only valid for a hexadecimal number (base 16) " )
2018-04-30 11:38:55 +00:00
elif str [ 1 ] in { ' o ' , ' O ' } :
2022-10-03 10:15:45 +00:00
if radix = = 8 :
current_idx = 2
else :
2021-10-06 16:53:52 +00:00
raise newException ( ValueError , " Parsing mismatch, 0o prefix is only valid for an octal number (base 8) " )
2018-04-30 11:38:55 +00:00
elif str [ 1 ] in { ' b ' , ' B ' } :
2022-10-03 10:15:45 +00:00
if radix = = 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) " )
2018-04-30 11:38:55 +00:00
func nextNonBlank ( current_idx : var int , s : string ) {. inline . } =
## Move the current index, skipping white spaces and "_" characters.
const blanks = { ' ' , ' _ ' }
inc current_idx
2018-05-02 15:24:17 +00:00
while current_idx < s . len and s [ current_idx ] in blanks :
2018-04-30 11:38:55 +00:00
inc current_idx
2021-10-08 08:08:56 +00:00
func readDecChar ( c : char ) : int {. inline . } =
2018-04-30 11:38:55 +00:00
## Converts a decimal char to an int
# specialization without branching for base <= 10.
2021-10-08 08:08:56 +00:00
if c notin { ' 0 ' .. ' 9 ' } :
raise newException ( ValueError , " Character out of ' 0 ' .. ' 9 ' range " )
2018-04-30 11:38:55 +00:00
ord ( c ) - ord ( ' 0 ' )
2022-02-24 19:09:53 +00:00
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].
2018-04-30 11:38:55 +00:00
2019-03-14 02:43:51 +00:00
static : doAssert ( radix > = 2 ) and radix < = 16 , " Only base from 2..16 are supported "
2018-04-30 11:38:55 +00:00
# TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
# TODO: we can special case hex result/input as an array of bytes
# and be much faster
2018-10-08 18:17:39 +00:00
const base = radix . uint8 . stuint ( bits )
2018-04-30 11:38:55 +00:00
var curr = 0 # Current index in the string
2018-10-08 18:17:39 +00:00
skipPrefixes ( curr , input , radix )
2018-04-30 11:38:55 +00:00
while curr < input . len :
# TODO: overflow detection
2018-10-08 18:17:39 +00:00
when radix < = 10 :
result = result * base + input [ curr ] . readDecChar . stuint ( bits )
2018-04-30 11:38:55 +00:00
else :
2018-10-08 18:17:39 +00:00
result = result * base + input [ curr ] . readHexChar . stuint ( bits )
2018-04-30 11:38:55 +00:00
nextNonBlank ( curr , input )
2022-02-24 19:09:53 +00:00
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].
2018-04-30 11:38:55 +00:00
2019-03-14 02:43:51 +00:00
static : doAssert ( radix > = 2 ) and radix < = 16 , " Only base from 2..16 are supported "
2018-04-30 11:38:55 +00:00
# TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
# TODO: we can special case hex result/input as an array of bytes
# and be much faster
# For conversion we require overflowing operations (for example for negative hex numbers)
2018-10-08 18:17:39 +00:00
const base = radix . int8 . stuint ( bits )
2018-04-30 11:38:55 +00:00
var
curr = 0 # Current index in the string
isNeg = false
2022-02-24 19:09:53 +00:00
no_overflow : StUint [ bits ]
2018-04-30 11:38:55 +00:00
if input [ curr ] = = ' - ' :
2019-03-14 02:43:51 +00:00
doAssert radix = = 10 , " Negative numbers are only supported with base 10 input. "
2018-04-30 11:38:55 +00:00
isNeg = true
inc curr
else :
2018-10-08 18:17:39 +00:00
skipPrefixes ( curr , input , radix )
2018-04-30 11:38:55 +00:00
while curr < input . len :
# TODO: overflow detection
2018-10-08 18:17:39 +00:00
when radix < = 10 :
no_overflow = no_overflow * base + input [ curr ] . readDecChar . stuint ( bits )
2018-04-30 11:38:55 +00:00
else :
2018-10-08 18:17:39 +00:00
no_overflow = no_overflow * base + input [ curr ] . readHexChar . stuint ( bits )
2018-04-30 11:38:55 +00:00
nextNonBlank ( curr , input )
# TODO: we can't create the lowest int this way
if isNeg :
2019-10-16 11:37:02 +00:00
result = - convert [ T ] ( no_overflow )
2018-04-30 11:38:55 +00:00
else :
2019-10-16 11:37:02 +00:00
result = convert [ T ] ( no_overflow )
2018-04-30 11:38:55 +00:00
2022-02-24 19:09:53 +00:00
func fromHex * ( T : typedesc [ StUint | StInt ] , s : string ) : T {. inline . } =
2018-07-04 15:35:16 +00:00
## Convert an hex string to the corresponding unsigned integer
2018-10-08 18:17:39 +00:00
parse ( s , type result , radix = 16 )
2018-07-04 15:35:16 +00:00
2022-02-24 19:09:53 +00:00
func hexToUint * [ bits : static [ int ] ] ( hexString : string ) : StUint [ bits ] {. inline . } =
2018-05-08 11:21:04 +00:00
## Convert an hex string to the corresponding unsigned integer
2018-10-08 18:17:39 +00:00
parse ( hexString , type result , radix = 16 )
2018-04-30 11:38:55 +00:00
2018-10-08 18:17:39 +00:00
func toString * [ bits : static [ int ] ] ( num : StUint [ bits ] , radix : static [ uint8 ] = 10 ) : string =
2022-02-24 19:09:53 +00:00
## Convert a StInt or StUint to string.
2018-04-30 11:38:55 +00:00
## In case of negative numbers:
## - they are prefixed with "-" for base 10.
## - if not base 10, they are returned raw in two-complement form.
2019-03-14 02:43:51 +00:00
static : doAssert ( radix > = 2 ) and radix < = 16 , " Only base from 2..16 are supported "
2018-04-30 11:38:55 +00:00
# TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
const hexChars = " 0123456789abcdef "
2018-10-08 18:17:39 +00:00
const base = radix . uint8 . stuint ( bits )
2018-04-30 11:38:55 +00:00
result = " "
2018-10-08 18:17:39 +00:00
var ( q , r ) = divmod ( num , base )
2018-04-30 11:38:55 +00:00
while true :
2019-10-16 11:37:02 +00:00
when bitsof ( r . data ) < = 64 :
result . add hexChars [ r . data . int ]
else :
result . add hexChars [ r . truncate ( int ) ]
2018-04-30 11:38:55 +00:00
if q . isZero :
break
2018-10-08 18:17:39 +00:00
( q , r ) = divmod ( q , base )
2018-04-30 11:38:55 +00:00
reverse ( result )
2022-02-24 19:09:53 +00:00
func toString * [ bits : static [ int ] ] ( num : StInt [ bits ] , radix : static [ int8 ] = 10 ) : string =
## Convert a StInt or StUint to string.
2018-04-30 11:38:55 +00:00
## In case of negative numbers:
## - they are prefixed with "-" for base 10.
## - if not base 10, they are returned raw in two-complement form.
2019-03-14 02:43:51 +00:00
static : doAssert ( radix > = 2 ) and radix < = 16 , " Only base from 2..16 are supported "
2018-04-30 11:38:55 +00:00
# TODO: use static[range[2 .. 16]], not supported at the moment (2018-04-26)
const hexChars = " 0123456789abcdef "
2019-10-16 11:37:02 +00:00
const base = radix . int8 . stuint ( bits )
2018-04-30 11:38:55 +00:00
result = " "
2022-02-24 19:09:53 +00:00
type T = StUint [ bits ]
2018-04-30 11:38:55 +00:00
let isNeg = num . isNegative
2019-10-16 11:37:02 +00:00
let num = convert [ T ] ( if radix = = 10 and isNeg : - num
else : num )
2018-04-30 11:38:55 +00:00
2018-10-08 18:17:39 +00:00
var ( q , r ) = divmod ( num , base )
2018-04-30 11:38:55 +00:00
while true :
2019-10-16 11:37:02 +00:00
when bitsof ( r . data ) < = 64 :
result . add hexChars [ r . data . int ]
else :
result . add hexChars [ r . truncate ( int ) ]
2018-04-30 11:38:55 +00:00
if q . isZero :
break
2018-10-08 18:17:39 +00:00
( q , r ) = divmod ( q , base )
2018-04-30 11:38:55 +00:00
2019-10-16 11:37:02 +00:00
if isNeg and radix = = 10 :
2018-04-30 11:38:55 +00:00
result . add ' - '
reverse ( result )
2022-02-24 19:09:53 +00:00
func ` $ ` * ( num : StInt or StUint ) : string {. inline . } =
2018-05-15 09:51:59 +00:00
when num . data is SomeInteger :
$ num . data
else :
toString ( num , 10 )
2018-04-30 11:38:55 +00:00
2022-02-24 19:09:53 +00:00
func toHex * [ bits : static [ int ] ] ( num : StInt [ bits ] or StUint [ bits ] ) : string {. inline . } =
2018-05-08 12:44:07 +00:00
## Convert to a hex string.
## Output is considered a big-endian base 16 string.
## Leading zeros are stripped. Use dumpHex instead if you need the in-memory representation
toString ( num , 16 )
2022-02-24 19:09:53 +00:00
func dumpHex * ( x : StInt or StUint , order : static [ Endianness ] = bigEndian ) : string =
2018-04-30 11:38:55 +00:00
## Stringify an int to hex.
2018-05-08 12:44:07 +00:00
## Note. Leading zeros are not removed. Use toString(n, base = 16)/toHex instead.
2018-04-30 11:38:55 +00:00
##
## You can specify bigEndian or littleEndian order.
## i.e. in bigEndian:
## - 1.uint64 will be 00000001
## - (2.uint128)^64 + 1 will be 0000000100000001
##
## in littleEndian:
## - 1.uint64 will be 01000000
## - (2.uint128)^64 + 1 will be 0100000001000000
const
hexChars = " 0123456789abcdef "
2018-10-25 10:58:40 +00:00
size = bitsof ( x . data ) div 8
2018-04-30 11:38:55 +00:00
result = newString ( 2 * size )
2019-10-08 13:11:08 +00:00
when nimvm :
for i in 0 .. < size :
when order = = system . cpuEndian :
2019-10-09 01:51:53 +00:00
let byte = x . data . getByte ( i )
2019-10-08 13:11:08 +00:00
else :
2019-10-09 01:51:53 +00:00
let byte = x . data . getByte ( size - 1 - i )
2019-10-08 13:11:08 +00:00
result [ 2 * i ] = hexChars [ int byte shr 4 and 0xF ]
result [ 2 * i + 1 ] = hexChars [ int byte and 0xF ]
else :
{. pragma : restrict , codegenDecl : " $# __restrict $# " . }
2022-02-24 19:09:53 +00:00
let bytes {. restrict . } = cast [ ptr array [ size , byte ] ] ( x . unsafeAddr )
2019-10-08 13:11:08 +00:00
for i in 0 .. < size :
when order = = system . cpuEndian :
result [ 2 * i ] = hexChars [ int bytes [ i ] shr 4 and 0xF ]
result [ 2 * i + 1 ] = hexChars [ int bytes [ i ] and 0xF ]
else :
result [ 2 * i ] = hexChars [ int bytes [ bytes [ ] . high - i ] shr 4 and 0xF ]
result [ 2 * i + 1 ] = hexChars [ int bytes [ bytes [ ] . high - i ] and 0xF ]
2018-04-30 11:38:55 +00:00
2022-02-24 19:09:53 +00:00
proc initFromBytesBE * [ bits : static [ int ] ] ( val : var StUint [ bits ] , ba : openArray [ byte ] , allowPadding : static [ bool ] = true ) =
2018-07-04 15:34:14 +00:00
## Initializes a UInt[bits] value from a byte buffer storing a big-endian
## representation of a number.
##
## If `allowPadding` is set to false, the input array must be exactly
## (bits div 8) bytes long. Otherwise, it may be shorter and the remaining
## bytes will be assumed to be zero.
const N = bits div 8
when not allowPadding :
2019-03-14 02:43:51 +00:00
doAssert ( ba . len = = N )
2018-07-04 15:34:14 +00:00
else :
2019-03-14 02:43:51 +00:00
doAssert ba . len < = N
2019-10-16 11:37:02 +00:00
when system . cpuEndian = = bigEndian :
2018-07-04 15:34:14 +00:00
let baseIdx = N - val . len
else :
let baseIdx = ba . len - 1
2019-10-16 11:37:02 +00:00
when nimvm :
when system . cpuEndian = = bigEndian :
when allowPadding :
for i , b in ba : val . data . setByte ( baseIdx + i , b )
else :
for i , b in ba : val . data . setByte ( i , b )
else :
when allowPadding :
for i , b in ba : val . data . setByte ( baseIdx - i , b )
else :
for i , b in ba : val . data . setByte ( N - 1 - i , b )
else :
{. pragma : restrict , codegenDecl : " $# __restrict $# " . }
let r_ptr {. restrict . } = cast [ ptr array [ N , byte ] ] ( val . addr )
when system . cpuEndian = = bigEndian :
# TODO: due to https://github.com/status-im/nim-stint/issues/38
# We can't cast a stack byte array to stuint with a convenient proc signature.
when allowPadding :
for i , b in ba : r_ptr [ baseIdx + i ] = b
else :
for i , b in ba : r_ptr [ i ] = b
2018-07-04 15:34:14 +00:00
else :
2019-10-16 11:37:02 +00:00
when allowPadding :
for i , b in ba : r_ptr [ baseIdx - i ] = b
else :
for i , b in ba : r_ptr [ N - 1 - i ] = b
2018-07-04 15:34:14 +00:00
2022-02-24 19:09:53 +00:00
func significantBytesBE * ( val : openArray [ byte ] ) : int {. deprecated . } =
2018-07-04 15:34:14 +00:00
## Returns the number of significant trailing bytes in a big endian
## representation of a number.
2018-10-06 09:43:51 +00:00
# TODO: move that in https://github.com/status-im/nim-byteutils
2018-07-04 15:34:14 +00:00
for i in 0 .. < val . len :
if val [ i ] ! = 0 :
return val . len - i
return 1
2022-02-24 19:09:53 +00:00
func fromBytesBE * ( T : type StUint , ba : openArray [ byte ] ,
2018-07-04 15:34:14 +00:00
allowPadding : static [ bool ] = true ) : T =
## This function provides a convenience wrapper around `initFromBytesBE`.
result . initFromBytesBE ( ba , allowPadding )
2022-02-24 19:09:53 +00:00
func readUintBE * [ bits : static [ int ] ] ( ba : openArray [ byte ] ) : StUint [ bits ] =
2018-05-08 11:21:04 +00:00
## Convert a big-endian array of (bits div 8) Bytes to an UInt[bits] (in native host endianness)
## Input:
2022-02-24 19:09:53 +00:00
## - a big-endian openArray of size (bits div 8) at least
2018-05-08 11:21:04 +00:00
## Returns:
## - A unsigned integer of the same size with `bits` bits
##
2022-02-24 19:09:53 +00:00
## ⚠ If the openArray length is bigger than bits div 8, part converted is undefined behaviour.
2018-07-04 15:34:14 +00:00
result . initFromBytesBE ( ba , false )
2018-05-08 11:21:04 +00:00
func toByteArrayBE * [ bits : static [ int ] ] ( n : StUint [ bits ] ) : array [ bits div 8 , byte ] =
## Convert a uint[bits] to to a big-endian array of bits div 8 bytes
## Input:
## - an unsigned integer
## Returns:
## - a big-endian array of the same size
const N = bits div 8
2019-10-16 11:37:02 +00:00
when nimvm :
2018-05-08 11:21:04 +00:00
for i in 0 .. < N :
2019-10-16 11:37:02 +00:00
when system . cpuEndian = = bigEndian :
result [ i ] = n . data . getByte ( i )
else :
result [ i ] = n . data . getByte ( N - 1 - i )
else :
when system . cpuEndian = = bigEndian :
result = cast [ type result ] ( n )
else :
{. pragma : restrict , codegenDecl : " $# __restrict $# " . }
let n_ptr {. restrict . } = cast [ ptr array [ N , byte ] ] ( n . unsafeAddr )
for i in 0 .. < N :
result [ N - 1 - i ] = n_ptr [ i ]
2019-12-18 13:02:16 +00:00
template hash * ( num : StUint | StInt ) : Hash =
# TODO:
# `hashData` is not particularly efficient.
# Explore better hashing solutions in nim-stew.
hashData ( unsafeAddr num , sizeof num )