87 lines
2.3 KiB
Nim
87 lines
2.3 KiB
Nim
# Stint
|
|
# Copyright 2018-Present 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
|
|
# Status lib
|
|
stew/bitops2,
|
|
# Internal
|
|
./datatypes
|
|
|
|
# Bitwise operations
|
|
# --------------------------------------------------------
|
|
{.push raises: [], inline, noinit, gcsafe.}
|
|
|
|
func bitnot*(r: var StUint, a: StUint) =
|
|
## Bitwise complement of unsigned integer a
|
|
## i.e. flips all bits of the input
|
|
for i in 0 ..< r.limbs.len:
|
|
r[i] = not a[i]
|
|
r.clearExtraBitsOverMSB()
|
|
|
|
func bitor*(r: var StUint, a, b: StUint) =
|
|
## `Bitwise or` of numbers a and b
|
|
for i in 0 ..< r.limbs.len:
|
|
r[i] = a[i] or b[i]
|
|
|
|
func bitand*(r: var StUint, a, b: StUint) =
|
|
## `Bitwise and` of numbers a and b
|
|
for i in 0 ..< r.limbs.len:
|
|
r[i] = a[i] and b[i]
|
|
|
|
func bitxor*(r: var StUint, a, b: StUint) =
|
|
## `Bitwise xor` of numbers x and y
|
|
for i in 0 ..< r.limbs.len:
|
|
r[i] = a[i] xor b[i]
|
|
r.clearExtraBitsOverMSB()
|
|
|
|
func countOnes*(a: StUint): int =
|
|
result = 0
|
|
for i in 0 ..< a.limbs.len:
|
|
result += countOnes(a[i])
|
|
|
|
func parity*(a: StUint): int =
|
|
result = parity(a.limbs[0])
|
|
for i in 1 ..< a.limbs.len:
|
|
result = result xor parity(a.limbs[i])
|
|
|
|
func leadingZeros*(a: StUint): int =
|
|
result = 0
|
|
|
|
# Adjust when we use only part of the word size
|
|
var extraBits = WordBitWidth * a.limbs.len - a.bits
|
|
|
|
for i in countdown(a.limbs.len-1, 0):
|
|
let zeroCount = a.limbs[i].leadingZeros()
|
|
if extraBits > 0:
|
|
result += zeroCount - min(extraBits, WordBitWidth)
|
|
extraBits -= WordBitWidth
|
|
else:
|
|
result += zeroCount
|
|
if zeroCount != WordBitWidth:
|
|
break
|
|
|
|
func trailingZeros*(a: StUint): int =
|
|
result = 0
|
|
for i in 0 ..< a.limbs.len:
|
|
let zeroCount = a[i].trailingZeros()
|
|
result += zeroCount
|
|
if zeroCount != WordBitWidth:
|
|
break
|
|
|
|
when a.limbs.len * WordBitWidth != a.bits:
|
|
if result > a.bits:
|
|
result = a.bits
|
|
|
|
func firstOne*(a: StUint): int =
|
|
result = trailingZeros(a)
|
|
if result == a.limbs.len * WordBitWidth:
|
|
result = 0
|
|
else:
|
|
result += 1
|