在 Cython 中包装 std::array 并将其暴露给内存视图 [英] Wrapping std::array in Cython and Exposing it to memory views
问题描述
目前 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屋!