numpy.pxd improvements, see details
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Fri, 15 Aug 2008 12:38:28 +0000 (14:38 +0200)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Fri, 15 Aug 2008 12:38:28 +0000 (14:38 +0200)
Do not require malloc for format string for common cases.
Provide __cythonbufferdefaults__
More robust for changing NumPy APIs
;

Cython/Includes/numpy.pxd

index 02f8d5f98a8748aab532e485c898ccb1ac9e49f7..7f3659676beae52062cb73d71fd3c760aacbea7d 100644 (file)
-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 = <void*>self.data
+            info.buf = PyArray_DATA(self)
             info.ndim = PyArray_NDIM(self)
-            info.strides = <Py_ssize_t*>self.strides
-            info.shape = <Py_ssize_t*>self.dimensions
+            info.strides = <Py_ssize_t*>PyArray_STRIDES(self)
+            info.shape = <Py_ssize_t*>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 = <char*>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