2016-07-31 15 views
3

Ich versuche, zwei Cython-Funktionen zu schreiben, um externe Funktionen zu umhüllen. Die Funktionen sind zueinander invers; Man akzeptiert eine Zeichenfolge und gibt eine Struktur mit zwei Feldern zurück: einen Zeiger auf ein 2D-Array (die zweite Dimension besteht immer aus zwei Elementen: [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0], … ]) und die Länge des Arrays. Der andere akzeptiert dieselbe Struktur und gibt eine Zeichenfolge zurück. Bisher habe ich Folgendes. Es kompiliert, aber die Umwandlung in und aus der verschachtelten Liste ist definitiv falsch.Wie gieße ich eine 2D-Liste auf einen void-Zeiger und zurück

Mein .pxd:

cdef extern from "header.h": 
    struct _FFIArray: 
     void* data 
     size_t len 

    cdef _FFIArray decode_polyline_ffi(char* polyline, int precision); 
    cdef char* encode_coordinates_ffi(_FFIArray, int precision); 
    cdef void drop_float_array(_FFIArray coords); 
    cdef void drop_cstring(char* polyline) 

Mein .pyx:

import numpy as np 
from pypolyline_p cimport (
    _FFIArray, 
    decode_polyline_ffi, 
    encode_coordinates_ffi, 
    drop_float_array, 
    drop_cstring 
    ) 

def encode_coordinates(coords, int precision): 
    """ coords looks like [[1.0, 2.0], [3.0, 4.0], …] """ 
    cdef double[::1] ncoords = np.array(coords, dtype=np.float64) 
    cdef _FFIArray coords_ffi 
    # Wrong 
    coords_ffi.data = <void*>&ncoords[0] 
    # Wrong 
    coords_ffi.len = ncoords.shape[0] 
    cdef char* result = encode_coordinates_ffi(coords_ffi, precision) 
    cdef bytes polyline = result 
    drop_cstring(result) 
    return polyline 

def decode_polyline(bytes polyline, int precision): 
    cdef char* to_send = polyline 
    cdef _FFIArray result = decode_polyline_ffi(to_send, precision) 
    # Wrong 
    cdef double* incoming_ptr = <double*>(result.data) 
    # Wrong 
    cdef double[::1] view = <double[:result.len:1]>incoming_ptr 
    coords = np.copy(view) 
    drop_float_array(result) 
    return coords 
+1

Sie versuchen, ein 2D-Array mit nur einer einzigen Länge zu beschreiben ... Wie erwarten Sie, dass es die Größe kennen die andere Dimension? (ist es immer 2?) – DavidW

+0

@davidw Sorry, hätte klar sein sollen: die andere Dimension ist immer 2 Elemente. – urschrei

Antwort

3

Ich denke, das Problem ist, dass Sie 2D-Arrays zu verwenden sind versuchen und 1D memoryviews

In der Codierungsfunktion

# the coords are a 2D, C contiguous array 
    cdef double[:,::1] ncoords = np.array(coords, dtype=np.float64) 
    # ... 
    coords_ffi.data = <void*>&ncoords[0,0] # take the 0,0 element 
    # the rest stays the same 

In der Decodierungsfunktion

# specify it as a 2D, len by 2, C contiguous array 
    cdef double[:,::1] view = <double[:result.len,:2:1]>incoming_ptr 
    # the rest stays the same 

(Es ist möglich, dass Ihre FFI Funktionen Fortran zusammenhängenden Arrays erwarten. In diesem Fall geht die ::1 auf die erste Dimension der Speicheransicht, und Sie ändern auch incoming_ptr)

+0

Ich denke, das ist richtig. Es ist schwierig, ohne die Schnittstelle zu testen, die es verwenden möchte. – DavidW

+0

Das funktioniert perfekt. Ich habe den cdef in der Decodierfunktion auf 'cdef double [:, :: 1] view = ...' geändert, um den in der Codierfunktion zu erreichen ... – urschrei

+0

Guter Punkt - ich habe diesen einen verpasst. Ich habe die Antwort so bearbeitet, dass sie richtig ist (aber wenn du sie schon gefunden hast, brauchst du das nicht zu wissen!) – DavidW