mirror of https://github.com/python/cpython
bpo-46311: Clean up PyLong_FromLong and PyLong_FromLongLong (GH-30496)
This commit is contained in:
parent
7820a5897e
commit
c60e6b6ad7
|
@ -0,0 +1,3 @@
|
||||||
|
Fixed a minor portability issue in the implementation of
|
||||||
|
:c:func:`PyLong_FromLong`, and added a fast path for single-digit integers
|
||||||
|
to :c:func:`PyLong_FromLongLong`.
|
|
@ -272,44 +272,40 @@ _PyLong_Negate(PyLongObject **x_p)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a new int object from a C long int */
|
/* Create a new int object from a C long int */
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyLong_FromLong(long ival)
|
PyLong_FromLong(long ival)
|
||||||
{
|
{
|
||||||
|
PyLongObject *v;
|
||||||
|
unsigned long abs_ival, t;
|
||||||
|
int ndigits;
|
||||||
|
|
||||||
|
/* Handle small and medium cases. */
|
||||||
if (IS_SMALL_INT(ival)) {
|
if (IS_SMALL_INT(ival)) {
|
||||||
return get_small_int((sdigit)ival);
|
return get_small_int((sdigit)ival);
|
||||||
}
|
}
|
||||||
unsigned long abs_ival;
|
if (-(long)PyLong_MASK <= ival && ival <= (long)PyLong_MASK) {
|
||||||
int sign;
|
|
||||||
if (ival < 0) {
|
|
||||||
/* negate: can't write this as abs_ival = -ival since that
|
|
||||||
invokes undefined behaviour when ival is LONG_MIN */
|
|
||||||
abs_ival = 0U-(twodigits)ival;
|
|
||||||
sign = -1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
abs_ival = (unsigned long)ival;
|
|
||||||
sign = 1;
|
|
||||||
}
|
|
||||||
/* Fast path for single-digit ints */
|
|
||||||
if (!(abs_ival >> PyLong_SHIFT)) {
|
|
||||||
return _PyLong_FromMedium((sdigit)ival);
|
return _PyLong_FromMedium((sdigit)ival);
|
||||||
}
|
}
|
||||||
/* Must be at least two digits.
|
|
||||||
* Do shift in two steps to avoid undefined behavior. */
|
/* Count digits (at least two - smaller cases were handled above). */
|
||||||
unsigned long t = (abs_ival >> PyLong_SHIFT) >> PyLong_SHIFT;
|
abs_ival = ival < 0 ? 0U-(unsigned long)ival : (unsigned long)ival;
|
||||||
Py_ssize_t ndigits = 2;
|
/* Do shift in two steps to avoid possible undefined behavior. */
|
||||||
|
t = abs_ival >> PyLong_SHIFT >> PyLong_SHIFT;
|
||||||
|
ndigits = 2;
|
||||||
while (t) {
|
while (t) {
|
||||||
++ndigits;
|
++ndigits;
|
||||||
t >>= PyLong_SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
PyLongObject *v = _PyLong_New(ndigits);
|
|
||||||
|
/* Construct output value. */
|
||||||
|
v = _PyLong_New(ndigits);
|
||||||
if (v != NULL) {
|
if (v != NULL) {
|
||||||
digit *p = v->ob_digit;
|
digit *p = v->ob_digit;
|
||||||
Py_SET_SIZE(v, ndigits * sign);
|
Py_SET_SIZE(v, ival < 0 ? -ndigits : ndigits);
|
||||||
t = abs_ival;
|
t = abs_ival;
|
||||||
while (t) {
|
while (t) {
|
||||||
*p++ = Py_SAFE_DOWNCAST(
|
*p++ = (digit)(t & PyLong_MASK);
|
||||||
t & PyLong_MASK, unsigned long, digit);
|
|
||||||
t >>= PyLong_SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1105,38 +1101,32 @@ PyObject *
|
||||||
PyLong_FromLongLong(long long ival)
|
PyLong_FromLongLong(long long ival)
|
||||||
{
|
{
|
||||||
PyLongObject *v;
|
PyLongObject *v;
|
||||||
unsigned long long abs_ival;
|
unsigned long long abs_ival, t;
|
||||||
unsigned long long t; /* unsigned so >> doesn't propagate sign bit */
|
int ndigits;
|
||||||
int ndigits = 0;
|
|
||||||
int negative = 0;
|
|
||||||
|
|
||||||
|
/* Handle small and medium cases. */
|
||||||
if (IS_SMALL_INT(ival)) {
|
if (IS_SMALL_INT(ival)) {
|
||||||
return get_small_int((sdigit)ival);
|
return get_small_int((sdigit)ival);
|
||||||
}
|
}
|
||||||
|
if (-(long long)PyLong_MASK <= ival && ival <= (long long)PyLong_MASK) {
|
||||||
if (ival < 0) {
|
return _PyLong_FromMedium((sdigit)ival);
|
||||||
/* avoid signed overflow on negation; see comments
|
|
||||||
in PyLong_FromLong above. */
|
|
||||||
abs_ival = (unsigned long long)(-1-ival) + 1;
|
|
||||||
negative = 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
abs_ival = (unsigned long long)ival;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Count the number of Python digits.
|
/* Count digits (at least two - smaller cases were handled above). */
|
||||||
We used to pick 5 ("big enough for anything"), but that's a
|
abs_ival = ival < 0 ? 0U-(unsigned long long)ival : (unsigned long long)ival;
|
||||||
waste of time and space given that 5*15 = 75 bits are rarely
|
/* Do shift in two steps to avoid possible undefined behavior. */
|
||||||
needed. */
|
t = abs_ival >> PyLong_SHIFT >> PyLong_SHIFT;
|
||||||
t = abs_ival;
|
ndigits = 2;
|
||||||
while (t) {
|
while (t) {
|
||||||
++ndigits;
|
++ndigits;
|
||||||
t >>= PyLong_SHIFT;
|
t >>= PyLong_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Construct output value. */
|
||||||
v = _PyLong_New(ndigits);
|
v = _PyLong_New(ndigits);
|
||||||
if (v != NULL) {
|
if (v != NULL) {
|
||||||
digit *p = v->ob_digit;
|
digit *p = v->ob_digit;
|
||||||
Py_SET_SIZE(v, negative ? -ndigits : ndigits);
|
Py_SET_SIZE(v, ival < 0 ? -ndigits : ndigits);
|
||||||
t = abs_ival;
|
t = abs_ival;
|
||||||
while (t) {
|
while (t) {
|
||||||
*p++ = (digit)(t & PyLong_MASK);
|
*p++ = (digit)(t & PyLong_MASK);
|
||||||
|
|
Loading…
Reference in New Issue