Haskell 从Bytestring获取任意位片
我想使用惰性的Haskell 从Bytestring获取任意位片,haskell,binary,bits,bytestring,bitstream,Haskell,Binary,Bits,Bytestring,Bitstream,我想使用惰性的Bytestring来表示位流。我需要能够有效地从这个流中获取任意比特片。例如,我可能有一个长度为10的ByteString,我想切片一个新的ByteString,它由原始ByteString的24-36位组成 问题是ByteStrings是Word8s的数组,因此很难获取不是8的倍数的范围。我能想到的最好的方法就是使用Data.Binary和Data.Binary.Bits。请注意,get32BitRange专门用于范围如果将ByteString作为API类型,则无法有效地实现这
Bytestring
来表示位流。我需要能够有效地从这个流中获取任意比特片。例如,我可能有一个长度为10的ByteString
,我想切片一个新的ByteString
,它由原始ByteString
的24-36位组成
问题是
ByteStrings
是Word8
s的数组,因此很难获取不是8的倍数的范围。我能想到的最好的方法就是使用Data.Binary
和Data.Binary.Bits
。请注意,get32BitRange
专门用于范围如果将ByteString
作为API类型,则无法有效地实现这一点,因为它不携带您想要的“位”真正从某个偏移量开始进入第一个字节的信息
最好的办法是制作包装器类型:
data BitStream =
BitStream {
info :: ByteString,
-- values from 0-7: ignore all bits in the first byte up to
-- but not including this offset
firstBitOffset :: !Int,to but not including this offset
-- values from 0-7: ignore all bits in the last byte after
-- but not including this offset
lastBitOffset :: !Int
}
然后,您可以围绕这一点设计一个基于位的API。如果将
ByteString
作为API类型,则无法有效地实现这一点,因为它不携带您想要的“位”真正从某个偏移量开始进入第一个字节的信息
最好的办法是制作包装器类型:
data BitStream =
BitStream {
info :: ByteString,
-- values from 0-7: ignore all bits in the first byte up to
-- but not including this offset
firstBitOffset :: !Int,to but not including this offset
-- values from 0-7: ignore all bits in the last byte after
-- but not including this offset
lastBitOffset :: !Int
}
然后,您可以围绕这一点设计基于位的API。我认为其他解决方案要好得多,但您可以使用内部模块了解底层结构:
然后,您可以使用标准指针工具,通过直接操作
ForeignPtr
,通过testring生成指向您想要的位置的。我认为其他解决方案更好,但您可以使用内部模块来获得底层结构:
然后,您可以使用标准指针工具,通过直接操纵ForeignPtr
,通过testring
s生成指向您想要的位置的。我将此标记为已解决。这就是我最终使用的:
get32BitRange :: Int -> Int -> ByteString -> Word32
get32BitRange lo hi = assert (lo < hi) $
runGet (runBitGet bitGet)
where bitGet = block $ byteString byteOff
*> word8 bitOff
*> word32be len
len = hi - lo
(byteOff, bitOff) = lo `quotRem` 8
get32BitRange::Int->Int->ByteString->Word32
get32BitRange lo hi=断言(lo字8比特
*>word32be len
len=高-低
(byteOff,bitOff)=loquotrem`8
我要将此标记为已解决。这就是我最终使用的:
get32BitRange :: Int -> Int -> ByteString -> Word32
get32BitRange lo hi = assert (lo < hi) $
runGet (runBitGet bitGet)
where bitGet = block $ byteString byteOff
*> word8 bitOff
*> word32be len
len = hi - lo
(byteOff, bitOff) = lo `quotRem` 8
get32BitRange::Int->Int->ByteString->Word32
get32BitRange lo hi=断言(lo字8比特
*>word32be len
len=高-低
(byteOff,bitOff)=loquotrem`8
这当然有助于清理我的示例函数,但我更感兴趣的是一种实际提取位片的方法。之后您想对它们做什么?将它们作为二进制数据解析,可能是一个字或Int
类型这当然有助于清理我的示例函数,但我更感兴趣的是一种实际提取位片的方法。你想在之后对它们做什么?将它们作为二进制数据解析,可能是一个字或Int
类型。你知道吗,如果它包含Bool
,那么简单、乏味的老UArray
已经使用了非常紧凑的表示法?为什么不使用它?@DanielWagner:我没有想到这一点,这将是解决我问题的一个优雅的解决方案,但不幸的是,我需要通过testring
s使用lazy,我认为在转换为UAarray
或unboxVector
时,我无法保持这种惰性。我可以尝试一种盒式表示,看看它是如何公平的,但效率在这里是关键。你知道吗,如果它包含Bool
,那么简单、乏味的老UArray
已经使用了非常紧凑的表示了?为什么不使用它?@DanielWagner:我没有想到这一点,这将是解决我问题的一个优雅的解决方案,但不幸的是,我需要通过testring
s使用lazy,我认为在转换为UAarray
或unboxVector
时,我无法保持这种惰性。我可以尝试一种盒装的表示,看看它是如何公平的,但效率是关键。
get32BitRange :: Int -> Int -> ByteString -> Word32
get32BitRange lo hi = assert (lo < hi) $
runGet (runBitGet bitGet)
where bitGet = block $ byteString byteOff
*> word8 bitOff
*> word32be len
len = hi - lo
(byteOff, bitOff) = lo `quotRem` 8