6

我正在为需要将向量列表传递给它的 ac 库制作一个简单的包装器。它需要一个指向数组的指针数组。为了制作一个漂亮的界面,我想要 Vectors 的 Vector(或列表),但我真的不知道如何在惯用的 haskell 中做到这一点。(或者除了记忆复制东西之外的任何其他方式)。

我正在寻找的是类似的东西

Vector (Vector Foo) -> (Ptr (Ptr Foo) -> IO a) -> IO a  
4

2 回答 2

4

由于您要传递给 C 函数,因此您应该使用Data.Vector.Storable. 您不能只传递向量的向量,Storable因为它不仅仅是指向数组的指针的向量,它还包括大小和偏移量信息。

如果 C 函数的参数是,int myCFunc(foo** arrays, int sz)那么下面的代码应该可以工作:

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 v f = 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 -> f p
于 2011-06-29T08:52:09.493 回答
2

编辑: hCsound 不处理这种确切的情况,所以我在下面添加了一个完整的例子。

你可能想看看我的包hCsound ( darcs repo ),它必须处理一个非常相似的案例。

请注意,C 库不修改. Data.Vector.Storable.Vector如果确实需要修改数据,则应先复制旧数据,通过ffi修改数组,最后将指针包装成新的Vector。

这是代码。正如评论中指出的那样,Data.Vector.Storable.Vector它本身没有 Storable 实例,因此您需要外部向量为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 v f = 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

请注意,数组是由 分配的withArray,因此在函数返回后它会自动 gc'd。

这些数组不是以空值结尾的,因此您需要确保通过其他方法将长度传递给 C 函数。

withForeignPtr不使用。相反,touchForeignPtr调用它以确保在 C 函数完成之前不会释放 ForeignPtr。为了使用withForeignPtr,您需要为每个内部向量嵌套调用。这就是nesthCsound 代码中的函数的作用。它比调用更复杂touchForeignPtr

于 2011-06-29T18:01:54.470 回答