From 56b5e1f1db4b8a1850c0624c400c0873690f77c6 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 5 Nov 2023 07:59:17 +0300 Subject: [PATCH 1/4] Minor refactoring of Object/abstract.c (from #111996) * PyNumber_AsSsize_t: remove inaccessible code (PyLong_AsSsize_t raises OverflowError) * Drop checks for broken float subclasses (like for PyNumber_Long in 31a655411a) * Ternary ops (currently only pow/ipow) don't use __r*__ dunders, thus removal of testing last slot in ternary_op() * Use BINARY_FUNC macro for some remaining ops * Add UNARY_FUNC macro to define unary PyNumber_* functions --- Objects/abstract.c | 144 +++++++++------------------------------------ 1 file changed, 27 insertions(+), 117 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index 43842fbdd6aedd..decbf626b3d094 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1012,7 +1012,7 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) Calling scheme used for ternary operations: Order operations are tried until either a valid result or error: - v.op(v,w,z), w.op(v,w,z), z.op(v,w,z) + v.op(v,w,z), w.op(v,w,z) */ static PyObject * @@ -1071,22 +1071,6 @@ ternary_op(PyObject *v, Py_DECREF(x); /* can't do it */ } - PyNumberMethods *mz = Py_TYPE(z)->tp_as_number; - if (mz != NULL) { - ternaryfunc slotz = NB_TERNOP(mz, op_slot); - if (slotz == slotv || slotz == slotw) { - slotz = NULL; - } - if (slotz) { - PyObject *x = slotz(v, w, z); - assert(_Py_CheckSlotResult(z, op_name, x != NULL)); - if (x != Py_NotImplemented) { - return x; - } - Py_DECREF(x); /* can't do it */ - } - } - if (z == Py_None) { PyErr_Format( PyExc_TypeError, @@ -1180,29 +1164,10 @@ PyNumber_Multiply(PyObject *v, PyObject *w) return result; } -PyObject * -PyNumber_MatrixMultiply(PyObject *v, PyObject *w) -{ - return binary_op(v, w, NB_SLOT(nb_matrix_multiply), "@"); -} - -PyObject * -PyNumber_FloorDivide(PyObject *v, PyObject *w) -{ - return binary_op(v, w, NB_SLOT(nb_floor_divide), "//"); -} - -PyObject * -PyNumber_TrueDivide(PyObject *v, PyObject *w) -{ - return binary_op(v, w, NB_SLOT(nb_true_divide), "/"); -} - -PyObject * -PyNumber_Remainder(PyObject *v, PyObject *w) -{ - return binary_op(v, w, NB_SLOT(nb_remainder), "%"); -} +BINARY_FUNC(PyNumber_MatrixMultiply, nb_matrix_multiply, "@") +BINARY_FUNC(PyNumber_FloorDivide, nb_floor_divide, "//") +BINARY_FUNC(PyNumber_TrueDivide, nb_true_divide, "/") +BINARY_FUNC(PyNumber_Remainder, nb_remainder, "%") PyObject * PyNumber_Power(PyObject *v, PyObject *w, PyObject *z) @@ -1379,73 +1344,27 @@ _PyNumber_InPlacePowerNoMod(PyObject *lhs, PyObject *rhs) /* Unary operators and functions */ -PyObject * -PyNumber_Negative(PyObject *o) -{ - if (o == NULL) { - return null_error(); - } - - PyNumberMethods *m = Py_TYPE(o)->tp_as_number; - if (m && m->nb_negative) { - PyObject *res = (*m->nb_negative)(o); - assert(_Py_CheckSlotResult(o, "__neg__", res != NULL)); - return res; - } - - return type_error("bad operand type for unary -: '%.200s'", o); -} - -PyObject * -PyNumber_Positive(PyObject *o) -{ - if (o == NULL) { - return null_error(); - } - - PyNumberMethods *m = Py_TYPE(o)->tp_as_number; - if (m && m->nb_positive) { - PyObject *res = (*m->nb_positive)(o); - assert(_Py_CheckSlotResult(o, "__pos__", res != NULL)); - return res; - } - - return type_error("bad operand type for unary +: '%.200s'", o); -} - -PyObject * -PyNumber_Invert(PyObject *o) -{ - if (o == NULL) { - return null_error(); - } - - PyNumberMethods *m = Py_TYPE(o)->tp_as_number; - if (m && m->nb_invert) { - PyObject *res = (*m->nb_invert)(o); - assert(_Py_CheckSlotResult(o, "__invert__", res != NULL)); - return res; - } - - return type_error("bad operand type for unary ~: '%.200s'", o); -} - -PyObject * -PyNumber_Absolute(PyObject *o) -{ - if (o == NULL) { - return null_error(); - } - - PyNumberMethods *m = Py_TYPE(o)->tp_as_number; - if (m && m->nb_absolute) { - PyObject *res = m->nb_absolute(o); - assert(_Py_CheckSlotResult(o, "__abs__", res != NULL)); - return res; - } - - return type_error("bad operand type for abs(): '%.200s'", o); -} +#define UNARY_FUNC(func, op, meth_name) \ + PyObject * \ + func(PyObject *o) { \ + if (o == NULL) { \ + return null_error(); \ + } \ + \ + PyNumberMethods *m = Py_TYPE(o)->tp_as_number; \ + if (m && m->op) { \ + PyObject *res = (*m->op)(o); \ + assert(_Py_CheckSlotResult(o, #meth_name, res != NULL)); \ + return res; \ + } \ + \ + return type_error("bad operand type for unary -: '%.200s'", o); \ + } + +UNARY_FUNC(PyNumber_Negative, nb_negative, __neg__) +UNARY_FUNC(PyNumber_Positive, nb_positive, __pow__) +UNARY_FUNC(PyNumber_Invert, nb_invert, __invert__) +UNARY_FUNC(PyNumber_Absolute, nb_absolute, __abs__) int @@ -1537,11 +1456,7 @@ PyNumber_AsSsize_t(PyObject *item, PyObject *err) if (!runerr) { goto finish; } - - /* Error handling code -- only manage OverflowError differently */ - if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) { - goto finish; - } + assert(PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)); _PyErr_Clear(tstate); /* If no error-handling desired then the default clipping @@ -1736,11 +1651,6 @@ PyNumber_Float(PyObject *o) } return PyFloat_FromDouble(val); } - - /* A float subclass with nb_float == NULL */ - if (PyFloat_Check(o)) { - return PyFloat_FromDouble(PyFloat_AS_DOUBLE(o)); - } return PyFloat_FromString(o); } From b0d2f785049a4f97a0411b06baa3ac028fa40a0c Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 16 Nov 2023 13:30:39 +0300 Subject: [PATCH 2/4] + last argument for UNARY_FUNC() --- Objects/abstract.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index decbf626b3d094..56cdfd696e5e35 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1344,7 +1344,7 @@ _PyNumber_InPlacePowerNoMod(PyObject *lhs, PyObject *rhs) /* Unary operators and functions */ -#define UNARY_FUNC(func, op, meth_name) \ +#define UNARY_FUNC(func, op, meth_name, descr) \ PyObject * \ func(PyObject *o) { \ if (o == NULL) { \ @@ -1358,13 +1358,13 @@ _PyNumber_InPlacePowerNoMod(PyObject *lhs, PyObject *rhs) return res; \ } \ \ - return type_error("bad operand type for unary -: '%.200s'", o); \ + return type_error("bad operand type for "descr": '%.200s'", o); \ } -UNARY_FUNC(PyNumber_Negative, nb_negative, __neg__) -UNARY_FUNC(PyNumber_Positive, nb_positive, __pow__) -UNARY_FUNC(PyNumber_Invert, nb_invert, __invert__) -UNARY_FUNC(PyNumber_Absolute, nb_absolute, __abs__) +UNARY_FUNC(PyNumber_Negative, nb_negative, __neg__, "unary -") +UNARY_FUNC(PyNumber_Positive, nb_positive, __pow__, "unary +") +UNARY_FUNC(PyNumber_Invert, nb_invert, __invert__, "unary ~") +UNARY_FUNC(PyNumber_Absolute, nb_absolute, __abs__, "abs()") int From 46620edc691f88ab0e71bfe95f127c917c20eb25 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 3 Dec 2023 04:17:10 +0300 Subject: [PATCH 3/4] revert ternary_op --- Objects/abstract.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index 56cdfd696e5e35..8b6eacd50f96df 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1012,7 +1012,7 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) Calling scheme used for ternary operations: Order operations are tried until either a valid result or error: - v.op(v,w,z), w.op(v,w,z) + v.op(v,w,z), w.op(v,w,z), z.op(v,w,z) */ static PyObject * @@ -1071,6 +1071,22 @@ ternary_op(PyObject *v, Py_DECREF(x); /* can't do it */ } + PyNumberMethods *mz = Py_TYPE(z)->tp_as_number; + if (mz != NULL) { + ternaryfunc slotz = NB_TERNOP(mz, op_slot); + if (slotz == slotv || slotz == slotw) { + slotz = NULL; + } + if (slotz) { + PyObject *x = slotz(v, w, z); + assert(_Py_CheckSlotResult(z, op_name, x != NULL)); + if (x != Py_NotImplemented) { + return x; + } + Py_DECREF(x); /* can't do it */ + } + } + if (z == Py_None) { PyErr_Format( PyExc_TypeError, From 631259aba488613d4aa703ce33e6c8a0949718a5 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 3 Dec 2023 05:39:30 +0300 Subject: [PATCH 4/4] revert everything, except UNARY/BINARY_FUNC --- Objects/abstract.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index 8b6eacd50f96df..1ec5c5b8c3dc2f 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1472,7 +1472,11 @@ PyNumber_AsSsize_t(PyObject *item, PyObject *err) if (!runerr) { goto finish; } - assert(PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)); + + /* Error handling code -- only manage OverflowError differently */ + if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) { + goto finish; + } _PyErr_Clear(tstate); /* If no error-handling desired then the default clipping @@ -1667,6 +1671,11 @@ PyNumber_Float(PyObject *o) } return PyFloat_FromDouble(val); } + + /* A float subclass with nb_float == NULL */ + if (PyFloat_Check(o)) { + return PyFloat_FromDouble(PyFloat_AS_DOUBLE(o)); + } return PyFloat_FromString(o); }