Я хочу использовать ленивый Bytestring
для представления потока битов. Мне нужно иметь возможность эффективно брать произвольные фрагменты битов из этого потока. Например, у меня может быть ByteString
длины 10, и я хотел бы нарезать новый ByteString
, состоящий из битов 24-36, из исходного ByteString
.
Проблема в том, что 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
будут лишние биты, поэтому пропустите их. - получить (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
? Почему бы не использовать это? - person Daniel Wagner   schedule 12.03.2013ByteString
, и я не думаю, что смогу сохранить лень при преобразовании вUAarray
или распакованныйVector
. Хотя я мог бы попробовать коробочное представление и посмотреть, как оно будет выглядеть, но здесь ключевым фактором является эффективность. - person cdk   schedule 12.03.2013