Skip to content

Commit 97a1edd

Browse files
committed
bpo-37907: Slightly improve performance of PyLong_AsSsize_t() with large longs
1 parent 0ace820 commit 97a1edd

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
@@ -484,7 +484,7 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
484484
{
485485
/* This version by Tim Peters */
486486
PyLongObject *v;
487-
unsigned long x, prev;
487+
unsigned long x;
488488
long res;
489489
Py_ssize_t i;
490490
int sign;
@@ -527,12 +527,11 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
527527
i = -(i);
528528
}
529529
while (--i >= 0) {
530-
prev = x;
531-
x = (x << PyLong_SHIFT) | v->ob_digit[i];
532-
if ((x >> PyLong_SHIFT) != prev) {
530+
if (x > (unsigned long)-1 >> PyLong_SHIFT) {
533531
*overflow = sign;
534532
goto exit;
535533
}
534+
x = (x << PyLong_SHIFT) | v->ob_digit[i];
536535
}
537536
/* Haven't lost any bits, but casting to long requires extra
538537
* care (see comment above).
@@ -596,7 +595,7 @@ _PyLong_AsInt(PyObject *obj)
596595
Py_ssize_t
597596
PyLong_AsSsize_t(PyObject *vv) {
598597
PyLongObject *v;
599-
size_t x, prev;
598+
size_t x;
600599
Py_ssize_t i;
601600
int sign;
602601

@@ -623,10 +622,10 @@ PyLong_AsSsize_t(PyObject *vv) {
623622
i = -(i);
624623
}
625624
while (--i >= 0) {
626-
prev = x;
627-
x = (x << PyLong_SHIFT) | v->ob_digit[i];
628-
if ((x >> PyLong_SHIFT) != prev)
625+
if (x > (size_t)-1 >> PyLong_SHIFT) {
629626
goto overflow;
627+
}
628+
x = (x << PyLong_SHIFT) | v->ob_digit[i];
630629
}
631630
/* Haven't lost any bits, but casting to a signed type requires
632631
* extra care (see comment above).
@@ -652,7 +651,7 @@ unsigned long
652651
PyLong_AsUnsignedLong(PyObject *vv)
653652
{
654653
PyLongObject *v;
655-
unsigned long x, prev;
654+
unsigned long x;
656655
Py_ssize_t i;
657656

658657
if (vv == NULL) {
@@ -677,14 +676,13 @@ PyLong_AsUnsignedLong(PyObject *vv)
677676
case 1: return v->ob_digit[0];
678677
}
679678
while (--i >= 0) {
680-
prev = x;
681-
x = (x << PyLong_SHIFT) | v->ob_digit[i];
682-
if ((x >> PyLong_SHIFT) != prev) {
679+
if (x > (unsigned long)-1 >> PyLong_SHIFT) {
683680
PyErr_SetString(PyExc_OverflowError,
684681
"Python int too large to convert "
685682
"to C unsigned long");
686683
return (unsigned long) -1;
687684
}
685+
x = (x << PyLong_SHIFT) | v->ob_digit[i];
688686
}
689687
return x;
690688
}
@@ -696,7 +694,7 @@ size_t
696694
PyLong_AsSize_t(PyObject *vv)
697695
{
698696
PyLongObject *v;
699-
size_t x, prev;
697+
size_t x;
700698
Py_ssize_t i;
701699

702700
if (vv == NULL) {
@@ -721,13 +719,12 @@ PyLong_AsSize_t(PyObject *vv)
721719
case 1: return v->ob_digit[0];
722720
}
723721
while (--i >= 0) {
724-
prev = x;
725-
x = (x << PyLong_SHIFT) | v->ob_digit[i];
726-
if ((x >> PyLong_SHIFT) != prev) {
722+
if (x > (size_t)-1 >> PyLong_SHIFT) {
727723
PyErr_SetString(PyExc_OverflowError,
728724
"Python int too large to convert to C size_t");
729725
return (size_t) -1;
730726
}
727+
x = (x << PyLong_SHIFT) | v->ob_digit[i];
731728
}
732729
return x;
733730
}

0 commit comments

Comments
 (0)