diff --git a/lib/pure/bitops.nim b/lib/pure/bitops.nim index 8cc5a9fed7..19e4d38536 100644 --- a/lib/pure/bitops.nim +++ b/lib/pure/bitops.nim @@ -446,3 +446,48 @@ proc rotateRightBits*(value: uint64; ## Right-rotate bits in a 64-bits value. let amount = amount and 63 result = (value shr amount) or (value shl ( (-amount) and 63)) + +proc repeatBits[T: SomeUnsignedInt](x: SomeUnsignedInt; retType: type[T]): T {. + noSideEffect.} = + result = x + var i = 1 + while i != (sizeof(T) div sizeof(x)): + result = (result shl (sizeof(x)*8*i)) or result + i *= 2 + +proc reverseBits*[T: SomeUnsignedInt](x: T): T {.noSideEffect.} = + ## Return the bit reversal of x. + runnableExamples: + doAssert reverseBits(0b10100100'u8) == 0b00100101'u8 + doAssert reverseBits(0xdd'u8) == 0xbb'u8 + doAssert reverseBits(0xddbb'u16) == 0xddbb'u16 + doAssert reverseBits(0xdeadbeef'u32) == 0xf77db57b'u32 + + template repeat(x: SomeUnsignedInt): T = repeatBits(x, T) + + result = x + result = + ((repeat(0x55u8) and result) shl 1) or + ((repeat(0xaau8) and result) shr 1) + result = + ((repeat(0x33u8) and result) shl 2) or + ((repeat(0xccu8) and result) shr 2) + when sizeof(T) == 1: + result = (result shl 4) or (result shr 4) + when sizeof(T) >= 2: + result = + ((repeat(0x0fu8) and result) shl 4) or + ((repeat(0xf0u8) and result) shr 4) + when sizeof(T) == 2: + result = (result shl 8) or (result shr 8) + when sizeof(T) >= 4: + result = + ((repeat(0x00ffu16) and result) shl 8) or + ((repeat(0xff00u16) and result) shr 8) + when sizeof(T) == 4: + result = (result shl 16) or (result shr 16) + when sizeof(T) == 8: + result = + ((repeat(0x0000ffffu32) and result) shl 16) or + ((repeat(0xffff0000u32) and result) shr 16) + result = (result shl 32) or (result shr 32) diff --git a/tests/stdlib/tbitops.nim b/tests/stdlib/tbitops.nim index 1cbab48707..640b289a1a 100644 --- a/tests/stdlib/tbitops.nim +++ b/tests/stdlib/tbitops.nim @@ -169,6 +169,48 @@ proc main() = v.setBit(63) doAssert v == 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000'u64 + block: + proc testReverseBitsInvo(x: SomeUnsignedInt) = + doAssert(reverseBits(reverseBits(x)) == x) + + proc testReverseBitsPerType(x, reversed: uint64) = + doAssert reverseBits(x) == reversed + doAssert reverseBits(uint32(x)) == uint32(reversed shr 32) + doAssert reverseBits(uint32(x shr 16)) == uint32(reversed shr 16) + doAssert reverseBits(uint16(x)) == uint16(reversed shr 48) + doAssert reverseBits(uint8(x)) == uint8(reversed shr 56) + + testReverseBitsInvo(x) + testReverseBitsInvo(uint32(x)) + testReverseBitsInvo(uint16(x)) + testReverseBitsInvo(uint8(x)) + + proc testReverseBitsRefl(x, reversed: uint64) = + testReverseBitsPerType(x, reversed) + testReverseBitsPerType(reversed, x) + + proc testReverseBitsShift(d, b: uint64) = + var + x = d + y = b + + for i in 1..64: + testReverseBitsRefl(x, y) + x = x shl 1 + y = y shr 1 + + proc testReverseBits(d, b: uint64) = + testReverseBitsShift(d, b) + + testReverseBits(0x0u64, 0x0u64) + testReverseBits(0xffffffffffffffffu64, 0xffffffffffffffffu64) + testReverseBits(0x0123456789abcdefu64, 0xf7b3d591e6a2c480u64) + testReverseBits(0x5555555555555555u64, 0xaaaaaaaaaaaaaaaau64) + testReverseBits(0x5555555500000001u64, 0x80000000aaaaaaaau64) + testReverseBits(0x55555555aaaaaaaau64, 0x55555555aaaaaaaau64) + testReverseBits(0xf0f0f0f00f0f0f0fu64, 0xf0f0f0f00f0f0f0fu64) + testReverseBits(0x181881810ff00916u64, 0x68900ff081811818u64) + echo "OK" block: # not ready for vm because exception is compile error