Vector (Vector Foo) & # 8594; (Ptr (Ptr Foo) & # 8594; IO a) & # 8594; IO a?

I am making a simple wrapper for the c library, which should have a list of vectors passed to it. It takes an array of pointers to arrays. To create a nice interface, I would like to have a vector (or list) of vectors, but I cannot figure out how to do this in the idiomatic haskell. (Or in any other way than assembling things around).

What I'm looking for is something like

Vector (Vector Foo) -> (Ptr (Ptr Foo) -> IO a) -> IO a 
+6
source share
2 answers

Edit: hCsound does not deal with this exact case, so I added a complete example below.

You might want to check out my hCsound package ( darcs repo ), which should deal with a very similar case.

Please note that it is very important that the C library does not Data.Vector.Storable.Vector arrays used by Data.Vector.Storable.Vector . If you need to change the data, first copy the old data, change the array via ffi, and finally wrap the pointers in a new vector.

Here is the code. As noted in the comment, Data.Vector.Storable.Vector does not have an instance of Storable, so you need the external vector to be Data.Vector.Vector .

 import Foreign.Storable import Foreign.Ptr import Foreign.ForeignPtr import Foreign.Marshal.Array import qualified Data.Vector as V import qualified Data.Vector.Storable as S import Data.Vector.Storable.Internal withPtrArray vf = do let vs = V.map S.unsafeToForeignPtr v -- (ForeignPtr, Offset, Length) ptrV = V.toList $ V.map (\(fp,off,_) -> offsetToPtr fp off) vs res <- withArray ptrV f V.mapM_ (\(fp,_,_) -> touchForeignPtr fp) vs return res 

Note that the array is allocated withArray , so it is automatically gc'd after the function returns.

These arrays do not end in zero, so you need to make sure that the length is passed to the C function by some other method.

withForeignPtr not used. Instead, touchForeignPtr is touchForeignPtr to ensure that ExternalPtr is not freed until function C is completed. To use withForeignPtr , you will need to call calls for each internal vector. This is what the nest function does in hCsound code. This is more complicated than just calling touchForeignPtr .

+2
source

Since you are moving to the C function, you should use Data.Vector.Storable . You cannot just pass the vector of Storable vectors, because it will not just be a vector of pointers to arrays, but also includes information about size and offset.

if the argument to the C function is, say, int myCFunc(foo** arrays, int sz) , then the following code should work:

 import Data.Vector.Storable import Foreign.Storable import Foreign.ForeignPtr withCFunction :: Storable a => -- ^ Storable so compatible with C Vector (Vector a) -- ^ vector of vectors -> (Ptr (Ptr a) -> IO b) -- ^ C function wrapped by FFI -> IO b withCFunction vf = do vs <- mapVectorM (\x -> let (fp,_,_) = unsafeToForeignPtr x in unsafeForeignPtrToPtr fp) v mapVectorM_ (\x -> let (tfp,_,_) = unsafeToForeignPtr x in touchForeignPtr tfp) vs let (vfp,_,_) = unsafeToForeignPtr vs withForeignPtr vfp $ \p -> fp 
+4
source

Source: https://habr.com/ru/post/891619/


All Articles