在 Cython 中包装 std::array 并将其暴露给内存视图 [英] Wrapping std::array in Cython and Exposing it to memory views

查看:21
本文介绍了在 Cython 中包装 std::array 并将其暴露给内存视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前 Cython 的 repo 中似乎有一个 pull request 来包装 c++ std::array 但在那之前,我可以使用一些帮助.我目前正在像这样包装 std::array :

It seems that there is currently a pull request in Cython's repo to wrap c++ std::array but until then, I could use some help. I am currently wrapping the std::array like so:

cdef extern from "<array>" namespace "std" nogil:
    cdef cppclass array2 "std::array<double, 2>":
        array2() except+
        double& operator[](size_t)

这行得通,但我必须循环一个 cython 内存视图,比如 double arr[:],然后一个一个复制值.有没有更简单的方法来做到这一点?基本上我想做以下事情:

This works, but I have to loop over a cython memory view say, double arr[:], and copy the values one by one. Is there an easier way to do this? Essentially I'd like to do the following:

cdef double arr[2]
arr[0] = 1.0
arr[1] = 2.0
cdef array2 array2_arr = arr
#and the reverse
cdef array2 reverse
reverse[0] = 1.0
reverse[1] = 2.0 
cdef double reverse_arr[2] = reverse

这完全不合理吗?因此,使用 std::array 非常乏味,因为我有一个 for 循环来将值从 cython 复制到 c++ 以及从 c++ 复制到 cython.此外,由于 cython 不能让我们拥有非类型模板参数,我必须为我的代码中 std::array 的每个变体定义一个包装器.关于如何有效地使用 std::array 的任何建议将不胜感激.

Is this completely unreasonable? As a result, working with std::array is extremely tedious because I have a to have a for-loop to copy values from cython to c++ and from c++ to cython. Furthermore, since cython doesn't give us the ability to have non-type template parameters, I have to define a wrapper for every variation of std::array in my code. Any suggestions on how to efficiently work with std::array would be greatly appreciated.

我现在可以使用以下内容从内存视图转到 array2 类型:

I'm now able to go from a memory view to an array2 type using the following:

def __cinit__(self, double[:] mem):
  cdef array2 *arr = <array2 *>(&mem[0])

但似乎无论我做什么,我都无法让 cython 将 array2 类型转换为内存视图:

But it seems that no matter what I do, I cannot get cython to convert an array2 type to a memoryview:

cdef array2 arr = self.thisptr.getArray()

# error: '__pyx_t_1' declared as a pointer to a reference of type 'double &'
cdef double[::1] mview = <double[:2]>(&arr[0]) 

#OR

# Stop must be provided to indicate shape
cdef double[::1] mview = <double[::2]>(&arr[0])

请帮我弄清楚如何将 C++ 指针转换为内存视图.我迄今为止尝试过的每种组合都导致了某种类型的铸造错误.

Please help me figure out how to cast a C++ pointer to a memory view. Every combination I have tried to date has resulted in some kind of casting error.

我发现我要使用较新版本的 Cython(我使用的是 Cythong 0.22)并升级到 0.23.5 执行以下语法没有错误.

I found that I am to perform the following syntax with no error using a newer version of Cython (I was using Cythong 0.22) and upgraded to 0.23.5.

cdef double[::1] mview = <double[:4]>(&arr[0])

但是,如果我尝试从我正在使用它的函数中返回 mview,我会得到垃圾内存.将 memoryview 返回到我的数组的指针会失去作用域,因此会自动破坏我的数组.一旦我弄清楚如何正确返回我的数组,我将尝试更新官方答案.

However, if I attempt to return mview from the function I am using it in, I get garbage memory. Returning the memoryview to the pointer of my array loses scope and therefore destructs my array automatically. As soon as I figure out how to properly return my array, I'll attempt to update the official answer.

推荐答案

经过一番折腾,我找到了问题的答案.

After much fiddling, I found the answer to my question.

cdef extern from "<array>" namespace "std" nogil:
  cdef cppclass array4 "std::array<int, 4>":
    array4() except+
    int& operator[](size_t)

cdef extern from "Rectangle.h" namespace "shapes":
  cdef cppclass ArrayFun:
    ArrayFun(array4&)
    array4 getArray()

Python 实现

cdef class PyArrayFun:
    cdef ArrayFun *thisptr      # hold a C++ instance which we're wrapping
    def __cinit__(self, int[:] mem):
      #
      # Conversion from memoryview to std::array<int,4>
      #
      cdef array4 *arr = <array4 *>(&mem[0])
      self.thisptr = new ArrayFun(arr[0])

    def getArray(self):
      cdef array4 arr = self.thisptr.getArray()
      #
      # Conversion from std::array<int, 4> to memoryview
      #
      cdef int[::1] mview = <int[:4]>(&arr[0])
      cdef int[::1] new_view = mview.copy()
      for i in range(0,4):
        print ("arr is ", arr[i])
        print("new_view is ", new_view[i])

      # A COPY MUST be returned because arr goes out of scope and is
      # default destructed when this function exist. Therefore we have to 
      # copy again. This kinda of sucks because we have to copy the 
      # internal array out from C++, and then we have to copy the array
      # out from Python, therefore 2 copies for one array. 
      return mview.copy()

这篇关于在 Cython 中包装 std::array 并将其暴露给内存视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆