See array_assign.h for parameter documentation */
| 26 | |
| 27 | /* See array_assign.h for parameter documentation */ |
| 28 | NPY_NO_EXPORT int |
| 29 | broadcast_strides(int ndim, npy_intp const *shape, |
| 30 | int strides_ndim, npy_intp const *strides_shape, npy_intp const *strides, |
| 31 | char const *strides_name, |
| 32 | npy_intp *out_strides) |
| 33 | { |
| 34 | int idim, idim_start = ndim - strides_ndim; |
| 35 | |
| 36 | /* Can't broadcast to fewer dimensions */ |
| 37 | if (idim_start < 0) { |
| 38 | goto broadcast_error; |
| 39 | } |
| 40 | |
| 41 | /* |
| 42 | * Process from the end to the start, so that 'strides' and 'out_strides' |
| 43 | * can point to the same memory. |
| 44 | */ |
| 45 | for (idim = ndim - 1; idim >= idim_start; --idim) { |
| 46 | npy_intp strides_shape_value = strides_shape[idim - idim_start]; |
| 47 | /* If it doesn't have dimension one, it must match */ |
| 48 | if (strides_shape_value == 1) { |
| 49 | out_strides[idim] = 0; |
| 50 | } |
| 51 | else if (strides_shape_value != shape[idim]) { |
| 52 | goto broadcast_error; |
| 53 | } |
| 54 | else { |
| 55 | out_strides[idim] = strides[idim - idim_start]; |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | /* New dimensions get a zero stride */ |
| 60 | for (idim = 0; idim < idim_start; ++idim) { |
| 61 | out_strides[idim] = 0; |
| 62 | } |
| 63 | |
| 64 | return 0; |
| 65 | |
| 66 | broadcast_error: { |
| 67 | PyObject *shape1 = convert_shape_to_string(strides_ndim, |
| 68 | strides_shape, ""); |
| 69 | if (shape1 == NULL) { |
| 70 | return -1; |
| 71 | } |
| 72 | |
| 73 | PyObject *shape2 = convert_shape_to_string(ndim, shape, ""); |
| 74 | if (shape2 == NULL) { |
| 75 | Py_DECREF(shape1); |
| 76 | return -1; |
| 77 | } |
| 78 | PyErr_Format(PyExc_ValueError, |
| 79 | "could not broadcast %s from shape %S into shape %S", |
| 80 | strides_name, shape1, shape2); |
| 81 | Py_DECREF(shape1); |
| 82 | Py_DECREF(shape2); |
| 83 | return -1; |
| 84 | } |
| 85 | } |
no test coverage detected