diff options
| author | Sebastian Berg <sebastianb@nvidia.com> | 2023-02-14 17:00:01 +0100 |
|---|---|---|
| committer | Sebastian Berg <sebastianb@nvidia.com> | 2023-02-14 20:32:33 +0100 |
| commit | 1bbe5821cc6afa134221367640380f403fa8d011 (patch) | |
| tree | 75b1327474df77b08ce38ceb440e7b039b56afce /numpy/core/src/multiarray | |
| parent | 482d3fadbfe23a1d2a2bb179e90369e0d08b11be (diff) | |
| download | numpy-1bbe5821cc6afa134221367640380f403fa8d011.tar.gz | |
MAINT: Merge public and private dtype API as much as possible
This merges header definitions that are private (enough) so that
we use the same definitions within NumPy as externally made available
through the experimental dtype API header.
Tested with string and mpfdtype from the experimental dtype API.
Diffstat (limited to 'numpy/core/src/multiarray')
| -rw-r--r-- | numpy/core/src/multiarray/array_method.c | 2 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/array_method.h | 187 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/convert_datatype.c | 12 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/datetime.c | 8 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/dtypemeta.h | 32 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/experimental_public_dtype_api.c | 22 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/usertypes.c | 4 |
7 files changed, 19 insertions, 248 deletions
diff --git a/numpy/core/src/multiarray/array_method.c b/numpy/core/src/multiarray/array_method.c index 5001a67e9..82f1423bb 100644 --- a/numpy/core/src/multiarray/array_method.c +++ b/numpy/core/src/multiarray/array_method.c @@ -264,7 +264,7 @@ fill_arraymethod_from_slots( case NPY_METH_resolve_descriptors: meth->resolve_descriptors = slot->pfunc; continue; - case NPY_METH_get_loop: + case _NPY_METH_get_loop: /* * NOTE: get_loop is considered "unstable" in the public API, * I do not like the signature, and the `move_references` diff --git a/numpy/core/src/multiarray/array_method.h b/numpy/core/src/multiarray/array_method.h index 138df69fa..c82a968cd 100644 --- a/numpy/core/src/multiarray/array_method.h +++ b/numpy/core/src/multiarray/array_method.h @@ -11,40 +11,7 @@ extern "C" { #endif -typedef enum { - /* Flag for whether the GIL is required */ - NPY_METH_REQUIRES_PYAPI = 1 << 0, - /* - * Some functions cannot set floating point error flags, this flag - * gives us the option (not requirement) to skip floating point error - * setup/check. No function should set error flags and ignore them - * since it would interfere with chaining operations (e.g. casting). - */ - NPY_METH_NO_FLOATINGPOINT_ERRORS = 1 << 1, - /* Whether the method supports unaligned access (not runtime) */ - NPY_METH_SUPPORTS_UNALIGNED = 1 << 2, - /* - * Used for reductions to allow reordering the operation. At this point - * assume that if set, it also applies to normal operations though! - */ - NPY_METH_IS_REORDERABLE = 1 << 3, - /* - * Private flag for now for *logic* functions. The logical functions - * `logical_or` and `logical_and` can always cast the inputs to booleans - * "safely" (because that is how the cast to bool is defined). - * @seberg: I am not sure this is the best way to handle this, so its - * private for now (also it is very limited anyway). - * There is one "exception". NA aware dtypes cannot cast to bool - * (hopefully), so the `??->?` loop should error even with this flag. - * But a second NA fallback loop will be necessary. - */ - _NPY_METH_FORCE_CAST_INPUTS = 1 << 17, - - /* All flags which can change at runtime */ - NPY_METH_RUNTIME_FLAGS = ( - NPY_METH_REQUIRES_PYAPI | - NPY_METH_NO_FLOATINGPOINT_ERRORS), -} NPY_ARRAYMETHOD_FLAGS; +#include "numpy/_dtype_api.h" /* @@ -60,143 +27,6 @@ typedef enum { ((flags1 | flags2) & ~PyArrayMethod_MINIMAL_FLAGS) \ | (flags1 & flags2))) - -struct PyArrayMethodObject_tag; - -/* - * This struct is specific to an individual (possibly repeated) call of - * the ArrayMethods strided operator, and as such is passed into the various - * methods of the ArrayMethod object (the resolve_descriptors function, - * the get_loop function and the individual lowlevel strided operator calls). - * It thus has to be persistent for one end-user call, and then be discarded. - * - * TODO: Before making this public, we should review which information should - * be stored on the Context/BoundArrayMethod vs. the ArrayMethod. - */ -typedef struct PyArrayMethod_Context_tag { - PyObject *caller; /* E.g. the original ufunc, may be NULL */ - struct PyArrayMethodObject_tag *method; - - /* Operand descriptors, filled in by resolve_descriptors */ - PyArray_Descr **descriptors; -} PyArrayMethod_Context; - - -typedef int (PyArrayMethod_StridedLoop)(PyArrayMethod_Context *context, - char *const *data, const npy_intp *dimensions, const npy_intp *strides, - NpyAuxData *transferdata); - - -typedef NPY_CASTING (resolve_descriptors_function)( - struct PyArrayMethodObject_tag *method, - PyArray_DTypeMeta **dtypes, - PyArray_Descr **given_descrs, - PyArray_Descr **loop_descrs, - npy_intp *view_offset); - - -typedef int (get_loop_function)( - PyArrayMethod_Context *context, - int aligned, int move_references, - const npy_intp *strides, - PyArrayMethod_StridedLoop **out_loop, - NpyAuxData **out_transferdata, - NPY_ARRAYMETHOD_FLAGS *flags); - - -/** - * Query an ArrayMethod for the initial value for use in reduction. - * - * @param context The arraymethod context, mainly to access the descriptors. - * @param reduction_is_empty Whether the reduction is empty. When it is, the - * value returned may differ. In this case it is a "default" value that - * may differ from the "identity" value normally used. For example: - * - `0.0` is the default for `sum([])`. But `-0.0` is the correct - * identity otherwise as it preserves the sign for `sum([-0.0])`. - * - We use no identity for object, but return the default of `0` and `1` - * for the empty `sum([], dtype=object)` and `prod([], dtype=object)`. - * This allows `np.sum(np.array(["a", "b"], dtype=object))` to work. - * - `-inf` or `INT_MIN` for `max` is an identity, but at least `INT_MIN` - * not a good *default* when there are no items. - * @param initial Pointer to initial data to be filled (if possible) - * - * @returns -1, 0, or 1 indicating error, no initial value, and initial being - * successfully filled. Errors must not be given where 0 is correct, NumPy - * may call this even when not strictly necessary. - */ -typedef int (get_reduction_initial_function)( - PyArrayMethod_Context *context, npy_bool reduction_is_empty, - char *initial); - -/* - * The following functions are only used be the wrapping array method defined - * in umath/wrapping_array_method.c - */ - -/* - * The function to convert the given descriptors (passed in to - * `resolve_descriptors`) and translates them for the wrapped loop. - * The new descriptors MUST be viewable with the old ones, `NULL` must be - * supported (for outputs) and should normally be forwarded. - * - * The function must clean up on error. - * - * NOTE: We currently assume that this translation gives "viewable" results. - * I.e. there is no additional casting related to the wrapping process. - * In principle that could be supported, but not sure it is useful. - * This currently also means that e.g. alignment must apply identically - * to the new dtypes. - * - * TODO: Due to the fact that `resolve_descriptors` is also used for `can_cast` - * there is no way to "pass out" the result of this function. This means - * it will be called twice for every ufunc call. - * (I am considering including `auxdata` as an "optional" parameter to - * `resolve_descriptors`, so that it can be filled there if not NULL.) - */ -typedef int translate_given_descrs_func(int nin, int nout, - PyArray_DTypeMeta *wrapped_dtypes[], - PyArray_Descr *given_descrs[], PyArray_Descr *new_descrs[]); - -/** - * The function to convert the actual loop descriptors (as returned by the - * original `resolve_descriptors` function) to the ones the output array - * should use. - * This function must return "viewable" types, it must not mutate them in any - * form that would break the inner-loop logic. Does not need to support NULL. - * - * The function must clean up on error. - * - * @param nargs Number of arguments - * @param new_dtypes The DTypes of the output (usually probably not needed) - * @param given_descrs Original given_descrs to the resolver, necessary to - * fetch any information related to the new dtypes from the original. - * @param original_descrs The `loop_descrs` returned by the wrapped loop. - * @param loop_descrs The output descriptors, compatible to `original_descrs`. - * - * @returns 0 on success, -1 on failure. - */ -typedef int translate_loop_descrs_func(int nin, int nout, - PyArray_DTypeMeta *new_dtypes[], PyArray_Descr *given_descrs[], - PyArray_Descr *original_descrs[], PyArray_Descr *loop_descrs[]); - - -/* - * This struct will be public and necessary for creating a new ArrayMethod - * object (casting and ufuncs). - * We could version the struct, although since we allow passing arbitrary - * data using the slots, and have flags, that may be enough? - * (See also PyBoundArrayMethodObject.) - */ -typedef struct { - const char *name; - int nin, nout; - NPY_CASTING casting; - NPY_ARRAYMETHOD_FLAGS flags; - PyArray_DTypeMeta **dtypes; - PyType_Slot *slots; -} PyArrayMethod_Spec; - - /* * Structure of the ArrayMethod. This structure should probably not be made * public. If necessary, we can make certain operations on it public @@ -254,21 +84,6 @@ typedef struct { extern NPY_NO_EXPORT PyTypeObject PyArrayMethod_Type; extern NPY_NO_EXPORT PyTypeObject PyBoundArrayMethod_Type; -/* - * SLOTS IDs For the ArrayMethod creation, one public, the IDs are fixed. - * TODO: Before making it public, consider adding a large constant to private - * slots. - */ -#define NPY_METH_resolve_descriptors 1 -#define NPY_METH_get_loop 2 -#define NPY_METH_get_reduction_initial 3 -/* specific loops for constructions/default get_loop: */ -#define NPY_METH_strided_loop 4 -#define NPY_METH_contiguous_loop 5 -#define NPY_METH_unaligned_strided_loop 6 -#define NPY_METH_unaligned_contiguous_loop 7 -#define NPY_METH_contiguous_indexed_loop 8 - /* * Used internally (initially) for real to complex loops only diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c index 14341c103..4798df7cc 100644 --- a/numpy/core/src/multiarray/convert_datatype.c +++ b/numpy/core/src/multiarray/convert_datatype.c @@ -2668,7 +2668,7 @@ add_numeric_cast(PyArray_DTypeMeta *from, PyArray_DTypeMeta *to) * consider moving this warning into the inner-loop at some point * for simplicity (this requires ensuring it is only emitted once). */ - slots[5].slot = NPY_METH_get_loop; + slots[5].slot = _NPY_METH_get_loop; slots[5].pfunc = &complex_to_noncomplex_get_loop; slots[6].slot = 0; slots[6].pfunc = NULL; @@ -2689,7 +2689,7 @@ add_numeric_cast(PyArray_DTypeMeta *from, PyArray_DTypeMeta *to) /* When there is no casting (equivalent C-types) use byteswap loops */ slots[0].slot = NPY_METH_resolve_descriptors; slots[0].pfunc = &legacy_same_dtype_resolve_descriptors; - slots[1].slot = NPY_METH_get_loop; + slots[1].slot = _NPY_METH_get_loop; slots[1].pfunc = &get_byteswap_loop; slots[2].slot = 0; slots[2].pfunc = NULL; @@ -2873,7 +2873,7 @@ add_other_to_and_from_string_cast( */ PyArray_DTypeMeta *dtypes[2] = {other, string}; PyType_Slot slots[] = { - {NPY_METH_get_loop, &legacy_cast_get_strided_loop}, + {_NPY_METH_get_loop, &legacy_cast_get_strided_loop}, {NPY_METH_resolve_descriptors, &cast_to_string_resolve_descriptors}, {0, NULL}}; PyArrayMethod_Spec spec = { @@ -3012,7 +3012,7 @@ PyArray_InitializeStringCasts(void) /* string<->string and unicode<->unicode have their own specialized casts */ PyArray_DTypeMeta *dtypes[2]; PyType_Slot slots[] = { - {NPY_METH_get_loop, &string_to_string_get_loop}, + {_NPY_METH_get_loop, &string_to_string_get_loop}, {NPY_METH_resolve_descriptors, &string_to_string_resolve_descriptors}, {0, NULL}}; PyArrayMethod_Spec spec = { @@ -3711,7 +3711,7 @@ PyArray_InitializeVoidToVoidCast(void) PyArray_DTypeMeta *Void = PyArray_DTypeFromTypeNum(NPY_VOID); PyArray_DTypeMeta *dtypes[2] = {Void, Void}; PyType_Slot slots[] = { - {NPY_METH_get_loop, &void_to_void_get_loop}, + {_NPY_METH_get_loop, &void_to_void_get_loop}, {NPY_METH_resolve_descriptors, &void_to_void_resolve_descriptors}, {0, NULL}}; PyArrayMethod_Spec spec = { @@ -3894,7 +3894,7 @@ PyArray_InitializeObjectToObjectCast(void) PyArray_DTypeMeta *Object = PyArray_DTypeFromTypeNum(NPY_OBJECT); PyArray_DTypeMeta *dtypes[2] = {Object, Object}; PyType_Slot slots[] = { - {NPY_METH_get_loop, &object_to_object_get_loop}, + {_NPY_METH_get_loop, &object_to_object_get_loop}, {0, NULL}}; PyArrayMethod_Spec spec = { .name = "object_to_object_cast", diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c index 695b696c2..820f40fd8 100644 --- a/numpy/core/src/multiarray/datetime.c +++ b/numpy/core/src/multiarray/datetime.c @@ -4100,7 +4100,7 @@ PyArray_InitializeDatetimeCasts() }; slots[0].slot = NPY_METH_resolve_descriptors; slots[0].pfunc = &time_to_time_resolve_descriptors; - slots[1].slot = NPY_METH_get_loop; + slots[1].slot = _NPY_METH_get_loop; slots[1].pfunc = &time_to_time_get_loop; slots[2].slot = 0; slots[2].pfunc = NULL; @@ -4130,7 +4130,7 @@ PyArray_InitializeDatetimeCasts() slots[0].slot = NPY_METH_resolve_descriptors; slots[0].pfunc = &datetime_to_timedelta_resolve_descriptors; - slots[1].slot = NPY_METH_get_loop; + slots[1].slot = _NPY_METH_get_loop; slots[1].pfunc = &legacy_cast_get_strided_loop; slots[2].slot = 0; slots[2].pfunc = NULL; @@ -4203,7 +4203,7 @@ PyArray_InitializeDatetimeCasts() slots[0].slot = NPY_METH_resolve_descriptors; slots[0].pfunc = &time_to_string_resolve_descriptors; /* Strided loop differs for the two */ - slots[1].slot = NPY_METH_get_loop; + slots[1].slot = _NPY_METH_get_loop; slots[2].slot = 0; slots[2].pfunc = NULL; @@ -4252,7 +4252,7 @@ PyArray_InitializeDatetimeCasts() /* The default type resolution should work fine. */ slots[0].slot = NPY_METH_resolve_descriptors; slots[0].pfunc = &string_to_datetime_cast_resolve_descriptors; - slots[1].slot = NPY_METH_get_loop; + slots[1].slot = _NPY_METH_get_loop; slots[1].pfunc = &string_to_datetime_cast_get_loop; slots[2].slot = 0; slots[2].pfunc = NULL; diff --git a/numpy/core/src/multiarray/dtypemeta.h b/numpy/core/src/multiarray/dtypemeta.h index ef702f923..db16fe04b 100644 --- a/numpy/core/src/multiarray/dtypemeta.h +++ b/numpy/core/src/multiarray/dtypemeta.h @@ -5,42 +5,14 @@ extern "C" { #endif +#include "numpy/_dtype_api.h" + /* DType flags, currently private, since we may just expose functions */ #define NPY_DT_LEGACY 1 << 0 #define NPY_DT_ABSTRACT 1 << 1 #define NPY_DT_PARAMETRIC 1 << 2 -typedef PyArray_Descr *(discover_descr_from_pyobject_function)( - PyArray_DTypeMeta *cls, PyObject *obj); - -/* - * Before making this public, we should decide whether it should pass - * the type, or allow looking at the object. A possible use-case: - * `np.array(np.array([0]), dtype=np.ndarray)` - * Could consider arrays that are not `dtype=ndarray` "scalars". - */ -typedef int (is_known_scalar_type_function)( - PyArray_DTypeMeta *cls, PyTypeObject *obj); - -typedef PyArray_Descr *(default_descr_function)(PyArray_DTypeMeta *cls); -typedef PyArray_DTypeMeta *(common_dtype_function)( - PyArray_DTypeMeta *dtype1, PyArray_DTypeMeta *dtype2); -typedef PyArray_Descr *(common_instance_function)( - PyArray_Descr *dtype1, PyArray_Descr *dtype2); -typedef PyArray_Descr *(ensure_canonical_function)(PyArray_Descr *dtype); - -/* - * TODO: These two functions are currently only used for experimental DType - * API support. Their relation should be "reversed": NumPy should - * always use them internally. - * There are open points about "casting safety" though, e.g. setting - * elements is currently always unsafe. - */ -typedef int(setitemfunction)(PyArray_Descr *, PyObject *, char *); -typedef PyObject *(getitemfunction)(PyArray_Descr *, char *); - - typedef struct { /* DType methods, these could be moved into its own struct */ discover_descr_from_pyobject_function *discover_descr_from_pyobject; diff --git a/numpy/core/src/multiarray/experimental_public_dtype_api.c b/numpy/core/src/multiarray/experimental_public_dtype_api.c index 1870a726b..a974bf390 100644 --- a/numpy/core/src/multiarray/experimental_public_dtype_api.c +++ b/numpy/core/src/multiarray/experimental_public_dtype_api.c @@ -16,18 +16,6 @@ #include "common_dtype.h" -#define EXPERIMENTAL_DTYPE_API_VERSION 7 - - -typedef struct{ - PyTypeObject *typeobj; /* type of python scalar or NULL */ - int flags; /* flags, including parametric and abstract */ - /* NULL terminated cast definitions. Use NULL for the newly created DType */ - PyArrayMethod_Spec **casts; - PyType_Slot *slots; -} PyArrayDTypeMeta_Spec; - - static PyArray_DTypeMeta * dtype_does_not_promote( @@ -116,10 +104,6 @@ PyArray_ArrFuncs default_funcs = { }; -/* other slots are in order, so keep only last around: */ -#define NUM_DTYPE_SLOTS 8 - - int PyArrayInitDTypeMeta_FromSpec( PyArray_DTypeMeta *DType, PyArrayDTypeMeta_Spec *spec) @@ -187,7 +171,7 @@ PyArrayInitDTypeMeta_FromSpec( if (slot == 0) { break; } - if (slot > NUM_DTYPE_SLOTS || slot < 0) { + if (slot > _NPY_NUM_DTYPE_SLOTS || slot < 0) { PyErr_Format(PyExc_RuntimeError, "Invalid slot with value %d passed in.", slot); return -1; @@ -443,12 +427,12 @@ _get_experimental_dtype_api(PyObject *NPY_UNUSED(mod), PyObject *arg) if (error_converting(version)) { return NULL; } - if (version != EXPERIMENTAL_DTYPE_API_VERSION) { + if (version != __EXPERIMENTAL_DTYPE_API_VERSION) { PyErr_Format(PyExc_RuntimeError, "Experimental DType API version %d requested, but NumPy " "is exporting version %d. Recompile your DType and/or upgrade " "NumPy to match.", - version, EXPERIMENTAL_DTYPE_API_VERSION); + version, __EXPERIMENTAL_DTYPE_API_VERSION); return NULL; } diff --git a/numpy/core/src/multiarray/usertypes.c b/numpy/core/src/multiarray/usertypes.c index a338d712d..7ada0403a 100644 --- a/numpy/core/src/multiarray/usertypes.c +++ b/numpy/core/src/multiarray/usertypes.c @@ -597,7 +597,7 @@ PyArray_AddLegacyWrapping_CastingImpl( if (from == to) { spec.flags = NPY_METH_REQUIRES_PYAPI | NPY_METH_SUPPORTS_UNALIGNED; PyType_Slot slots[] = { - {NPY_METH_get_loop, &legacy_cast_get_strided_loop}, + {_NPY_METH_get_loop, &legacy_cast_get_strided_loop}, {NPY_METH_resolve_descriptors, &legacy_same_dtype_resolve_descriptors}, {0, NULL}}; spec.slots = slots; @@ -606,7 +606,7 @@ PyArray_AddLegacyWrapping_CastingImpl( else { spec.flags = NPY_METH_REQUIRES_PYAPI; PyType_Slot slots[] = { - {NPY_METH_get_loop, &legacy_cast_get_strided_loop}, + {_NPY_METH_get_loop, &legacy_cast_get_strided_loop}, {NPY_METH_resolve_descriptors, &simple_cast_resolve_descriptors}, {0, NULL}}; spec.slots = slots; |
