From 97a1eddde6b3ca2c9f7d9383e64c6f71ccecb5d6 Mon Sep 17 00:00:00 2001 From: Sergey Fedoseev Date: Tue, 20 Aug 2019 22:28:27 +0500 Subject: [PATCH 1/2] bpo-37907: Slightly improve performance of PyLong_AsSsize_t() with large longs --- .../2019-08-21-21-19-38.bpo-37907.0SNcSw.rst | 3 ++ Objects/longobject.c | 29 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-08-21-21-19-38.bpo-37907.0SNcSw.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-08-21-21-19-38.bpo-37907.0SNcSw.rst b/Misc/NEWS.d/next/Core and Builtins/2019-08-21-21-19-38.bpo-37907.0SNcSw.rst new file mode 100644 index 00000000000000..2237c905365936 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-08-21-21-19-38.bpo-37907.0SNcSw.rst @@ -0,0 +1,3 @@ +Slightly improve performance of :c:func:`PyLong_AsSsize_t`, +:c:func:`PyLong_AsSize_t`, :c:func:`PyLong_AsLong` and +:c:func:`PyLong_AsUnsignedLong` with large longs. Patch by Sergey Fedoseev. diff --git a/Objects/longobject.c b/Objects/longobject.c index 90ed02b8c27a19..b1997e0b62b086 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -484,7 +484,7 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) { /* This version by Tim Peters */ PyLongObject *v; - unsigned long x, prev; + unsigned long x; long res; Py_ssize_t i; int sign; @@ -527,12 +527,11 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) i = -(i); } while (--i >= 0) { - prev = x; - x = (x << PyLong_SHIFT) | v->ob_digit[i]; - if ((x >> PyLong_SHIFT) != prev) { + if (x > (unsigned long)-1 >> PyLong_SHIFT) { *overflow = sign; goto exit; } + x = (x << PyLong_SHIFT) | v->ob_digit[i]; } /* Haven't lost any bits, but casting to long requires extra * care (see comment above). @@ -596,7 +595,7 @@ _PyLong_AsInt(PyObject *obj) Py_ssize_t PyLong_AsSsize_t(PyObject *vv) { PyLongObject *v; - size_t x, prev; + size_t x; Py_ssize_t i; int sign; @@ -623,10 +622,10 @@ PyLong_AsSsize_t(PyObject *vv) { i = -(i); } while (--i >= 0) { - prev = x; - x = (x << PyLong_SHIFT) | v->ob_digit[i]; - if ((x >> PyLong_SHIFT) != prev) + if (x > (size_t)-1 >> PyLong_SHIFT) { goto overflow; + } + x = (x << PyLong_SHIFT) | v->ob_digit[i]; } /* Haven't lost any bits, but casting to a signed type requires * extra care (see comment above). @@ -652,7 +651,7 @@ unsigned long PyLong_AsUnsignedLong(PyObject *vv) { PyLongObject *v; - unsigned long x, prev; + unsigned long x; Py_ssize_t i; if (vv == NULL) { @@ -677,14 +676,13 @@ PyLong_AsUnsignedLong(PyObject *vv) case 1: return v->ob_digit[0]; } while (--i >= 0) { - prev = x; - x = (x << PyLong_SHIFT) | v->ob_digit[i]; - if ((x >> PyLong_SHIFT) != prev) { + if (x > (unsigned long)-1 >> PyLong_SHIFT) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert " "to C unsigned long"); return (unsigned long) -1; } + x = (x << PyLong_SHIFT) | v->ob_digit[i]; } return x; } @@ -696,7 +694,7 @@ size_t PyLong_AsSize_t(PyObject *vv) { PyLongObject *v; - size_t x, prev; + size_t x; Py_ssize_t i; if (vv == NULL) { @@ -721,13 +719,12 @@ PyLong_AsSize_t(PyObject *vv) case 1: return v->ob_digit[0]; } while (--i >= 0) { - prev = x; - x = (x << PyLong_SHIFT) | v->ob_digit[i]; - if ((x >> PyLong_SHIFT) != prev) { + if (x > (size_t)-1 >> PyLong_SHIFT) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C size_t"); return (size_t) -1; } + x = (x << PyLong_SHIFT) | v->ob_digit[i]; } return x; } From 99ab95dada65f90ecc02ea6ba48f5d2b4ae61ecb Mon Sep 17 00:00:00 2001 From: Sergey Fedoseev Date: Sat, 27 Aug 2022 13:42:21 +0500 Subject: [PATCH 2/2] use limits consts --- Objects/longobject.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index b1997e0b62b086..f3c74a4fe1b5f9 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -527,7 +527,7 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) i = -(i); } while (--i >= 0) { - if (x > (unsigned long)-1 >> PyLong_SHIFT) { + if (x > ULONG_MAX >> PyLong_SHIFT) { *overflow = sign; goto exit; } @@ -622,7 +622,7 @@ PyLong_AsSsize_t(PyObject *vv) { i = -(i); } while (--i >= 0) { - if (x > (size_t)-1 >> PyLong_SHIFT) { + if (x > SIZE_MAX >> PyLong_SHIFT) { goto overflow; } x = (x << PyLong_SHIFT) | v->ob_digit[i]; @@ -676,7 +676,7 @@ PyLong_AsUnsignedLong(PyObject *vv) case 1: return v->ob_digit[0]; } while (--i >= 0) { - if (x > (unsigned long)-1 >> PyLong_SHIFT) { + if (x > ULONG_MAX >> PyLong_SHIFT) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert " "to C unsigned long"); @@ -719,7 +719,7 @@ PyLong_AsSize_t(PyObject *vv) case 1: return v->ob_digit[0]; } while (--i >= 0) { - if (x > (size_t)-1 >> PyLong_SHIFT) { + if (x > SIZE_MAX >> PyLong_SHIFT) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C size_t"); return (size_t) -1;