I'm trying to represent a Haskell vector of arbitrarily right-nested pairs (i.e. Vector (Int64, (Int64, (...)))
) as a 2-d array in C (i.e. int64_t**
), indexed first as the vector component, then the tuple component.
Here's 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)
This prints
Moduli: 10,11,
vec
Segmentation fault
which leads me to think that my Storable (a,b)
instance is fine: I'm getting a pointer for (Int64,Int64)
, then casting it to Ptr Int64
, and reading the data just fine in C. So the question is what is going wrong with the vector? I'm attempting to do the same thing: create a Vector (Int64, Int64)
, get a pointer of type Ptr (Int64, Int64)
for it, and cast it to a Ptr (Ptr Int64)
. Why am I getting a segfault when I try to access the array in C, and what is the proper way to marshal this data?
You're not using the same data format on the two sides. Your Haskell code produces a flat array of all the values in all the tuples of the vector, while your C code expects an array of pointers, one for each element of the vector, pointing to the values in that tuple.
If you could declare your C function like this (maybe this is valid C nowadays, I don't know)
void test(int64_t (*y)[tupSize], int32_t vecSize, int16_t tupSize, int64_t *tup)
then C would be using the same layout as Haskell. Otherwise, you can index manually with
// SINGLE pointer |
// v
void test(int64_t *y, int32_t vecSize, int16_t tupSize, int64_t *tup)
...
printf("%" PRId64 ",", y[i*tupSize+j]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With