Skip to content Skip to sidebar Skip to footer

Cython - Memoryview Of A Dynamic 2d C++array

The Goal: Get a Memoryview from a 2D C++ char array using Cython. A little background: I have a native C++ library which generates some data and returns it via a char** to the Cyth

Solution 1:

The Answer :

Manually implement the buffer-protocol:

The wrapper class which wraps the unsigned char** and implements the buffer-protocol (Indirect2DArray.pyx):

cdefclass Indirect2DArray:
    cdefPy_ssize_tlen
    cdefunsigned char** raw_data
    cdefndim
    cdefPy_ssize_t item_size
    cdefPy_ssize_t strides[2]
    cdefPy_ssize_t shape[2]
    cdefPy_ssize_t suboffsets[2]


    def__cinit__(self,int nrows,int ncols):
        self.ndim = 2
        self.len = nrows * ncols
        self.item_size = sizeof(unsigned char)

        self.shape[0] = nrows
        self.shape[1] = ncols

        self.strides[0] = sizeof(void*)
        self.strides[1] = sizeof(unsigned char)

        self.suboffsets[0] = 0
        self.suboffsets[1] = -1


    cdefset_raw_data(self, unsigned char** raw_data):
        self.raw_data = raw_data        

    def__getbuffer__(self,Py_buffer * buffer, int flags):
        if self.raw_data is NULL:
            raise Exception("raw_data was NULL when calling __getbuffer__ Use set_raw_data(...) before the buffer is requested!")

        buffer.buf = <void*> self.raw_data
        buffer.obj = self
        buffer.ndim = self.ndim
        buffer.len = self.len
        buffer.itemsize = self.item_size
        buffer.shape = self.shape
        buffer.strides = self.strides
        buffer.suboffsets = self.suboffsets
        buffer.format = "B"# unsigbed bytesdef__releasebuffer__(self, Py_buffer * buffer):
        print("CALL TO __releasebuffer__")

Note: I wasn't able to pass the raw pointer via the wrapper's constructor so I had to use a seperate cdef-function to set set the pointer

Here's its usage:

deftest_wrapper(self):
    cdefnrows= 10000
    cdefncols = 81    

    cdefunsigned char** raw_pointer = self.raw_data
    wrapper = Indirect2DArray(nrows,ncols)    
    wrapper.set_raw_data(raw_pointer)

    # now create the memoryview:
    cdefunsigned char[::view.indirect_contiguous, ::1] view = wrapper

    # print some slices print(list(view[0,0:30]))
    print(list(view[1,0:30]))
    print(list(view[2,0:30]))

producing the following output:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 4, 5, 6, 7, 8, 9, 1, 2, 3, 7, 8, 9, 1, 2, 3, 4, 5, 6, 2, 1, 4]
[2, 1, 3, 4, 5, 6, 7, 8, 9, 4, 5, 6, 7, 8, 9, 1, 2, 3, 7, 8, 9, 1, 2, 3, 4, 5, 6, 1, 2, 4]
[3, 1, 2, 4, 5, 6, 7, 8, 9, 4, 5, 6, 7, 8, 9, 1, 2, 3, 7, 8, 9, 1, 2, 3, 4, 5, 6, 1, 2, 3]

This is exactly what I expected. Thanks to all who helped me

Post a Comment for "Cython - Memoryview Of A Dynamic 2d C++array"