* The main implementation to find the correct DType signature and ArrayMethod * to use for a ufunc. This function may recurse with `do_legacy_fallback` * set to False. * * If value-based promotion is necessary, this is handled ahead of time by * `promote_and_get_ufuncimpl`. */
| 727 | * `promote_and_get_ufuncimpl`. |
| 728 | */ |
| 729 | static inline PyObject * |
| 730 | promote_and_get_info_and_ufuncimpl(PyUFuncObject *ufunc, |
| 731 | PyArrayObject *const ops[], |
| 732 | PyArray_DTypeMeta *signature[], |
| 733 | PyArray_DTypeMeta *op_dtypes[], |
| 734 | npy_bool allow_legacy_promotion) |
| 735 | { |
| 736 | /* |
| 737 | * Fetch the dispatching info which consists of the implementation and |
| 738 | * the DType signature tuple. There are three steps: |
| 739 | * |
| 740 | * 1. Check the cache. |
| 741 | * 2. Check all registered loops/promoters to find the best match. |
| 742 | * 3. Fall back to the legacy implementation if no match was found. |
| 743 | */ |
| 744 | PyObject *info = PyArrayIdentityHash_GetItem(ufunc->_dispatch_cache, |
| 745 | (PyObject **)op_dtypes); |
| 746 | if (info != NULL && PyObject_TypeCheck( |
| 747 | PyTuple_GET_ITEM(info, 1), &PyArrayMethod_Type)) { |
| 748 | /* Found the ArrayMethod and NOT a promoter: return it */ |
| 749 | return info; |
| 750 | } |
| 751 | |
| 752 | /* |
| 753 | * If `info == NULL`, loading from cache failed, use the full resolution |
| 754 | * in `resolve_implementation_info` (which caches its result on success). |
| 755 | */ |
| 756 | if (info == NULL) { |
| 757 | if (resolve_implementation_info(ufunc, |
| 758 | op_dtypes, NPY_FALSE, &info) < 0) { |
| 759 | return NULL; |
| 760 | } |
| 761 | if (info != NULL && PyObject_TypeCheck( |
| 762 | PyTuple_GET_ITEM(info, 1), &PyArrayMethod_Type)) { |
| 763 | /* |
| 764 | * Found the ArrayMethod and NOT promoter. Before returning it |
| 765 | * add it to the cache for faster lookup in the future. |
| 766 | */ |
| 767 | if (PyArrayIdentityHash_SetItem(ufunc->_dispatch_cache, |
| 768 | (PyObject **)op_dtypes, info, 0) < 0) { |
| 769 | return NULL; |
| 770 | } |
| 771 | return info; |
| 772 | } |
| 773 | } |
| 774 | |
| 775 | /* |
| 776 | * At this point `info` is NULL if there is no matching loop, or it is |
| 777 | * a promoter that needs to be used/called: |
| 778 | */ |
| 779 | if (info != NULL) { |
| 780 | PyObject *promoter = PyTuple_GET_ITEM(info, 1); |
| 781 | |
| 782 | info = call_promoter_and_recurse(ufunc, |
| 783 | promoter, op_dtypes, signature, ops); |
| 784 | if (info == NULL && PyErr_Occurred()) { |
| 785 | return NULL; |
| 786 | } |
no test coverage detected