stew updates
* simplify int api (fixes #68) * implement endians api * implement some more bitops
This commit is contained in:
parent
33562884a1
commit
8bf328b4f0
|
@ -7,8 +7,8 @@
|
||||||
#
|
#
|
||||||
# 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 stint/[uint_public, int_public, io, modular_arithmetic, literals_stint]
|
import stint/[bitops2, endians2, intops, io, modular_arithmetic, literals_stint]
|
||||||
export uint_public, int_public, io, modular_arithmetic, literals_stint
|
export bitops2, endians2, intops, io, modular_arithmetic, literals_stint
|
||||||
|
|
||||||
type
|
type
|
||||||
Int128* = Stint[128]
|
Int128* = Stint[128]
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import ./private/[bitops2_priv, datatypes]
|
||||||
|
|
||||||
|
func countOnes*(x: StUint): int {.inline.} = countOnes(x.data)
|
||||||
|
func parity*(x: StUint): int {.inline.} = parity(x.data)
|
||||||
|
func firstOne*(x: StUint): int {.inline.} = firstOne(x.data)
|
||||||
|
func leadingZeros*(x: StUint): int {.inline.} = leadingZeros(x.data)
|
||||||
|
func trailingZeros*(x: StUint): int {.inline.} = trailingZeros(x.data)
|
|
@ -0,0 +1,105 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import private/[bitops2_priv, endians2_priv, datatypes]
|
||||||
|
|
||||||
|
import stew/endians2
|
||||||
|
export endians2
|
||||||
|
|
||||||
|
func swapBytes*(x: StUint): StUint {.inline.} = StUint(data: swapBytes(x.data))
|
||||||
|
|
||||||
|
func toBytes*[bits: static int](x: StUint[bits], endian: Endianness = system.cpuEndian):
|
||||||
|
array[bits div 8, byte] {.inline.} =
|
||||||
|
toBytes(x.data, endian)
|
||||||
|
|
||||||
|
func toBytesLE*[bits: static int](x: StUint[bits]):
|
||||||
|
array[bits div 8, byte] {.inline.} =
|
||||||
|
toBytes(x, littleEndian)
|
||||||
|
|
||||||
|
func toBytesBE*[bits: static int](x: StUint[bits]):
|
||||||
|
array[bits div 8, byte] {.inline.} =
|
||||||
|
toBytes(x, bigEndian)
|
||||||
|
|
||||||
|
func fromBytes*[bits: static int](
|
||||||
|
T: typedesc[StUint[bits]],
|
||||||
|
x: array[bits div 8, byte],
|
||||||
|
endian: Endianness = system.cpuEndian): T {.inline, noinit.} =
|
||||||
|
# TODO compile-time version
|
||||||
|
copyMem(addr result, unsafeAddr x[0], bits div 8)
|
||||||
|
|
||||||
|
if endian != system.cpuEndian:
|
||||||
|
result = swapBytes(result)
|
||||||
|
|
||||||
|
func fromBytes*[bits: static int](
|
||||||
|
T: typedesc[StUint[bits]],
|
||||||
|
x: openArray[byte],
|
||||||
|
endian: Endianness = system.cpuEndian): T {.inline.} =
|
||||||
|
# TODO fromBytesBE in io.nim handles this better, merge the two!
|
||||||
|
var tmp: array[bits div 8, byte]
|
||||||
|
if x.len < tmp.len:
|
||||||
|
let offset = if endian == bigEndian: tmp.len - x.len else: 0
|
||||||
|
for i in 0..<x.len: # Loop since vm can't copymem
|
||||||
|
tmp[i + offset] = x[i]
|
||||||
|
else:
|
||||||
|
for i in 0..<tmp.len: # Loop since vm can't copymem
|
||||||
|
tmp[i] = x[i]
|
||||||
|
fromBytes(T, tmp, endian)
|
||||||
|
|
||||||
|
func fromBytesBE*[bits: static int](
|
||||||
|
T: typedesc[StUint[bits]],
|
||||||
|
x: array[bits div 8, byte]): T {.inline.} =
|
||||||
|
## Read big endian bytes and convert to an integer. By default, native
|
||||||
|
## endianess is used which is not
|
||||||
|
## portable!
|
||||||
|
fromBytes(T, x, bigEndian)
|
||||||
|
|
||||||
|
func fromBytesBE*[bits: static int](
|
||||||
|
T: typedesc[StUint[bits]],
|
||||||
|
x: openArray[byte]): T {.inline.} =
|
||||||
|
## Read big endian bytes and convert to an integer. At runtime, v must contain
|
||||||
|
## at least sizeof(T) bytes. By default, native endianess is used which is not
|
||||||
|
## portable!
|
||||||
|
fromBytes(T, x, bigEndian)
|
||||||
|
|
||||||
|
func toBE*[bits: static int](x: StUint[bits]): StUint[bits] {.inline.} =
|
||||||
|
## Convert a native endian value to big endian. Consider toBytesBE instead
|
||||||
|
## which may prevent some confusion.
|
||||||
|
if cpuEndian == bigEndian: x
|
||||||
|
else: x.swapBytes
|
||||||
|
|
||||||
|
func fromBE*[bits: static int](x: StUint[bits]): StUint[bits] {.inline.} =
|
||||||
|
## Read a big endian value and return the corresponding native endian
|
||||||
|
# there's no difference between this and toBE, except when reading the code
|
||||||
|
toBE(x)
|
||||||
|
|
||||||
|
func fromBytesLE*[bits: static int](
|
||||||
|
T: typedesc[StUint[bits]],
|
||||||
|
x: array[bits div 8, byte]): StUint[bits] {.inline.} =
|
||||||
|
## Read little endian bytes and convert to an integer. By default, native
|
||||||
|
## endianess is used which is not portable!
|
||||||
|
fromBytes(T, x, littleEndian)
|
||||||
|
|
||||||
|
func fromBytesLE*[bits: static int](
|
||||||
|
T: typedesc[StUint[bits]],
|
||||||
|
x: openArray[byte]): StUint[bits] {.inline.} =
|
||||||
|
## Read little endian bytes and convert to an integer. At runtime, v must
|
||||||
|
## contain at least sizeof(T) bytes. By default, native endianess is used
|
||||||
|
## which is not portable!
|
||||||
|
fromBytes(T, x, littleEndian)
|
||||||
|
|
||||||
|
func toLE*[bits: static int](x: StUint[bits]): StUint[bits] {.inline.} =
|
||||||
|
## Convert a native endian value to little endian. Consider toBytesLE instead
|
||||||
|
## which may prevent some confusion.
|
||||||
|
if cpuEndian == littleEndian: x
|
||||||
|
else: x.swapBytes
|
||||||
|
|
||||||
|
func fromLE*[bits: static int](x: StUint[bits]): StUint[bits] {.inline.} =
|
||||||
|
## Read a little endian value and return the corresponding native endian
|
||||||
|
# there's no difference between this and toLE, except when reading the code
|
||||||
|
toLE(x)
|
|
@ -1,94 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
import ./private/datatypes
|
|
||||||
export StInt
|
|
||||||
export IntImpl, intImpl, bitsof # TODO remove the need to export these
|
|
||||||
|
|
||||||
template make_unary(op, ResultTy): untyped =
|
|
||||||
func `op`*(x: Stint): ResultTy {.inline.} =
|
|
||||||
when ResultTy is Stint:
|
|
||||||
result.data = op(x.data)
|
|
||||||
else:
|
|
||||||
op(x.data)
|
|
||||||
export op
|
|
||||||
|
|
||||||
template make_binary(op, ResultTy): untyped =
|
|
||||||
func `op`*(x, y: Stint): ResultTy {.inline.} =
|
|
||||||
when ResultTy is Stint:
|
|
||||||
result.data = op(x.data, y.data)
|
|
||||||
else:
|
|
||||||
op(x.data, y.data)
|
|
||||||
export `op`
|
|
||||||
|
|
||||||
template make_binary_inplace(op): untyped =
|
|
||||||
func `op`*(x: var Stint, y: Stint) {.inline.} =
|
|
||||||
op(x.data, y.data)
|
|
||||||
export op
|
|
||||||
|
|
||||||
import ./private/int_addsub
|
|
||||||
|
|
||||||
make_binary(`+`, Stint)
|
|
||||||
make_binary_inplace(`+=`)
|
|
||||||
make_binary(`-`, Stint)
|
|
||||||
make_binary_inplace(`-=`)
|
|
||||||
|
|
||||||
import ./private/int_negabs
|
|
||||||
make_unary(`-`, Stint)
|
|
||||||
make_unary(abs, Stint)
|
|
||||||
|
|
||||||
import ./private/int_mul
|
|
||||||
make_binary(`*`, Stint)
|
|
||||||
|
|
||||||
import ./private/int_div
|
|
||||||
|
|
||||||
make_binary(`div`, Stint)
|
|
||||||
make_binary(`mod`, Stint)
|
|
||||||
func divmod*(x, y: Stint): tuple[quot, rem: Stint] {.inline.} =
|
|
||||||
(result.quot.data, result.rem.data) = divmod(x.data, y.data)
|
|
||||||
|
|
||||||
import ./private/int_comparison
|
|
||||||
|
|
||||||
make_binary(`<`, bool)
|
|
||||||
make_binary(`<=`, bool)
|
|
||||||
make_binary(`==`, bool)
|
|
||||||
make_unary(isZero, bool)
|
|
||||||
make_unary(isNegative, bool)
|
|
||||||
|
|
||||||
func isOdd(x: SomeSignedInt): bool {.inline.}=
|
|
||||||
# internal
|
|
||||||
bool(x and 1)
|
|
||||||
|
|
||||||
func isEven(x: SomeSignedInt): bool {.inline.}=
|
|
||||||
# internal
|
|
||||||
not x.isOdd
|
|
||||||
|
|
||||||
make_unary(isOdd, bool)
|
|
||||||
make_unary(isEven, bool)
|
|
||||||
|
|
||||||
import ./private/int_bitwise_ops
|
|
||||||
|
|
||||||
make_unary(`not`, Stint)
|
|
||||||
make_binary(`or`, Stint)
|
|
||||||
make_binary(`and`, Stint)
|
|
||||||
make_binary(`xor`, Stint)
|
|
||||||
func `shr`*(x: Stint, y: SomeInteger): Stint {.inline.} =
|
|
||||||
result.data = x.data shr y
|
|
||||||
func `shl`*(x: Stint, y: SomeInteger): Stint {.inline.} =
|
|
||||||
result.data = x.data shl y
|
|
||||||
func ashr*(x: Stint, y: SomeInteger): Stint {.inline.} =
|
|
||||||
result.data = ashr(x.data, y)
|
|
||||||
|
|
||||||
import ./private/int_highlow
|
|
||||||
|
|
||||||
func high*[bits: static[int]](_: typedesc[Stint[bits]]): Stint[bits] {.inline.} =
|
|
||||||
result.data = high(type result.data)
|
|
||||||
|
|
||||||
func low*[bits: static[int]](_: typedesc[Stint[bits]]): Stint[bits] {.inline.} =
|
|
||||||
result.data = low(type result.data)
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import ./private/[bitops2_priv, datatypes]
|
||||||
|
|
||||||
|
export Stint, StUint
|
||||||
|
export IntImpl, intImpl, UintImpl, uintImpl, bitsof # TODO: remove the need to export those
|
||||||
|
|
||||||
|
type SomeBigInteger = Stuint|Stint
|
||||||
|
|
||||||
|
import ./private/initialization
|
||||||
|
|
||||||
|
func zero*[bits: static[int]](T: typedesc[Stuint[bits] or Stint[bits]]): T {.inline.} =
|
||||||
|
## Returns the zero of the input type
|
||||||
|
discard
|
||||||
|
|
||||||
|
func one*[bits: static[int]](T: typedesc[Stuint[bits]]): T {.inline.} =
|
||||||
|
## Returns the one of the input type
|
||||||
|
result.data = one(type result.data)
|
||||||
|
|
||||||
|
import ./private/[int_addsub, uint_addsub]
|
||||||
|
|
||||||
|
func `+`*(x, y: SomeBigInteger): SomeBigInteger {.inline.} =
|
||||||
|
## Integer addition
|
||||||
|
result.data = x.data + y.data
|
||||||
|
func `+=`*(x: var SomeBigInteger, y: SomeBigInteger) {.inline.} =
|
||||||
|
## Integer addition
|
||||||
|
x.data += y.data
|
||||||
|
func `-`*(x, y: SomeBigInteger): SomeBigInteger {.inline.} =
|
||||||
|
## Integer substraction
|
||||||
|
result.data = x.data - y.data
|
||||||
|
func `-=`*(x: var SomeBigInteger, y: SomeBigInteger) {.inline.} =
|
||||||
|
## Integer substraction
|
||||||
|
x.data -= y.data
|
||||||
|
|
||||||
|
import ./private/int_negabs
|
||||||
|
|
||||||
|
func `-`*(x: Stint): Stint {.inline.} =
|
||||||
|
## Returns true if input is zero
|
||||||
|
## false otherwise
|
||||||
|
result.data = -x.data
|
||||||
|
|
||||||
|
func abs*(x: Stint): Stint {.inline.} =
|
||||||
|
## Returns true if input is zero
|
||||||
|
## false otherwise
|
||||||
|
result.data = abs(x.data)
|
||||||
|
|
||||||
|
import ./private/[int_mul, uint_mul]
|
||||||
|
|
||||||
|
func `*`*(x, y: SomeBigInteger): SomeBigInteger {.inline.} =
|
||||||
|
## Integer multiplication
|
||||||
|
result.data = x.data * y.data
|
||||||
|
|
||||||
|
import ./private/[int_div, uint_div]
|
||||||
|
|
||||||
|
func `div`*(x, y: SomeBigInteger): SomeBigInteger {.inline.} =
|
||||||
|
## Integer division
|
||||||
|
result.data = x.data div y.data
|
||||||
|
func `mod`*(x, y: SomeBigInteger): SomeBigInteger {.inline.} =
|
||||||
|
## Integer modulo
|
||||||
|
## This returns the remainder of x / y.
|
||||||
|
## i.e. x = y * quotient + remainder
|
||||||
|
result.data = x.data mod y.data
|
||||||
|
func divmod*(x, y: SomeBigInteger): tuple[quot, rem: SomeBigInteger] {.inline.} =
|
||||||
|
## Fused integer division and modulo
|
||||||
|
## Return both the quotient and remainder
|
||||||
|
## of x / y
|
||||||
|
(result.quot.data, result.rem.data) = divmod(x.data, y.data)
|
||||||
|
|
||||||
|
import ./private/[int_comparison, uint_comparison]
|
||||||
|
|
||||||
|
func `<`*(x, y: SomeBigInteger): bool {.inline.} =
|
||||||
|
## Unsigned `less than` comparison
|
||||||
|
x.data < y.data
|
||||||
|
func `<=`*(x, y: SomeBigInteger): bool {.inline.} =
|
||||||
|
## Unsigned `less or equal` comparison
|
||||||
|
x.data <= y.data
|
||||||
|
func `==`*(x, y: SomeBigInteger): bool {.inline.} =
|
||||||
|
## Unsigned `equal` comparison
|
||||||
|
x.data == y.data
|
||||||
|
export `<`, `<=`, `==` # Address Generic Instantiation too nested: https://github.com/status-im/nim-stint/pull/66#issuecomment-427557655
|
||||||
|
|
||||||
|
func isZero*(x: SomeBigInteger): bool {.inline.} =
|
||||||
|
## Returns true if input is zero
|
||||||
|
## false otherwise
|
||||||
|
x.data.isZero
|
||||||
|
|
||||||
|
func isNegative*(x: SomeBigInteger): bool {.inline.} =
|
||||||
|
## Returns true if input is negative (< 0)
|
||||||
|
## false otherwise
|
||||||
|
x.data.isNegative
|
||||||
|
|
||||||
|
func isOdd*(x: SomeBigInteger): bool {.inline.} =
|
||||||
|
## Returns true if input is zero
|
||||||
|
## false otherwise
|
||||||
|
x.data.isOdd
|
||||||
|
|
||||||
|
func isEven*(x: SomeBigInteger): bool {.inline.} =
|
||||||
|
## Returns true if input is zero
|
||||||
|
## false otherwise
|
||||||
|
x.data.isEven
|
||||||
|
|
||||||
|
export isEven, isOdd
|
||||||
|
|
||||||
|
import ./private/[int_bitwise_ops, uint_bitwise_ops]
|
||||||
|
|
||||||
|
func `not`*(x: SomeBigInteger): SomeBigInteger {.inline.}=
|
||||||
|
## Bitwise `not` i.e. flips all bits of the input
|
||||||
|
result.data = x.data.not
|
||||||
|
func `or`*(x, y: SomeBigInteger): SomeBigInteger {.inline.}=
|
||||||
|
## Bitwise `or`
|
||||||
|
result.data = x.data or y.data
|
||||||
|
func `and`*(x, y: SomeBigInteger): SomeBigInteger {.inline.}=
|
||||||
|
## Bitwise `and`
|
||||||
|
result.data = x.data and y.data
|
||||||
|
func `xor`*(x, y: SomeBigInteger): SomeBigInteger {.inline.}=
|
||||||
|
## Bitwise `xor`
|
||||||
|
result.data = x.data xor y.data
|
||||||
|
|
||||||
|
func `shr`*(x: SomeBigInteger, y: SomeInteger): SomeBigInteger {.inline.} =
|
||||||
|
result.data = x.data shr y
|
||||||
|
func `shl`*(x: SomeBigInteger, y: SomeInteger): SomeBigInteger {.inline.} =
|
||||||
|
result.data = x.data shl y
|
||||||
|
func ashr*(x: Stint, y: SomeInteger): Stint {.inline.} =
|
||||||
|
result.data = ashr(x.data, y)
|
||||||
|
|
||||||
|
import ./private/[int_highlow, uint_highlow]
|
||||||
|
|
||||||
|
func high*[bits](_: typedesc[Stint[bits]]): Stint[bits] {.inline.} =
|
||||||
|
result.data = high(type result.data)
|
||||||
|
func high*[bits](_: typedesc[Stuint[bits]]): Stuint[bits] {.inline.} =
|
||||||
|
result.data = high(type result.data)
|
||||||
|
|
||||||
|
func low*[bits](_: typedesc[Stint[bits]]): Stint[bits] {.inline.} =
|
||||||
|
result.data = low(type result.data)
|
||||||
|
func low*[bits](_: typedesc[Stuint[bits]]): Stuint[bits] {.inline.} =
|
||||||
|
result.data = low(type result.data)
|
||||||
|
|
||||||
|
import ./private/uint_exp, math
|
||||||
|
|
||||||
|
func pow*(x: StUint, y: Natural): StUint {.inline.} =
|
||||||
|
## Returns x raised at the power of y
|
||||||
|
when x.data is UintImpl:
|
||||||
|
result.data = x.data.pow(y)
|
||||||
|
else:
|
||||||
|
result.data = x.data ^ y
|
||||||
|
|
||||||
|
func pow*(x: StUint, y: StUint): StUint {.inline.} =
|
||||||
|
## Returns x raised at the power of y
|
||||||
|
when x.data is UintImpl:
|
||||||
|
result.data = x.data.pow(y.data)
|
||||||
|
else:
|
||||||
|
result.data = x.data ^ y.data
|
|
@ -10,7 +10,7 @@
|
||||||
import
|
import
|
||||||
./private/datatypes,
|
./private/datatypes,
|
||||||
./private/int_negabs,
|
./private/int_negabs,
|
||||||
./int_public, ./uint_public,
|
./intops,
|
||||||
typetraits, algorithm
|
typetraits, algorithm
|
||||||
|
|
||||||
template static_check_size(T: typedesc[SomeInteger], bits: static[int]) =
|
template static_check_size(T: typedesc[SomeInteger], bits: static[int]) =
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
## This file provides syntactic sugar to work with literals
|
## This file provides syntactic sugar to work with literals
|
||||||
|
|
||||||
import ./int_public, ./uint_public, macros
|
import ./intops, 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 ./uint_public
|
import ./intops
|
||||||
|
|
||||||
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,27 @@ export bitops2
|
||||||
|
|
||||||
# Bitops from support library
|
# Bitops from support library
|
||||||
|
|
||||||
|
template bitsof*(x: UintImpl): int =
|
||||||
|
# XXX: https://github.com/nim-lang/Nim/issues/9494
|
||||||
|
mixin bitsof
|
||||||
|
bitsof(x.lo) * 2
|
||||||
|
|
||||||
|
template bitsof*(x: IntImpl): int =
|
||||||
|
# XXX: https://github.com/nim-lang/Nim/issues/9494
|
||||||
|
mixin bitsof
|
||||||
|
bitsof(x.lo) * 2
|
||||||
|
|
||||||
|
template bitsof*(x: typedesc[UintImpl]): int =
|
||||||
|
# XXX: https://github.com/nim-lang/Nim/issues/9494
|
||||||
|
mixin bitsof
|
||||||
|
bitsof(x.lo) * 2
|
||||||
|
|
||||||
func countOnes*(x: UintImpl): int {.inline.} =
|
func countOnes*(x: UintImpl): int {.inline.} =
|
||||||
countOnes(x.lo) + countOnes(x.hi)
|
countOnes(x.lo) + countOnes(x.hi)
|
||||||
|
|
||||||
|
func countZeros*(x: UintImpl): int {.inline.} =
|
||||||
|
countZeros(x.lo) + countOnes(x.hi)
|
||||||
|
|
||||||
func parity*(x: UintImpl): int {.inline.} =
|
func parity*(x: UintImpl): int {.inline.} =
|
||||||
parity(x.lo) xor parity(x.hi)
|
parity(x.lo) xor parity(x.hi)
|
||||||
|
|
|
@ -166,14 +166,6 @@ type
|
||||||
StInt*[bits: static[int]] = object
|
StInt*[bits: static[int]] = object
|
||||||
data*: intImpl(bits)
|
data*: intImpl(bits)
|
||||||
|
|
||||||
|
|
||||||
template bitsof*(x: SomeInteger): untyped =
|
|
||||||
sizeof(x) * 8
|
|
||||||
template bitsof*(x: UintImpl|IntImpl): untyped =
|
|
||||||
# XXX: https://github.com/nim-lang/Nim/issues/9494
|
|
||||||
mixin bitsof
|
|
||||||
bitsof(x.lo) * 2
|
|
||||||
|
|
||||||
template applyHiLo*(a: UintImpl | IntImpl, c: untyped): untyped =
|
template applyHiLo*(a: UintImpl | IntImpl, c: untyped): untyped =
|
||||||
## Apply `c` to each of `hi` and `lo`
|
## Apply `c` to each of `hi` and `lo`
|
||||||
var res: type a
|
var res: type a
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import ./bitops2_priv, ./datatypes
|
||||||
|
|
||||||
|
import stew/endians2
|
||||||
|
export endians2
|
||||||
|
|
||||||
|
func swapBytes*(x: UintImpl): UintImpl {.inline.} =
|
||||||
|
let lo = swapBytes(x.hi)
|
||||||
|
let hi = swapBytes(x.lo)
|
||||||
|
|
||||||
|
UintImpl(hi: hi, lo: lo)
|
||||||
|
|
||||||
|
func toBytes*(x: UintImpl, endian: Endianness = system.cpuEndian): auto {.inline.} =
|
||||||
|
# TODO can't use bitsof in return type (compiler bug?), hence return auto
|
||||||
|
# TODO compile-time version
|
||||||
|
var ret: array[bitsof(x) div 8, byte]
|
||||||
|
if endian == system.cpuEndian:
|
||||||
|
copyMem(addr ret[0], unsafeAddr x, ret.len)
|
||||||
|
else:
|
||||||
|
let v = swapBytes(x)
|
||||||
|
copyMem(addr ret[0], unsafeAddr v, ret.len)
|
||||||
|
ret
|
|
@ -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 ./datatypes, ./uint_bitwise_ops
|
import ./datatypes, ./bitops2_priv, ./uint_bitwise_ops
|
||||||
|
|
||||||
func `not`*(x: IntImpl): IntImpl {.inline.}=
|
func `not`*(x: IntImpl): IntImpl {.inline.}=
|
||||||
## Bitwise complement of unsigned integer x
|
## Bitwise complement of unsigned integer x
|
||||||
|
|
|
@ -36,6 +36,12 @@ func `<=`*(x, y: IntImpl): bool {.inline.}=
|
||||||
x.hi < y.hi or
|
x.hi < y.hi or
|
||||||
(x.hi == y.hi and x.lo <= y.lo)
|
(x.hi == y.hi and x.lo <= y.lo)
|
||||||
|
|
||||||
|
func isOdd*(x: SomeSignedInt): bool {.inline.}=
|
||||||
|
bool(x and 1)
|
||||||
|
|
||||||
|
func isEven*(x: SomeSignedInt): bool {.inline.}=
|
||||||
|
not x.isOdd
|
||||||
|
|
||||||
func isEven*(x: IntImpl): bool {.inline.}=
|
func isEven*(x: IntImpl): bool {.inline.}=
|
||||||
x.lo.isEven
|
x.lo.isEven
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
import
|
import
|
||||||
./datatypes,
|
./datatypes,
|
||||||
./initialization, ./int_highlow,
|
./initialization, ./int_highlow,
|
||||||
./int_addsub, ./int_comparison
|
./int_addsub, ./int_comparison, ./int_bitwise_ops
|
||||||
|
|
||||||
func `-`*(x: IntImpl): IntImpl {.inline.}=
|
func `-`*(x: IntImpl): IntImpl {.inline.}=
|
||||||
# Negate a multi-precision signed int.
|
# Negate a multi-precision signed int.
|
||||||
|
|
|
@ -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 ./datatypes
|
import ./datatypes, ./bitops2_priv
|
||||||
|
|
||||||
func `not`*(x: UintImpl): UintImpl {.inline.}=
|
func `not`*(x: UintImpl): UintImpl {.inline.}=
|
||||||
## Bitwise complement of unsigned integer x
|
## Bitwise complement of unsigned integer x
|
||||||
|
|
|
@ -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 ./bitops2, ./conversion, ./initialization,
|
import ./bitops2_priv, ./conversion, ./initialization,
|
||||||
./datatypes,
|
./datatypes,
|
||||||
./uint_comparison,
|
./uint_comparison,
|
||||||
./uint_bitwise_ops,
|
./uint_bitwise_ops,
|
||||||
|
|
|
@ -1,146 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
import ./private/datatypes
|
|
||||||
|
|
||||||
export StUint
|
|
||||||
export UintImpl, uintImpl, bitsof # TODO: remove the need to export those
|
|
||||||
|
|
||||||
import ./private/uint_addsub
|
|
||||||
|
|
||||||
func `+`*(x, y: Stuint): Stuint {.inline.} =
|
|
||||||
## Unsigned integer addition
|
|
||||||
result.data = x.data + y.data
|
|
||||||
func `+=`*(x: var Stuint, y: Stuint) {.inline.} =
|
|
||||||
## Unsigned integer addition
|
|
||||||
x.data += y.data
|
|
||||||
func `-`*(x, y: Stuint): Stuint {.inline.} =
|
|
||||||
## Unsigned integer substraction
|
|
||||||
result.data = x.data - y.data
|
|
||||||
func `-=`*(x: var Stuint, y: Stuint) {.inline.} =
|
|
||||||
## Unsigned integer substraction
|
|
||||||
x.data -= y.data
|
|
||||||
|
|
||||||
import ./private/uint_mul
|
|
||||||
|
|
||||||
func `*`*(x, y: Stuint): Stuint {.inline.} =
|
|
||||||
## Unsigned integer multiplication
|
|
||||||
result.data = x.data * y.data
|
|
||||||
|
|
||||||
import ./private/uint_div
|
|
||||||
|
|
||||||
func `div`*(x, y: Stuint): Stuint {.inline.} =
|
|
||||||
## Unsigned integer division
|
|
||||||
result.data = x.data div y.data
|
|
||||||
func `mod`*(x, y: Stuint): Stuint {.inline.} =
|
|
||||||
## Unsigned integer modulo
|
|
||||||
## This returns the remainder of x / y.
|
|
||||||
## i.e. x = y * quotient + remainder
|
|
||||||
result.data = x.data mod y.data
|
|
||||||
func divmod*(x, y: StUint): tuple[quot, rem: StUint] {.inline.} =
|
|
||||||
## Fused unsigned integer division and modulo
|
|
||||||
## Return both the quotient and remainder
|
|
||||||
## of x / y
|
|
||||||
(result.quot.data, result.rem.data) = divmod(x.data, y.data)
|
|
||||||
|
|
||||||
import ./private/uint_comparison
|
|
||||||
|
|
||||||
func `<`*(x, y: Stuint): bool {.inline.} =
|
|
||||||
## Unsigned `less than` comparison
|
|
||||||
x.data < y.data
|
|
||||||
func `<=`*(x, y: Stuint): bool {.inline.} =
|
|
||||||
## Unsigned `less or equal` comparison
|
|
||||||
x.data <= y.data
|
|
||||||
func `==`*(x, y: Stuint): bool {.inline.} =
|
|
||||||
## Unsigned `equal` comparison
|
|
||||||
x.data == y.data
|
|
||||||
export `<`, `<=`, `==` # Address Generic Instantiation too nested: https://github.com/status-im/nim-stint/pull/66#issuecomment-427557655
|
|
||||||
|
|
||||||
func isZero*(x: Stuint): bool {.inline.} =
|
|
||||||
## Returns true if input is zero
|
|
||||||
## false otherwise
|
|
||||||
x.data.isZero
|
|
||||||
|
|
||||||
export isEven, isOdd
|
|
||||||
func isEven*(x: Stuint): bool {.inline.}=
|
|
||||||
## Returns true if input is even
|
|
||||||
## false otherwise
|
|
||||||
x.data.isEven
|
|
||||||
func isOdd*(x: Stuint): bool {.inline.}=
|
|
||||||
## Returns true if input is odd
|
|
||||||
## false otherwise
|
|
||||||
not x.isEven
|
|
||||||
|
|
||||||
import ./private/uint_bitwise_ops
|
|
||||||
|
|
||||||
func `not`*(x: Stuint): Stuint {.inline.}=
|
|
||||||
## Bitwise `not` i.e. flips all bits of the input
|
|
||||||
result.data = x.data.not
|
|
||||||
func `or`*(x, y: Stuint): Stuint {.inline.}=
|
|
||||||
## Bitwise `or`
|
|
||||||
result.data = x.data or y.data
|
|
||||||
func `and`*(x, y: Stuint): Stuint {.inline.}=
|
|
||||||
## Bitwise `and`
|
|
||||||
result.data = x.data and y.data
|
|
||||||
func `xor`*(x, y: Stuint): Stuint {.inline.}=
|
|
||||||
## Bitwise `xor`
|
|
||||||
result.data = x.data xor y.data
|
|
||||||
|
|
||||||
func `shr`*(x: StUint, y: SomeInteger): StUint {.inline.} =
|
|
||||||
## Logical shift right
|
|
||||||
result.data = x.data shr y
|
|
||||||
func `shl`*(x: StUint, y: SomeInteger): StUint {.inline.} =
|
|
||||||
## Logical shift right
|
|
||||||
## Similar to C standard, result is undefined if y is bigger
|
|
||||||
## than the number of bits in x.
|
|
||||||
result.data = x.data shl y
|
|
||||||
|
|
||||||
import ./private/uint_highlow
|
|
||||||
|
|
||||||
func high*[bits: static[int]](_: typedesc[Stuint[bits]]): Stuint[bits] {.inline.} =
|
|
||||||
## Returns the highest unsigned int of this size. I.e. bits are all ones.
|
|
||||||
result.data = high(type result.data)
|
|
||||||
|
|
||||||
func low*[bits: static[int]](_: typedesc[Stuint[bits]]): Stuint[bits] {.inline.} =
|
|
||||||
## Returns the lowest unsigned int of this size. This is always 0.
|
|
||||||
result.data = low(type result.data)
|
|
||||||
|
|
||||||
import ./private/bitops2
|
|
||||||
|
|
||||||
func countOnes*(x: StUint): int {.inline.} = countOnes(x.data)
|
|
||||||
func parity*(x: StUint): int {.inline.} = parity(x.data)
|
|
||||||
func firstOne*(x: StUint): int {.inline.} = firstOne(x.data)
|
|
||||||
func leadingZeros*(x: StUint): int {.inline.} = leadingZeros(x.data)
|
|
||||||
func trailingZeros*(x: StUint): int {.inline.} = trailingZeros(x.data)
|
|
||||||
|
|
||||||
import ./private/initialization
|
|
||||||
|
|
||||||
func zero*[bits: static[int]](T: typedesc[Stuint[bits] or Stint[bits]]): T {.inline.} =
|
|
||||||
## Returns the zero of the input type
|
|
||||||
discard
|
|
||||||
|
|
||||||
func one*[bits: static[int]](T: typedesc[Stuint[bits]]): T {.inline.} =
|
|
||||||
## Returns the one of the input type
|
|
||||||
result.data = one(type result.data)
|
|
||||||
|
|
||||||
import ./private/uint_exp, math
|
|
||||||
|
|
||||||
func pow*(x: StUint, y: Natural): StUint {.inline.} =
|
|
||||||
## Returns x raised at the power of y
|
|
||||||
when x.data is UintImpl:
|
|
||||||
result.data = x.data.pow(y)
|
|
||||||
else:
|
|
||||||
result.data = x.data ^ y
|
|
||||||
|
|
||||||
func pow*(x: StUint, y: StUint): StUint {.inline.} =
|
|
||||||
## Returns x raised at the power of y
|
|
||||||
when x.data is UintImpl:
|
|
||||||
result.data = x.data.pow(y.data)
|
|
||||||
else:
|
|
||||||
result.data = x.data ^ y.data
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import ../stint, unittest
|
||||||
|
|
||||||
|
suite "Testing endians":
|
||||||
|
test "Endians give sane results":
|
||||||
|
|
||||||
|
check:
|
||||||
|
1.u128.toBytesBE() ==
|
||||||
|
[0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
|
||||||
|
|
||||||
|
1.u128.toBytesLE() ==
|
||||||
|
[1'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
|
||||||
|
1.u128 == UInt128.fromBytesBE(
|
||||||
|
[0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
|
||||||
|
|
||||||
|
1.u128 == UInt128.fromBytesLE(
|
||||||
|
[1'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
Loading…
Reference in New Issue