Repository: numpy/numpy
File: numpy/_core/src/umath/_scaled_float_dtype.c (C)

Code before:
        {NPY_METH_get_loop, &sfloat_argsort_get_loop},
        {0, NULL}
    };
    PyArrayMethod_Spec argsort_spec = {
        .nin = 1,
        .nout = 1,
        .dtypes = argsort_dtypes,
        .slots = argsort_slots,
    };
    argsort_spec.name = "sfloat_argsort";
    argsort_spec.casting = NPY_NO_CASTING;
    argsort_spec.flags = NPY_METH_NO_FLOATINGPOINT_ERRORS;

    PyUFunc_LoopSlot loops[5] = {
        {"multiply", &multiply_spec},
        {"add", &add_spec},
        {"sort", &sort_spec},
        {"argsort", &argsort_spec},
        {NULL, NULL}
    };
    if (PyUFunc_AddLoopsFromSpecs(loops) < 0) {
        return -1;
    }

    /* N.B.: Wrapping isn't actually correct if scaling can be negative */
    if (sfloat_add_wrapping_loop("hypot", multiply_dtypes) < 0) {
        return -1;
    }

    /*
     * Add a promoter for both directions of multiply with double.
     */
    int res;
    PyArray_DTypeMeta *double_DType = &PyArray_DoubleDType;

    PyArray_DTypeMeta *promoter_dtypes[3] = {
            &PyArray_SFloatDType, double_DType, NULL};

    PyObject *promoter = PyCapsule_New(
            &promote_to_sfloat, "numpy._ufunc_promoter", NULL);
    if (promoter == NULL) {
        return -1;
    }
    res = sfloat_add_loop("multiply", promoter_dtypes, promoter);
    if (res < 0) {
        Py_DECREF(promoter);
        return -1;
    }
    promoter_dtypes[0] = double_DType;
    promoter_dtypes[1] = &PyArray_SFloatDType;
    res = sfloat_add_loop("multiply", promoter_dtypes, promoter);

Review comment (suggestion):
Hmm, would it be possible to do this with the new registration too? It would seem something that might be used a lot. Though maybe the easiest is to then define a new `PyUFunc_AddWrappingLoopsFromSpecs`. Anyway, would seem absolutely fine to leave this for later! (It is nice in that it would remove the need for `sfloat_get_ufunc`...)

p.s. Here `multiply_dtypes` is re-used, so I think it indeed can be done elsewhere too.

Code after:
    };
    PyArrayMethod_Spec argsort_spec = {
        .nin = 1,
        .nout = 1,
        .dtypes = argsort_dtypes,
        .slots = argsort_slots,
    };
    argsort_spec.name = "sfloat_argsort";
    argsort_spec.casting = NPY_NO_CASTING;
    argsort_spec.flags = NPY_METH_NO_FLOATINGPOINT_ERRORS;

    PyUFunc_LoopSlot loops[] = {
        {"multiply", &multiply_spec},
        {"add", &add_spec},
        {"sort", &sort_spec},
        {"argsort", &argsort_spec},
        {NULL, NULL}
    };
    if (PyUFunc_AddLoopsFromSpecs(loops) < 0) {
        return -1;
    }

    /* N.B.: Wrapping isn't actually correct if scaling can be negative */
    if (sfloat_add_wrapping_loop("hypot", all_sfloat_dtypes) < 0) {
        return -1;
    }

    /*
     * Add a promoter for both directions of multiply with double.
     */
    int res = -1;
    PyArray_DTypeMeta *double_DType = &PyArray_DoubleDType;

    PyArray_DTypeMeta *promoter_dtypes[3] = {
            &PyArray_SFloatDType, double_DType, NULL};

    PyObject *promoter = PyCapsule_New(
            &promote_to_sfloat, "numpy._ufunc_promoter", NULL);
    if (promoter == NULL) {
        return -1;
    }
    res = sfloat_add_loop("multiply", promoter_dtypes, promoter);
    if (res < 0) {
        Py_DECREF(promoter);
        return -1;
    }
    promoter_dtypes[0] = double_DType;
    promoter_dtypes[1] = &PyArray_SFloatDType;
    res = sfloat_add_loop("multiply", promoter_dtypes, promoter);
    Py_DECREF(promoter);
    if (res < 0) {