Issue #22445: PyBuffer_IsContiguous() now implements precise contiguity

tests, compatible with NumPy's NPY_RELAXED_STRIDES_CHECKING compilation
flag.  Previously the function reported false negatives for corner cases.
This commit is contained in:
Stefan Krah 2015-02-01 14:53:54 +01:00
parent a5e1dbef14
commit 363af44a4a
4 changed files with 90 additions and 29 deletions

View file

@ -1510,6 +1510,19 @@ ndarray_getbuf(NDArrayObject *self, Py_buffer *view, int flags)
view->shape = NULL;
}
/* Ascertain that the new buffer has the same contiguity as the exporter */
if (ND_C_CONTIGUOUS(baseflags) != PyBuffer_IsContiguous(view, 'C') ||
/* skip cast to 1-d */
(view->format != NULL && view->shape != NULL &&
ND_FORTRAN_CONTIGUOUS(baseflags) != PyBuffer_IsContiguous(view, 'F')) ||
/* cast to 1-d */
(view->format == NULL && view->shape == NULL &&
!PyBuffer_IsContiguous(view, 'F'))) {
PyErr_SetString(PyExc_BufferError,
"ndarray: contiguity mismatch in getbuf()");
return -1;
}
view->obj = (PyObject *)self;
Py_INCREF(view->obj);
self->head->exports++;
@ -2206,6 +2219,8 @@ ndarray_add_suboffsets(PyObject *self, PyObject *dummy)
for (i = 0; i < base->ndim; i++)
base->suboffsets[i] = -1;
nd->head->flags &= ~(ND_C|ND_FORTRAN);
Py_RETURN_NONE;
}
@ -2469,13 +2484,12 @@ arraycmp(const Py_ssize_t *a1, const Py_ssize_t *a2, const Py_ssize_t *shape,
{
Py_ssize_t i;
if (ndim == 1 && shape && shape[0] == 1) {
/* This is for comparing strides: For example, the array
[175], shape=[1], strides=[-5] is considered contiguous. */
return 1;
}
for (i = 0; i < ndim; i++) {
if (shape && shape[i] <= 1) {
/* strides can differ if the dimension is less than 2 */
continue;
}
if (a1[i] != a2[i]) {
return 0;
}
@ -2555,30 +2569,35 @@ is_contiguous(PyObject *self, PyObject *args)
PyObject *obj;
PyObject *order;
PyObject *ret = NULL;
Py_buffer view;
Py_buffer view, *base;
char ord;
if (!PyArg_ParseTuple(args, "OO", &obj, &order)) {
return NULL;
}
if (PyObject_GetBuffer(obj, &view, PyBUF_FULL_RO) < 0) {
PyErr_SetString(PyExc_TypeError,
"is_contiguous: object does not implement the buffer "
"protocol");
ord = get_ascii_order(order);
if (ord == CHAR_MAX) {
return NULL;
}
ord = get_ascii_order(order);
if (ord == CHAR_MAX) {
goto release;
if (NDArray_Check(obj)) {
/* Skip the buffer protocol to check simple etc. buffers directly. */
base = &((NDArrayObject *)obj)->head->base;
ret = PyBuffer_IsContiguous(base, ord) ? Py_True : Py_False;
}
else {
if (PyObject_GetBuffer(obj, &view, PyBUF_FULL_RO) < 0) {
PyErr_SetString(PyExc_TypeError,
"is_contiguous: object does not implement the buffer "
"protocol");
return NULL;
}
ret = PyBuffer_IsContiguous(&view, ord) ? Py_True : Py_False;
PyBuffer_Release(&view);
}
ret = PyBuffer_IsContiguous(&view, ord) ? Py_True : Py_False;
Py_INCREF(ret);
release:
PyBuffer_Release(&view);
return ret;
}