Add bitops2.getBitsBE

This commit is contained in:
Zahary Karadjov 2020-06-01 19:49:46 +03:00
parent a99dafab42
commit b9e847a143
No known key found for this signature in database
GPG Key ID: C8936F8A3073D609
2 changed files with 86 additions and 0 deletions

View File

@ -20,6 +20,9 @@
{.push raises: [].}
import
endians2
const
useBuiltins = not defined(noIntrinsicsBitOpts)
@ -595,3 +598,47 @@ template lowerBitLE*(bytes: var openarray[byte], pos: Natural) {.deprecated: "cl
clearBitLE(bytes, pos)
template lowerBitBE*(bytes: var openarray[byte], pos: Natural) {.deprecated: "clearBitBE".} =
clearBitBE(bytes, pos)
func getBitsBE*(data: openarray[byte], slice: HSlice, T: type[SomeUnsignedInt]): T =
## Treats `data` as an unsigned big endian integer and returns a slice of bits
## extracted from it, assuming 0 to be the possition of the most significant bit.
let totalBits = data.len * 8
template normalizeIdx(idx): int =
when idx is BackwardsIndex: totalBits - int(idx)
else: int(idx)
let
a = normalizeIdx(slice.a)
b = normalizeIdx(slice.b) + 1
sliceLen = b - a
const resultBits = sizeof(result) * 8
doAssert a < b and sliceLen <= resultBits and b <= totalBits
let limbs = cast[ptr UncheckedArray[T]](unsafeAddr data[0])
template readLimb(idx: int): auto =
when cpuEndian == bigEndian or sizeof(result) == 1:
limbs[][idx]
else:
swapBytes(limbs[][idx])
let
firstLimbIdx = a div resultBits
firstLimbUnusedBits = (a mod resultBits)
firstLimbUsedBits = resultBits - firstLimbUnusedBits
firstLimb = readLimb firstLimbIdx
if sliceLen > firstLimbUsedBits:
let
bitsFromSecondLimb = sliceLen - firstLimbUsedBits
secondLimb = readLimb(firstLimbIdx + 1)
((firstLimb shl firstLimbUnusedBits) shr (firstLimbUnusedBits - bitsFromSecondLimb)) or
(secondLimb shr (resultBits - bitsFromSecondLimb))
else:
(firstLimb shl firstLimbUnusedBits) shr (resultBits - sliceLen)
template getBitsBE*(data: openarray[byte], slice: HSlice): BiggestUInt =
getBitsBE(data, slice, BiggestUInt)

View File

@ -86,8 +86,47 @@ template test() =
# T(1 shl 63) raises!
doAssert bit64 == 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000'u64
proc runtimeTest =
var bytes = @[byte 0b11001101, 0b10010010, 0b00000000, 0b11111111,
0b11000010, 0b00110110, 0b11010110, 0b00101010,
0b01101110, 0b11101001, 0b10101011, 0b00110010]
doAssert getBitsBE(bytes, 0..0, byte) == byte(1)
doAssert getBitsBE(bytes, 1..1, byte) == byte(1)
doAssert getBitsBE(bytes, 2..2, byte) == byte(0)
doAssert getBitsBE(bytes, 6..6, byte) == byte(0)
doAssert getBitsBE(bytes, 7..7, byte) == byte(1)
doAssert getBitsBE(bytes, 0..1, byte) == byte(0b11)
doAssert getBitsBE(bytes, 1..2, byte) == byte(0b10)
doAssert getBitsBE(bytes, 2..3, byte) == byte(0)
doAssert getBitsBE(bytes, 5..6, byte) == byte(0b10)
doAssert getBitsBE(bytes, 6..7, byte) == byte(0b1)
doAssert getBitsBE(bytes, 7..8, byte) == byte(0b11)
doAssert getBitsBE(bytes, 0..2, byte) == byte(0b110)
doAssert getBitsBE(bytes, 1..3, byte) == byte(0b100)
doAssert getBitsBE(bytes, 6..9, byte) == byte(0b110)
doAssert getBitsBE(bytes, 0..3, byte) == byte(0b1100)
doAssert getBitsBE(bytes, 0..7, byte) == byte(0b11001101)
doAssert getBitsBE(bytes, 0..10, uint16) == uint16(0b11001101100)
doAssert getBitsBE(bytes, 0..15, uint16) == uint16(0b1100110110010010)
doAssert getBitsBE(bytes, 1..11, uint16) == uint16(0b10011011001)
doAssert getBitsBE(bytes, 3..18, uint16) == uint16(0b110110010010000)
doAssert getBitsBE(bytes, 35..50, uint16) == uint16(0b1000110110110)
doAssert getBitsBE(bytes, 4..7, uint16) == uint16(0b1101)
doAssert getBitsBE(bytes, 1..29) == 0b10011011001001000000000111111'u64
doAssert getBitsBE(bytes, 1..25, uint32) == 0b1001101100100100000000011'u32
doAssert getBitsBE(bytes, 1..25, uint32) == 0b1001101100100100000000011'u32
static: test()
suite "bitops2":
test "bitops2_test":
test() # Cannot use unittest at compile time..
runtimeTest()