diff options
author | Sebastian Berg <sebastian@sipsolutions.net> | 2020-11-18 11:46:54 -0600 |
---|---|---|
committer | Sebastian Berg <sebastian@sipsolutions.net> | 2020-11-24 21:25:02 -0600 |
commit | a9a44e9ac554a7b58804764e9149f38732baccb6 (patch) | |
tree | c4706583b5977ae4c2071e84f3782fe0e802ce6a | |
parent | df1b2a8077052d539ff29b763413360434f3d44a (diff) | |
download | numpy-a9a44e9ac554a7b58804764e9149f38732baccb6.tar.gz |
Address Matti's comments from yesterday
-rw-r--r-- | numpy/core/src/multiarray/array_method.c | 88 | ||||
-rw-r--r-- | numpy/core/src/multiarray/array_method.h | 55 | ||||
-rw-r--r-- | numpy/core/src/multiarray/convert_datatype.c | 170 | ||||
-rw-r--r-- | numpy/core/src/multiarray/convert_datatype.h | 8 | ||||
-rw-r--r-- | numpy/core/src/multiarray/datetime.c | 42 | ||||
-rw-r--r-- | numpy/core/src/multiarray/usertypes.c | 8 |
6 files changed, 191 insertions, 180 deletions
diff --git a/numpy/core/src/multiarray/array_method.c b/numpy/core/src/multiarray/array_method.c index 076dd43aa..cae452454 100644 --- a/numpy/core/src/multiarray/array_method.c +++ b/numpy/core/src/multiarray/array_method.c @@ -50,16 +50,17 @@ */ static NPY_CASTING default_resolve_descriptors( - PyArrayMethod_Context *context, + PyArrayMethodObject *method, + PyArray_DTypeMeta **dtypes, PyArray_Descr **input_descrs, PyArray_Descr **output_descrs) { - int nin = context->nin; - int nout = context->nout; + int nin = method->nin; + int nout = method->nout; int all_defined = 1; for (int i = 0; i < nin + nout; i++) { - PyArray_DTypeMeta *dtype = context->dtypes[i]; + PyArray_DTypeMeta *dtype = dtypes[i]; if (dtype == NULL) { output_descrs[i] = NULL; all_defined = 0; @@ -76,10 +77,10 @@ default_resolve_descriptors( } } if (all_defined) { - return context->method->casting; + return method->casting; } - if (NPY_UNLIKELY(nin == 0 || context->dtypes[0] == NULL)) { + if (NPY_UNLIKELY(nin == 0 || dtypes[0] == NULL)) { /* Registration should reject this, so this would be indicates a bug */ PyErr_SetString(PyExc_RuntimeError, "Invalid use of default resolver without inputs or with " @@ -87,10 +88,10 @@ default_resolve_descriptors( goto fail; } /* We find the common dtype of all inputs, and use it for the unknowns */ - PyArray_DTypeMeta *common_dtype = context->dtypes[0]; + PyArray_DTypeMeta *common_dtype = dtypes[0]; assert(common_dtype != NULL); for (int i = 1; i < nin; i++) { - Py_SETREF(common_dtype, PyArray_CommonDType(common_dtype, context->dtypes[i])); + Py_SETREF(common_dtype, PyArray_CommonDType(common_dtype, dtypes[i])); if (common_dtype == NULL) { goto fail; } @@ -110,7 +111,7 @@ default_resolve_descriptors( } } - return context->method->casting; + return method->casting; fail: for (int i = 0; i < nin + nout; i++) { @@ -207,6 +208,15 @@ validate_spec(PyArrayMethod_Spec *spec) } +/** + * Initialize a new BoundArrayMethodObject from slots. Slots which are + * not provided may be filled with defaults. + * + * @param res The new PyBoundArrayMethodObject to be filled. + * @param spec The specification list passed by the user. + * @param private Private flag to limit certain slots to use in NumPy. + * @return -1 on error 0 on success + */ static int fill_arraymethod_from_slots( PyBoundArrayMethodObject *res, PyArrayMethod_Spec *spec, @@ -226,26 +236,26 @@ fill_arraymethod_from_slots( */ for (PyType_Slot *slot = &spec->slots[0]; slot->slot != 0; slot++) { switch (slot->slot) { - case NPY_DTMETH_resolve_descriptors: + case NPY_METH_resolve_descriptors: meth->resolve_descriptors = slot->pfunc; continue; - case NPY_DTMETH_get_loop: + case NPY_METH_get_loop: if (private) { /* Only allow override for private functions initially */ meth->get_strided_loop = slot->pfunc; continue; } break; - case NPY_DTMETH_strided_loop: + case NPY_METH_strided_loop: meth->strided_loop = slot->pfunc; continue; - case NPY_DTMETH_contiguous_loop: + case NPY_METH_contiguous_loop: meth->contiguous_loop = slot->pfunc; continue; - case NPY_DTMETH_unaligned_strided_loop: + case NPY_METH_unaligned_strided_loop: meth->unaligned_strided_loop = slot->pfunc; continue; - case NPY_DTMETH_unaligned_contiguous_loop: + case NPY_METH_unaligned_contiguous_loop: meth->unaligned_contiguous_loop = slot->pfunc; continue; default: @@ -259,16 +269,16 @@ fill_arraymethod_from_slots( /* Check whether the slots are valid: */ if (meth->resolve_descriptors == &default_resolve_descriptors) { - for (int i = 0; i < res->nin + res->nout; i++) { + for (int i = 0; i < meth->nin + meth->nout; i++) { if (res->dtypes[i] == NULL) { - if (i < res->nin) { + if (i < meth->nin) { PyErr_Format(PyExc_TypeError, "All input DTypes must be specified when using " "the default `resolve_descriptors` function. " "(method: %s)", spec->name); return -1; } - else if (res->nin == 0) { + else if (meth->nin == 0) { PyErr_Format(PyExc_TypeError, "Must specify output DTypes or use custom " "`resolve_descriptors` when there are no inputs. " @@ -276,7 +286,7 @@ fill_arraymethod_from_slots( return -1; } } - if (i >= res->nin && res->dtypes[i]->parametric) { + if (i >= meth->nin && res->dtypes[i]->parametric) { PyErr_Format(PyExc_TypeError, "must provide a `resolve_descriptors` function if any " "output DType is parametric. (method: %s)", @@ -350,8 +360,6 @@ PyArrayMethod_FromSpec_int(PyArrayMethod_Spec *spec, int private) if (res == NULL) { return NULL; } - res->nin = spec->nin; - res->nout = spec->nout; res->method = NULL; res->dtypes = PyMem_Malloc(sizeof(PyArray_DTypeMeta *) * nargs); @@ -374,6 +382,8 @@ PyArrayMethod_FromSpec_int(PyArrayMethod_Spec *spec, int private) memset((char *)(res->method) + sizeof(PyObject), 0, sizeof(PyArrayMethodObject) - sizeof(PyObject)); + res->method->nin = spec->nin; + res->method->nout = spec->nout; res->method->flags = spec->flags; res->method->casting = spec->casting; if (fill_arraymethod_from_slots(res, spec, private) < 0) { @@ -419,11 +429,12 @@ NPY_NO_EXPORT PyTypeObject PyArrayMethod_Type = { static PyObject * boundarraymethod_repr(PyBoundArrayMethodObject *self) { - PyObject *dtypes = PyTuple_New(self->nin + self->nout); + int nargs = self->method->nin + self->method->nout; + PyObject *dtypes = PyTuple_New(nargs); if (dtypes == NULL) { return NULL; } - for (int i = 0; i < self->nin + self->nout; i++) { + for (int i = 0; i < nargs; i++) { Py_INCREF(self->dtypes[i]); PyTuple_SET_ITEM(dtypes, i, (PyObject *)self->dtypes[i]); } @@ -438,8 +449,9 @@ boundarraymethod_dealloc(PyObject *self) { PyBoundArrayMethodObject *meth; meth = ((PyBoundArrayMethodObject *)self); + int nargs = meth->method->nin + meth->method->nout; - for (int i = 0; i < meth->nin + meth->nout; i++) { + for (int i = 0; i < nargs; i++) { Py_XDECREF(meth->dtypes[i]); } PyMem_Free(meth->dtypes); @@ -461,25 +473,27 @@ static PyObject * boundarraymethod__resolve_descripors( PyBoundArrayMethodObject *self, PyObject *descr_tuple) { + int nin = self->method->nin; + int nout = self->method->nout; + PyArray_Descr *given_descrs[NPY_MAXARGS]; PyArray_Descr *loop_descrs[NPY_MAXARGS]; if (!PyTuple_CheckExact(descr_tuple) || - PyTuple_Size(descr_tuple) != self->nin + self->nout) { + PyTuple_Size(descr_tuple) != nin + nout) { PyErr_Format(PyExc_ValueError, "_resolve_descriptors() takes exactly one tuple with as many " - "elements as the method takes arguments (%d+%d).", - self->nin, self->nout); + "elements as the method takes arguments (%d+%d).", nin, nout); return NULL; } - for (int i = 0; i < self->nin + self->nout; i++) { + for (int i = 0; i < nin + nout; i++) { PyObject *tmp = PyTuple_GetItem(descr_tuple, i); if (tmp == NULL) { return NULL; } else if (tmp == Py_None) { - if (i < self->nin) { + if (i < nin) { PyErr_SetString(PyExc_ValueError, "only output dtypes may be omitted (set to None)."); return NULL; @@ -502,16 +516,8 @@ boundarraymethod__resolve_descripors( } } - PyArrayMethod_Context context = { - .caller = NULL, - .method = self->method, - .dtypes = self->dtypes, - .nin = self->nin, - .nout = self->nout, - .descriptors = NULL, /* Used after resolve_descriptors */ - }; NPY_CASTING casting = self->method->resolve_descriptors( - &context, given_descrs, loop_descrs); + self->method, self->dtypes, given_descrs, loop_descrs); if (casting < 0 && PyErr_Occurred()) { return NULL; @@ -520,11 +526,11 @@ boundarraymethod__resolve_descripors( return Py_BuildValue("iO", casting, Py_None); } - PyObject *result_tuple = PyTuple_New(self->nin + self->nout); + PyObject *result_tuple = PyTuple_New(nin + nout); if (result_tuple == NULL) { return NULL; } - for (int i = 0; i < self->nin + self->nout; i++) { + for (int i = 0; i < nin + nout; i++) { /* transfer ownership to the tuple. */ PyTuple_SET_ITEM(result_tuple, i, (PyObject *)loop_descrs[i]); } @@ -534,7 +540,7 @@ boundarraymethod__resolve_descripors( * cast-is-view flag. If no input is parametric, it must match exactly. */ int parametric = 0; - for (int i = 0; i < self->nin + self->nout; i++) { + for (int i = 0; i < nin + nout; i++) { if (self->dtypes[i]->parametric) { parametric = 1; break; diff --git a/numpy/core/src/multiarray/array_method.h b/numpy/core/src/multiarray/array_method.h index a3361d20a..15ea948ce 100644 --- a/numpy/core/src/multiarray/array_method.h +++ b/numpy/core/src/multiarray/array_method.h @@ -33,27 +33,26 @@ struct PyArrayMethodObject_tag; /* * This struct is specific to an individual (possibly repeated) call of - * the DTypeMethods strided operator, and as such is passed into the various - * methods of the DTypeMethod object (the adjust_descriptors function, + * 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. * - * We recycle this as a specification for creating new DTypeMethods - * right now. (This should probably be reviewed before making it public) + * TODO: Before making this public, we should review which information should + * be stored on the Context/BoundArrayMethod vs. the ArrayMethod. */ typedef struct { - PyObject *caller; + PyObject *caller; /* E.g. the original ufunc, may be NULL */ struct PyArrayMethodObject_tag *method; - int nin, nout; - PyArray_DTypeMeta **dtypes; - /* Operand descriptors, filled in by adjust_desciptors */ + /* Operand descriptors, filled in by resolve_descriptors */ PyArray_Descr **descriptors; } PyArrayMethod_Context; typedef NPY_CASTING (resolve_descriptors_function)( - PyArrayMethod_Context *context, + struct PyArrayMethodObject_tag *method, + PyArray_DTypeMeta **dtypes, PyArray_Descr **given_descrs, PyArray_Descr **loop_descrs); @@ -68,7 +67,7 @@ typedef int (get_loop_function)( /* - * This struct will be public and necessary for creating a new DTypeMethod + * 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? @@ -85,13 +84,19 @@ typedef struct { /* - * Structure of the DTypeMethod. This structure should probably not be made + * Structure of the ArrayMethod. This structure should probably not be made * public. If necessary, we can make certain operations on it public - * (e.g. to allow users access to `get_strided_loop`). + * (e.g. to allow users indirect access to `get_strided_loop`). + * + * NOTE: In some cases, it may not be clear whether information should be + * stored here or on the bound version. E.g. `nin` and `nout` (and in the + * future the gufunc `signature`) is already stored on the ufunc so that + * storing these here duplicates the information. */ typedef struct PyArrayMethodObject_tag { PyObject_HEAD char *name; + int nin, nout; /* Casting is normally "safe" for functions, but is important for casts */ NPY_CASTING casting; /* default flags. The get_strided_loop function can override these */ @@ -107,17 +112,17 @@ typedef struct PyArrayMethodObject_tag { /* - * We will sometimes have to create a DTypeMethod and allow passing it around, + * We will sometimes have to create a ArrayMethod and allow passing it around, * similar to `instance.method` returning a bound method, e.g. a function like * `ufunc.resolve()` can return a bound object. - * This or the method itself may need further attributes, such as the `owner` - * (which could be the bound ufunc), the `signature` (of the gufunc), or - * the identity for reduction support. + * The current main purpose of the BoundArrayMethod is that it holds on to the + * `dtypes` (the classes), so that the `ArrayMethod` (e.g. for casts) will + * not create references cycles. In principle, it could hold any information + * which is also stored on the ufunc (and thus does not need to be repeated + * on the `ArrayMethod` itself. */ typedef struct { PyObject_HEAD - int nin; - int nout; PyArray_DTypeMeta **dtypes; PyArrayMethodObject *method; } PyBoundArrayMethodObject; @@ -127,16 +132,16 @@ extern NPY_NO_EXPORT PyTypeObject PyArrayMethod_Type; extern NPY_NO_EXPORT PyTypeObject PyBoundArrayMethod_Type; /* - * SLOTS IDs For the DTypeMethod creation, one public, the IDs are fixed. + * 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_DTMETH_resolve_descriptors 1 -#define NPY_DTMETH_get_loop 2 -#define NPY_DTMETH_strided_loop 3 -#define NPY_DTMETH_contiguous_loop 4 -#define NPY_DTMETH_unaligned_strided_loop 5 -#define NPY_DTMETH_unaligned_contiguous_loop 6 +#define NPY_METH_resolve_descriptors 1 +#define NPY_METH_get_loop 2 +#define NPY_METH_strided_loop 3 +#define NPY_METH_contiguous_loop 4 +#define NPY_METH_unaligned_strided_loop 5 +#define NPY_METH_unaligned_contiguous_loop 6 NPY_NO_EXPORT PyBoundArrayMethodObject * diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c index 7cee072bd..a9e9051af 100644 --- a/numpy/core/src/multiarray/convert_datatype.c +++ b/numpy/core/src/multiarray/convert_datatype.c @@ -161,8 +161,6 @@ PyArray_GetBoundCastingImpl(PyArray_DTypeMeta *from, PyArray_DTypeMeta *to) if (res == NULL) { return NULL; } - res->nin = 1; - res->nout = 1; res->method = (PyArrayMethodObject *)method; res->dtypes = PyMem_Malloc(2 * sizeof(PyArray_DTypeMeta *)); if (res->dtypes == NULL) { @@ -379,15 +377,9 @@ PyArray_GetCastSafety( PyArray_DTypeMeta *dtypes[2] = {NPY_DTYPE(from), to_dtype}; PyArray_Descr *descrs[2] = {from, to}; PyArray_Descr *out_descrs[2]; - PyArrayMethod_Context context = { - .caller = NULL, - .nin = 1, .nout = 1, - .method = castingimpl, - .dtypes = dtypes, - .descriptors = NULL, - }; - casting = castingimpl->resolve_descriptors(&context, descrs, out_descrs); + casting = castingimpl->resolve_descriptors( + castingimpl, dtypes, descrs, out_descrs); Py_DECREF(meth); if (casting < 0) { return -1; @@ -804,7 +796,7 @@ ensure_dtype_nbo(PyArray_Descr *type) /** * This function should possibly become public API eventually. At this * time it is implemented by falling back to `PyArray_AdaptFlexibleDType`. - * We will use `CastingImpl[from, to].adjust_descriptors(...)` to implement + * We will use `CastingImpl[from, to].resolve_descriptors(...)` to implement * this logic. * Before that, the API needs to be reviewed though. * @@ -843,19 +835,13 @@ PyArray_CastDescrToDType(PyArray_Descr *descr, PyArray_DTypeMeta *given_DType) goto error; } PyArray_DTypeMeta *dtypes[2] = {NPY_DTYPE(descr), given_DType}; - PyArrayMethod_Context context = { - .caller = NULL, - .method = (PyArrayMethodObject *)tmp, - .dtypes = dtypes, - .nin = 1, - .nout = 1, - .descriptors = NULL, - }; PyArray_Descr *given_descrs[2] = {descr, NULL}; PyArray_Descr *loop_descrs[2]; - NPY_CASTING casting = context.method->resolve_descriptors( - &context, given_descrs, loop_descrs); - Py_DECREF(context.method); + + PyArrayMethodObject *meth = (PyArrayMethodObject *)tmp; + NPY_CASTING casting = meth->resolve_descriptors( + meth, dtypes, given_descrs, loop_descrs); + Py_DECREF(tmp); if (casting < 0) { goto error; } @@ -1824,7 +1810,7 @@ PyArray_ConvertToCommonType(PyObject *op, int *retn) NPY_NO_EXPORT int PyArray_AddCastingImplmentation(PyBoundArrayMethodObject *meth) { - if (meth->nin != 1 || meth->nout != 1) { + if (meth->method->nin != 1 || meth->method->nout != 1) { PyErr_SetString(PyExc_TypeError, "A cast must have one input and one output."); return -1; @@ -1885,7 +1871,8 @@ PyArray_AddCastingImplementation_FromSpec(PyArrayMethod_Spec *spec, int private) NPY_NO_EXPORT NPY_CASTING legacy_same_dtype_resolve_descriptors( - PyArrayMethod_Context *NPY_UNUSED(context), + PyArrayMethodObject *NPY_UNUSED(self), + PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]), PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2]) { @@ -1925,11 +1912,12 @@ legacy_same_dtype_resolve_descriptors( */ NPY_NO_EXPORT NPY_CASTING simple_cast_resolve_descriptors( - PyArrayMethod_Context *context, + PyArrayMethodObject *self, + PyArray_DTypeMeta *dtypes[2], PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2]) { - assert(context->dtypes[0]->legacy && context->dtypes[1]->legacy); + assert(dtypes[0]->legacy && dtypes[1]->legacy); loop_descrs[0] = ensure_dtype_nbo(given_descrs[0]); if (loop_descrs[0] == NULL) { @@ -1943,11 +1931,11 @@ simple_cast_resolve_descriptors( } } else { - loop_descrs[1] = context->dtypes[1]->default_descr(context->dtypes[1]); + loop_descrs[1] = dtypes[1]->default_descr(dtypes[1]); } - if (context->method->casting != NPY_NO_CASTING) { - return context->method->casting; + if (self->casting != NPY_NO_CASTING) { + return self->casting; } if (PyDataType_ISNOTSWAPPED(loop_descrs[0]) == PyDataType_ISNOTSWAPPED(loop_descrs[1])) { @@ -1974,19 +1962,19 @@ add_numeric_cast(PyArray_DTypeMeta *from, PyArray_DTypeMeta *to) npy_intp from_itemsize = dtypes[0]->singleton->elsize; npy_intp to_itemsize = dtypes[1]->singleton->elsize; - slots[0].slot = NPY_DTMETH_resolve_descriptors; + slots[0].slot = NPY_METH_resolve_descriptors; slots[0].pfunc = &simple_cast_resolve_descriptors; /* Fetch the optimized loops (2<<10 is a non-contiguous stride) */ - slots[1].slot = NPY_DTMETH_strided_loop; + slots[1].slot = NPY_METH_strided_loop; slots[1].pfunc = PyArray_GetStridedNumericCastFn( 1, 2<<10, 2<<10, from->type_num, to->type_num); - slots[2].slot = NPY_DTMETH_contiguous_loop; + slots[2].slot = NPY_METH_contiguous_loop; slots[2].pfunc = PyArray_GetStridedNumericCastFn( 1, from_itemsize, to_itemsize, from->type_num, to->type_num); - slots[3].slot = NPY_DTMETH_unaligned_strided_loop; + slots[3].slot = NPY_METH_unaligned_strided_loop; slots[3].pfunc = PyArray_GetStridedNumericCastFn( 0, 2<<10, 2<<10, from->type_num, to->type_num); - slots[4].slot = NPY_DTMETH_unaligned_contiguous_loop; + slots[4].slot = NPY_METH_unaligned_contiguous_loop; slots[4].pfunc = PyArray_GetStridedNumericCastFn( 0, from_itemsize, to_itemsize, from->type_num, to->type_num); slots[5].slot = 0; @@ -1999,9 +1987,9 @@ add_numeric_cast(PyArray_DTypeMeta *from, PyArray_DTypeMeta *to) spec.casting = NPY_NO_CASTING; /* When there is no casting (equivalent C-types) use byteswap loops */ - slots[0].slot = NPY_DTMETH_resolve_descriptors; + slots[0].slot = NPY_METH_resolve_descriptors; slots[0].pfunc = &legacy_same_dtype_resolve_descriptors; - slots[1].slot = NPY_DTMETH_get_loop; + slots[1].slot = NPY_METH_get_loop; slots[1].pfunc = NULL; slots[2].slot = 0; slots[2].pfunc = NULL; @@ -2058,9 +2046,10 @@ PyArray_InitializeNumericCasts() static int cast_to_string_resolve_descriptors( - PyArrayMethod_Context *context, - PyArray_Descr **given_descrs, - PyArray_Descr **loop_descrs) + PyArrayMethodObject *self, + PyArray_DTypeMeta *dtypes[2], + PyArray_Descr *given_descrs[2], + PyArray_Descr *loop_descrs[2]) { /* * NOTE: The following code used to be part of PyArray_AdaptFlexibleDType @@ -2070,7 +2059,7 @@ cast_to_string_resolve_descriptors( * a multiple of eight. */ npy_intp size = -1; - switch (context->dtypes[0]->type_num) { + switch (dtypes[0]->type_num) { case NPY_BOOL: case NPY_UBYTE: case NPY_BYTE: @@ -2082,18 +2071,18 @@ cast_to_string_resolve_descriptors( case NPY_LONG: case NPY_ULONGLONG: case NPY_LONGLONG: - assert(context->dtypes[0]->singleton->elsize <= 8); - assert(context->dtypes[0]->singleton->elsize > 0); - if (context->dtypes[0]->kind == 'b') { + assert(dtypes[0]->singleton->elsize <= 8); + assert(dtypes[0]->singleton->elsize > 0); + if (dtypes[0]->kind == 'b') { /* 5 chars needed for cast to 'True' or 'False' */ size = 5; } - else if (context->dtypes[0]->kind == 'u') { - size = REQUIRED_STR_LEN[context->dtypes[0]->singleton->elsize]; + else if (dtypes[0]->kind == 'u') { + size = REQUIRED_STR_LEN[dtypes[0]->singleton->elsize]; } - else if (context->dtypes[0]->kind == 'i') { + else if (dtypes[0]->kind == 'i') { /* Add character for sign symbol */ - size = REQUIRED_STR_LEN[context->dtypes[0]->singleton->elsize] + 1; + size = REQUIRED_STR_LEN[dtypes[0]->singleton->elsize] + 1; } break; case NPY_HALF: @@ -2123,12 +2112,12 @@ cast_to_string_resolve_descriptors( "Impossible cast to string path requested."); return -1; } - if (context->dtypes[1]->type_num == NPY_UNICODE) { + if (dtypes[1]->type_num == NPY_UNICODE) { size *= 4; } if (given_descrs[1] == NULL) { - loop_descrs[1] = PyArray_DescrNewFromType(context->dtypes[1]->type_num); + loop_descrs[1] = PyArray_DescrNewFromType(dtypes[1]->type_num); if (loop_descrs[1] == NULL) { return -1; } @@ -2148,12 +2137,12 @@ cast_to_string_resolve_descriptors( return -1; } - if (context->method->casting == NPY_UNSAFE_CASTING) { - assert(context->dtypes[0]->type_num == NPY_UNICODE && - context->dtypes[1]->type_num == NPY_STRING); + if (self->casting == NPY_UNSAFE_CASTING) { + assert(dtypes[0]->type_num == NPY_UNICODE && + dtypes[1]->type_num == NPY_STRING); return NPY_UNSAFE_CASTING; } - assert(context->method->casting == NPY_SAFE_CASTING); + assert(self->casting == NPY_SAFE_CASTING); if (loop_descrs[1]->elsize >= size) { return NPY_SAFE_CASTING; @@ -2184,9 +2173,9 @@ add_other_to_and_from_string_cast( */ PyArray_DTypeMeta *dtypes[2] = {other, string}; PyType_Slot slots[] = { - {NPY_DTMETH_get_loop, NULL}, - {NPY_DTMETH_resolve_descriptors, &cast_to_string_resolve_descriptors}, - {0, NULL}}; + {NPY_METH_get_loop, NULL}, + {NPY_METH_resolve_descriptors, &cast_to_string_resolve_descriptors}, + {0, NULL}}; PyArrayMethod_Spec spec = { .name = "legacy_cast_to_string", .nin = 1, @@ -2209,7 +2198,8 @@ add_other_to_and_from_string_cast( NPY_NO_EXPORT NPY_CASTING string_to_string_resolve_descriptors( - PyArrayMethod_Context *NPY_UNUSED(context), + PyArrayMethodObject *NPY_UNUSED(self), + PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]), PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2]) { @@ -2282,9 +2272,9 @@ PyArray_InitializeStringCasts() /* string<->string and unicode<->unicode have their own specialized casts */ PyArray_DTypeMeta *dtypes[2]; PyType_Slot slots[] = { - {NPY_DTMETH_get_loop, NULL}, - {NPY_DTMETH_resolve_descriptors, &string_to_string_resolve_descriptors}, - {0, NULL}}; + {NPY_METH_get_loop, NULL}, + {NPY_METH_resolve_descriptors, &string_to_string_resolve_descriptors}, + {0, NULL}}; PyArrayMethod_Spec spec = { .name = "string_to_string_cast", .casting = NPY_NO_CASTING, @@ -2341,9 +2331,10 @@ cast_to_void_dtype_class( static NPY_CASTING nonstructured_to_structured_resolve_descriptors( - PyArrayMethod_Context *NPY_UNUSED(context), - PyArray_Descr **given_descrs, - PyArray_Descr **loop_descrs) + PyArrayMethodObject *NPY_UNUSED(self), + PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]), + PyArray_Descr *given_descrs[2], + PyArray_Descr *loop_descrs[2]) { NPY_CASTING casting; @@ -2458,9 +2449,10 @@ PyArray_GetGenericToVoidCastingImpl() static NPY_CASTING structured_to_nonstructured_resolve_descriptors( - PyArrayMethod_Context *context, - PyArray_Descr **given_descrs, - PyArray_Descr **loop_descrs) + PyArrayMethodObject *NPY_UNUSED(self), + PyArray_DTypeMeta *dtypes[2], + PyArray_Descr *given_descrs[2], + PyArray_Descr *loop_descrs[2]) { PyArray_Descr *base_descr; @@ -2489,22 +2481,22 @@ structured_to_nonstructured_resolve_descriptors( * result currently does not matter. */ if (base_descr != NULL && PyArray_GetCastSafety( - base_descr, given_descrs[1], context->dtypes[1]) < 0) { + base_descr, given_descrs[1], dtypes[1]) < 0) { return -1; } /* Void dtypes always do the full cast. */ if (given_descrs[1] == NULL) { - loop_descrs[1] = context->dtypes[1]->default_descr(context->dtypes[1]); + loop_descrs[1] = dtypes[1]->default_descr(dtypes[1]); /* * Special case strings here, this is probably unnecessary and * should be useless (i.e. it is necessary to use empty arrays to * trigger this path.). */ - if (context->dtypes[1]->type_num == NPY_STRING) { + if (dtypes[1]->type_num == NPY_STRING) { loop_descrs[1]->elsize = given_descrs[0]->elsize; } - else if (context->dtypes[1]->type_num == NPY_UNICODE) { + else if (dtypes[1]->type_num == NPY_UNICODE) { loop_descrs[1]->elsize = given_descrs[0]->elsize * 4; } } @@ -2626,9 +2618,10 @@ can_cast_fields_safety(PyArray_Descr *from, PyArray_Descr *to) static NPY_CASTING void_to_void_resolve_descriptors( - PyArrayMethod_Context *context, - PyArray_Descr **given_descrs, - PyArray_Descr **loop_descrs) + PyArrayMethodObject *self, + PyArray_DTypeMeta *dtypes[2], + PyArray_Descr *given_descrs[2], + PyArray_Descr *loop_descrs[2]) { NPY_CASTING casting; @@ -2643,11 +2636,11 @@ void_to_void_resolve_descriptors( } else if (given_descrs[0]->names != NULL) { return structured_to_nonstructured_resolve_descriptors( - context, given_descrs, loop_descrs); + self, dtypes, given_descrs, loop_descrs); } else if (given_descrs[1]->names != NULL) { return nonstructured_to_structured_resolve_descriptors( - context, given_descrs, loop_descrs); + self, dtypes, given_descrs, loop_descrs); } else if (given_descrs[0]->subarray == NULL && given_descrs[1]->subarray == NULL) { @@ -2712,9 +2705,9 @@ PyArray_InitializeVoidToVoidCast() PyArray_DTypeMeta *Void = PyArray_DTypeFromTypeNum(NPY_VOID); PyArray_DTypeMeta *dtypes[2] = {Void, Void}; PyType_Slot slots[] = { - {NPY_DTMETH_get_loop, NULL}, - {NPY_DTMETH_resolve_descriptors, &void_to_void_resolve_descriptors}, - {0, NULL}}; + {NPY_METH_get_loop, NULL}, + {NPY_METH_resolve_descriptors, &void_to_void_resolve_descriptors}, + {0, NULL}}; PyArrayMethod_Spec spec = { .name = "void_to_void_cast", .casting = NPY_NO_CASTING, @@ -2739,7 +2732,8 @@ PyArray_InitializeVoidToVoidCast() */ static NPY_CASTING object_to_any_resolve_descriptors( - PyArrayMethod_Context *context, + PyArrayMethodObject *NPY_UNUSED(self), + PyArray_DTypeMeta *dtypes[2], PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2]) { @@ -2750,20 +2744,19 @@ object_to_any_resolve_descriptors( * here is that e.g. "M8" input is considered to be the DType class, * and by allowing it here, we go back to the "M8" instance. */ - if (context->dtypes[1]->parametric && !context->dtypes[1]->legacy) { + if (dtypes[1]->parametric && !dtypes[1]->legacy) { PyErr_Format(PyExc_TypeError, "casting from object to the parametric DType %S requires " "the specified output dtype instance. " "This may be a NumPy issue, since the correct instance " - "should be discovered automatically, however.", - context->dtypes[1]); + "should be discovered automatically, however.", dtypes[1]); return -1; } - loop_descrs[1] = context->dtypes[1]->default_descr(context->dtypes[1]); + loop_descrs[1] = dtypes[1]->default_descr(dtypes[1]); if (loop_descrs[1] == NULL) { return -1; } - if (context->dtypes[1]->type_num == NPY_VOID) { + if (dtypes[1]->type_num == NPY_VOID) { /* NOTE: This appears to be behaviour as of 1.19 (void is not * adjusted) */ loop_descrs[1]->elsize = sizeof(PyObject *); @@ -2812,12 +2805,13 @@ PyArray_GetObjectToGenericCastingImpl() /* Any object object is simple (could even use the default) */ static NPY_CASTING any_to_object_resolve_descriptors( - PyArrayMethod_Context *context, + PyArrayMethodObject *NPY_UNUSED(self), + PyArray_DTypeMeta *dtypes[2], PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2]) { if (given_descrs[1] == NULL) { - loop_descrs[1] = context->dtypes[1]->default_descr(context->dtypes[1]); + loop_descrs[1] = dtypes[1]->default_descr(dtypes[1]); if (loop_descrs[1] == NULL) { return -1; } @@ -2871,8 +2865,8 @@ PyArray_InitializeObjectToObjectCast() PyArray_DTypeMeta *Object = PyArray_DTypeFromTypeNum(NPY_OBJECT); PyArray_DTypeMeta *dtypes[2] = {Object, Object}; PyType_Slot slots[] = { - {NPY_DTMETH_get_loop, NULL}, - {0, NULL}}; + {NPY_METH_get_loop, NULL}, + {0, NULL}}; PyArrayMethod_Spec spec = { .name = "object_to_object_cast", .casting = NPY_NO_CASTING | _NPY_CAST_IS_VIEW, diff --git a/numpy/core/src/multiarray/convert_datatype.h b/numpy/core/src/multiarray/convert_datatype.h index 351365701..0b33f51c0 100644 --- a/numpy/core/src/multiarray/convert_datatype.h +++ b/numpy/core/src/multiarray/convert_datatype.h @@ -64,14 +64,16 @@ PyArray_GetCastSafety( NPY_NO_EXPORT NPY_CASTING legacy_same_dtype_resolve_descriptors( - PyArrayMethod_Context *NPY_UNUSED(context), + PyArrayMethodObject *self, + PyArray_DTypeMeta **dtypes, PyArray_Descr **given_descrs, PyArray_Descr **loop_descrs); NPY_NO_EXPORT NPY_CASTING simple_cast_resolve_descriptors( - PyArrayMethod_Context *context, - PyArray_Descr **NPY_UNUSED(input_descrs), + PyArrayMethodObject *self, + PyArray_DTypeMeta **dtypes, + PyArray_Descr **input_descrs, PyArray_Descr **loop_descrs); NPY_NO_EXPORT int diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c index d41c190e1..9c1b606bb 100644 --- a/numpy/core/src/multiarray/datetime.c +++ b/numpy/core/src/multiarray/datetime.c @@ -3737,9 +3737,10 @@ find_object_datetime_type(PyObject *obj, int type_num) */ static NPY_CASTING time_to_time_resolve_descriptors( - PyArrayMethod_Context *NPY_UNUSED(context), - PyArray_Descr **given_descrs, - PyArray_Descr **loop_descrs) + PyArrayMethodObject *NPY_UNUSED(self), + PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]), + PyArray_Descr *given_descrs[2], + PyArray_Descr *loop_descrs[2]) { /* This is a within-dtype cast, which currently must handle byteswapping */ Py_INCREF(given_descrs[0]); @@ -3805,7 +3806,8 @@ time_to_time_resolve_descriptors( /* Handles datetime<->timedelta type resolution (both directions) */ static NPY_CASTING datetime_to_timedelta_resolve_descriptors( - PyArrayMethod_Context *context, + PyArrayMethodObject *NPY_UNUSED(self), + PyArray_DTypeMeta *dtypes[2], PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2]) { @@ -3816,7 +3818,7 @@ datetime_to_timedelta_resolve_descriptors( if (given_descrs[1] == NULL) { PyArray_DatetimeMetaData *meta = get_datetime_metadata_from_dtype(given_descrs[0]); assert(meta != NULL); - loop_descrs[1] = create_datetime_dtype(context->dtypes[1]->type_num, meta); + loop_descrs[1] = create_datetime_dtype(dtypes[1]->type_num, meta); } else { loop_descrs[1] = ensure_dtype_nbo(given_descrs[1]); @@ -3837,7 +3839,8 @@ datetime_to_timedelta_resolve_descriptors( /* In the current setup both strings and unicode casts support all outputs */ static NPY_CASTING time_to_string_resolve_descriptors( - PyArrayMethod_Context *context, + PyArrayMethodObject *self, + PyArray_DTypeMeta *dtypes[2], PyArray_Descr **given_descrs, PyArray_Descr **loop_descrs) { @@ -3862,24 +3865,25 @@ time_to_string_resolve_descriptors( else { size = 21; } - if (context->dtypes[1]->type_num == NPY_UNICODE) { + if (dtypes[1]->type_num == NPY_UNICODE) { size *= 4; } - loop_descrs[1] = PyArray_DescrNewFromType(context->dtypes[1]->type_num); + loop_descrs[1] = PyArray_DescrNewFromType(dtypes[1]->type_num); if (loop_descrs[1] == NULL) { Py_DECREF(loop_descrs[0]); return -1; } loop_descrs[1]->elsize = size; } - assert(context->method->casting == NPY_UNSAFE_CASTING); + assert(self->casting == NPY_UNSAFE_CASTING); return NPY_UNSAFE_CASTING; } static NPY_CASTING string_to_datetime_cast_resolve_descriptors( - PyArrayMethod_Context *context, + PyArrayMethodObject *NPY_UNUSED(self), + PyArray_DTypeMeta *dtypes[2], PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2]) { @@ -3889,7 +3893,7 @@ string_to_datetime_cast_resolve_descriptors( if (given_descrs[1] == NULL) { /* NOTE: This doesn't actually work, and will error during the cast */ - loop_descrs[1] = context->dtypes[1]->default_descr(context->dtypes[1]); + loop_descrs[1] = dtypes[1]->default_descr(dtypes[1]); if (loop_descrs[1] == NULL) { Py_DECREF(loop_descrs[0]); return -1; @@ -3923,9 +3927,9 @@ PyArray_InitializeDatetimeCasts() .slots = slots, .dtypes = dtypes, }; - slots[0].slot = NPY_DTMETH_resolve_descriptors; + slots[0].slot = NPY_METH_resolve_descriptors; slots[0].pfunc = &time_to_time_resolve_descriptors; - slots[1].slot = NPY_DTMETH_get_loop; + slots[1].slot = NPY_METH_get_loop; slots[1].pfunc = NULL; slots[2].slot = 0; slots[2].pfunc = NULL; @@ -3951,9 +3955,9 @@ PyArray_InitializeDatetimeCasts() * Casting between timedelta and datetime uses legacy casting loops, but * custom dtype resolution (to handle copying of the time unit). */ - slots[0].slot = NPY_DTMETH_resolve_descriptors; + slots[0].slot = NPY_METH_resolve_descriptors; slots[0].pfunc = &datetime_to_timedelta_resolve_descriptors; - slots[1].slot = NPY_DTMETH_get_loop; + slots[1].slot = NPY_METH_get_loop; slots[1].pfunc = NULL; slots[2].slot = 0; slots[2].pfunc = NULL; @@ -4023,9 +4027,9 @@ PyArray_InitializeDatetimeCasts() */ spec.flags = NPY_METH_SUPPORTS_UNALIGNED | NPY_METH_REQUIRES_PYAPI; - slots[0].slot = NPY_DTMETH_resolve_descriptors; + slots[0].slot = NPY_METH_resolve_descriptors; slots[0].pfunc = &time_to_string_resolve_descriptors; - slots[1].slot = NPY_DTMETH_get_loop; + slots[1].slot = NPY_METH_get_loop; slots[1].pfunc = NULL; slots[2].slot = 0; slots[2].pfunc = NULL; @@ -4063,9 +4067,9 @@ PyArray_InitializeDatetimeCasts() spec.casting = NPY_UNSAFE_CASTING; /* The default type resolution should work fine. */ - slots[0].slot = NPY_DTMETH_resolve_descriptors; + slots[0].slot = NPY_METH_resolve_descriptors; slots[0].pfunc = &string_to_datetime_cast_resolve_descriptors; - slots[1].slot = NPY_DTMETH_get_loop; + slots[1].slot = NPY_METH_get_loop; slots[1].pfunc = NULL; slots[2].slot = 0; slots[2].pfunc = NULL; diff --git a/numpy/core/src/multiarray/usertypes.c b/numpy/core/src/multiarray/usertypes.c index de880eb1c..3eaf99196 100644 --- a/numpy/core/src/multiarray/usertypes.c +++ b/numpy/core/src/multiarray/usertypes.c @@ -538,8 +538,8 @@ PyArray_AddLegacyWrapping_CastingImpl( if (from == to) { spec.flags = NPY_METH_REQUIRES_PYAPI | NPY_METH_SUPPORTS_UNALIGNED; PyType_Slot slots[] = { - {NPY_DTMETH_get_loop, NULL}, - {NPY_DTMETH_resolve_descriptors, &legacy_same_dtype_resolve_descriptors}, + {NPY_METH_get_loop, NULL}, + {NPY_METH_resolve_descriptors, &legacy_same_dtype_resolve_descriptors}, {0, NULL}}; spec.slots = slots; return PyArray_AddCastingImplementation_FromSpec(&spec, 1); @@ -547,8 +547,8 @@ PyArray_AddLegacyWrapping_CastingImpl( else { spec.flags = NPY_METH_REQUIRES_PYAPI; PyType_Slot slots[] = { - {NPY_DTMETH_get_loop, NULL}, - {NPY_DTMETH_resolve_descriptors, &simple_cast_resolve_descriptors}, + {NPY_METH_get_loop, NULL}, + {NPY_METH_resolve_descriptors, &simple_cast_resolve_descriptors}, {0, NULL}}; spec.slots = slots; return PyArray_AddCastingImplementation_FromSpec(&spec, 1); |