Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve performance of ``PyLongObject`` conversion method ``PyLong_AsLongAndOverflow``.
76 changes: 48 additions & 28 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,26 @@ PyLong_FromDouble(double dval)
#define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN)
#define PY_ABS_SSIZE_T_MIN (0-(size_t)PY_SSIZE_T_MIN)

static inline unsigned long
_unroll_digits(PyLongObject *v, Py_ssize_t *i)
{
digit *digits = v->long_value.ob_digit;
assert(*i >= 2);
/* unroll 1 digit */
--(*i);
assert(ULONG_MAX >= ((1UL << PyLong_SHIFT) - 1));
unsigned long x = digits[*i];

#if ((ULONG_MAX >> PyLong_SHIFT)) >= ((1UL << PyLong_SHIFT) - 1)
/* unroll another digit */
x <<= PyLong_SHIFT;
--(*i);
x |= digits[*i];
#endif

return x;
}

/* Get a C long int from an int object or any object that has an __index__
method.

Expand All @@ -507,13 +527,12 @@ PyLong_FromDouble(double dval)
For other errors (e.g., TypeError), return -1 and set an error condition.
In this case *overflow will be 0.
*/

long
PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
{
/* This version by Tim Peters */
/* This version originally by Tim Peters */
PyLongObject *v;
unsigned long x, prev;
unsigned long x;
long res;
Py_ssize_t i;
int sign;
Expand Down Expand Up @@ -556,14 +575,14 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
res = -1;
i = _PyLong_DigitCount(v);
sign = _PyLong_NonCompactSign(v);
x = 0;

x = _unroll_digits(v, &i);
while (--i >= 0) {
prev = x;
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
if ((x >> PyLong_SHIFT) != prev) {
if (x > SIZE_MAX >> PyLong_SHIFT) {
*overflow = sign;
goto exit;
}
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
}
/* Haven't lost any bits, but casting to long requires extra
* care (see comment above).
Expand Down Expand Up @@ -627,7 +646,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;

Expand All @@ -646,12 +665,13 @@ PyLong_AsSsize_t(PyObject *vv) {
}
i = _PyLong_DigitCount(v);
sign = _PyLong_NonCompactSign(v);
x = 0;

x = _unroll_digits(v, &i);
while (--i >= 0) {
prev = x;
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
if ((x >> PyLong_SHIFT) != prev)
if (x > SIZE_MAX >> PyLong_SHIFT) {
goto overflow;
}
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
}
/* Haven't lost any bits, but casting to a signed type requires
* extra care (see comment above).
Expand All @@ -677,7 +697,7 @@ unsigned long
PyLong_AsUnsignedLong(PyObject *vv)
{
PyLongObject *v;
unsigned long x, prev;
unsigned long x;
Py_ssize_t i;

if (vv == NULL) {
Expand Down Expand Up @@ -708,13 +728,13 @@ PyLong_AsUnsignedLong(PyObject *vv)
return (unsigned long) -1;
}
i = _PyLong_DigitCount(v);
x = 0;

x = _unroll_digits(v, &i);
while (--i >= 0) {
prev = x;
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
if ((x >> PyLong_SHIFT) != prev) {
if (x > SIZE_MAX >> PyLong_SHIFT) {
goto overflow;
}
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
}
return x;
overflow:
Expand All @@ -731,7 +751,7 @@ size_t
PyLong_AsSize_t(PyObject *vv)
{
PyLongObject *v;
size_t x, prev;
size_t x;
Py_ssize_t i;

if (vv == NULL) {
Expand All @@ -753,16 +773,16 @@ PyLong_AsSize_t(PyObject *vv)
return (size_t) -1;
}
i = _PyLong_DigitCount(v);
x = 0;

x = _unroll_digits(v, &i);
while (--i >= 0) {
prev = x;
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
if ((x >> PyLong_SHIFT) != prev) {
PyErr_SetString(PyExc_OverflowError,
"Python int too large to convert to C size_t");
return (size_t) -1;
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->long_value.ob_digit[i];
}
}
return x;
}

Expand Down Expand Up @@ -790,7 +810,7 @@ _PyLong_AsUnsignedLongMask(PyObject *vv)
}
i = _PyLong_DigitCount(v);
int sign = _PyLong_NonCompactSign(v);
x = 0;
x = _unroll_digits(v, &i);
while (--i >= 0) {
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
}
Expand Down Expand Up @@ -1609,7 +1629,7 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv)
}
i = _PyLong_DigitCount(v);
sign = _PyLong_NonCompactSign(v);
x = 0;
x = _unroll_digits(v, &i);
while (--i >= 0) {
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
}
Expand Down
Loading