Skip to content

Commit

Permalink
Merge pull request numpy#8284 from rainwoodman/fix-8264
Browse files Browse the repository at this point in the history
BUG: Fix iteration over reversed subspaces in mapiter_@name@
  • Loading branch information
seberg authored Nov 22, 2016
2 parents a913097 + cce86d6 commit ce6d3ff
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 8 deletions.
39 changes: 31 additions & 8 deletions numpy/core/src/multiarray/lowlevel_strided_loops.c.src
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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#
Expand Down Expand Up @@ -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];
Expand All @@ -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@
Expand Down
9 changes: 9 additions & 0 deletions numpy/core/tests/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,15 @@ def test_indexing_array_weird_strides(self):
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):
Expand Down

0 comments on commit ce6d3ff

Please sign in to comment.