Bytestring
レイジーを使用してビット ストリームを表現したいと考えています。このストリームからビットの任意のスライスを効率的に取得できる必要があります。たとえば、長さが10 の があり、元の からビット 24 ~ 36 で構成されるByteString
新しい をスライスしたいとします。ByteString
ByteString
問題は、ByteStrings
が の配列であるWord8
ため、8 の倍数ではない範囲を取得するのが難しいことです。私が思いついた最高のものは、 and を使用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
ため、それらをスキップします。 - (hi - lo) ビットを取得し、a に格納します。
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