Marshaling Pointer Vectors

I am trying to represent Haskell vector arbitrary nested pairs (i.e. Vector (Int64, (Int64, (...))) ) as a 2-d array in C (i.e. int64_t** ), first indexed as a vector component , then the tuple component.

Here is my C function:

 void test(int64_t** y, int32_t vecSize int16_t tupSize, int64_t* tup) { printf("Tup vals: "); for(int i = 0; i < tupSize; i++) { printf("%" PRId64 ",",tup[i]); } printf("\n"); printf("vec\n"); for(int i = 0; i < vecSize; i++) { printf("%d: (", i); for(int j = 0; j < tupSize; j++) { printf("%" PRId64 ",", y[i][j]); } printf(")\n"); } } 

On the Haskell side, I have:

 {-# LANGUAGE ScopedTypeVariables #-} import Data.Int import Data.Vector.Storable (Vector, singleton, unsafeWith) import Foreign.Marshal.Utils (with) import Foreign.Ptr import Foreign.Storable (Storable (..)) foreign import ccall unsafe "test" test :: Ptr (Ptr Int64) -> Int64 -> Int16 -> Ptr Int64 -> IO () -- instance assumes right-nested pairs, but not enforced at type level instance (Storable a, Storable b) => Storable (a,b) where sizeOf _ = (sizeOf (undefined :: a)) + (sizeOf (undefined :: b)) alignment _ = max (alignment (undefined :: a)) (alignment (undefined :: b)) peek p = do a <- peek (castPtr p :: Ptr a) b <- peek (castPtr (plusPtr p (sizeOf a)) :: Ptr b) return (a,b) poke p (a,b) = do poke (castPtr p :: Ptr a) a poke (castPtr (plusPtr p (sizeOf a)) :: Ptr b) b main :: IO () main = do let tup = (10,11) :: (Int64, Int64) vec = singleton (2,3) :: Vector (Int64, Int64) with tup $ \tptr -> unsafeWith vec $ \vptr -> test (castPtr vptr) 1 2 (castPtr tptr) 

Will print

 Moduli: 10,11, vec Segmentation fault 

which makes me think that my Storable (a,b) instance is fine: I get a pointer to (Int64,Int64) and then drop it on Ptr Int64 and read the data only in order. C. The question is what goes wrong with the vector? I'm trying to do the same thing: create a Vector (Int64, Int64) , get a pointer like Ptr (Int64, Int64) and pass it to Ptr (Ptr Int64) . Why do I get segfault when I try to access an array in C, and what is the correct way to marshal it?

+5
source share
1 answer

You do not use the same data format on both sides. Your Haskell code creates a flat array of all the values โ€‹โ€‹in all tuples of the vector, while your C code expects an array of pointers, one for each element of the vector, indicating the values โ€‹โ€‹in that tuple.

If you could declare your C function like this (maybe it's really C these days, I don't know)

 void test(int64_t (*y)[tupSize], int32_t vecSize, int16_t tupSize, int64_t *tup) 

then C will use the same layout as Haskell. Otherwise, you can index manually using

 // SINGLE pointer | // v void test(int64_t *y, int32_t vecSize, int16_t tupSize, int64_t *tup) ... printf("%" PRId64 ",", y[i*tupSize+j]); 
+4
source

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


All Articles