diff options
author | Stefan Krah <skrah@bytereef.org> | 2012-07-28 10:25:55 (GMT) |
---|---|---|
committer | Stefan Krah <skrah@bytereef.org> | 2012-07-28 10:25:55 (GMT) |
commit | 7d12d9df136b45785fb945dcb4812fdb068a2498 (patch) | |
tree | a68da71ef9e618cad72d9d6b589d6bdbc589873e /Objects | |
parent | 6c779ea55329947577119b8a7ea732f6d540d516 (diff) | |
download | cpython-7d12d9df136b45785fb945dcb4812fdb068a2498.zip cpython-7d12d9df136b45785fb945dcb4812fdb068a2498.tar.gz cpython-7d12d9df136b45785fb945dcb4812fdb068a2498.tar.bz2 |
Issue #12834: Fix PyBuffer_ToContiguous() for non-contiguous arrays.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/abstract.c | 56 | ||||
-rw-r--r-- | Objects/bytearrayobject.c | 2 | ||||
-rw-r--r-- | Objects/bytesobject.c | 1 | ||||
-rw-r--r-- | Objects/memoryobject.c | 77 |
4 files changed, 71 insertions, 65 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c index 42cd169..aa43b72 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -445,62 +445,6 @@ _Py_add_one_to_index_C(int nd, Py_ssize_t *index, const Py_ssize_t *shape) } } - /* view is not checked for consistency in either of these. It is - assumed that the size of the buffer is view->len in - view->len / view->itemsize elements. - */ - -int -PyBuffer_ToContiguous(void *buf, Py_buffer *view, Py_ssize_t len, char fort) -{ - int k; - void (*addone)(int, Py_ssize_t *, const Py_ssize_t *); - Py_ssize_t *indices, elements; - char *dest, *ptr; - - if (len > view->len) { - len = view->len; - } - - if (PyBuffer_IsContiguous(view, fort)) { - /* simplest copy is all that is needed */ - memcpy(buf, view->buf, len); - return 0; - } - - /* Otherwise a more elaborate scheme is needed */ - - /* XXX(nnorwitz): need to check for overflow! */ - indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim)); - if (indices == NULL) { - PyErr_NoMemory(); - return -1; - } - for (k=0; k<view->ndim;k++) { - indices[k] = 0; - } - - if (fort == 'F') { - addone = _Py_add_one_to_index_F; - } - else { - addone = _Py_add_one_to_index_C; - } - dest = buf; - /* XXX : This is not going to be the fastest code in the world - several optimizations are possible. - */ - elements = len / view->itemsize; - while (elements--) { - addone(view->ndim, indices, view->shape); - ptr = PyBuffer_GetPointer(view, indices); - memcpy(dest, ptr, view->itemsize); - dest += view->itemsize; - } - PyMem_Free(indices); - return 0; -} - int PyBuffer_FromContiguous(Py_buffer *view, void *buf, Py_ssize_t len, char fort) { diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 5b7083d..2bb3a29 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -789,7 +789,7 @@ bytearray_init(PyByteArrayObject *self, PyObject *args, PyObject *kwds) size = view.len; if (PyByteArray_Resize((PyObject *)self, size) < 0) goto fail; if (PyBuffer_ToContiguous(self->ob_bytes, &view, size, 'C') < 0) - goto fail; + goto fail; PyBuffer_Release(&view); return 0; fail: diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 14bd8e6..bf9259f 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2591,7 +2591,6 @@ PyBytes_FromObject(PyObject *x) new = PyBytes_FromStringAndSize(NULL, view.len); if (!new) goto fail; - /* XXX(brett.cannon): Better way to get to internal buffer? */ if (PyBuffer_ToContiguous(((PyBytesObject *)new)->ob_sval, &view, view.len, 'C') < 0) goto fail; diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 62427d4..c7185f0 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -438,15 +438,17 @@ init_fortran_strides_from_shape(Py_buffer *view) view->strides[i] = view->strides[i-1] * view->shape[i-1]; } -/* Copy src to a C-contiguous representation. Assumptions: +/* Copy src to a contiguous representation. order is one of 'C', 'F' (Fortran) + or 'A' (Any). Assumptions: src has PyBUF_FULL information, src->ndim >= 1, len(mem) == src->len. */ static int -buffer_to_c_contiguous(char *mem, Py_buffer *src) +buffer_to_contiguous(char *mem, Py_buffer *src, char order) { Py_buffer dest; Py_ssize_t *strides; int ret; + assert(src->ndim >= 1); assert(src->shape != NULL); assert(src->strides != NULL); @@ -456,12 +458,22 @@ buffer_to_c_contiguous(char *mem, Py_buffer *src) return -1; } - /* initialize dest as a C-contiguous buffer */ + /* initialize dest */ dest = *src; dest.buf = mem; - /* shape is constant and shared */ + /* shape is constant and shared: the logical representation of the + array is unaltered. */ + + /* The physical representation determined by strides (and possibly + suboffsets) may change. */ dest.strides = strides; - init_strides_from_shape(&dest); + if (order == 'C' || order == 'A') { + init_strides_from_shape(&dest); + } + else { + init_fortran_strides_from_shape(&dest); + } + dest.suboffsets = NULL; ret = copy_buffer(&dest, src); @@ -922,6 +934,57 @@ memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) /****************************************************************************/ +/* Previously in abstract.c */ +/****************************************************************************/ + +typedef struct { + Py_buffer view; + Py_ssize_t array[1]; +} Py_buffer_full; + +int +PyBuffer_ToContiguous(void *buf, Py_buffer *src, Py_ssize_t len, char order) +{ + Py_buffer_full *fb = NULL; + int ret; + + assert(order == 'C' || order == 'F' || order == 'A'); + + if (len != src->len) { + PyErr_SetString(PyExc_ValueError, + "PyBuffer_ToContiguous: len != view->len"); + return -1; + } + + if (PyBuffer_IsContiguous(src, order)) { + memcpy((char *)buf, src->buf, len); + return 0; + } + + /* buffer_to_contiguous() assumes PyBUF_FULL */ + fb = PyMem_Malloc(sizeof *fb + 3 * src->ndim * (sizeof *fb->array)); + if (fb == NULL) { + PyErr_NoMemory(); + return -1; + } + fb->view.ndim = src->ndim; + fb->view.shape = fb->array; + fb->view.strides = fb->array + src->ndim; + fb->view.suboffsets = fb->array + 2 * src->ndim; + + init_shared_values(&fb->view, src); + init_shape_strides(&fb->view, src); + init_suboffsets(&fb->view, src); + + src = &fb->view; + + ret = buffer_to_contiguous(buf, src, order); + PyMem_Free(fb); + return ret; +} + + +/****************************************************************************/ /* Release/GC management */ /****************************************************************************/ @@ -1889,7 +1952,7 @@ memory_tobytes(PyMemoryViewObject *self, PyObject *dummy) if (bytes == NULL) return NULL; - if (buffer_to_c_contiguous(PyBytes_AS_STRING(bytes), src) < 0) { + if (buffer_to_contiguous(PyBytes_AS_STRING(bytes), src, 'C') < 0) { Py_DECREF(bytes); return NULL; } @@ -2423,7 +2486,7 @@ memory_hash(PyMemoryViewObject *self) PyErr_NoMemory(); return -1; } - if (buffer_to_c_contiguous(mem, view) < 0) { + if (buffer_to_contiguous(mem, view, 'C') < 0) { PyMem_Free(mem); return -1; } |