From 62ef74876437c142e24973edfb53203070bbc1f9 Mon Sep 17 00:00:00 2001 From: Dag Sverre Seljebotn Date: Fri, 15 Aug 2008 14:38:28 +0200 Subject: [PATCH] numpy.pxd improvements, see details Do not require malloc for format string for common cases. Provide __cythonbufferdefaults__ More robust for changing NumPy APIs ; --- Cython/Includes/numpy.pxd | 153 ++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 87 deletions(-) diff --git a/Cython/Includes/numpy.pxd b/Cython/Includes/numpy.pxd index 02f8d5f9..7f365967 100644 --- a/Cython/Includes/numpy.pxd +++ b/Cython/Includes/numpy.pxd @@ -1,111 +1,93 @@ -from stdlib cimport malloc, free - - cdef extern from "Python.h": ctypedef int Py_intptr_t cdef extern from "numpy/arrayobject.h": ctypedef Py_intptr_t npy_intp - ctypedef struct PyArray_Descr: - int elsize - char byteorder - - ctypedef class numpy.ndarray [object PyArrayObject] - - int PyArray_NDIM(ndarray) - bint PyTypeNum_ISNUMBER(int) - bint PyTypeNum_ISCOMPLEX(int) - + cdef enum: + NPY_BOOL, + NPY_BYTE, NPY_UBYTE, + NPY_SHORT, NPY_USHORT, + NPY_INT, NPY_UINT, + NPY_LONG, NPY_ULONG, + NPY_LONGLONG, NPY_ULONGLONG, + NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE, + NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE, + NPY_OBJECT, + NPY_STRING, NPY_UNICODE, + NPY_VOID, + NPY_NTYPES, + NPY_NOTYPE, + NPY_CHAR, + NPY_USERDEF ctypedef class numpy.ndarray [object PyArrayObject]: + cdef __cythonbufferdefaults__ = {"mode": "strided"} + cdef: char *data - int nd - npy_intp *dimensions + int ndim "nd" + npy_intp *shape "dimensions" npy_intp *strides - object base - # descr not implemented yet here... - int flags - int itemsize - object weakreflist - PyArray_Descr* descr + # Note: This syntax (function definition in pxd files) is an + # experimental exception made for __getbuffer__ and __releasebuffer__ + # -- the details of this may change. def __getbuffer__(ndarray self, Py_buffer* info, int flags): + # This implementation of getbuffer is geared towards Cython + # requirements, and does not yet fullfill the PEP (specifically, + # Cython always requests and we always provide strided access, + # so the flags are not even checked). + if sizeof(npy_intp) != sizeof(Py_ssize_t): raise RuntimeError("Py_intptr_t and Py_ssize_t differs in size, numpy.pxd does not support this") - cdef int typenum = PyArray_TYPE(self) - # NumPy format codes doesn't completely match buffer codes; - # seems safest to retranslate. - cdef char* base_codes = "?bBhHiIlLqQfdgfdgO" - if not base_codes[typenum] == 'O' and not PyTypeNum_ISNUMBER(typenum): - raise ValueError, "Only numeric and object NumPy types currently supported." - - info.buf = self.data + info.buf = PyArray_DATA(self) info.ndim = PyArray_NDIM(self) - info.strides = self.strides - info.shape = self.dimensions + info.strides = PyArray_STRIDES(self) + info.shape = PyArray_DIMS(self) info.suboffsets = NULL - info.itemsize = self.descr.elsize + info.itemsize = PyArray_ITEMSIZE(self) info.readonly = not PyArray_ISWRITEABLE(self) - - cdef char* fp - fp = info.format = malloc(4) - fp[0] = self.descr.byteorder - cdef bint is_complex = not not PyTypeNum_ISCOMPLEX(typenum) - if is_complex: - fp[1] = 'Z' - fp[1+is_complex] = base_codes[typenum] - fp[2+is_complex] = 0 - - - def __releasebuffer__(ndarray self, Py_buffer* info): - free(info.format) - - - # PS TODO TODO!: Py_ssize_t vs Py_intptr_t + # Formats that are not tested and working in Cython are not + # made available from this pxd file yet. + cdef int t = PyArray_TYPE(self) + cdef char* f = NULL + if t == NPY_BYTE: f = "b" + elif t == NPY_UBYTE: f = "B" + elif t == NPY_SHORT: f = "h" + elif t == NPY_USHORT: f = "H" + elif t == NPY_INT: f = "i" + elif t == NPY_UINT: f = "I" + elif t == NPY_LONG: f = "l" + elif t == NPY_ULONG: f = "L" + elif t == NPY_LONGLONG: f = "q" + elif t == NPY_ULONGLONG: f = "Q" + elif t == NPY_FLOAT: f = "f" + elif t == NPY_DOUBLE: f = "d" + elif t == NPY_LONGDOUBLE: f = "g" + elif t == NPY_OBJECT: f = "O" + + if f == NULL: + raise ValueError("only objects, int and float dtypes supported for ndarray buffer access so far (dtype is %d)" % t) + info.format = f -## PyArrayObject *arr = (PyArrayObject*)obj; -## PyArray_Descr *type = (PyArray_Descr*)arr->descr; - - -## int typenum = PyArray_TYPE(obj); -## if (!PyTypeNum_ISNUMBER(typenum)) { -## PyErr_Format(PyExc_TypeError, "Only numeric NumPy types currently supported."); -## return -1; -## } - -## /* -## NumPy format codes doesn't completely match buffer codes; -## seems safest to retranslate. -## 01234567890123456789012345*/ -## const char* base_codes = "?bBhHiIlLqQfdgfdgO"; - -## char* format = (char*)malloc(4); -## char* fp = format; -## *fp++ = type->byteorder; -## if (PyTypeNum_ISCOMPLEX(typenum)) *fp++ = 'Z'; -## *fp++ = base_codes[typenum]; -## *fp = 0; - -## view->buf = arr->data; -## view->readonly = !PyArray_ISWRITEABLE(obj); -## view->ndim = PyArray_NDIM(arr); -## view->strides = PyArray_STRIDES(arr); -## view->shape = PyArray_DIMS(arr); -## view->suboffsets = NULL; -## view->format = format; -## view->itemsize = type->elsize; - -## view->internal = 0; -## return 0; -## print "hello" + str(43) + "asdf" + "three" -## pass + cdef void* PyArray_DATA(ndarray arr) cdef int PyArray_TYPE(ndarray arr) + cdef int PyArray_NDIM(ndarray arr) cdef int PyArray_ISWRITEABLE(ndarray arr) + cdef npy_intp PyArray_STRIDES(ndarray arr) + cdef npy_intp PyArray_DIMS(ndarray arr) + cdef Py_ssize_t PyArray_ITEMSIZE(ndarray arr) + + ctypedef signed int npy_int8 + ctypedef signed int npy_int16 + ctypedef signed int npy_int32 + ctypedef signed int npy_int64 + ctypedef signed int npy_int96 + ctypedef signed int npy_int128 ctypedef unsigned int npy_uint8 ctypedef unsigned int npy_uint16 @@ -113,7 +95,6 @@ cdef extern from "numpy/arrayobject.h": ctypedef unsigned int npy_uint64 ctypedef unsigned int npy_uint96 ctypedef unsigned int npy_uint128 - ctypedef signed int npy_int64 ctypedef float npy_float32 ctypedef float npy_float64 @@ -121,5 +102,3 @@ cdef extern from "numpy/arrayobject.h": ctypedef float npy_float96 ctypedef float npy_float128 - -ctypedef npy_int64 int64 -- 2.26.2