我使用Haskell的FFI與一個C庫,其限定了許多含構件,其是指向double
S,旨在被視爲struct
類型的的double
小號陣列:哈斯克爾Data.Vector.Storable.unsafeFromForeignPtr用C結構的指針/陣列字段
typedef struct Foo {
int length;
double* values;
} FooT;
在我的Haskell綁定到該庫我有一個等效的數據類型,其中我試圖使用Data.Vector.Storable.Vector Double
爲陣:
data Foo = Foo {
length :: Int,
values :: Data.Vector.Storable.Vector Double
} deriving (Show, Eq)
爲了ŧ o C庫和我的Haskell代碼之間的數據,當然,我必須爲這些類型編寫Storable
實例。我試圖找出一種方法,使用Data.Vector.Storable.unsafeFromForeignPtr
從C庫已經分配並填充到堆上的double*
數組中創建Haskell Vector
。我希望通過這樣做,我可以避免複製double*
數組的內容,並且只需將Vector
作爲包裝在數組上的一種包裝。 (側面的問題是:鑑於double*
陣列可以高達10000s的double
秒,這是值得追求這種非複製?)
這是我迄今爲止。我使用hsc2hs
宏來幫助生成Storable peek
實現:
instance Storable Foo where
alignment _ = alignment (undefined :: CDouble)
sizeOf _ = #{size FooT}
peek ptr = do
len <- (#peek FooT, length) ptr
valuesField <- ((#peek FooT, values) ptr) :: IO (ForeignPtr Double)
let values' = DV.unsafeFromForeignPtr0 valuesField len
return Foo { length = len, values = values' }
poke ptr (Foo len values') = do
(#poke FooT, length) ptr len
DV.unsafeWith values' (\ptrValues -> (#poke FooT, values) ptr ptrValues)
所以在我peek
我試圖#peek
的values
成員作爲ForeignPtr Double
,我可以再與unsafeFromForeignPtr
使用。然而,#peek
產生這樣的代碼:
valuesField <- (((\ hsc_ptr -> peekByteOff hsc_ptr 16)) ptr) :: IO (ForeignPtr Double)
,並卡住,因爲沒有Storable
實例ForeignPtr Double
。我認爲如果我試圖爲ForeignPtr Double
實現一個實例,那麼我只會將如何訪問struct
成員的地址值的問題轉換爲該實例的peek
實現。
因此,總之,我怎樣才能以這樣的方式訪問地址值(即指針)struct
成員,以便我可以將它用作參數unsafeFromForeignPtr
?
看起來'newForeignPtr_'在這裏很重要。我無法手動計算'plusPtr'右手參數的工作方式,但將'newForeignPtr_'與'hsc2hs'的'#peek'生成的指針一起使用。 – ironchicken
我已經使用這個建議編寫了一個答案,但我不能發佈它,直到後來,因爲我太n00b和互聯網不相信我: - /希望我仍然會被打擾發佈它... – ironchicken
@ rjlewis如果你願意,可以在底部用你的解決方案編輯我的答案。我應該可以接受編輯。 – user2407038