问题 如何转换ByteString和Storable Vector?


什么是转换之间的最佳方式 Storable.Vector Word8 而且严格 ByteString

当然,非常感谢非复制(无操作)方式。

我应该 unsafeCoerce 或者是否有库函数(我找不到)?

此外,方法是否相同 Unboxed.Vector Word8


3934
2017-09-08 10:08


起源

在某些情况下,复制是有益的。如果你的字节串是较长的原始字节串的短段,例如(BS.take 10 someLongByteString),整个长块将被保留 ForeignPtr。在这种情况下,复制通常更好,因为它将使用更少的内存。这是一种特殊情况,但似乎经常出现。 - John L


答案:


一个简单的 unsafeCoerce 不起作用,因为数据构造函数的布局不同:

data StorableArray i e = StorableArray !i !i Int !(ForeignPtr e)

data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
                     {-# UNPACK #-} !Int                -- offset
                     {-# UNPACK #-} !Int                -- length

你可以导入 Data.Array.Storable.Internals 和 Data.ByteString.Internal 访问原始构造函数然后构造一个而不复制数据:

> let bs = pack [1,2,3]
> bs
"\SOH\STX\ETX"
> let sa = case bs of (PS ptr 0 n) -> StorableArray 0 (n-1) n ptr
> :t sa
sa :: StorableArray Int GHC.Word.Word8
> Data.Array.MArray.readArray sa 1
2
> Data.Array.MArray.readArray sa 0
1
> Data.Array.MArray.readArray sa 3
*** Exception: Ix{Int}.index: Index (3) out of range ((0,2))

(我删除了相当长的提示 Prelude Data.Array.Storable.Internals Data.ByteString.Internal Data.ByteString>)。

这不适用 Data.Vector.Unboxed,因为这里的数据在Haskell堆上并由GHC运行时管理,而其他两个管理Haskell堆外的数据。


9
2017-09-08 17:12





byteStringToVector :: (Storable a) => BS.ByteString -> V.Vector a
byteStringToVector bs = vec where
    vec = V.unsafeFromForeignPtr (castForeignPtr fptr) (scale off) (scale len)
    (fptr, off, len) = BS.toForeignPtr bs
    scale = (`div` sizeOfElem vec)

sizeOfElem vec = sizeOf (undefined `asTypeOf` V.head vec)

http://hackage.haskell.org/packages/archive/spool/0.1/doc/html/Data-Vector-Storable-ByteString.html


3
2017-09-19 07:46



谢谢你把它放在Hackage上! - nh2