Skip to content

Commit 6d0996d

Browse files
committed
bpo-37907: Slightly improve performance of PyLong_AsSsize_t() with large longs
1 parent 18f8dcf commit 6d0996d

File tree

2 files changed

+16
-16
lines changed

2 files changed

+16
-16
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Slightly improve performance of :c:func:`PyLong_AsSsize_t`,
2+
:c:func:`PyLong_AsSize_t`, :c:func:`PyLong_AsLong` and
3+
:c:func:`PyLong_AsUnsignedLong` with large longs. Patch by Sergey Fedoseev.

Objects/longobject.c

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
471471
{
472472
/* This version by Tim Peters */
473473
PyLongObject *v;
474-
unsigned long x, prev;
474+
unsigned long x;
475475
long res;
476476
Py_ssize_t i;
477477
int sign;
@@ -514,12 +514,11 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
514514
i = -(i);
515515
}
516516
while (--i >= 0) {
517-
prev = x;
518-
x = (x << PyLong_SHIFT) | v->ob_digit[i];
519-
if ((x >> PyLong_SHIFT) != prev) {
517+
if (x > (unsigned long)-1 >> PyLong_SHIFT) {
520518
*overflow = sign;
521519
goto exit;
522520
}
521+
x = (x << PyLong_SHIFT) | v->ob_digit[i];
523522
}
524523
/* Haven't lost any bits, but casting to long requires extra
525524
* care (see comment above).
@@ -583,7 +582,7 @@ _PyLong_AsInt(PyObject *obj)
583582
Py_ssize_t
584583
PyLong_AsSsize_t(PyObject *vv) {
585584
PyLongObject *v;
586-
size_t x, prev;
585+
size_t x;
587586
Py_ssize_t i;
588587
int sign;
589588

@@ -610,10 +609,10 @@ PyLong_AsSsize_t(PyObject *vv) {
610609
i = -(i);
611610
}
612611
while (--i >= 0) {
613-
prev = x;
614-
x = (x << PyLong_SHIFT) | v->ob_digit[i];
615-
if ((x >> PyLong_SHIFT) != prev)
612+
if (x > (size_t)-1 >> PyLong_SHIFT) {
616613
goto overflow;
614+
}
615+
x = (x << PyLong_SHIFT) | v->ob_digit[i];
617616
}
618617
/* Haven't lost any bits, but casting to a signed type requires
619618
* extra care (see comment above).
@@ -639,7 +638,7 @@ unsigned long
639638
PyLong_AsUnsignedLong(PyObject *vv)
640639
{
641640
PyLongObject *v;
642-
unsigned long x, prev;
641+
unsigned long x;
643642
Py_ssize_t i;
644643

645644
if (vv == NULL) {
@@ -664,14 +663,13 @@ PyLong_AsUnsignedLong(PyObject *vv)
664663
case 1: return v->ob_digit[0];
665664
}
666665
while (--i >= 0) {
667-
prev = x;
668-
x = (x << PyLong_SHIFT) | v->ob_digit[i];
669-
if ((x >> PyLong_SHIFT) != prev) {
666+
if (x > (unsigned long)-1 >> PyLong_SHIFT) {
670667
PyErr_SetString(PyExc_OverflowError,
671668
"Python int too large to convert "
672669
"to C unsigned long");
673670
return (unsigned long) -1;
674671
}
672+
x = (x << PyLong_SHIFT) | v->ob_digit[i];
675673
}
676674
return x;
677675
}
@@ -683,7 +681,7 @@ size_t
683681
PyLong_AsSize_t(PyObject *vv)
684682
{
685683
PyLongObject *v;
686-
size_t x, prev;
684+
size_t x;
687685
Py_ssize_t i;
688686

689687
if (vv == NULL) {
@@ -708,13 +706,12 @@ PyLong_AsSize_t(PyObject *vv)
708706
case 1: return v->ob_digit[0];
709707
}
710708
while (--i >= 0) {
711-
prev = x;
712-
x = (x << PyLong_SHIFT) | v->ob_digit[i];
713-
if ((x >> PyLong_SHIFT) != prev) {
709+
if (x > (size_t)-1 >> PyLong_SHIFT) {
714710
PyErr_SetString(PyExc_OverflowError,
715711
"Python int too large to convert to C size_t");
716712
return (size_t) -1;
717713
}
714+
x = (x << PyLong_SHIFT) | v->ob_digit[i];
718715
}
719716
return x;
720717
}

0 commit comments

Comments
 (0)