Skip to content

Commit a38cbfb

Browse files
committed
Improve performance of pylong_as_xxx conversions
1 parent b3cde88 commit a38cbfb

1 file changed

Lines changed: 45 additions & 42 deletions

File tree

Objects/longobject.c

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
513513
{
514514
/* This version originally by Tim Peters */
515515
PyLongObject *v;
516-
unsigned long x, prev;
516+
unsigned long x;
517517
long res;
518518
Py_ssize_t i;
519519
int sign;
@@ -556,45 +556,29 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
556556
res = -1;
557557
i = _PyLong_DigitCount(v);
558558
sign = _PyLong_NonCompactSign(v);
559-
x = 0;
560-
while (--i >= 0) {
561-
prev = x;
562-
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
563-
if ((x >> PyLong_SHIFT) != prev) {
564-
*overflow = sign;
565-
goto exit;
566-
}
567-
}
568559

569-
/*
570560
digit *digits = v->long_value.ob_digit;
571-
572561
assert(i >= 2);
573-
#if ((ULONG_MAX >> PyLong_SHIFT)) >= ((1UL << PyLong_SHIFT) - 1)
574-
/* use 2 digits *
562+
/* unroll 1 digit */
575563
--i;
564+
assert(ULONG_MAX >= ((1UL << PyLong_SHIFT) - 1));
576565
x = digits[i];
566+
567+
#if ((ULONG_MAX >> PyLong_SHIFT)) >= ((1UL << PyLong_SHIFT) - 1)
568+
/* unroll another digit */
577569
x <<= PyLong_SHIFT;
578570
--i;
579571
x |= digits[i];
580-
#else
581-
/* use 1 digit *
582-
//--i;
583-
assert(ULONG_MAX >= ((1UL << PyLong_SHIFT) - 1));
584-
//x = digits[i];
585-
x=0;
586572
#endif
587-
*/
588573

589-
/*
574+
590575
while (--i >= 0) {
591576
if (x > SIZE_MAX >> PyLong_SHIFT) {
592577
*overflow = sign;
593578
goto exit;
594579
}
595580
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
596581
}
597-
*/
598582
/* Haven't lost any bits, but casting to long requires extra
599583
* care (see comment above).
600584
*/
@@ -657,7 +641,7 @@ PyLong_AsInt(PyObject *obj)
657641
Py_ssize_t
658642
PyLong_AsSsize_t(PyObject *vv) {
659643
PyLongObject *v;
660-
size_t x, prev;
644+
size_t x;
661645
Py_ssize_t i;
662646
int sign;
663647

@@ -676,12 +660,19 @@ PyLong_AsSsize_t(PyObject *vv) {
676660
}
677661
i = _PyLong_DigitCount(v);
678662
sign = _PyLong_NonCompactSign(v);
679-
x = 0;
663+
664+
digit *digits = v->long_value.ob_digit;
665+
assert(i >= 2);
666+
/* unroll 1 digit */
667+
--i;
668+
assert(ULONG_MAX >= ((1UL << PyLong_SHIFT) - 1));
669+
x = digits[i];
670+
680671
while (--i >= 0) {
681-
prev = x;
682-
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
683-
if ((x >> PyLong_SHIFT) != prev)
672+
if (x > SIZE_MAX >> PyLong_SHIFT) {
684673
goto overflow;
674+
}
675+
x = (x << PyLong_SHIFT) | digits[i];
685676
}
686677
/* Haven't lost any bits, but casting to a signed type requires
687678
* extra care (see comment above).
@@ -707,7 +698,7 @@ unsigned long
707698
PyLong_AsUnsignedLong(PyObject *vv)
708699
{
709700
PyLongObject *v;
710-
unsigned long x, prev;
701+
unsigned long x;
711702
Py_ssize_t i;
712703

713704
if (vv == NULL) {
@@ -738,13 +729,19 @@ PyLong_AsUnsignedLong(PyObject *vv)
738729
return (unsigned long) -1;
739730
}
740731
i = _PyLong_DigitCount(v);
741-
x = 0;
732+
733+
digit *digits = v->long_value.ob_digit;
734+
assert(i >= 2);
735+
/* unroll 1 digit */
736+
--i;
737+
assert(ULONG_MAX >= ((1UL << PyLong_SHIFT) - 1));
738+
x = digits[i];
739+
742740
while (--i >= 0) {
743-
prev = x;
744-
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
745-
if ((x >> PyLong_SHIFT) != prev) {
741+
if (x > SIZE_MAX >> PyLong_SHIFT) {
746742
goto overflow;
747743
}
744+
x = (x << PyLong_SHIFT) | digits[i];
748745
}
749746
return x;
750747
overflow:
@@ -761,7 +758,7 @@ size_t
761758
PyLong_AsSize_t(PyObject *vv)
762759
{
763760
PyLongObject *v;
764-
size_t x, prev;
761+
size_t x;
765762
Py_ssize_t i;
766763

767764
if (vv == NULL) {
@@ -783,16 +780,22 @@ PyLong_AsSize_t(PyObject *vv)
783780
return (size_t) -1;
784781
}
785782
i = _PyLong_DigitCount(v);
786-
x = 0;
783+
784+
digit *digits = v->long_value.ob_digit;
785+
assert(i >= 2);
786+
/* unroll 1 digit */
787+
--i;
788+
assert(ULONG_MAX >= ((1UL << PyLong_SHIFT) - 1));
789+
x = digits[i];
790+
787791
while (--i >= 0) {
788-
prev = x;
789-
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
790-
if ((x >> PyLong_SHIFT) != prev) {
791-
PyErr_SetString(PyExc_OverflowError,
792-
"Python int too large to convert to C size_t");
793-
return (size_t) -1;
792+
if (x > SIZE_MAX >> PyLong_SHIFT) {
793+
PyErr_SetString(PyExc_OverflowError,
794+
"Python int too large to convert to C size_t");
795+
return (size_t) -1;
796+
}
797+
x = (x << PyLong_SHIFT) | digits[i];
794798
}
795-
}
796799
return x;
797800
}
798801

0 commit comments

Comments
 (0)