diff options
author | Eric Wieser <wieser.eric@gmail.com> | 2020-01-29 12:51:55 +0000 |
---|---|---|
committer | Eric Wieser <wieser.eric@gmail.com> | 2020-01-30 00:08:53 +0000 |
commit | 7389163da161ffbcff59596a4b78089f1833fd7d (patch) | |
tree | 0c30d2dc29305b11c62271f96f30d7d4791f7db7 | |
parent | df1347dba08a7c67a38bd1dfcd180342e579195f (diff) | |
download | numpy-7389163da161ffbcff59596a4b78089f1833fd7d.tar.gz |
MAINT: Simplify scalar __new__ some more
The comment about base-classes doing conversions was incorrect - these always return objects of the right type
The only way the `Py_TYPE(robj) == type` can fail is if the type cannot survive round-tripping through `PyArray_DescrFromType` and `PyArray_FromAny`.
The former applies to subclasses of numpy types, while the latter is probably caused by a bug elsewhere.
This allows the `goto` to be eliminated, which means all the declarations can be pushed down.
-rw-r--r-- | numpy/core/src/multiarray/scalartypes.c.src | 81 |
1 files changed, 42 insertions, 39 deletions
diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index c18c05353..055b2ea1d 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -2534,13 +2534,17 @@ object_arrtype_dealloc(PyObject *v) assert(cls.tp_bases && (PyTuple_GET_SIZE(cls.tp_bases) == 2)); \ /* We are inheriting from a Python type as well so \ give it first dibs on conversion */ \ - PyTypeObject *sup = (PyTypeObject *)PyTuple_GET_ITEM(cls.tp_bases, num); \ - robj = sup->tp_new(type, args, kwds); \ - if (robj != NULL) goto finish; \ - if (PyTuple_GET_SIZE(args) != 1 || (kwds && PyDict_Size(kwds) != 0)) { \ - return NULL; \ + { \ + PyTypeObject *sup = (PyTypeObject *)PyTuple_GET_ITEM(cls.tp_bases, num); \ + PyObject *robj = sup->tp_new(type, args, kwds); \ + if (robj != NULL) { \ + return robj; \ + }; \ + if (PyTuple_GET_SIZE(args) != 1 || (kwds && PyDict_Size(kwds) != 0)) { \ + return NULL; \ + } \ + PyErr_Clear(); \ } \ - PyErr_Clear(); \ /* now do default conversion */ /**begin repeat @@ -2561,13 +2565,9 @@ object_arrtype_dealloc(PyObject *v) static PyObject * @name@_arrtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - PyObject *obj = NULL; - PyObject *robj; - PyArrayObject *arr; - /* * allow base-class (if any) to do conversion - * If successful, this will jump to finish: + * If successful, this will return. */ #if defined(_@TYPE@_IS_UNICODE) || defined(_@TYPE@_IS_STRING) _WORK(Py@Name@ArrType_Type, 0) @@ -2576,6 +2576,7 @@ static PyObject * #endif /* TODO: include type name in error message, which is not @name@ */ + PyObject *obj = NULL; char *kwnames[] = {"", NULL}; /* positional-only */ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwnames, &obj)) { return NULL; @@ -2584,45 +2585,48 @@ static PyObject * if (typecode == NULL) { return NULL; } - /* - * typecode is new reference and stolen by - * PyArray_FromAny but not PyArray_Scalar - */ if (obj == NULL) { - robj = PyArray_Scalar(NULL, typecode, NULL); + PyObject *robj = PyArray_Scalar(NULL, typecode, NULL); + Py_DECREF(typecode); if (robj == NULL) { - Py_DECREF(typecode); return NULL; } #if !defined(_@TYPE@_IS_STRING) && !defined(_@TYPE@_IS_UNICODE) memset(&PyArrayScalar_VAL(robj, @Name@), 0, sizeof(npy_@name@)); #endif - Py_DECREF(typecode); - goto finish; + return robj; } - /* - * It is expected at this point that robj is a PyArrayScalar - */ - arr = (PyArrayObject *)PyArray_FromAny(obj, typecode, - 0, 0, NPY_ARRAY_FORCECAST, NULL); - if ((arr == NULL) || (PyArray_NDIM(arr) > 0)) { + /* PyArray_FromAny steals a reference, reclaim it before it's gone */ + Py_INCREF(typecode); + PyArrayObject *arr = (PyArrayObject *)PyArray_FromAny( + obj, typecode, 0, 0, NPY_ARRAY_FORCECAST, NULL); + if (arr == NULL) { + Py_DECREF(typecode); + return NULL; + } + if (PyArray_NDIM(arr) > 0) { + Py_DECREF(typecode); return (PyObject *)arr; } - /* 0-d array */ - robj = PyArray_ToScalar(PyArray_DATA(arr), arr); + + /* Convert the 0-d array to a scalar*/ + PyObject *robj = PyArray_ToScalar(PyArray_DATA(arr), arr); Py_DECREF(arr); -finish: - /* Normal return */ - if ((robj == NULL) || (Py_TYPE(robj) == type)) { + if (robj == NULL || Py_TYPE(robj) == type) { + Py_DECREF(typecode); return robj; } /* - * This return path occurs when the requested type is not created - * but another scalar object is created instead (i.e. when - * the base-class does the conversion in _WORK macro) + * `typecode` does not contain any subclass information, as it was thrown + * out by the call to `PyArray_DescrFromType` - we need to add this back. + * + * FIXME[gh-15467]: This branch is also hit for the "shadowed" builtin + * types like `longdouble` (which on platforms where they are the same size + * is shadowed by `double`), because `PyArray_FromAny` returns the + * shadowing type rather than the requested one. */ /* Need to allocate new type and copy data-area over */ @@ -2633,14 +2637,13 @@ finish: else { itemsize = 0; } - obj = type->tp_alloc(type, itemsize); - if (obj == NULL) { + PyObject *new_obj = type->tp_alloc(type, itemsize); + if (new_obj == NULL) { Py_DECREF(robj); + Py_DECREF(typecode); return NULL; } - /* typecode will be NULL */ - typecode = PyArray_DescrFromType(NPY_@TYPE@); - void *dest = scalar_value(obj, typecode); + void *dest = scalar_value(new_obj, typecode); void *src = scalar_value(robj, typecode); Py_DECREF(typecode); #if defined(_@TYPE@_IS_STRING) || defined(_@TYPE@_IS_UNICODE) @@ -2652,7 +2655,7 @@ finish: *((npy_@name@ *)dest) = *((npy_@name@ *)src); #endif Py_DECREF(robj); - return obj; + return new_obj; } #undef _@TYPE@_IS_@TYPE@ |