我想用一个lazyBytestring
来表示一个比特流。我需要能够有效地从该流中获取任意位片。例如,我可能有一个ByteString
长度为 10 的 a,我想ByteString
从原始的ByteString
.
问题是sByteStrings
的数组Word8
,所以取不是 8 的倍数的范围很困难。我能想到的最好的就是这个,使用Data.Binary
and 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