diff options
| author | Sebastian Berg <sebastian@sipsolutions.net> | 2021-04-19 19:20:50 -0500 |
|---|---|---|
| committer | Sebastian Berg <sebastian@sipsolutions.net> | 2021-04-20 17:36:28 -0500 |
| commit | b2926034b6056e42525ad702b380339940755124 (patch) | |
| tree | da98a8a240843e635a394c9ab063219b6c4fade1 | |
| parent | bb2a1ad9161838212ac90af4f6d6af430bbab00d (diff) | |
| download | numpy-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.c | 32 | ||||
| -rw-r--r-- | numpy/core/tests/test_nditer.py | 4 |
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) |
