diff options
author | Ico Doornekamp <github@zevv.nl> | 2019-01-23 09:16:14 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2019-01-23 09:16:14 +0100 |
commit | 0d480bfe22651edc9bdf7c5976668b47eb61b0a5 (patch) | |
tree | a82f206749e30be63e7c210a29c3d526cbebcfc4 | |
parent | 36e34d9aedd5d6f39dcc78a2239752c94227c542 (diff) | |
download | Nim-0d480bfe22651edc9bdf7c5976668b47eb61b0a5.tar.gz |
Added basic bit manipulation procs to bitops (#10338)
-rw-r--r-- | lib/pure/bitops.nim | 60 | ||||
-rw-r--r-- | tests/stdlib/tbitops.nim | 57 |
2 files changed, 116 insertions, 1 deletions
diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 3f213c5ea..d258a42de 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -8,7 +8,8 @@ # ## 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``. ## ## 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 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 #### proc firstSetBit_nim(x: uint32): int {.inline, nosideeffect.} = diff --git a/tests/stdlib/tbitops.nim b/tests/stdlib/tbitops.nim index d8c6da1d4..b8b44703c 100644 --- a/tests/stdlib/tbitops.nim +++ b/tests/stdlib/tbitops.nim @@ -162,6 +162,63 @@ proc main() = doAssert( U64A.rotateLeftBits(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" main() |