Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert between ByteString and Storable Vector?

Tags:

haskell

What is the best way to convert between Storable.Vector Word8 and a strict ByteString?

Of course a non-copying (no-op) way would be most appreciated.

Should I just unsafeCoerce or is there a library function for that (I couldn't find one)?

Also, will the approach be the same for an Unboxed.Vector Word8?

like image 511
nh2 Avatar asked Sep 08 '13 10:09

nh2


1 Answers

A simple unsafeCoerce will not work, as the layout of the data constructors is different:

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

vs.

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

You can import Data.Array.Storable.Internals and Data.ByteString.Internal to get access to the raw constructors and then construct one out of the other without copying the data:

> 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))

(I removed the rather long prompt of Prelude Data.Array.Storable.Internals Data.ByteString.Internal Data.ByteString>).

This will not work for Data.Vector.Unboxed, because here the data is on the Haskell heap and managed by the GHC runtime, while the other two manage the data outside the Haskell heap.

like image 198
Joachim Breitner Avatar answered Oct 02 '22 16:10

Joachim Breitner