Reputation: 141
The following C++ code goes off the standard Cython rectangle example, with an arbitrary added "+" operator:
#include "Rectangle.h"
using namespace shapes;
Rectangle::Rectangle(int X0, int Y0, int X1, int Y1)
{
x0 = X0;
y0 = Y0;
x1 = X1;
y1 = Y1;
}
Rectangle::~Rectangle() {}
int Rectangle::getLength()
{
return (x1 - x0);
}
Rectangle operator+(const Rectangle &r1, const Rectangle &r2)
{
return Rectangle(r1.X0 + r2.X0, r1.Y0 + r2.Y0, r1.X1 + r2.X1, r1.Y1 + r2.Y1)
}
This goes with the Cython C++ class definition:
cdef extern from "Rectangle.h" namespace "shapes":
cdef cppclass Rectangle:
Rectangle(int, int, int, int) except +
int x0, y0, x1, y1
int getLength()
Rectangle operator+(Rectangle) nogil
The only way we've figured out of doing this is by the following Cython code:
cdef class PyRectangle:
cdef Rectangle *thisptr # hold a C++ instance which we're wrapping
def __cinit__(self, int x0=0, int y0=0, int x1=0, int y1=0):
if x0 == 0:
self.thisptr = NULL
else:
self.thisptr = new Rectangle(x0, y0, x1, y1)
def __dealloc__(self):
del self.thisptr
def getLength(self):
return self.thisptr.getLength()
def __add__(self, other):
cdef Rectangle rect = deref(self.thisptr) + deref(other.thisptr)
cdef Rectangle* ptr_rect = new Rectangle(rect.x0, rect.y0, rect.x1, rect.y1)
ret = PyRectangle()
ret.thisptr = ptr_rect
return ret
This is not very optimal, since we have an extra copy in __add__
, and the code is not very simple/short either. This is for wrapping an external library, so we can't simply define any new constructors to Rectangle, and we can't rewrite the addition at the Cython level.
We thought that we could simply write something like:
ret = PyRectangle()
deref(ret.thisptr) = deref(self.thisptr) + deref(other.thisptr)
return ret
But this gives the error "Cannot assign to or delete this."
Is there a more preferred way of doing this sort of thing in Cython? The solution we found is not viable in our code.
Upvotes: 3
Views: 775
Reputation: 5104
For pointers, x[0]
is the same as deref(x)
, so you can instead write
ret.thisptr[0] = self.thisptr[0] + other.thisptr[0]
Note also that if the object being wrapped has a nullary constructor, there's no need for pointers at all, simply do
cdef class PyRectangle:
cdef Rectangle c_rect
def __init__(self, int x0=0, int y0=0, int x1=0, int y1=0):
self.c_rect = Rectangle(x0, y0, x1, y1)
# no __dealloc__ needed
def __add__(PyRectangle left, PyRectangle right):
PyRectangle ret = PyRectangle()
ret.c_rect = left.c_rect + right.c_rect
return ret
I find it handy in this case to add a static method
cdef class PyRectangle:
[...]
@staticmethod
cdef create(Rectangle r):
PyRectangle ret = PyRectangle()
ret.c_rect = r
return ret
then you can simply do
def __add__(PyRectangle left, PyRectangle right):
return PyRectangle.create(left.c_rect + right.c_rect)
Upvotes: 3