我想用一个lazyBytestring来表示一个比特流。我需要能够有效地从该流中获取任意位片。例如,我可能有一个ByteString长度为 10 的 a,我想ByteString从原始的ByteString.
问题是sByteStrings的数组Word8,所以取不是 8 的倍数的范围很困难。我能想到的最好的就是这个,使用Data.Binaryand Data.Binary.Bits。请注意,这get32BitRange专门针对范围 <= 32。
get32BitRange :: Int -> Int -> ByteString -> ByteString
get32BitRange lo hi = runPut . putWord32be
. runGet (runBitGet . block $ word8 (8 - (lo `quot` 8)) *> word32be len)
. drop offset
where len = hi - lo
lo' = lo `div` 8
offset = fromIntegral lo' - 1
算法是:
- 找到第一个
Word8包含我想要的位的索引 - 从最高下降
ByteString到该指数 - 如果位范围的低端不是 8 的倍数,则在 的开头会有一些多余的位
Word8,所以跳过那些 - 获取 (hi - lo) 位,并存储在
Word32 - 把它
Word32放进一个ByteString
它看起来有点难看,有没有更有效的方法可以从 a 中获取任意切片ByteString?
编辑:这是一个更有效的版本
get32BitRange :: Int -> Int -> ByteString -> Word32
get32BitRange lo hi = runGet get
where get = runBitGet . block $ byteString byteOff *> word8 bitOff *> word32be len
len = hi - lo
(byteOff, bitOff) = lo `quotRem` 8