Add most significant bit and isNegative proc

This commit is contained in:
mratsim 2018-04-25 15:41:59 +02:00
parent b3dedf7824
commit 97fbe56353
3 changed files with 52 additions and 31 deletions

View File

@ -30,6 +30,28 @@ proc optim(x: NimNode): NimNode =
else: else:
error "Unreachable path reached" error "Unreachable path reached"
proc isUint(x: NimNode): static[bool] =
if eqIdent(x, "uint64"): true
elif eqIdent(x, "uint32"): true
elif eqIdent(x, "uint16"): true
elif eqIdent(x, "uint8"): true
else: false
macro most_significant_word*(x: IntImpl): untyped =
let optim_type = optim(x)
if optim_type.isUint:
result = quote do:
cast[`optim_type`](`x`)
else:
when system.cpuEndian == littleEndian:
let size = getSize(x)
let msw_pos = size - 1
else:
let msw_pos = 0
result = quote do:
cast[`optim_type`](`x`)[`msw_pos`]
proc replaceNodes(ast: NimNode, replacing: NimNode, to_replace: NimNode): NimNode = proc replaceNodes(ast: NimNode, replacing: NimNode, to_replace: NimNode): NimNode =
# Args: # Args:
# - The full syntax tree # - The full syntax tree
@ -53,13 +75,6 @@ proc replaceNodes(ast: NimNode, replacing: NimNode, to_replace: NimNode): NimNod
return rTree return rTree
result = inspect(ast) result = inspect(ast)
proc isUint(x: NimNode): static[bool] =
if eqIdent(x, "uint64"): true
elif eqIdent(x, "uint32"): true
elif eqIdent(x, "uint16"): true
elif eqIdent(x, "uint8"): true
else: false
macro asWords*[T](n: UintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped = macro asWords*[T](n: UintImpl[T], ignoreEndianness: static[bool], loopBody: untyped): untyped =
## Iterates over n, as an array of words. ## Iterates over n, as an array of words.
## Input: ## Input:

View File

@ -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, stdlib_bitops import ./datatypes, stdlib_bitops, as_words
export stdlib_bitops export stdlib_bitops
# We reuse bitops from Nim standard lib, and expand it for multi-precision int. # We reuse bitops from Nim standard lib, and expand it for multi-precision int.
@ -24,3 +24,25 @@ func countLeadingZeroBits*(n: UintImpl): int {.inline.} =
result = if hi_clz == maxHalfRepr: result = if hi_clz == maxHalfRepr:
n.lo.countLeadingZeroBits + maxHalfRepr n.lo.countLeadingZeroBits + maxHalfRepr
else: hi_clz else: hi_clz
func msb*[T: SomeInteger](n: T): T =
## Returns the most significant bit of an integer.
when T is int64 or (T is int and sizeof(int) == 8):
type UInt = uint64
elif T is int32 or (T is int and sizeof(int) == 4):
type Uint = uint32
elif T is int16:
type Uint = uint16
elif T is int8:
type Uint = uint8
else:
type Uint = T
const msb_pos = sizeof(T) * 8 - 1
result = T(cast[Uint](n) shr msb_pos)
func msb*(n: IntImpl): auto =
## Returns the most significant bit of an arbitrary precision integer.
result = msb most_significant_word(n)

View File

@ -7,34 +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 ./datatypes, ./as_words, ./uint_comparison import ./datatypes, ./bithacks, ./as_words,
./bithacks
func isZero*(n: SomeUnsignedInt): bool {.inline.} = func isZero*(n: SomeSignedInt): bool {.inline.} =
n == 0 n == 0
func isZero*(n: UintImpl): bool {.inline.} = func isZero*(n: IntImpl): bool {.inline.} =
asWords(n, ignoreEndianness = true): asWords(n, ignoreEndianness = true):
if n != 0: if n != 0:
return false return false
return true return true
func `<`*(x, y: UintImpl): bool {.inline.}= func isNegative*(n: IntImpl): bool {.inline.} =
# Lower comparison for multi-precision integers ## Returns true if a number is negative:
asWordsZip(x, y, ignoreEndianness = false): n.msb.bool
if x != y:
return x < y
return false # they're equal
func `==`*(x, y: UintImpl): bool {.inline.}=
# Equal comparison for multi-precision integers
asWordsZip(x, y, ignoreEndianness = true):
if x != y:
return false
return true # they're equal
func `<=`*(x, y: UintImpl): bool {.inline.}=
# Lower or equal comparison for multi-precision integers
asWordsZip(x, y, ignoreEndianness = false):
if x != y:
return x < y
return true # they're equal