* Resolves the implementation to use, this uses typical multiple dispatching * methods of finding the best matching implementation or resolver. * (Based on `isinstance()`, the knowledge that non-abstract DTypes cannot * be subclassed is used, however.) * * NOTE: This currently does not take into account output dtypes which do not * have to match. The possible extension here is that if
| 213 | * success if nothing is found. |
| 214 | */ |
| 215 | static int |
| 216 | resolve_implementation_info(PyUFuncObject *ufunc, |
| 217 | PyArray_DTypeMeta *op_dtypes[], npy_bool only_promoters, |
| 218 | PyObject **out_info) |
| 219 | { |
| 220 | int nin = ufunc->nin, nargs = ufunc->nargs; |
| 221 | Py_ssize_t size = PySequence_Length(ufunc->_loops); |
| 222 | PyObject *best_dtypes = NULL; |
| 223 | PyObject *best_resolver_info = NULL; |
| 224 | |
| 225 | #if PROMOTION_DEBUG_TRACING |
| 226 | printf("Promoting for '%s' promoters only: %d\n", |
| 227 | ufunc->name ? ufunc->name : "<unknown>", (int)only_promoters); |
| 228 | printf(" DTypes: "); |
| 229 | PyObject *tmp = PyArray_TupleFromItems(ufunc->nargs, op_dtypes, 1); |
| 230 | PyObject_Print(tmp, stdout, 0); |
| 231 | Py_DECREF(tmp); |
| 232 | printf("\n"); |
| 233 | Py_DECREF(tmp); |
| 234 | #endif |
| 235 | |
| 236 | for (Py_ssize_t res_idx = 0; res_idx < size; res_idx++) { |
| 237 | /* Test all resolvers */ |
| 238 | PyObject *resolver_info = PySequence_Fast_GET_ITEM( |
| 239 | ufunc->_loops, res_idx); |
| 240 | |
| 241 | if (only_promoters && PyObject_TypeCheck( |
| 242 | PyTuple_GET_ITEM(resolver_info, 1), &PyArrayMethod_Type)) { |
| 243 | continue; |
| 244 | } |
| 245 | |
| 246 | PyObject *curr_dtypes = PyTuple_GET_ITEM(resolver_info, 0); |
| 247 | /* |
| 248 | * Test if the current resolver matches, it could make sense to |
| 249 | * reorder these checks to avoid the IsSubclass check as much as |
| 250 | * possible. |
| 251 | */ |
| 252 | |
| 253 | npy_bool matches = NPY_TRUE; |
| 254 | /* |
| 255 | * NOTE: We currently match the output dtype exactly here, this is |
| 256 | * actually only necessary if the signature includes. |
| 257 | * Currently, we rely that op-dtypes[nin:nout] is NULLed if not. |
| 258 | */ |
| 259 | for (Py_ssize_t i = 0; i < nargs; i++) { |
| 260 | PyArray_DTypeMeta *given_dtype = op_dtypes[i]; |
| 261 | PyArray_DTypeMeta *resolver_dtype = ( |
| 262 | (PyArray_DTypeMeta *)PyTuple_GET_ITEM(curr_dtypes, i)); |
| 263 | assert((PyObject *)given_dtype != Py_None); |
| 264 | if (given_dtype == NULL) { |
| 265 | if (i >= nin) { |
| 266 | /* Unspecified out always matches (see below for inputs) */ |
| 267 | continue; |
| 268 | } |
| 269 | /* |
| 270 | * This is a reduce-like operation, which always have the form |
| 271 | * `(res_DType, op_DType, res_DType)`. If the first and last |
| 272 | * dtype of the loops match, this should be reduce-compatible. |
no test coverage detected