* Function to add a new loop to the ufunc. This mainly appends it to the * list (as it currently is just a list). * * @param ufunc The universal function to add the loop to. * @param info The tuple (dtype_tuple, ArrayMethod/promoter). * @param ignore_duplicate If 1 and a loop with the same `dtype_tuple` is * found, the function does nothing. */
| 77 | * found, the function does nothing. |
| 78 | */ |
| 79 | NPY_NO_EXPORT int |
| 80 | PyUFunc_AddLoop(PyUFuncObject *ufunc, PyObject *info, int ignore_duplicate) |
| 81 | { |
| 82 | /* |
| 83 | * Validate the info object, this should likely move to a different |
| 84 | * entry-point in the future (and is mostly unnecessary currently). |
| 85 | */ |
| 86 | if (!PyTuple_CheckExact(info) || PyTuple_GET_SIZE(info) != 2) { |
| 87 | PyErr_SetString(PyExc_TypeError, |
| 88 | "Info must be a tuple: " |
| 89 | "(tuple of DTypes or None, ArrayMethod or promoter)"); |
| 90 | return -1; |
| 91 | } |
| 92 | PyObject *DType_tuple = PyTuple_GetItem(info, 0); |
| 93 | if (PyTuple_GET_SIZE(DType_tuple) != ufunc->nargs) { |
| 94 | PyErr_SetString(PyExc_TypeError, |
| 95 | "DType tuple length does not match ufunc number of operands"); |
| 96 | return -1; |
| 97 | } |
| 98 | for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(DType_tuple); i++) { |
| 99 | PyObject *item = PyTuple_GET_ITEM(DType_tuple, i); |
| 100 | if (item != Py_None |
| 101 | && !PyObject_TypeCheck(item, &PyArrayDTypeMeta_Type)) { |
| 102 | PyErr_SetString(PyExc_TypeError, |
| 103 | "DType tuple may only contain None and DType classes"); |
| 104 | return -1; |
| 105 | } |
| 106 | } |
| 107 | PyObject *meth_or_promoter = PyTuple_GET_ITEM(info, 1); |
| 108 | if (!PyObject_TypeCheck(meth_or_promoter, &PyArrayMethod_Type) |
| 109 | && !PyCapsule_IsValid(meth_or_promoter, "numpy._ufunc_promoter")) { |
| 110 | PyErr_SetString(PyExc_TypeError, |
| 111 | "Second argument to info must be an ArrayMethod or promoter"); |
| 112 | return -1; |
| 113 | } |
| 114 | |
| 115 | if (ufunc->_loops == NULL) { |
| 116 | ufunc->_loops = PyList_New(0); |
| 117 | if (ufunc->_loops == NULL) { |
| 118 | return -1; |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | PyObject *loops = ufunc->_loops; |
| 123 | Py_ssize_t length = PyList_Size(loops); |
| 124 | for (Py_ssize_t i = 0; i < length; i++) { |
| 125 | PyObject *item = PyList_GetItem(loops, i); |
| 126 | PyObject *cur_DType_tuple = PyTuple_GetItem(item, 0); |
| 127 | int cmp = PyObject_RichCompareBool(cur_DType_tuple, DType_tuple, Py_EQ); |
| 128 | if (cmp < 0) { |
| 129 | return -1; |
| 130 | } |
| 131 | if (cmp == 0) { |
| 132 | continue; |
| 133 | } |
| 134 | if (ignore_duplicate) { |
| 135 | return 0; |
| 136 | } |
no test coverage detected