Added basic bit manipulation procs to bitops (#10338)
This commit is contained in:
parent
36e34d9aed
commit
0d480bfe22
2 changed files with 116 additions and 1 deletions
|
|
@ -8,7 +8,8 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements a series of low level methods for bit manipulation.
|
## This module implements a series of low level methods for bit manipulation.
|
||||||
## By default, this module use compiler intrinsics to improve performance
|
|
||||||
|
## By default, this module use compiler intrinsics where possible to improve performance
|
||||||
## on supported compilers: ``GCC``, ``LLVM_GCC``, ``CLANG``, ``VCC``, ``ICC``.
|
## on supported compilers: ``GCC``, ``LLVM_GCC``, ``CLANG``, ``VCC``, ``ICC``.
|
||||||
##
|
##
|
||||||
## The module will fallback to pure nim procs incase the backend is not supported.
|
## The module will fallback to pure nim procs incase the backend is not supported.
|
||||||
|
|
@ -32,6 +33,63 @@ const useICC_builtins = defined(icc) and useBuiltins
|
||||||
const useVCC_builtins = defined(vcc) and useBuiltins
|
const useVCC_builtins = defined(vcc) and useBuiltins
|
||||||
const arch64 = sizeof(int) == 8
|
const arch64 = sizeof(int) == 8
|
||||||
|
|
||||||
|
when defined(nimHasalignOf):
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
type BitsRange*[T] = range[0..sizeof(T)*8-1]
|
||||||
|
## Returns a range with all bit positions for type ``T``
|
||||||
|
|
||||||
|
proc setMask*[T: SomeInteger](v: var T, mask: T) {.inline.} =
|
||||||
|
## Returns ``v``, with all the ``1`` bits from ``mask`` set to 1
|
||||||
|
v = v or mask
|
||||||
|
|
||||||
|
proc clearMask*[T: SomeInteger](v: var T, mask: T) {.inline.} =
|
||||||
|
## Returns ``v``, with all the ``1`` bits from ``mask`` set to 0
|
||||||
|
v = v and not mask
|
||||||
|
|
||||||
|
proc flipMask*[T: SomeInteger](v: var T, mask: T) {.inline.} =
|
||||||
|
## Returns ``v``, with all the ``1`` bits from ``mask`` flipped
|
||||||
|
v = v xor mask
|
||||||
|
|
||||||
|
proc setBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} =
|
||||||
|
## Returns ``v``, with the bit at position ``bit`` set to 1
|
||||||
|
v.setMask(1.T shl bit)
|
||||||
|
|
||||||
|
proc clearBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} =
|
||||||
|
## Returns ``v``, with the bit at position ``bit`` set to 0
|
||||||
|
v.clearMask(1.T shl bit)
|
||||||
|
|
||||||
|
proc flipBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} =
|
||||||
|
## Returns ``v``, with the bit at position ``bit`` flipped
|
||||||
|
v.flipMask(1.T shl bit)
|
||||||
|
|
||||||
|
macro setBits*(v: typed, bits: varargs[typed]): untyped =
|
||||||
|
## Returns ``v``, with the bits at positions ``bits`` set to 1
|
||||||
|
bits.expectKind(nnkBracket)
|
||||||
|
result = newStmtList()
|
||||||
|
for bit in bits:
|
||||||
|
result.add newCall("setBit", v, bit)
|
||||||
|
|
||||||
|
macro clearBits*(v: typed, bits: varargs[typed]): untyped =
|
||||||
|
## Returns ``v``, with the bits at positions ``bits`` set to 0
|
||||||
|
bits.expectKind(nnkBracket)
|
||||||
|
result = newStmtList()
|
||||||
|
for bit in bits:
|
||||||
|
result.add newCall("clearBit", v, bit)
|
||||||
|
|
||||||
|
macro flipBits*(v: typed, bits: varargs[typed]): untyped =
|
||||||
|
## Returns ``v``, with the bits at positions ``bits`` set to 0
|
||||||
|
bits.expectKind(nnkBracket)
|
||||||
|
result = newStmtList()
|
||||||
|
for bit in bits:
|
||||||
|
result.add newCall("flipBit", v, bit)
|
||||||
|
|
||||||
|
proc testBit*[T: SomeInteger](v: var T, bit: BitsRange[T]): bool {.inline.} =
|
||||||
|
## Returns true if the bit in ``v`` at positions ``bit`` is set to 1
|
||||||
|
let mask = 1.T shl bit
|
||||||
|
return (v and mask) == mask
|
||||||
|
|
||||||
# #### Pure Nim version ####
|
# #### Pure Nim version ####
|
||||||
|
|
||||||
proc firstSetBit_nim(x: uint32): int {.inline, nosideeffect.} =
|
proc firstSetBit_nim(x: uint32): int {.inline, nosideeffect.} =
|
||||||
|
|
|
||||||
|
|
@ -162,6 +162,63 @@ proc main() =
|
||||||
doAssert( U64A.rotateLeftBits(64) == U64A)
|
doAssert( U64A.rotateLeftBits(64) == U64A)
|
||||||
doAssert( U64A.rotateRightBits(64) == U64A)
|
doAssert( U64A.rotateRightBits(64) == U64A)
|
||||||
|
|
||||||
|
block:
|
||||||
|
# mask operations
|
||||||
|
var v: uint8
|
||||||
|
v.setMask(0b1100_0000)
|
||||||
|
v.setMask(0b0000_1100)
|
||||||
|
doAssert(v == 0b1100_1100)
|
||||||
|
v.flipMask(0b0101_0101)
|
||||||
|
doAssert(v == 0b1001_1001)
|
||||||
|
v.clearMask(0b1000_1000)
|
||||||
|
doAssert(v == 0b0001_0001)
|
||||||
|
v.clearMask(0b0001_0001)
|
||||||
|
doAssert(v == 0b0000_0000)
|
||||||
|
block:
|
||||||
|
# single bit operations
|
||||||
|
var v: uint8
|
||||||
|
v.setBit(0)
|
||||||
|
doAssert v == 0x0000_0001
|
||||||
|
v.setBit(1)
|
||||||
|
doAssert v == 0b0000_0011
|
||||||
|
v.flipBit(7)
|
||||||
|
doAssert v == 0b1000_0011
|
||||||
|
v.clearBit(0)
|
||||||
|
doAssert v == 0b1000_0010
|
||||||
|
v.flipBit(1)
|
||||||
|
doAssert v == 0b1000_0000
|
||||||
|
doAssert v.testbit(7)
|
||||||
|
doAssert not v.testbit(6)
|
||||||
|
block:
|
||||||
|
# multi bit operations
|
||||||
|
var v: uint8
|
||||||
|
v.setBits(0, 1, 7)
|
||||||
|
doAssert v == 0b1000_0011
|
||||||
|
v.flipBits(2, 3)
|
||||||
|
doAssert v == 0b1000_1111
|
||||||
|
v.clearBits(7, 0, 1)
|
||||||
|
doAssert v == 0b0000_1100
|
||||||
|
block:
|
||||||
|
# signed
|
||||||
|
var v: int8
|
||||||
|
v.setBit(7)
|
||||||
|
doAssert v == -128
|
||||||
|
block:
|
||||||
|
var v: uint64
|
||||||
|
v.setBit(63)
|
||||||
|
doAssert v == 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000'u64
|
||||||
|
block:
|
||||||
|
# Test if RangeError is thrown if indexing out of range
|
||||||
|
try:
|
||||||
|
var v: uint32
|
||||||
|
var i = 32
|
||||||
|
v.setBit(i)
|
||||||
|
doAssert false
|
||||||
|
except RangeError:
|
||||||
|
discard
|
||||||
|
except:
|
||||||
|
doAssert false
|
||||||
|
|
||||||
echo "OK"
|
echo "OK"
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue