diff options
author | jiro <jiroron666@gmail.com> | 2020-04-13 21:21:45 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-13 14:21:45 +0200 |
commit | 40b64ccd7b2d6c42ebe3c3ad1e7fdfa3fa7a00dd (patch) | |
tree | acd3a7cf7050f0f339f6d90ef02204f2934b5510 /lib/pure/bitops.nim | |
parent | 8ba915e4498be3d17af894f5fb46c7b621ef5abb (diff) | |
download | Nim-40b64ccd7b2d6c42ebe3c3ad1e7fdfa3fa7a00dd.tar.gz |
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
Diffstat (limited to 'lib/pure/bitops.nim')
-rw-r--r-- | lib/pure/bitops.nim | 158 |
1 files changed, 143 insertions, 15 deletions
diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 9ebdabb7b..cf6013c77 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -68,55 +68,109 @@ when defined(nimHasalignOf): import macros 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.} = - ## 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 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 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 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) 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) 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) - macro setBits*(v: typed, bits: varargs[typed]): untyped = - ## Returns ``v``, with the bits at positions ``bits`` set to 1 + macro setBits*(v: var typed, bits: varargs[typed]): untyped = + ## 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) 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 + macro clearBits*(v: var typed, bits: varargs[typed]): untyped = + ## 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) 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 + macro flipBits*(v: var typed, bits: varargs[typed]): untyped = + ## 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) result = newStmtList() for bit in bits: result.add newCall("flipBit", v, bit) 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 return (v and mask) == mask @@ -272,6 +326,10 @@ elif useICC_builtins: proc countSetBits*(x: SomeInteger): int {.inline, noSideEffect.} = ## 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. # like GCC and MSVC when x is SomeSignedInt: @@ -298,12 +356,18 @@ proc countSetBits*(x: SomeInteger): int {.inline, noSideEffect.} = else: result = countSetBitsNim(x.uint64) proc popcount*(x: SomeInteger): int {.inline, noSideEffect.} = - ## Alias for for countSetBits (Hamming weight.) + ## Alias for for `countSetBits <#countSetBits,SomeInteger>`_. (Hamming weight.) result = countSetBits(x) proc parityBits*(x: SomeInteger): int {.inline, noSideEffect.} = ## Calculate the bit parity in integer. If number of 1-bit ## 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. # https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd 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. ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0, ## 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. when x is SomeSignedInt: let x = x.toUnsigned @@ -359,6 +430,13 @@ proc fastLog2*(x: SomeInteger): int {.inline, noSideEffect.} = ## Quickly find the log base 2 of an integer. ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is -1, ## 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: let x = x.toUnsigned when noUndefined: @@ -392,6 +470,16 @@ proc countLeadingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} = ## Returns the number of leading zero bits in integer. ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0, ## 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: let x = x.toUnsigned when noUndefined: @@ -411,6 +499,16 @@ proc countTrailingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} = ## Returns the number of trailing zeros in integer. ## If `x` is zero, when ``noUndefinedBitOpts`` is set, result is 0, ## 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: let x = x.toUnsigned when noUndefined: @@ -429,6 +527,12 @@ proc countTrailingZeroBits*(x: SomeInteger): int {.inline, noSideEffect.} = proc rotateLeftBits*(value: uint8; amount: range[0..8]): uint8 {.inline, noSideEffect.} = ## 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 # out of range as well as negative values. # result = (value shl amount) or (value shr (8 - amount)) @@ -439,18 +543,27 @@ proc rotateLeftBits*(value: uint8; proc rotateLeftBits*(value: uint16; amount: range[0..16]): uint16 {.inline, noSideEffect.} = ## Left-rotate bits in a 16-bits value. + ## + ## See also: + ## * `rotateLeftBits proc <#rotateLeftBits,uint8,range[]>`_ let amount = amount and 15 result = (value shl amount) or (value shr ( (-amount) and 15)) proc rotateLeftBits*(value: uint32; amount: range[0..32]): uint32 {.inline, noSideEffect.} = ## Left-rotate bits in a 32-bits value. + ## + ## See also: + ## * `rotateLeftBits proc <#rotateLeftBits,uint8,range[]>`_ let amount = amount and 31 result = (value shl amount) or (value shr ( (-amount) and 31)) proc rotateLeftBits*(value: uint64; amount: range[0..64]): uint64 {.inline, noSideEffect.} = ## Left-rotate bits in a 64-bits value. + ## + ## See also: + ## * `rotateLeftBits proc <#rotateLeftBits,uint8,range[]>`_ let amount = 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; amount: range[0..8]): uint8 {.inline, noSideEffect.} = ## 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 result = (value shr amount) or (value shl ( (-amount) and 7)) proc rotateRightBits*(value: uint16; amount: range[0..16]): uint16 {.inline, noSideEffect.} = ## Right-rotate bits in a 16-bits value. + ## + ## See also: + ## * `rotateRightBits proc <#rotateRightBits,uint8,range[]>`_ let amount = amount and 15 result = (value shr amount) or (value shl ( (-amount) and 15)) proc rotateRightBits*(value: uint32; amount: range[0..32]): uint32 {.inline, noSideEffect.} = ## Right-rotate bits in a 32-bits value. + ## + ## See also: + ## * `rotateRightBits proc <#rotateRightBits,uint8,range[]>`_ let amount = amount and 31 result = (value shr amount) or (value shl ( (-amount) and 31)) proc rotateRightBits*(value: uint64; amount: range[0..64]): uint64 {.inline, noSideEffect.} = ## Right-rotate bits in a 64-bits value. + ## + ## See also: + ## * `rotateRightBits proc <#rotateRightBits,uint8,range[]>`_ let amount = amount and 63 result = (value shr amount) or (value shl ( (-amount) and 63)) |