diff options
author | Pauli Virtanen <pav@iki.fi> | 2010-02-20 18:05:21 +0000 |
---|---|---|
committer | Pauli Virtanen <pav@iki.fi> | 2010-02-20 18:05:21 +0000 |
commit | 69ba79ac12c615102cd1a6b8947d3ad736f6e936 (patch) | |
tree | a9bd6a30348bad576628184eec4e97c3ec810bca | |
parent | a59bbf7a8790ed0495e2641c92bf3c3ce055faea (diff) | |
download | numpy-69ba79ac12c615102cd1a6b8947d3ad736f6e936.tar.gz |
ENH: core: implement support for PEP 3118 buffer objects in asarray() and array()
This is available only for Python >= 2.7, since the MemoryView object is
not present in earlier versions of Python. (It makes releasing the
buffer much easier, via garbage collection.)
-rw-r--r-- | numpy/core/src/multiarray/common.c | 36 | ||||
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 114 |
2 files changed, 145 insertions, 5 deletions
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c index f76e61460..c87f0d061 100644 --- a/numpy/core/src/multiarray/common.c +++ b/numpy/core/src/multiarray/common.c @@ -153,6 +153,9 @@ _array_find_type(PyObject *op, PyArray_Descr *minitype, int max) PyObject *ip; PyArray_Descr *chktype = NULL; PyArray_Descr *outtype; +#if PY_VERSION_HEX >= 0x02070000 + Py_buffer buffer_view; +#endif /* * These need to come first because if op already carries @@ -192,6 +195,33 @@ _array_find_type(PyObject *op, PyArray_Descr *minitype, int max) goto finish; } +#if PY_VERSION_HEX >= 0x02070000 + /* PEP 3118 buffer interface */ + memset(&buffer_view, 0, sizeof(Py_buffer)); + if (PyObject_GetBuffer(op, &buffer_view, PyBUF_FORMAT|PyBUF_STRIDES) == 0 || + PyObject_GetBuffer(op, &buffer_view, PyBUF_FORMAT) == 0) { + + PyErr_Clear(); + chktype = _descriptor_from_pep3118_format(buffer_view.format); + PyBuffer_Release(&buffer_view); + if (chktype) { + goto finish; + } + } + else if (PyObject_GetBuffer(op, &buffer_view, PyBUF_STRIDES) == 0 || + PyObject_GetBuffer(op, &buffer_view, PyBUF_SIMPLE) == 0) { + + PyErr_Clear(); + chktype = PyArray_DescrNewFromType(PyArray_VOID); + chktype->elsize = buffer_view.itemsize; + PyBuffer_Release(&buffer_view); + goto finish; + } + else { + PyErr_Clear(); + } +#endif + if ((ip=PyObject_GetAttrString(op, "__array_interface__"))!=NULL) { if (PyDict_Check(ip)) { PyObject *new; @@ -243,16 +273,14 @@ _array_find_type(PyObject *op, PyArray_Descr *minitype, int max) goto finish; } -#if defined(NPY_PY3K) - if (PyMemoryView_Check(op)) { -#else +#if !defined(NPY_PY3K) if (PyBuffer_Check(op)) { -#endif chktype = PyArray_DescrNewFromType(PyArray_VOID); chktype->elsize = Py_TYPE(op)->tp_as_sequence->sq_length(op); PyErr_Clear(); goto finish; } +#endif if (PyObject_HasAttrString(op, "__array__")) { ip = PyObject_CallMethod(op, "__array__", NULL); diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index b64eaa908..9a24cdf3c 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -1083,6 +1083,9 @@ discover_depth(PyObject *s, int max, int stop_at_string, int stop_at_tuple) { int d = 0; PyObject *e; +#if PY_VERSION_HEX >= 0x02070000 + Py_buffer buffer_view; +#endif if(max < 1) { return -1; @@ -1105,7 +1108,6 @@ discover_depth(PyObject *s, int max, int stop_at_string, int stop_at_tuple) } if (PyString_Check(s) || #if defined(NPY_PY3K) - PyMemoryView_Check(s) || #else PyBuffer_Check(s) || #endif @@ -1115,6 +1117,23 @@ discover_depth(PyObject *s, int max, int stop_at_string, int stop_at_tuple) if (stop_at_tuple && PyTuple_Check(s)) { return 0; } +#if PY_VERSION_HEX >= 0x02070000 + /* PEP 3118 buffer interface */ + memset(&buffer_view, 0, sizeof(Py_buffer)); + if (PyObject_GetBuffer(s, &buffer_view, PyBUF_STRIDES) == 0 || + PyObject_GetBuffer(s, &buffer_view, PyBUF_ND) == 0) { + d = buffer_view.ndim; + PyBuffer_Release(&buffer_view); + return d; + } + else if (PyObject_GetBuffer(s, &buffer_view, PyBUF_SIMPLE) == 0) { + PyBuffer_Release(&buffer_view); + return 1; + } + else { + PyErr_Clear(); + } +#endif if ((e = PyObject_GetAttrString(s, "__array_struct__")) != NULL) { d = -1; if (PyCObject_Check(e)) { @@ -1608,6 +1627,94 @@ PyArray_New(PyTypeObject *subtype, int nd, intp *dims, int type_num, return new; } + +NPY_NO_EXPORT int +_array_from_buffer_3118(PyObject *obj, PyObject **out) +{ +#if PY_VERSION_HEX >= 0x02070000 + /* XXX: Pythons < 2.7 do not have the memory view object. This makes + * using buffers somewhat difficult, since one cannot release them + * using the garbage collection + */ + + /* PEP 3118 */ + PyObject *memoryview; + Py_buffer *view; + PyArray_Descr *descr = NULL; + PyObject *r; + int nd, flags, k; + Py_ssize_t d; + npy_intp shape[NPY_MAXDIMS], strides[NPY_MAXDIMS]; + + memoryview = PyMemoryView_FromObject(obj); + if (memoryview == NULL) { + PyErr_Clear(); + return -1; + } + + view = PyMemoryView_GET_BUFFER(memoryview); + if (view->format != NULL) { + descr = _descriptor_from_pep3118_format(view->format); + if (descr == NULL) { + goto fail; + } + } + else { + descr = PyArray_DescrNewFromType(PyArray_STRING); + descr->elsize = view->itemsize; + } + + if (view->shape != NULL) { + nd = view->ndim; + if (nd >= NPY_MAXDIMS || nd < 0) { + goto fail; + } + for (k = 0; k < nd; ++k) { + if (k >= NPY_MAXDIMS) { + goto fail; + } + shape[k] = view->shape[k]; + } + if (view->strides != NULL) { + for (k = 0; k < nd; ++k) { + strides[k] = view->strides[k]; + } + } + else { + d = view->len; + for (k = 0; k < nd; ++k) { + d /= view->shape[k]; + strides[k] = d; + } + } + } + else { + nd = 1; + shape[0] = view->len / view->itemsize; + strides[0] = view->itemsize; + } + + flags = (view->readonly ? 0 : NPY_WRITEABLE); + r = PyArray_NewFromDescr(&PyArray_Type, descr, + nd, shape, strides, view->buf, + flags, NULL); + ((PyArrayObject *)r)->base = memoryview; + PyArray_UpdateFlags((PyArrayObject *)r, UPDATE_ALL); + + *out = r; + return 0; + +fail: + Py_XDECREF(descr); + Py_DECREF(memoryview); + return -1; + +#else + return -1; +#endif +} + + /*NUMPY_API * Does not check for ENSURECOPY and NOTSWAPPED in flags * Steals a reference to newtype --- which can be NULL @@ -1645,6 +1752,11 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth, } r = Array_FromPyScalar(op, newtype); } +#if PY_VERSION_HEX >= 0x02070000 + else if (_array_from_buffer_3118(op, &r) == 0) { + r = r; + } +#endif else if (PyArray_HasArrayInterfaceType(op, newtype, context, r)) { PyObject *new; if (r == NULL) { |