Add runnableExamples to bitops module (#13951)
* doc: bitops: add runnableExamples * doc: bitops: add notes to documentation comments of macros * doc: bitops: add periods to documentation comments * doc: bitops: add static * Revert "doc: bitops: add static" This reverts commit 595ee134abcd451e73ddde963c1b3e49a275f2e5. * doc: bitops: add `var` to arguments of macros * doc: bitops: remove examples of testBit
This commit is contained in:
parent
8ba915e449
commit
40b64ccd7b
1 changed files with 143 additions and 15 deletions
|
|
@ -68,55 +68,109 @@ when defined(nimHasalignOf):
|
||||||
import macros
|
import macros
|
||||||
|
|
||||||
type BitsRange*[T] = range[0..sizeof(T)*8-1]
|
type BitsRange*[T] = range[0..sizeof(T)*8-1]
|
||||||
## Returns a range with all bit positions for type ``T``
|
## Returns a range with all bit positions for type ``T``.
|
||||||
|
|
||||||
proc setMask*[T: SomeInteger](v: var T, mask: T) {.inline.} =
|
proc setMask*[T: SomeInteger](v: var T, mask: T) {.inline.} =
|
||||||
## Returns ``v``, with all the ``1`` bits from ``mask`` set to 1
|
## Returns ``v``, with all the ``1`` bits from ``mask`` set to 1.
|
||||||
|
runnableExamples:
|
||||||
|
var v = 0b0000_0011'u8
|
||||||
|
v.setMask(0b0000_1010'u8)
|
||||||
|
doAssert v == 0b0000_1011'u8
|
||||||
|
|
||||||
v = v or mask
|
v = v or mask
|
||||||
|
|
||||||
proc clearMask*[T: SomeInteger](v: var T, mask: T) {.inline.} =
|
proc clearMask*[T: SomeInteger](v: var T, mask: T) {.inline.} =
|
||||||
## Returns ``v``, with all the ``1`` bits from ``mask`` set to 0
|
## Returns ``v``, with all the ``1`` bits from ``mask`` set to 0.
|
||||||
|
runnableExamples:
|
||||||
|
var v = 0b0000_0011'u8
|
||||||
|
v.clearMask(0b0000_1010'u8)
|
||||||
|
doAssert v == 0b0000_0001'u8
|
||||||
|
|
||||||
v = v and not mask
|
v = v and not mask
|
||||||
|
|
||||||
proc flipMask*[T: SomeInteger](v: var T, mask: T) {.inline.} =
|
proc flipMask*[T: SomeInteger](v: var T, mask: T) {.inline.} =
|
||||||
## Returns ``v``, with all the ``1`` bits from ``mask`` flipped
|
## Returns ``v``, with all the ``1`` bits from ``mask`` flipped.
|
||||||
|
runnableExamples:
|
||||||
|
var v = 0b0000_0011'u8
|
||||||
|
v.flipMask(0b0000_1010'u8)
|
||||||
|
doAssert v == 0b0000_1001'u8
|
||||||
|
|
||||||
v = v xor mask
|
v = v xor mask
|
||||||
|
|
||||||
proc setBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} =
|
proc setBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} =
|
||||||
## Returns ``v``, with the bit at position ``bit`` set to 1
|
## Returns ``v``, with the bit at position ``bit`` set to 1.
|
||||||
|
runnableExamples:
|
||||||
|
var v = 0b0000_0011'u8
|
||||||
|
v.setBit(5'u8)
|
||||||
|
doAssert v == 0b0010_0011'u8
|
||||||
|
|
||||||
v.setMask(1.T shl bit)
|
v.setMask(1.T shl bit)
|
||||||
|
|
||||||
proc clearBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} =
|
proc clearBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} =
|
||||||
## Returns ``v``, with the bit at position ``bit`` set to 0
|
## Returns ``v``, with the bit at position ``bit`` set to 0.
|
||||||
|
runnableExamples:
|
||||||
|
var v = 0b0000_0011'u8
|
||||||
|
v.clearBit(1'u8)
|
||||||
|
doAssert v == 0b0000_0001'u8
|
||||||
|
|
||||||
v.clearMask(1.T shl bit)
|
v.clearMask(1.T shl bit)
|
||||||
|
|
||||||
proc flipBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} =
|
proc flipBit*[T: SomeInteger](v: var T, bit: BitsRange[T]) {.inline.} =
|
||||||
## Returns ``v``, with the bit at position ``bit`` flipped
|
## Returns ``v``, with the bit at position ``bit`` flipped.
|
||||||
|
runnableExamples:
|
||||||
|
var v = 0b0000_0011'u8
|
||||||
|
v.flipBit(1'u8)
|
||||||
|
doAssert v == 0b0000_0001'u8
|
||||||
|
|
||||||
|
v = 0b0000_0011'u8
|
||||||
|
v.flipBit(2'u8)
|
||||||
|
doAssert v == 0b0000_0111'u8
|
||||||
|
|
||||||
v.flipMask(1.T shl bit)
|
v.flipMask(1.T shl bit)
|
||||||
|
|
||||||
macro setBits*(v: typed, bits: varargs[typed]): untyped =
|
macro setBits*(v: var typed, bits: varargs[typed]): untyped =
|
||||||
## Returns ``v``, with the bits at positions ``bits`` set to 1
|
## Returns ``v``, with the bits at positions ``bits`` set to 1.
|
||||||
|
runnableExamples:
|
||||||
|
var v = 0b0000_0011'u8
|
||||||
|
v.setBits(3, 5, 7)
|
||||||
|
doAssert v == 0b1010_1011'u8
|
||||||
|
|
||||||
bits.expectKind(nnkBracket)
|
bits.expectKind(nnkBracket)
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
for bit in bits:
|
for bit in bits:
|
||||||
result.add newCall("setBit", v, bit)
|
result.add newCall("setBit", v, bit)
|
||||||
|
|
||||||
macro clearBits*(v: typed, bits: varargs[typed]): untyped =
|
macro clearBits*(v: var typed, bits: varargs[typed]): untyped =
|
||||||
## Returns ``v``, with the bits at positions ``bits`` set to 0
|
## Returns ``v``, with the bits at positions ``bits`` set to 0.
|
||||||
|
runnableExamples:
|
||||||
|
var v = 0b1111_1111'u8
|
||||||
|
v.clearBits(1, 3, 5, 7)
|
||||||
|
doAssert v == 0b0101_0101'u8
|
||||||
|
|
||||||
bits.expectKind(nnkBracket)
|
bits.expectKind(nnkBracket)
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
for bit in bits:
|
for bit in bits:
|
||||||
result.add newCall("clearBit", v, bit)
|
result.add newCall("clearBit", v, bit)
|
||||||
|
|
||||||
macro flipBits*(v: typed, bits: varargs[typed]): untyped =
|
macro flipBits*(v: var typed, bits: varargs[typed]): untyped =
|
||||||
## Returns ``v``, with the bits at positions ``bits`` set to 0
|
## Returns ``v``, with the bits at positions ``bits`` set to 0.
|
||||||
|
runnableExamples:
|
||||||
|
var v = 0b0000_1111'u8
|
||||||
|
v.flipBits(1, 3, 5, 7)
|
||||||
|
doAssert v == 0b1010_0101'u8
|
||||||
|
|
||||||
bits.expectKind(nnkBracket)
|
bits.expectKind(nnkBracket)
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
for bit in bits:
|
for bit in bits:
|
||||||
result.add newCall("flipBit", v, bit)
|
result.add newCall("flipBit", v, bit)
|
||||||
|
|
||||||
proc testBit*[T: SomeInteger](v: T, bit: BitsRange[T]): bool {.inline.} =
|
proc testBit*[T: SomeInteger](v: T, bit: BitsRange[T]): bool {.inline.} =
|
||||||
## Returns true if the bit in ``v`` at positions ``bit`` is set to 1
|
## Returns true if the bit in ``v`` at positions ``bit`` is set to 1.
|
||||||
|
runnableExamples:
|
||||||
|
var v = 0b0000_1111'u8
|
||||||
|
doAssert v.testBit(0)
|
||||||
|
doAssert not v.testBit(7)
|
||||||
|
|
||||||
let mask = 1.T shl bit
|
let mask = 1.T shl bit
|
||||||
return (v and mask) == mask
|
return (v and mask) == mask
|
||||||
|
|
||||||
|
|
@ -272,6 +326,10 @@ elif useICC_builtins:
|
||||||
|
|
||||||
proc countSetBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
proc countSetBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||||
## Counts the set bits in integer. (also called `Hamming weight`:idx:.)
|
## Counts the set bits in integer. (also called `Hamming weight`:idx:.)
|
||||||
|
runnableExamples:
|
||||||
|
doAssert countSetBits(0b0000_0011'u8) == 2
|
||||||
|
doAssert countSetBits(0b1010_1010'u8) == 4
|
||||||
|
|
||||||
# TODO: figure out if ICC support _popcnt32/_popcnt64 on platform without POPCNT.
|
# TODO: figure out if ICC support _popcnt32/_popcnt64 on platform without POPCNT.
|
||||||
# like GCC and MSVC
|
# like GCC and MSVC
|
||||||
when x is SomeSignedInt:
|
when x is SomeSignedInt:
|
||||||
|
|
@ -298,12 +356,18 @@ proc countSetBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||||
else: result = countSetBitsNim(x.uint64)
|
else: result = countSetBitsNim(x.uint64)
|
||||||
|
|
||||||
proc popcount*(x: SomeInteger): int {.inline, noSideEffect.} =
|
proc popcount*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||||
## Alias for for countSetBits (Hamming weight.)
|
## Alias for for `countSetBits <#countSetBits,SomeInteger>`_. (Hamming weight.)
|
||||||
result = countSetBits(x)
|
result = countSetBits(x)
|
||||||
|
|
||||||
proc parityBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
proc parityBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||||
## Calculate the bit parity in integer. If number of 1-bit
|
## Calculate the bit parity in integer. If number of 1-bit
|
||||||
## is odd parity is 1, otherwise 0.
|
## is odd parity is 1, otherwise 0.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert parityBits(0b0000_0000'u8) == 0
|
||||||
|
doAssert parityBits(0b0101_0001'u8) == 1
|
||||||
|
doAssert parityBits(0b0110_1001'u8) == 0
|
||||||
|
doAssert parityBits(0b0111_1111'u8) == 1
|
||||||
|
|
||||||
# Can be used a base if creating ASM version.
|
# Can be used a base if creating ASM version.
|
||||||
# https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd
|
# https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd
|
||||||
when x is SomeSignedInt:
|
when x is SomeSignedInt:
|
||||||
|
|
@ -322,6 +386,13 @@ proc firstSetBit*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||||
## Returns the 1-based index of the least significant set bit of x.
|
## Returns the 1-based index of the least significant set bit of x.
|
||||||
## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0,
|
## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0,
|
||||||
## otherwise result is undefined.
|
## otherwise result is undefined.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert firstSetBit(0b0000_0001'u8) == 1
|
||||||
|
doAssert firstSetBit(0b0000_0010'u8) == 2
|
||||||
|
doAssert firstSetBit(0b0000_0100'u8) == 3
|
||||||
|
doAssert firstSetBit(0b0000_1000'u8) == 4
|
||||||
|
doAssert firstSetBit(0b0000_1111'u8) == 1
|
||||||
|
|
||||||
# GCC builtin 'builtin_ffs' already handle zero input.
|
# GCC builtin 'builtin_ffs' already handle zero input.
|
||||||
when x is SomeSignedInt:
|
when x is SomeSignedInt:
|
||||||
let x = x.toUnsigned
|
let x = x.toUnsigned
|
||||||
|
|
@ -359,6 +430,13 @@ proc fastLog2*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||||
## Quickly find the log base 2 of an integer.
|
## Quickly find the log base 2 of an integer.
|
||||||
## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is -1,
|
## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is -1,
|
||||||
## otherwise result is undefined.
|
## otherwise result is undefined.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert fastLog2(0b0000_0001'u8) == 0
|
||||||
|
doAssert fastLog2(0b0000_0010'u8) == 1
|
||||||
|
doAssert fastLog2(0b0000_0100'u8) == 2
|
||||||
|
doAssert fastLog2(0b0000_1000'u8) == 3
|
||||||
|
doAssert fastLog2(0b0000_1111'u8) == 3
|
||||||
|
|
||||||
when x is SomeSignedInt:
|
when x is SomeSignedInt:
|
||||||
let x = x.toUnsigned
|
let x = x.toUnsigned
|
||||||
when noUndefined:
|
when noUndefined:
|
||||||
|
|
@ -392,6 +470,16 @@ proc countLeadingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||||
## Returns the number of leading zero bits in integer.
|
## Returns the number of leading zero bits in integer.
|
||||||
## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0,
|
## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0,
|
||||||
## otherwise result is undefined.
|
## otherwise result is undefined.
|
||||||
|
##
|
||||||
|
## See also:
|
||||||
|
## * `countTrailingZeroBits proc <#countTrailingZeroBits,SomeInteger>`_
|
||||||
|
runnableExamples:
|
||||||
|
doAssert countLeadingZeroBits(0b0000_0001'u8) == 7
|
||||||
|
doAssert countLeadingZeroBits(0b0000_0010'u8) == 6
|
||||||
|
doAssert countLeadingZeroBits(0b0000_0100'u8) == 5
|
||||||
|
doAssert countLeadingZeroBits(0b0000_1000'u8) == 4
|
||||||
|
doAssert countLeadingZeroBits(0b0000_1111'u8) == 4
|
||||||
|
|
||||||
when x is SomeSignedInt:
|
when x is SomeSignedInt:
|
||||||
let x = x.toUnsigned
|
let x = x.toUnsigned
|
||||||
when noUndefined:
|
when noUndefined:
|
||||||
|
|
@ -411,6 +499,16 @@ proc countTrailingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||||
## Returns the number of trailing zeros in integer.
|
## Returns the number of trailing zeros in integer.
|
||||||
## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0,
|
## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0,
|
||||||
## otherwise result is undefined.
|
## otherwise result is undefined.
|
||||||
|
##
|
||||||
|
## See also:
|
||||||
|
## * `countLeadingZeroBits proc <#countLeadingZeroBits,SomeInteger>`_
|
||||||
|
runnableExamples:
|
||||||
|
doAssert countTrailingZeroBits(0b0000_0001'u8) == 0
|
||||||
|
doAssert countTrailingZeroBits(0b0000_0010'u8) == 1
|
||||||
|
doAssert countTrailingZeroBits(0b0000_0100'u8) == 2
|
||||||
|
doAssert countTrailingZeroBits(0b0000_1000'u8) == 3
|
||||||
|
doAssert countTrailingZeroBits(0b0000_1111'u8) == 0
|
||||||
|
|
||||||
when x is SomeSignedInt:
|
when x is SomeSignedInt:
|
||||||
let x = x.toUnsigned
|
let x = x.toUnsigned
|
||||||
when noUndefined:
|
when noUndefined:
|
||||||
|
|
@ -429,6 +527,12 @@ proc countTrailingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} =
|
||||||
proc rotateLeftBits*(value: uint8;
|
proc rotateLeftBits*(value: uint8;
|
||||||
amount: range[0..8]): uint8 {.inline, noSideEffect.} =
|
amount: range[0..8]): uint8 {.inline, noSideEffect.} =
|
||||||
## Left-rotate bits in a 8-bits value.
|
## Left-rotate bits in a 8-bits value.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert rotateLeftBits(0b0000_0001'u8, 1) == 0b0000_0010'u8
|
||||||
|
doAssert rotateLeftBits(0b0000_0001'u8, 2) == 0b0000_0100'u8
|
||||||
|
doAssert rotateLeftBits(0b0100_0001'u8, 1) == 0b1000_0010'u8
|
||||||
|
doAssert rotateLeftBits(0b0100_0001'u8, 2) == 0b0000_0101'u8
|
||||||
|
|
||||||
# using this form instead of the one below should handle any value
|
# using this form instead of the one below should handle any value
|
||||||
# out of range as well as negative values.
|
# out of range as well as negative values.
|
||||||
# result = (value shl amount) or (value shr (8 - amount))
|
# result = (value shl amount) or (value shr (8 - amount))
|
||||||
|
|
@ -439,18 +543,27 @@ proc rotateLeftBits*(value: uint8;
|
||||||
proc rotateLeftBits*(value: uint16;
|
proc rotateLeftBits*(value: uint16;
|
||||||
amount: range[0..16]): uint16 {.inline, noSideEffect.} =
|
amount: range[0..16]): uint16 {.inline, noSideEffect.} =
|
||||||
## Left-rotate bits in a 16-bits value.
|
## Left-rotate bits in a 16-bits value.
|
||||||
|
##
|
||||||
|
## See also:
|
||||||
|
## * `rotateLeftBits proc <#rotateLeftBits,uint8,range[]>`_
|
||||||
let amount = amount and 15
|
let amount = amount and 15
|
||||||
result = (value shl amount) or (value shr ( (-amount) and 15))
|
result = (value shl amount) or (value shr ( (-amount) and 15))
|
||||||
|
|
||||||
proc rotateLeftBits*(value: uint32;
|
proc rotateLeftBits*(value: uint32;
|
||||||
amount: range[0..32]): uint32 {.inline, noSideEffect.} =
|
amount: range[0..32]): uint32 {.inline, noSideEffect.} =
|
||||||
## Left-rotate bits in a 32-bits value.
|
## Left-rotate bits in a 32-bits value.
|
||||||
|
##
|
||||||
|
## See also:
|
||||||
|
## * `rotateLeftBits proc <#rotateLeftBits,uint8,range[]>`_
|
||||||
let amount = amount and 31
|
let amount = amount and 31
|
||||||
result = (value shl amount) or (value shr ( (-amount) and 31))
|
result = (value shl amount) or (value shr ( (-amount) and 31))
|
||||||
|
|
||||||
proc rotateLeftBits*(value: uint64;
|
proc rotateLeftBits*(value: uint64;
|
||||||
amount: range[0..64]): uint64 {.inline, noSideEffect.} =
|
amount: range[0..64]): uint64 {.inline, noSideEffect.} =
|
||||||
## Left-rotate bits in a 64-bits value.
|
## Left-rotate bits in a 64-bits value.
|
||||||
|
##
|
||||||
|
## See also:
|
||||||
|
## * `rotateLeftBits proc <#rotateLeftBits,uint8,range[]>`_
|
||||||
let amount = amount and 63
|
let amount = amount and 63
|
||||||
result = (value shl amount) or (value shr ( (-amount) and 63))
|
result = (value shl amount) or (value shr ( (-amount) and 63))
|
||||||
|
|
||||||
|
|
@ -458,24 +571,39 @@ proc rotateLeftBits*(value: uint64;
|
||||||
proc rotateRightBits*(value: uint8;
|
proc rotateRightBits*(value: uint8;
|
||||||
amount: range[0..8]): uint8 {.inline, noSideEffect.} =
|
amount: range[0..8]): uint8 {.inline, noSideEffect.} =
|
||||||
## Right-rotate bits in a 8-bits value.
|
## Right-rotate bits in a 8-bits value.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert rotateRightBits(0b0000_0001'u8, 1) == 0b1000_0000'u8
|
||||||
|
doAssert rotateRightBits(0b0000_0001'u8, 2) == 0b0100_0000'u8
|
||||||
|
doAssert rotateRightBits(0b0100_0001'u8, 1) == 0b1010_0000'u8
|
||||||
|
doAssert rotateRightBits(0b0100_0001'u8, 2) == 0b0101_0000'u8
|
||||||
|
|
||||||
let amount = amount and 7
|
let amount = amount and 7
|
||||||
result = (value shr amount) or (value shl ( (-amount) and 7))
|
result = (value shr amount) or (value shl ( (-amount) and 7))
|
||||||
|
|
||||||
proc rotateRightBits*(value: uint16;
|
proc rotateRightBits*(value: uint16;
|
||||||
amount: range[0..16]): uint16 {.inline, noSideEffect.} =
|
amount: range[0..16]): uint16 {.inline, noSideEffect.} =
|
||||||
## Right-rotate bits in a 16-bits value.
|
## Right-rotate bits in a 16-bits value.
|
||||||
|
##
|
||||||
|
## See also:
|
||||||
|
## * `rotateRightBits proc <#rotateRightBits,uint8,range[]>`_
|
||||||
let amount = amount and 15
|
let amount = amount and 15
|
||||||
result = (value shr amount) or (value shl ( (-amount) and 15))
|
result = (value shr amount) or (value shl ( (-amount) and 15))
|
||||||
|
|
||||||
proc rotateRightBits*(value: uint32;
|
proc rotateRightBits*(value: uint32;
|
||||||
amount: range[0..32]): uint32 {.inline, noSideEffect.} =
|
amount: range[0..32]): uint32 {.inline, noSideEffect.} =
|
||||||
## Right-rotate bits in a 32-bits value.
|
## Right-rotate bits in a 32-bits value.
|
||||||
|
##
|
||||||
|
## See also:
|
||||||
|
## * `rotateRightBits proc <#rotateRightBits,uint8,range[]>`_
|
||||||
let amount = amount and 31
|
let amount = amount and 31
|
||||||
result = (value shr amount) or (value shl ( (-amount) and 31))
|
result = (value shr amount) or (value shl ( (-amount) and 31))
|
||||||
|
|
||||||
proc rotateRightBits*(value: uint64;
|
proc rotateRightBits*(value: uint64;
|
||||||
amount: range[0..64]): uint64 {.inline, noSideEffect.} =
|
amount: range[0..64]): uint64 {.inline, noSideEffect.} =
|
||||||
## Right-rotate bits in a 64-bits value.
|
## Right-rotate bits in a 64-bits value.
|
||||||
|
##
|
||||||
|
## See also:
|
||||||
|
## * `rotateRightBits proc <#rotateRightBits,uint8,range[]>`_
|
||||||
let amount = amount and 63
|
let amount = amount and 63
|
||||||
result = (value shr amount) or (value shl ( (-amount) and 63))
|
result = (value shr amount) or (value shl ( (-amount) and 63))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue