diff options
author | seberg <sebastian@sipsolutions.net> | 2016-11-22 19:39:04 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-22 19:39:04 +0100 |
commit | ce6d3ffc991c63c1a91fd806b4eb3d0008caace2 (patch) | |
tree | 2c1e0f8dfd44c1a3b82eeeca0a754d93b5dfc0d4 /numpy | |
parent | a91309771b0025c4e291501d0c00bf4178a66c38 (diff) | |
parent | cce86d6241d6fa8253ca119a0b47b05a5b375996 (diff) | |
download | numpy-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.src | 39 | ||||
-rw-r--r-- | numpy/core/tests/test_indexing.py | 9 |
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): |