summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2021-04-19 19:20:50 -0500
committerSebastian Berg <sebastian@sipsolutions.net>2021-04-20 17:36:28 -0500
commitb2926034b6056e42525ad702b380339940755124 (patch)
treeda98a8a240843e635a394c9ab063219b6c4fade1
parentbb2a1ad9161838212ac90af4f6d6af430bbab00d (diff)
downloadnumpy-b2926034b6056e42525ad702b380339940755124.tar.gz
MAINT: Remove buffer-clearing from copy code
Buffer must always either contain NULL or valid references (assuming the dtype supports references) in order to allow cleanup in case of errors. It is thus unnecessary to clear buffers before every copy, if they contain NULL, all is fine. If they contain non-NULL, we should also DECREF those references (so it would be incorrect as well). Buffers thus need the memset exactly once: directly upon allcoation (which we do now). After this any transfer from/to the buffer needs to ensure that the buffer is always in a good state.
-rw-r--r--numpy/core/src/multiarray/nditer_api.c32
-rw-r--r--numpy/core/tests/test_nditer.py4
2 files changed, 14 insertions, 22 deletions
diff --git a/numpy/core/src/multiarray/nditer_api.c b/numpy/core/src/multiarray/nditer_api.c
index 063e30919..a1ca5bff5 100644
--- a/numpy/core/src/multiarray/nditer_api.c
+++ b/numpy/core/src/multiarray/nditer_api.c
@@ -2532,16 +2532,18 @@ npyiter_copy_to_buffers(NpyIter *iter, char **prev_dataptrs)
skip_transfer = 1;
}
- /* If the data type requires zero-inititialization */
- if (PyDataType_FLAGCHK(dtypes[iop], NPY_NEEDS_INIT)) {
- NPY_IT_DBG_PRINT("Iterator: Buffer requires init, "
- "memsetting to 0\n");
- memset(ptrs[iop], 0, dtypes[iop]->elsize*op_transfersize);
- /* Can't skip the transfer in this case */
- skip_transfer = 0;
- }
-
- if (!skip_transfer) {
+ /*
+ * Copy data to the buffers if necessary.
+ *
+ * We always copy if the operand has references. In that case
+ * a "write" function must be in use that either copies or clears
+ * the buffer.
+ * This write from buffer call does not check for skip-transfer
+ * so we have to assume the buffer is cleared. For dtypes that
+ * do not have references, we can assume that the write function
+ * will leave the source (buffer) unmodified.
+ */
+ if (!skip_transfer || PyDataType_REFCHK(dtypes[iop])) {
NPY_IT_DBG_PRINT2("Iterator: Copying operand %d to "
"buffer (%d items)\n",
(int)iop, (int)op_transfersize);
@@ -2557,16 +2559,6 @@ npyiter_copy_to_buffers(NpyIter *iter, char **prev_dataptrs)
}
}
}
- else if (ptrs[iop] == buffers[iop]) {
- /* If the data type requires zero-inititialization */
- if (PyDataType_FLAGCHK(dtypes[iop], NPY_NEEDS_INIT)) {
- NPY_IT_DBG_PRINT1("Iterator: Write-only buffer for "
- "operand %d requires init, "
- "memsetting to 0\n", (int)iop);
- memset(ptrs[iop], 0, dtypes[iop]->elsize*transfersize);
- }
- }
-
}
/*
diff --git a/numpy/core/tests/test_nditer.py b/numpy/core/tests/test_nditer.py
index c32822944..b44343c57 100644
--- a/numpy/core/tests/test_nditer.py
+++ b/numpy/core/tests/test_nditer.py
@@ -2922,8 +2922,8 @@ def test_object_iter_cleanup():
def test_object_iter_cleanup_reduce():
# Similar as above, but a complex reduction case that was previously
- # missed (see gh-18810)/
- # the following array is special in that it cananot be flattened:
+ # missed (see gh-18810).
+ # The following array is special in that it cannot be flattened:
arr = np.array([[None, 1], [-1, -1], [None, 2], [-1, -1]])[::2]
with pytest.raises(TypeError):
np.sum(arr)