Adding __add__ operator to Cython wrapper class?

The following C ++ code breaks away from the standard Cython rectangle example with an arbitrary "+" operator added:

#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 refers to 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 decided to do it was 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 as we have an extra copy in __add__

and the code is not very simple / short too. This is for wrapping an external library, so we cannot just define any new constructors for the Rectangle, and we cannot rewrite the addition at the Cython level.

We thought we could just write something like:

ret = PyRectangle()
deref(ret.thisptr) = deref(self.thisptr) + deref(other.thisptr)
return ret

      

But it gives the error "Cannot assign or remove this".

Is there a better way to do this kind of thing in Keaton? The solution we found is not viable in our code.

+3


source to share


1 answer


For pointers, it is the x[0]

same as deref(x)

, so you can write

ret.thisptr[0] = self.thisptr[0] + other.thisptr[0]

      

Note also that if the wrapped object has a nullable constructor then there is no need for pointers, just 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

      



It is convenient for me 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 just do

def __add__(PyRectangle left, PyRectangle right):
    return PyRectangle.create(left.c_rect + right.c_rect)

      

+3


source







All Articles