Best way to get raw pointer from ctypes array?

182 views
Skip to first unread message

ser...@genjipress.com

unread,
Aug 24, 2021, 3:07:48 PM8/24/21
to cython-users
I have the following:

    # vertices is a ctypes array, c_float_Array_80000
    cdef float* verts = <float*><size_t>ctypes.addressof(vertices)    

Is there a better way to obtain the pointer to the underlying data?

D Woods

unread,
Aug 24, 2021, 4:33:54 PM8/24/21
to cython-users
I think (but I'm not 100% sure) that ctypes arrays support the buffer protocol. Therefore you could use them with a memoryview:

cdef float[::1] verts = vertices

If you want a pointer instead of a memoryview then you can take the address of the first element.

There isn't a huge advantage either way, but the memoryview does some type validation (which you lose with the cast).

ser...@genjipress.com

unread,
Aug 24, 2021, 7:11:17 PM8/24/21
to cython-users
Thanks, this appears to work. However, something odd happens if I try to release the GIL when performing any operations with the resulting pointer.

def move(vertices, vectors, int size):
    
    cdef float[::1] _verts = vertices
    cdef float* verts = &_verts[0]

    cdef array.array[float] _vecs = vectors
    vecs = _vecs.data.as_floats
    
    cdef size_t l = len(vertices), n, v=0
    cdef float x, y, x1, y1,v0, v1

    with nogil:
        for n in range(0, l, 8):
            v0 = vecs[v]
            v1 = vecs[v+1]

            x = (verts[n]+v0) % 960.0
            y = (verts[n+1]+v1) % 540.0

            x1 = x+size
            y1 = y+size
            
            verts[n:n+8] = [x, y, x1, y, x1, y1, x, y1]
            
            v+=2

This code generates this error:

Error compiling Cython file:
------------------------------------------------------------
...
            verts[n:n+8] = [x, y, x1, y, x1, y1, x, y1]
                ^
------------------------------------------------------------

life.pyx:194:17: Slicing Python object not allowed without gil

I tried unrolling the slice into 8 separate assignments, and that worked, but I'm wondering why this operation doesn't.

D Woods

unread,
Aug 26, 2021, 1:56:00 AM8/26/21
to cython-users
> verts[n:n+8] = [x, y, x1, y, x1, y1, x, y1]

This failing isn't a huge surprise (although I'm not sure the message actually diagnoses the real problem). Memoryviews are only really designed to give quick access to individual elements and don't do a lot else. I think the only slicing operation they actually support is to fill them from a single double value.

At some point we should probably support a wider range of slicing operations. Possibly. It definitely isn't the intention for memoryviews to every be a fully-featured array/matrix object, but they could do more than they do now I think.

Stefan Behnel

unread,
Aug 31, 2021, 5:30:01 AM8/31/21
to cython...@googlegroups.com
Did you try "_verts"?

Stefan

ser...@genjipress.com

unread,
Sep 1, 2021, 10:27:21 AM9/1/21
to cython-users
If I just use this:

cdef float[::1] verts = vertices

And this is my loop:

    with nogil:
        for n in range(0, l, 8):
            v0 = vecs[v]
            v1 = vecs[v+1]

            x = (verts[n]+v0) % 960.0
            y = (verts[n+1]+v1) % 540.0

            x1 = x+size
            y1 = y+size

            verts[n:n+8] = [x, y, x1, y, x1, y1, x, y1]
            
            v+=2

This happens:

Error compiling Cython file:
------------------------------------------------------------
...
            # verts[n+5]=y1
            # verts[n+6]=x
            # verts[n+7]=y1

            # unrolled version of
            verts[n:n+8] = [x, y, x1, y, x1, y1, x, y1]
                          ^
------------------------------------------------------------

life.pyx:194:27: Cannot coerce list to type 'float'

Stefan Behnel

unread,
Sep 1, 2021, 11:00:28 AM9/1/21
to cython...@googlegroups.com
ser...@genjipress.com schrieb am 01.09.21 um 16:27:
Is this using Cython 3?

If so, then this seems a missing feature. It seems perfectly reasonable to
write such code. Having to spell out the single assignments is annoying.

I mean, it should all have the same speed in the end, it's just more code
to write.

I'm surprised, though, that your previous version (which used the sliced
pointer) didn't work. It should, pointers support this kind of assignment.
Could you make sure that you tried that with Cython 3 as well?

Stefan
Reply all
Reply to author
Forward
0 new messages