On 12/06/15 13:24, Sturla Molden wrote:
> If you use a single std::vector as buffer you avoid the problem with
> strides, as the whole buffer is now contiguous. But you still need to
> prevent the deallocation. You could do that by defining an Allocator.
> Another method would be to create a Cython cdef class which exports an
> __array_interface__ to NumPy and owns the C++ std::vector. Then call del
> on it in __dealloc__.
Unless I made a typo, this should work for an 1D array. If you have 3D
you need to reshape the numpy array and do whatever you need to do in
C++, e.g. make a class that interprets a std::vector as a 3D array.
// asvoid.h
template <class T>
inline void *asvoid(std::vector<T> *buf)
{
T& tmp = *buf;
return (void*)(&tmp[0]);
}
// foobar.h
extern
void foobar(std::vector<unsigned char>& v);
# whatever.pyx
from libcpp.vector cimport vector
import nupy as np
cimport numpy as cnp
cdef extern from "asvoid.h":
void *asvoid(vector[unsigned char] *buf)
cdef extern from "foobar.h":
void foobar(vector[unsigned char] tmp) # ignore the &
class stdvector_base:
pass
cdef class vector_wrapper:
cdef:
vector[unsigned char] *buf
def __cinit__(vector_wrapper self, n):
self.buf = NULL
def __init__(VectorWrapper self, cnp.intp_t n):
self.buf = new vector[unsigned char](n)
def __dealloc__(vector_wrapper self):
if self.buf != NULL:
del self.buf
def asarray(vector_wrapper self):
"""
Interpret the vector as np.ndarray without
copying the data.
"""
base = stdvector_base()
intbuf = <cnp.uintp_t> asvoid(self.buf)
dtype = np.dtype(np.uint8)
base.__array_interface__ = dict(
data = (intbuf, False),
descr = dtype.descr,
shape = (n,),
strides = (dtype.itemsize,),
typestr = dtype.str,
version = 3,
)
base.vector_wrapper = self
return np.asarray(base)
# and then you would do something like this
def example(n):
cdef vector_wrapper w
w = vector_wrapper(n)
foobar(w.buf[0])
return w.asarray()
It is important that we create the numpy array from the std::vector
after we are done working with it in C++ because it can reallocate
its data buffer.
Sturla