* Allocates a temporary array which can be used to replace op * in the iteration. Its dtype will be op_dtype. * * The result array has a memory ordering which matches the iterator, * which may or may not match that of op. The parameter 'shape' may be * NULL, in which case it is filled in from the iterator's shape. * * This function must be called before any axes are coalesced. */
| 2484 | * This function must be called before any axes are coalesced. |
| 2485 | */ |
| 2486 | static PyArrayObject * |
| 2487 | npyiter_new_temp_array(NpyIter *iter, PyTypeObject *subtype, |
| 2488 | npy_uint32 flags, npyiter_opitflags *op_itflags, |
| 2489 | int op_ndim, npy_intp const *shape, |
| 2490 | PyArray_Descr *op_dtype, const int *op_axes) |
| 2491 | { |
| 2492 | npy_uint32 itflags = NIT_ITFLAGS(iter); |
| 2493 | int idim, ndim = NIT_NDIM(iter); |
| 2494 | int used_op_ndim; |
| 2495 | int nop = NIT_NOP(iter); |
| 2496 | |
| 2497 | npy_int8 *perm = NIT_PERM(iter); |
| 2498 | npy_intp new_shape[NPY_MAXDIMS], strides[NPY_MAXDIMS]; |
| 2499 | npy_intp stride = op_dtype->elsize; |
| 2500 | NpyIter_AxisData *axisdata; |
| 2501 | npy_intp sizeof_axisdata; |
| 2502 | int i; |
| 2503 | |
| 2504 | PyArrayObject *ret; |
| 2505 | |
| 2506 | /* |
| 2507 | * There is an interaction with array-dtypes here, which |
| 2508 | * generally works. Let's say you make an nditer with an |
| 2509 | * output dtype of a 2-double array. All-scalar inputs |
| 2510 | * will result in a 1-dimensional output with shape (2). |
| 2511 | * Everything still works out in the nditer, because the |
| 2512 | * new dimension is always added on the end, and it cares |
| 2513 | * about what happens at the beginning. |
| 2514 | */ |
| 2515 | |
| 2516 | /* If it's a scalar, don't need to check the axes */ |
| 2517 | if (op_ndim == 0) { |
| 2518 | Py_INCREF(op_dtype); |
| 2519 | ret = (PyArrayObject *)PyArray_NewFromDescr(subtype, op_dtype, 0, |
| 2520 | NULL, NULL, NULL, 0, NULL); |
| 2521 | |
| 2522 | return ret; |
| 2523 | } |
| 2524 | |
| 2525 | axisdata = NIT_AXISDATA(iter); |
| 2526 | sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop); |
| 2527 | |
| 2528 | /* Initialize the strides to invalid values */ |
| 2529 | for (i = 0; i < op_ndim; ++i) { |
| 2530 | strides[i] = NPY_MAX_INTP; |
| 2531 | } |
| 2532 | |
| 2533 | if (op_axes != NULL) { |
| 2534 | used_op_ndim = 0; |
| 2535 | for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) { |
| 2536 | npy_bool reduction_axis; |
| 2537 | |
| 2538 | /* Apply the perm to get the original axis */ |
| 2539 | i = npyiter_undo_iter_axis_perm(idim, ndim, perm, NULL); |
| 2540 | i = npyiter_get_op_axis(op_axes[i], &reduction_axis); |
| 2541 | |
| 2542 | /* |
| 2543 | * If i < 0, this is a new axis (the operand does not have it) |
no test coverage detected