summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorseberg <sebastian@sipsolutions.net>2016-11-22 19:39:04 +0100
committerGitHub <noreply@github.com>2016-11-22 19:39:04 +0100
commitce6d3ffc991c63c1a91fd806b4eb3d0008caace2 (patch)
tree2c1e0f8dfd44c1a3b82eeeca0a754d93b5dfc0d4 /numpy
parenta91309771b0025c4e291501d0c00bf4178a66c38 (diff)
parentcce86d6241d6fa8253ca119a0b47b05a5b375996 (diff)
downloadnumpy-ce6d3ffc991c63c1a91fd806b4eb3d0008caace2.tar.gz
Merge pull request #8284 from rainwoodman/fix-8264
BUG: Fix iteration over reversed subspaces in mapiter_@name@
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/lowlevel_strided_loops.c.src39
-rw-r--r--numpy/core/tests/test_indexing.py9
2 files changed, 40 insertions, 8 deletions
diff --git a/numpy/core/src/multiarray/lowlevel_strided_loops.c.src b/numpy/core/src/multiarray/lowlevel_strided_loops.c.src
index b8381ab68..9a5c3004d 100644
--- a/numpy/core/src/multiarray/lowlevel_strided_loops.c.src
+++ b/numpy/core/src/multiarray/lowlevel_strided_loops.c.src
@@ -1632,7 +1632,8 @@ mapiter_@name@(PyArrayMapIterObject *mit)
char *subspace_baseptrs[2];
char **subspace_ptrs = mit->subspace_ptrs;
npy_intp *subspace_strides = mit->subspace_strides;
- int skip = 0;
+ int is_subiter_trivial = 0; /* has three states */
+ npy_intp reset_offsets[2] = {0, 0};
/* Use strided transfer functions for the inner loop */
PyArray_StridedUnaryOp *stransfer = NULL;
@@ -1667,9 +1668,12 @@ mapiter_@name@(PyArrayMapIterObject *mit)
counter = NpyIter_GetInnerLoopSizePtr(mit->subspace_iter);
if (*counter == PyArray_SIZE(mit->subspace)) {
- skip = 1;
+ /*
+ * subspace is trivially iterable.
+ * manipulate pointers to avoid expensive resetting
+ */
+ is_subiter_trivial = 1;
}
-
/**begin repeat1
* #one_iter = 1, 0#
* #numiter = 1, numiter#
@@ -1707,10 +1711,15 @@ mapiter_@name@(PyArrayMapIterObject *mit)
}
/*
- * Resetting is slow, so skip if the subspace iteration has
- * only a single inner loop.
+ * Resetting is slow, so try to avoid resetting
+ * if subspace iteration is trivial.
+ * Watch out: reset_offsets are kept outside of the loop,
+ * assuming the subspaces of different external iterations
+ * share the same structure.
*/
- if (!skip) {
+ if (is_subiter_trivial <= 1) {
+ /* slower resetting: first iteration or non-trivial subspace */
+
char * errmsg = NULL;
subspace_baseptrs[0] = self_ptr;
subspace_baseptrs[1] = mit->extra_op_ptrs[0];
@@ -1724,10 +1733,24 @@ mapiter_@name@(PyArrayMapIterObject *mit)
NPY_AUXDATA_FREE(transferdata);
return -1;
}
+ if (is_subiter_trivial != 0) {
+ /* reset_offsets are nonzero for negative strides.*/
+ reset_offsets[0] = subspace_ptrs[0] - self_ptr;
+ reset_offsets[1] = subspace_ptrs[1] - mit->extra_op_ptrs[0];
+
+ /* use the faster adjustment further on */
+ is_subiter_trivial ++;
+ }
}
else {
- subspace_ptrs[0] = self_ptr;
- subspace_ptrs[1] = mit->extra_op_ptrs[0];
+ /*
+ * faster resetting if the subspace iteration is trival.
+ * reset_offsets are zero for positive strides,
+ * for negative strides this shifts the pointer to the last
+ * item.
+ */
+ subspace_ptrs[0] = self_ptr + reset_offsets[0];
+ subspace_ptrs[1] = mit->extra_op_ptrs[0] + reset_offsets[1];
}
#if !@isget@
diff --git a/numpy/core/tests/test_indexing.py b/numpy/core/tests/test_indexing.py
index f16756221..e986221f5 100644
--- a/numpy/core/tests/test_indexing.py
+++ b/numpy/core/tests/test_indexing.py
@@ -497,6 +497,15 @@ class TestIndexing(TestCase):
zind = np.zeros(4, dtype=np.intp)
assert_array_equal(x2[ind, zind], x2[ind.copy(), zind])
+ def test_indexing_array_negative_strides(self):
+ # From gh-8264,
+ # core dumps if negative strides are used in iteration
+ arro = np.zeros((4, 4))
+ arr = arro[::-1, ::-1]
+
+ slices = [slice(None), [0, 1, 2, 3]]
+ arr[slices] = 10
+ assert_array_equal(arr, 10.)
class TestFieldIndexing(TestCase):
def test_scalar_return_type(self):