diff --git a/src/private/utils.nim b/src/private/utils.nim index 55f0d4c..81c631b 100644 --- a/src/private/utils.nim +++ b/src/private/utils.nim @@ -1,7 +1,9 @@ # Copyright (c) 2018 Status Research & Development GmbH # Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). -import ../uint_type +import ../uint_type, + macros + proc bit_length*[T: BaseUint](n: T): int {.noSideEffect.}= ## Calculates how many bits are necessary to represent the number @@ -50,4 +52,9 @@ proc asDoubleUint*[T: BaseUint](n: T): auto {.noSideEffect, inline.} = else: uint16 ) - n.asUint.Double \ No newline at end of file + n.asUint.Double + +macro getSubType*(T: typedesc): untyped = + ## Returns the subtype of a generic type + ## MpUint[uint32] --> uint32 + getTypeInst(T)[1][1] \ No newline at end of file diff --git a/src/uint_bitwise_ops.nim b/src/uint_bitwise_ops.nim index e51233f..ac04161 100644 --- a/src/uint_bitwise_ops.nim +++ b/src/uint_bitwise_ops.nim @@ -1,7 +1,8 @@ # Copyright (c) 2018 Status Research & Development GmbH # Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). -import uint_type +import ./private/utils, + uint_type proc `not`*(x: MpUint): MpUint {.noInit, noSideEffect, inline.}= @@ -22,4 +23,51 @@ proc `and`*(x, y: MpUint): MpUint {.noInit, noSideEffect, inline.}= proc `xor`*(x, y: MpUint): MpUint {.noInit, noSideEffect, inline.}= ## `Bitwise xor` of numbers x and y result.lo = x.lo xor y.lo - result.hi = x.hi xor y.hi \ No newline at end of file + result.hi = x.hi xor y.hi + +proc `shl`*[T: MpUint](x: T, y: SomeInteger): T {.noInit, noSideEffect.} + # Forward declaration + +proc `shl`*[T: MpUint](x: T, y: SomeInteger): T {.noInit, noSideEffect.}= + ## Compute the `shift left` operation of x and y + + if y == 0: + return x + + let # TODO: should be a const - https://github.com/nim-lang/Nim/pull/5664 + size = (T.sizeof * 8) + halfSize = size div 2 + + type Sub = getSubType T + + if y > halfSize: + result.hi = x.lo shl (y - halfSize) + result.lo = 0.Sub + elif y < halfSize: + result.hi = (x.hi shl y) or (x.lo shr (halfSize - y)) + result.lo = x.lo shl y + else: + result.hi = x.lo + result.lo = 0.Sub + +proc `shr`*[T: MpUint](x: T, y: SomeInteger): T {.noInit, noSideEffect.}= + ## Compute the `shift right` operation of x and y + + if y == 0: + return x + + let # TODO: should be a const - https://github.com/nim-lang/Nim/pull/5664 + size = (T.sizeof * 8) + halfSize = size div 2 + + type Sub = getSubType T + + if y > halfSize: + result.hi = x.hi shr (y - halfSize) + result.lo = 0.Sub + elif y < halfSize: + result.lo = (x.lo shr y) or (x.hi shl (halfSize - y)) + result.hi = x.hi shr y + else: + result.lo = x.hi + result.hi = 0.Sub \ No newline at end of file diff --git a/tests/test_bitwise.nim b/tests/test_bitwise.nim new file mode 100644 index 0000000..159fd0d --- /dev/null +++ b/tests/test_bitwise.nim @@ -0,0 +1,34 @@ +# Copyright (c) 2018 Status Research & Development GmbH +# Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT). + +import ../src/mpint, unittest + +suite "Testing bitwise operations": + let a = initMpUint(100, uint8) + + let b = a * a + let z = 10000'u16 + + test "Shift left - by less than half the size of the integer": + check: cast[uint16](b) == z # Sanity check + check: cast[uint16](b shl 2) == z shl 2 + + test "Shift left - by more than half the size of the integer": + check: cast[uint16](b) == z # Sanity check + check: cast[uint16](b shl 10) == z shl 10 + + test "Shift left - by half the size of the integer": + check: cast[uint16](b) == z # Sanity check + check: cast[uint16](b shl 8) == z shl 8 + + test "Shift right - by less than half the size of the integer": + check: cast[uint16](b) == z # Sanity check + check: cast[uint16](b shr 2) == z shr 2 + + test "Shift right - by more than half the size of the integer": + check: cast[uint16](b) == z # Sanity check + check: cast[uint16](b shr 10) == z shr 10 + + test "Shift right - by half the size of the integer": + check: cast[uint16](b) == z # Sanity check + check: cast[uint16](b shr 8) == z shr 8