* The ufunc loop implementation for both normal ufunc calls and masked calls * when the iterator has to be used. * * See `PyUFunc_GenericFunctionInternal` for more information (where this is * called from). */
| 1454 | * called from). |
| 1455 | */ |
| 1456 | static int |
| 1457 | execute_ufunc_loop(PyArrayMethod_Context *context, int masked, |
| 1458 | PyArrayObject **op, NPY_ORDER order, npy_intp buffersize, |
| 1459 | NPY_CASTING casting, |
| 1460 | PyObject **arr_prep, ufunc_full_args full_args, |
| 1461 | npy_uint32 *op_flags, int errormask, PyObject *extobj) |
| 1462 | { |
| 1463 | PyUFuncObject *ufunc = (PyUFuncObject *)context->caller; |
| 1464 | int nin = context->method->nin, nout = context->method->nout; |
| 1465 | int nop = nin + nout; |
| 1466 | |
| 1467 | if (validate_casting(context->method, |
| 1468 | ufunc, op, context->descriptors, casting) < 0) { |
| 1469 | return -1; |
| 1470 | } |
| 1471 | |
| 1472 | if (masked) { |
| 1473 | assert(PyArray_TYPE(op[nop]) == NPY_BOOL); |
| 1474 | if (ufunc->_always_null_previously_masked_innerloop_selector != NULL) { |
| 1475 | if (PyErr_WarnFormat(PyExc_UserWarning, 1, |
| 1476 | "The ufunc %s has a custom masked-inner-loop-selector." |
| 1477 | "NumPy assumes that this is NEVER used. If you do make " |
| 1478 | "use of this please notify the NumPy developers to discuss " |
| 1479 | "future solutions. (See NEP 41 and 43)\n" |
| 1480 | "NumPy will continue, but ignore the custom loop selector. " |
| 1481 | "This should only affect performance.", |
| 1482 | ufunc_get_name_cstr(ufunc)) < 0) { |
| 1483 | return -1; |
| 1484 | } |
| 1485 | } |
| 1486 | |
| 1487 | /* |
| 1488 | * NOTE: In the masked version, we consider the output read-write, |
| 1489 | * this gives a best-effort of preserving the input, but does |
| 1490 | * not always work. It could allow the operand to be copied |
| 1491 | * due to copy-if-overlap, but only if it was passed in. |
| 1492 | * In that case `__array_prepare__` is called before it happens. |
| 1493 | */ |
| 1494 | for (int i = nin; i < nop; ++i) { |
| 1495 | op_flags[i] |= (op[i] != NULL ? NPY_ITER_READWRITE : NPY_ITER_WRITEONLY); |
| 1496 | } |
| 1497 | op_flags[nop] = NPY_ITER_READONLY | NPY_ITER_ARRAYMASK; /* mask */ |
| 1498 | } |
| 1499 | |
| 1500 | NPY_UF_DBG_PRINT("Making iterator\n"); |
| 1501 | |
| 1502 | npy_uint32 iter_flags = ufunc->iter_flags | |
| 1503 | NPY_ITER_EXTERNAL_LOOP | |
| 1504 | NPY_ITER_REFS_OK | |
| 1505 | NPY_ITER_ZEROSIZE_OK | |
| 1506 | NPY_ITER_BUFFERED | |
| 1507 | NPY_ITER_GROWINNER | |
| 1508 | NPY_ITER_DELAY_BUFALLOC | |
| 1509 | NPY_ITER_COPY_IF_OVERLAP; |
| 1510 | |
| 1511 | /* |
| 1512 | * Call the __array_prepare__ functions for already existing output arrays. |
| 1513 | * Do this before creating the iterator, as the iterator may UPDATEIFCOPY |
no test coverage detected