矢量(矢量Foo)-> (Ptr(Ptr Foo)->IO a)->奥一个?

发布于 2024-11-17 19:03:55 字数 243 浏览 4 评论 0原文

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

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

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

I am making a simple wrapper for a c library that needs to have a list of vectors passed to it. It takes an array of pointers to arrays. To make a nice interface I'd like to have Vector (or list) of Vectors, but I can't really find out how to do this in idiomatic haskell. (Or any other way than memcopying stuff around).

What I'm looking for is something like

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

手心的温暖 2024-11-24 19:03:55

由于您要传递给 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

Since you're passing to a C function, you should use Data.Vector.Storable. You can't just pass a vector of vectors of Storable because that will not be a vector merely of pointers to arrays, it also includes size and offset information.

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 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
浪菊怪哟 2024-11-24 19:03:55

编辑: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。

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

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

Edit: hCsound doesn't deal with this exact case, so I've added a full example below.

You might want to look at my package hCsound (darcs repo), which has to deal with a very similar case.

Note that it's very important that the C library doesn't modify the arrays used by a Data.Vector.Storable.Vector. If you do need to modify the data, you should copy the old data first, modify the array through the ffi, and finally wrap the pointers into a new Vector.

Here's the code. As was pointed out in a comment, Data.Vector.Storable.Vector doesn't have a Storable instance itself, so you'll need the outer vector to be a 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

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

These arrays aren't null-terminated, so you'll need to make sure that the length is passed to the C function by some other method.

withForeignPtr isn't used. Instead, touchForeignPtr is called to ensure that the ForeignPtr's aren't deallocated before the C function is finished. In order to use withForeignPtr, you'd need to nest calls for each internal vector. That's what the nest function in the hCsound code does. It's rather more complicated than just calling touchForeignPtr.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文