Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to poke a Vector (or to get a Ptr Vector to it's data)?

Tags:

haskell

ffi

I've read that Data.Vector.Storable stores it's elements in a consecutive memory region. I've been expecting that Vector would be an instance of Foreign.Storable or at least there would be a function :: Vector a -> Ptr (Vector a), but there is only unsafeToForeignPtr0 :: Storable a => Vector a -> (ForeignPtr a, Int).

My Haskell code produces a list of Foreign.Storable things and i want access this list from the C code. Is Vector.Storable right data type to do this, and if yes - how should i access it's elements from the C side?

like image 822
arrowd Avatar asked Jan 02 '13 15:01

arrowd


2 Answers

If you're not changing the memory from C, you can use unsafeWith. If you do need to make changes from C, you can copy the vector first, or make a copy on the C side. (In case you do need to make changes from C, but don't need the data on the Haskell side any more, you can also use unsafeWith without copying, but then you have to make sure that the vector is never again used. This can be tricky, with laziness and all...)

So, why isn't Vector a an instance of Storable when a is? Well, for one: what should sizeOf be for a vector? Recall that even though that function has signature (Storable a) => a -> Int, the documentation says "the argument is not used". Hopefully someone who knows the internals comes around and gives an authoritative answer, but as far as I know, all the Storable instances are "fixed-size" types.

Addendum: The function signatures you're requesting can't really make sense. Suppose you had a foo :: Vector a -> Ptr (Vector a), would it really make sense that foo (fromList [1,2]) == foo (init (fromList [1,2,3]))? Remember, these are now pointers, and could very well be different.

like image 152
gspr Avatar answered Oct 30 '22 18:10

gspr


A possible solution:

import qualified Foreign.Ptr as P
import qualified Data.Vector.Storable as SV
import qualified Data.Vector.Storable.Internal as SVI
import qualified GHC.ForeignPtr as FP

ptr0ToVector :: SV.Storable a => P.Ptr a -> Int -> IO (SV.Vector a)
ptr0ToVector ptr size =
 FP.newForeignPtr_ ptr >>= \foreignPtr ->
 return (SV.unsafeFromForeignPtr0 foreignPtr size)

vectorToPtr0 :: SV.Storable a => SV.Vector a -> (P.Ptr a,Int)
vectorToPtr0 vector =
 let (foreignPtr,size) = SV.unsafeToForeignPtr0 vector
 in (SVI.getPtr foreignPtr,size)
like image 23
Juan Carlos Kuri Pinto Avatar answered Oct 30 '22 18:10

Juan Carlos Kuri Pinto