summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2020-11-18 11:46:54 -0600
committerSebastian Berg <sebastian@sipsolutions.net>2020-11-24 21:25:02 -0600
commita9a44e9ac554a7b58804764e9149f38732baccb6 (patch)
treec4706583b5977ae4c2071e84f3782fe0e802ce6a
parentdf1b2a8077052d539ff29b763413360434f3d44a (diff)
downloadnumpy-a9a44e9ac554a7b58804764e9149f38732baccb6.tar.gz
Address Matti's comments from yesterday
-rw-r--r--numpy/core/src/multiarray/array_method.c88
-rw-r--r--numpy/core/src/multiarray/array_method.h55
-rw-r--r--numpy/core/src/multiarray/convert_datatype.c170
-rw-r--r--numpy/core/src/multiarray/convert_datatype.h8
-rw-r--r--numpy/core/src/multiarray/datetime.c42
-rw-r--r--numpy/core/src/multiarray/usertypes.c8
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);