#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_ulong(PyLongObject *v, Py_ssize_t *iptr)
+{
+ assert(ULONG_MAX >= ((1UL << PyLong_SHIFT) - 1));
+
+ Py_ssize_t i = *iptr;
+ assert(i >= 2);
+
+ /* unroll 1 digit */
+ --i;
+ digit *digits = v->long_value.ob_digit;
+ 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
+
+ *iptr = i;
+ return x;
+}
+
+static inline size_t
+unroll_digits_size_t(PyLongObject *v, Py_ssize_t *iptr)
+{
+ assert(SIZE_MAX >= ((1UL << PyLong_SHIFT) - 1));
+
+ Py_ssize_t i = *iptr;
+ assert(i >= 2);
+
+ /* unroll 1 digit */
+ --i;
+ digit *digits = v->long_value.ob_digit;
+ size_t x = digits[i];
+
+#if (SIZE_MAX >> PyLong_SHIFT) >= ((1 << PyLong_SHIFT) - 1)
+ /* unroll another digit */
+ x <<= PyLong_SHIFT;
+ --i;
+ x |= digits[i];
+#endif
+
+ *iptr = i;
+ return x;
+}
+
/* Get a C long int from an int object or any object that has an __index__
method.
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;
long res;
Py_ssize_t i;
int sign;
res = -1;
i = _PyLong_DigitCount(v);
sign = _PyLong_NonCompactSign(v);
- x = 0;
+
+ unsigned long x = unroll_digits_ulong(v, &i);
while (--i >= 0) {
- prev = x;
- x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
- if ((x >> PyLong_SHIFT) != prev) {
+ if (x > (ULONG_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).
Py_ssize_t
PyLong_AsSsize_t(PyObject *vv) {
PyLongObject *v;
- size_t x, prev;
Py_ssize_t i;
int sign;
}
i = _PyLong_DigitCount(v);
sign = _PyLong_NonCompactSign(v);
- x = 0;
+
+ size_t x = unroll_digits_size_t(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).
PyLong_AsUnsignedLong(PyObject *vv)
{
PyLongObject *v;
- unsigned long x, prev;
Py_ssize_t i;
if (vv == NULL) {
return (unsigned long) -1;
}
i = _PyLong_DigitCount(v);
- x = 0;
+
+ unsigned long x = unroll_digits_ulong(v, &i);
while (--i >= 0) {
- prev = x;
- x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
- if ((x >> PyLong_SHIFT) != prev) {
+ if (x > (ULONG_MAX >> PyLong_SHIFT)) {
goto overflow;
}
+ x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
}
return x;
overflow:
PyLong_AsSize_t(PyObject *vv)
{
PyLongObject *v;
- size_t x, prev;
Py_ssize_t i;
if (vv == NULL) {
return (size_t) -1;
}
i = _PyLong_DigitCount(v);
- x = 0;
+
+ size_t x = unroll_digits_size_t(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;
}
_PyLong_AsUnsignedLongMask(PyObject *vv)
{
PyLongObject *v;
- unsigned long x;
Py_ssize_t i;
if (vv == NULL || !PyLong_Check(vv)) {
}
i = _PyLong_DigitCount(v);
int sign = _PyLong_NonCompactSign(v);
- x = 0;
+ unsigned long x = unroll_digits_ulong(v, &i);
while (--i >= 0) {
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
}
_PyLong_AsUnsignedLongLongMask(PyObject *vv)
{
PyLongObject *v;
- unsigned long long x;
Py_ssize_t i;
int sign;
}
i = _PyLong_DigitCount(v);
sign = _PyLong_NonCompactSign(v);
- x = 0;
+ unsigned long long x = unroll_digits_ulong(v, &i);
while (--i >= 0) {
x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i];
}
{
/* This version by Tim Peters */
PyLongObject *v;
- unsigned long long x, prev;
long long res;
Py_ssize_t i;
int sign;
else {
i = _PyLong_DigitCount(v);
sign = _PyLong_NonCompactSign(v);
- x = 0;
+ unsigned long long x = unroll_digits_ulong(v, &i);
while (--i >= 0) {
- prev = x;
- x = (x << PyLong_SHIFT) + v->long_value.ob_digit[i];
- if ((x >> PyLong_SHIFT) != prev) {
+ if (x > ULLONG_MAX >> PyLong_SHIFT) {
*overflow = sign;
res = -1;
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).