Commit 62ef7487 authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

numpy.pxd improvements, see details

Do not require malloc for format string for common cases.
Provide __cythonbufferdefaults__
More robust for changing NumPy APIs
;
parent a4572ec9
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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment