diff options
-rw-r--r-- | doc/source/reference/c-api/types-and-structures.rst | 6 | ||||
-rw-r--r-- | numpy/core/src/multiarray/array_method.c | 125 | ||||
-rw-r--r-- | numpy/core/src/multiarray/array_method.h | 11 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_type_resolution.c | 117 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_type_resolution.h | 7 |
5 files changed, 137 insertions, 129 deletions
diff --git a/doc/source/reference/c-api/types-and-structures.rst b/doc/source/reference/c-api/types-and-structures.rst index ab82fda87..75a97c20e 100644 --- a/doc/source/reference/c-api/types-and-structures.rst +++ b/doc/source/reference/c-api/types-and-structures.rst @@ -811,7 +811,7 @@ PyUFunc_Type and PyUFuncObject char *core_signature; PyUFunc_TypeResolutionFunc *type_resolver; PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector; - PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector; + void *reserved2; npy_uint32 *op_flags; npy_uint32 *iter_flags; /* new in API version 0x0000000D */ @@ -965,10 +965,6 @@ PyUFunc_Type and PyUFuncObject For a possible future loop selector with a different signature. - .. c:member:: PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector - - Function which returns a masked inner loop for the ufunc - .. c:member:: npy_uint32 op_flags Override the default operand flags for each ufunc operand. diff --git a/numpy/core/src/multiarray/array_method.c b/numpy/core/src/multiarray/array_method.c index ab992a3ae..cc841ee64 100644 --- a/numpy/core/src/multiarray/array_method.c +++ b/numpy/core/src/multiarray/array_method.c @@ -756,6 +756,131 @@ boundarraymethod__simple_strided_call( } +/* + * TODO: Currently still based on the old ufunc system and not ArrayMethod! + * This requires fixing the ufunc code first. + * + * Support for masked inner-strided loops. Masked inner-strided loops are + * only used in the ufunc machinery. So this special cases them. + * In the future it probably makes sense to create an:: + * + * Arraymethod->get_masked_strided_loop() + * + * Function which this can wrap instead. + */ +typedef struct { + NpyAuxData base; + PyUFuncGenericFunction unmasked_stridedloop; + void *innerloopdata; + int nargs; + char *dataptrs[]; +} _masked_stridedloop_data; + + +static void +_masked_stridedloop_data_free(NpyAuxData *auxdata) +{ + _masked_stridedloop_data *data = (_masked_stridedloop_data *)auxdata; + PyMem_Free(data); +} + + +/* + * This function wraps a regular unmasked strided-loop as a + * masked strided-loop, only calling the function for elements + * where the mask is True. + */ +static void +unmasked_ufunc_loop_as_masked( + char **data, const npy_intp *dimensions, + const npy_intp *strides, void *_auxdata) +{ + _masked_stridedloop_data *auxdata = (_masked_stridedloop_data *)_auxdata; + int nargs = auxdata->nargs; + PyUFuncGenericFunction strided_loop = auxdata->unmasked_stridedloop; + void *innerloopdata = auxdata->innerloopdata; + + char **dataptrs = auxdata->dataptrs; + memcpy(dataptrs, data, nargs * sizeof(char *)); + char *mask = data[nargs]; + npy_intp mask_stride = strides[nargs]; + + npy_intp N = dimensions[0]; + /* Process the data as runs of unmasked values */ + do { + ssize_t subloopsize; + + /* Skip masked values */ + mask = npy_memchr(mask, 0, mask_stride, N, &subloopsize, 1); + for (int i = 0; i < nargs; i++) { + dataptrs[i] += subloopsize * strides[i]; + } + N -= subloopsize; + + /* Process unmasked values */ + mask = npy_memchr(mask, 0, mask_stride, N, &subloopsize, 0); + strided_loop(dataptrs, &subloopsize, strides, innerloopdata); + for (int i = 0; i < nargs; i++) { + dataptrs[i] += subloopsize * strides[i]; + } + N -= subloopsize; + } while (N > 0); +} + + +/* + * TODO: This function will be the masked equivalent to `get_loop`. + * This function wraps a legacy inner loop so it becomes masked. + * + * Returns 0 on success, -1 on error. + */ +NPY_NO_EXPORT int +PyUFunc_DefaultMaskedInnerLoopSelector(PyUFuncObject *ufunc, + PyArray_Descr **dtypes, + PyUFuncGenericFunction *out_innerloop, + NpyAuxData **out_innerloopdata, + int *out_needs_api) +{ + int retcode; + _masked_stridedloop_data *data; + int nargs = ufunc->nin + ufunc->nout; + + if (ufunc->legacy_inner_loop_selector == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "the ufunc default masked inner loop selector doesn't " + "yet support wrapping the new inner loop selector, it " + "still only wraps the legacy inner loop selector"); + return -1; + } + + /* Add working memory for the data pointers, to modify them in-place */ + data = PyMem_Malloc(sizeof(_masked_stridedloop_data) + + sizeof(char *) * nargs); + if (data == NULL) { + PyErr_NoMemory(); + return -1; + } + data->base.free = _masked_stridedloop_data_free; + data->base.clone = NULL; /* not currently used */ + data->unmasked_stridedloop = NULL; + data->nargs = nargs; + + /* Get the unmasked ufunc inner loop */ + retcode = ufunc->legacy_inner_loop_selector(ufunc, dtypes, + &data->unmasked_stridedloop, &data->innerloopdata, + out_needs_api); + if (retcode < 0) { + PyArray_free(data); + return retcode; + } + + /* Return the loop function + aux data */ + *out_innerloop = &unmasked_ufunc_loop_as_masked; + *out_innerloopdata = (NpyAuxData *)data; + return 0; +} + + PyMethodDef boundarraymethod_methods[] = { {"_resolve_descriptors", (PyCFunction)boundarraymethod__resolve_descripors, METH_O, "Resolve the given dtypes."}, diff --git a/numpy/core/src/multiarray/array_method.h b/numpy/core/src/multiarray/array_method.h index 88167a6bb..c2122a2da 100644 --- a/numpy/core/src/multiarray/array_method.h +++ b/numpy/core/src/multiarray/array_method.h @@ -158,6 +158,17 @@ npy_default_get_strided_loop( PyArrayMethod_StridedLoop **out_loop, NpyAuxData **out_transferdata, NPY_ARRAYMETHOD_FLAGS *flags); +/* + * TODO: This function will not rely on the current ufunc code after the + * ufunc refactor. + */ +#include "numpy/ufuncobject.h" +NPY_NO_EXPORT int +PyUFunc_DefaultMaskedInnerLoopSelector(PyUFuncObject *ufunc, + PyArray_Descr **dtypes, + PyUFuncGenericFunction *out_innerloop, + NpyAuxData **out_innerloopdata, + int *out_needs_api); /* * TODO: This function is the internal version, and its error paths may diff --git a/numpy/core/src/umath/ufunc_type_resolution.c b/numpy/core/src/umath/ufunc_type_resolution.c index e09ce3233..468327b8c 100644 --- a/numpy/core/src/umath/ufunc_type_resolution.c +++ b/numpy/core/src/umath/ufunc_type_resolution.c @@ -1496,123 +1496,6 @@ PyUFunc_DefaultLegacyInnerLoopSelector(PyUFuncObject *ufunc, } -/* - * Support for masked inner-strided loops. These are currently ONLY used - * for normal ufuncs, and only a generic loop getter exists. - * It may make sense to generalize this in the future or allow specialization. - * Until then, the inner-loop signature is flexible. - */ -typedef struct { - NpyAuxData base; - PyUFuncGenericFunction unmasked_stridedloop; - void *innerloopdata; - int nargs; - char *dataptrs[]; -} _masked_stridedloop_data; - - -static void -_masked_stridedloop_data_free(NpyAuxData *auxdata) -{ - _masked_stridedloop_data *data = (_masked_stridedloop_data *)auxdata; - PyMem_Free(data); -} - - -/* - * This function wraps a regular unmasked ufunc inner loop as a - * masked ufunc inner loop, only calling the function for - * elements where the mask is True. - */ -static void -unmasked_ufunc_loop_as_masked( - char **data, const npy_intp *dimensions, - const npy_intp *strides, void *_auxdata) -{ - _masked_stridedloop_data *auxdata = (_masked_stridedloop_data *)_auxdata; - int nargs = auxdata->nargs; - PyUFuncGenericFunction strided_loop = auxdata->unmasked_stridedloop; - void *innerloopdata = auxdata->innerloopdata; - - char **dataptrs = auxdata->dataptrs; - memcpy(dataptrs, data, nargs * sizeof(char *)); - char *mask = data[nargs]; - npy_intp mask_stride = strides[nargs]; - - npy_intp N = dimensions[0]; - /* Process the data as runs of unmasked values */ - do { - ssize_t subloopsize; - - /* Skip masked values */ - mask = npy_memchr(mask, 0, mask_stride, N, &subloopsize, 1); - for (int i = 0; i < nargs; i++) { - dataptrs[i] += subloopsize * strides[i]; - } - N -= subloopsize; - - /* Process unmasked values */ - mask = npy_memchr(mask, 0, mask_stride, N, &subloopsize, 0); - strided_loop(dataptrs, &subloopsize, strides, innerloopdata); - for (int i = 0; i < nargs; i++) { - dataptrs[i] += subloopsize * strides[i]; - } - N -= subloopsize; - } while (N > 0); -} - - -/* - * This function wraps a legacy inner loop so it becomes masked. - * - * Returns 0 on success, -1 on error. - */ -NPY_NO_EXPORT int -PyUFunc_DefaultMaskedInnerLoopSelector(PyUFuncObject *ufunc, - PyArray_Descr **dtypes, - PyUFuncGenericFunction *out_innerloop, - NpyAuxData **out_innerloopdata, - int *out_needs_api) -{ - int retcode; - _masked_stridedloop_data *data; - int nargs = ufunc->nin + ufunc->nout; - - if (ufunc->legacy_inner_loop_selector == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "the ufunc default masked inner loop selector doesn't " - "yet support wrapping the new inner loop selector, it " - "still only wraps the legacy inner loop selector"); - return -1; - } - - /* Add working memory for the data pointers, to modify them in-place */ - data = PyMem_Malloc(sizeof(_masked_stridedloop_data) + - sizeof(char *) * nargs); - if (data == NULL) { - PyErr_NoMemory(); - return -1; - } - data->base.free = _masked_stridedloop_data_free; - data->base.clone = NULL; /* not currently used */ - data->unmasked_stridedloop = NULL; - data->nargs = nargs; - - /* Get the unmasked ufunc inner loop */ - retcode = ufunc->legacy_inner_loop_selector(ufunc, dtypes, - &data->unmasked_stridedloop, &data->innerloopdata, - out_needs_api); - if (retcode < 0) { - PyArray_free(data); - return retcode; - } - - /* Return the loop function + aux data */ - *out_innerloop = &unmasked_ufunc_loop_as_masked; - *out_innerloopdata = (NpyAuxData *)data; - return 0; -} - static int ufunc_loop_matches(PyUFuncObject *self, PyArrayObject **op, diff --git a/numpy/core/src/umath/ufunc_type_resolution.h b/numpy/core/src/umath/ufunc_type_resolution.h index fdad19b3d..cd0ff4a0d 100644 --- a/numpy/core/src/umath/ufunc_type_resolution.h +++ b/numpy/core/src/umath/ufunc_type_resolution.h @@ -135,11 +135,4 @@ PyUFunc_DefaultLegacyInnerLoopSelector(PyUFuncObject *ufunc, void **out_innerloopdata, int *out_needs_api); -NPY_NO_EXPORT int -PyUFunc_DefaultMaskedInnerLoopSelector(PyUFuncObject *ufunc, - PyArray_Descr **dtypes, - PyUFuncGenericFunction *out_innerloop, - NpyAuxData **out_innerloopdata, - int *out_needs_api); - #endif |