我想用懶惰的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