* Allows creating of a fairly lightweight wrapper around an existing ufunc * loop. The idea is mainly for units, as this is currently slightly limited * in that it enforces that you cannot use a loop from another ufunc. * * @param ufunc_obj * @param new_dtypes * @param wrapped_dtypes * @param translate_given_descrs See typedef comment * @param translate_loop_descrs See typedef comment *
| 223 | * @return 0 on success -1 on failure |
| 224 | */ |
| 225 | NPY_NO_EXPORT int |
| 226 | PyUFunc_AddWrappingLoop(PyObject *ufunc_obj, |
| 227 | PyArray_DTypeMeta *new_dtypes[], PyArray_DTypeMeta *wrapped_dtypes[], |
| 228 | translate_given_descrs_func *translate_given_descrs, |
| 229 | translate_loop_descrs_func *translate_loop_descrs) |
| 230 | { |
| 231 | int res = -1; |
| 232 | PyUFuncObject *ufunc = (PyUFuncObject *)ufunc_obj; |
| 233 | PyObject *wrapped_dt_tuple = NULL; |
| 234 | PyObject *new_dt_tuple = NULL; |
| 235 | PyArrayMethodObject *meth = NULL; |
| 236 | |
| 237 | if (!PyObject_TypeCheck(ufunc_obj, &PyUFunc_Type)) { |
| 238 | PyErr_SetString(PyExc_TypeError, |
| 239 | "ufunc object passed is not a ufunc!"); |
| 240 | return -1; |
| 241 | } |
| 242 | |
| 243 | wrapped_dt_tuple = PyArray_TupleFromItems( |
| 244 | ufunc->nargs, (PyObject **)wrapped_dtypes, 1); |
| 245 | if (wrapped_dt_tuple == NULL) { |
| 246 | goto finish; |
| 247 | } |
| 248 | |
| 249 | PyArrayMethodObject *wrapped_meth = NULL; |
| 250 | PyObject *loops = ufunc->_loops; |
| 251 | Py_ssize_t length = PyList_Size(loops); |
| 252 | for (Py_ssize_t i = 0; i < length; i++) { |
| 253 | PyObject *item = PyList_GetItem(loops, i); |
| 254 | PyObject *cur_DType_tuple = PyTuple_GetItem(item, 0); |
| 255 | int cmp = PyObject_RichCompareBool(cur_DType_tuple, wrapped_dt_tuple, Py_EQ); |
| 256 | if (cmp < 0) { |
| 257 | goto finish; |
| 258 | } |
| 259 | if (cmp == 0) { |
| 260 | continue; |
| 261 | } |
| 262 | wrapped_meth = (PyArrayMethodObject *)PyTuple_GET_ITEM(item, 1); |
| 263 | if (!PyObject_TypeCheck(wrapped_meth, &PyArrayMethod_Type)) { |
| 264 | PyErr_SetString(PyExc_TypeError, |
| 265 | "Matching loop was not an ArrayMethod."); |
| 266 | goto finish; |
| 267 | } |
| 268 | break; |
| 269 | } |
| 270 | if (wrapped_meth == NULL) { |
| 271 | PyErr_Format(PyExc_TypeError, |
| 272 | "Did not find the to-be-wrapped loop in the ufunc with given " |
| 273 | "DTypes. Received wrapping types: %S", wrapped_dt_tuple); |
| 274 | goto finish; |
| 275 | } |
| 276 | |
| 277 | PyType_Slot slots[] = { |
| 278 | {NPY_METH_resolve_descriptors, &wrapping_method_resolve_descriptors}, |
| 279 | {_NPY_METH_get_loop, &wrapping_method_get_loop}, |
| 280 | {NPY_METH_get_reduction_initial, |
| 281 | &wrapping_method_get_identity_function}, |
| 282 | {0, NULL} |
no test coverage detected