我想用懒惰的Bytestring
来表示位流。我需要能够有效地从这个流中获取任意位的位。例如,我可能有一个长度为10的ByteString
,并且我想要分割由原始ByteString
的第24-36位组成的新ByteString
。从字节串获取任意位bits
问题是ByteStrings
是Word8
的数组,因此取不是8的倍数的范围很困难。我已经能够提出的最好的是,使用Data.Binary
和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
的开头将会有一些额外的位,所以跳过那些 - GET(HI - LO)位,并存储在一个
Word32
- 把那
Word32
成ByteString
它看起来比一个难看一点多,有没有抢到的任意片更有效的方法来自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
你知不知道那个平淡无味的'旧'UArray'如果包含'Bool',它已经使用了非常紧凑的表示形式?为什么不使用它? – 2013-03-11 22:46:50
@DanielWagner:我没有想到这一点,这将是我的问题的一个优雅的解决方案,但不幸的是我需要使用懒惰的'ByteString's,我不认为我能够保持懒惰,而转换为'UAarray'或取消装箱的'Vector'。尽管我可以尝试一个盒装表示,并看看它如何展示,但效率是关键。 – cdk 2013-03-11 23:05:28