Numpy array interface to SWIG wrapped C++ Class with --builtin

Tobias Winchen <[email protected]>
Newsgroups gmane.comp.programming.swig
Message-ID <1990648.nfdQr6AkM3@guymontag>
Dear SWIG Users and Developers,

I am trying to generate a python interface to a C++ class with SWIG that is 
conform with the numpy array interface. For SWIG without --builtin option I 
succeeded with the approach described below. How can I generate the correct 
wrappers when using swig with the --builtin option?

The following class is part of a larger C++ code with python wrappers using 
SWIG. Unessential methods have been removed to create a minimum example. File 
vector3.h:

template<typename T>
class Vector3
{
public:

union {
    struct
    {
        T x;
        T y;
        T z;
    };
    T data[3];
};

// avoid creation of default non-conversion constructor
Vector3(const Vector3 &v) : data{v.data[0], v.data[1], v.data[2]} {
}

// Provides implicit conversion
template<typename U>
Vector3(const Vector3<U> &v) {
    data[0] = v.x;
    data[1] = v.y;
    data[2] = v.z;
}

~Vector3()
{
}

explicit Vector3(const double *v) {
    data[0] = v[0];
    data[1] = v[1];
    data[2] = v[2];
}

explicit Vector3(const float *v) {
    data[0] = v[0];
    data[1] = v[1];
    data[2] = v[2];
}

explicit Vector3(const T &X, const T &Y, const T &Z) : data{X, Y, Z} {
}

explicit Vector3(T t) : data{t, t, t} {
}
};

I can create a python wrapper with the swig file vector3.i:

%module(directors="1", threads="1", allprotected="1") vector3
%init %{
  import_array();
  import_ufunc();
%}
%{
/* Include numpy array interface, if available */
  #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
  #include "numpy/arrayobject.h"
  #include "numpy/ufuncobject.h"
  #include "vector3.h"
%}

%feature("python:slot", "sq_length", functype="lenfunc") Vector3::__len__;
%feature("python:slot", "mp_subscript", functype="binaryfunc") 
Vector3::__getitem__;
%feature("python:slot", "mp_ass_subscript", functype="objobjargproc") 
Vector3::__setitem__;

%include "vector3.h"
%extend Vector3
{
  size_t __len__()
  {
    return 3;
  }

  size_t getdataPointer()
  {
    return (size_t) $self->data;
  }

  double __getitem__(size_t i)
  {
    return $self->data[i];
  }

  int __setitem__(size_t i, T value)
  {
    $self->data[i] = value;
    return 0;
  }

%pythoncode %{
  def __getArrayInterface(obj):
    return {'shape':(3,), 'data': (obj.getdataPointer(), False), 'typestr': 
'f8'}

  __swig_getmethods__["__array_interface__"] = __getArrayInterface
%template(Vector3d) Vector3<double>;

swig -c++ -python -I. -dirprot -o vector3_wrap.cxx vector3.i
g++  -std=c++11 -g -fPIC -c vector3_wrap.cxx -I/usr/include/python2.7 -I. 
g++ -std=c++11 -g -shared vector3_wrap.o -o _vector3.so 

Adding the array_interface dict above gives the desired functionality, e.g.

v = Vector3d(0,2,3)
print "Np sum:", np.sum(v)
print "Np array", np.array(v) 

    Instead of adding an array_interface dictionary I extended the vector3 in 
swig with an array method:
Also in vector3.i:

 extend Vector3{
 PyObject* __array__()
 {
   npy_intp shape[1];
   shape[0] = 3;
   PyObject *ro = Py_None;
   if (sizeof($self->data[0]) == NPY_SIZEOF_FLOAT)
   {
     ro = PyArray_SimpleNewFromData(1, shape, NPY_FLOAT, $self->data);
   }
   else if (sizeof($self->data[0]) == NPY_SIZEOF_DOUBLE)
   {
     ro = PyArray_SimpleNewFromData(1, shape, NPY_DOUBLE, $self->data);
   }
     return Py_None;
   }
 return ro;
 }
correctly. The interface may segfault because (I think) the vector3 may be 
deleted while the array `view' on the data still exists. I tried adding a base 
PyArray_SetBaseObject((PyArrayObject *) ro, SWIG_This()); 

without success. But also the approach to add a method that returns a python 
object directly via extend seems to be not correct. I already asked this 
question Any suggestions are appreciated. Please note that I first asked this 
question on stackoverflow [1] without receiving an answer yet - just in case 
you prefer to answer there.

Bests,

Tobi



[1] https://stackoverflow.com/questions/60207293/numpy-array-interface-to-swig-wrapped-c-class-with-builtin
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.