-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
bpo-37907: Slightly improve performance of PyLong_AsSsize_t() with large longs #15363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be possible to start at "x = v->ob_digit[0];" and "i=1;" to avoid starting the loop with x=0 which means one useless if at the first iteration. With 64-bit unsigned long and PyLong_SHIFT, we can even combine two digits without having to check for overflow, no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Something like:
|
||
while (--i >= 0) { | ||
prev = x; | ||
x = (x << PyLong_SHIFT) | v->ob_digit[i]; | ||
if ((x >> PyLong_SHIFT) != prev) { | ||
if (x > ULONG_MAX >> 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_MAX >> 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 > ULONG_MAX >> 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_MAX >> 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; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a completely trivial internal change. I don't think it needs a
NEWS
entry.