summaryrefslogtreecommitdiffstats
path: root/Objects/longobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/longobject.c')
-rw-r--r--Objects/longobject.c72
1 files changed, 31 insertions, 41 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 3438906..f85ef24 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -272,44 +272,40 @@ _PyLong_Negate(PyLongObject **x_p)
}
/* Create a new int object from a C long int */
+
PyObject *
PyLong_FromLong(long ival)
{
+ PyLongObject *v;
+ unsigned long abs_ival, t;
+ int ndigits;
+
+ /* Handle small and medium cases. */
if (IS_SMALL_INT(ival)) {
return get_small_int((sdigit)ival);
}
- unsigned long abs_ival;
- 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)) {
+ if (-(long)PyLong_MASK <= ival && ival <= (long)PyLong_MASK) {
return _PyLong_FromMedium((sdigit)ival);
}
- /* Must be at least two digits.
- * Do shift in two steps to avoid undefined behavior. */
- unsigned long t = (abs_ival >> PyLong_SHIFT) >> PyLong_SHIFT;
- Py_ssize_t ndigits = 2;
+
+ /* Count digits (at least two - smaller cases were handled above). */
+ abs_ival = ival < 0 ? 0U-(unsigned long)ival : (unsigned long)ival;
+ /* Do shift in two steps to avoid possible undefined behavior. */
+ t = abs_ival >> PyLong_SHIFT >> PyLong_SHIFT;
+ ndigits = 2;
while (t) {
++ndigits;
t >>= PyLong_SHIFT;
}
- PyLongObject *v = _PyLong_New(ndigits);
+
+ /* Construct output value. */
+ v = _PyLong_New(ndigits);
if (v != NULL) {
digit *p = v->ob_digit;
- Py_SET_SIZE(v, ndigits * sign);
+ Py_SET_SIZE(v, ival < 0 ? -ndigits : ndigits);
t = abs_ival;
while (t) {
- *p++ = Py_SAFE_DOWNCAST(
- t & PyLong_MASK, unsigned long, digit);
+ *p++ = (digit)(t & PyLong_MASK);
t >>= PyLong_SHIFT;
}
}
@@ -1105,38 +1101,32 @@ PyObject *
PyLong_FromLongLong(long long ival)
{
PyLongObject *v;
- unsigned long long abs_ival;
- unsigned long long t; /* unsigned so >> doesn't propagate sign bit */
- int ndigits = 0;
- int negative = 0;
+ unsigned long long abs_ival, t;
+ int ndigits;
+ /* Handle small and medium cases. */
if (IS_SMALL_INT(ival)) {
return get_small_int((sdigit)ival);
}
-
- if (ival < 0) {
- /* 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;
+ if (-(long long)PyLong_MASK <= ival && ival <= (long long)PyLong_MASK) {
+ return _PyLong_FromMedium((sdigit)ival);
}
- /* Count the number of Python digits.
- We used to pick 5 ("big enough for anything"), but that's a
- waste of time and space given that 5*15 = 75 bits are rarely
- needed. */
- t = abs_ival;
+ /* Count digits (at least two - smaller cases were handled above). */
+ abs_ival = ival < 0 ? 0U-(unsigned long long)ival : (unsigned long long)ival;
+ /* Do shift in two steps to avoid possible undefined behavior. */
+ t = abs_ival >> PyLong_SHIFT >> PyLong_SHIFT;
+ ndigits = 2;
while (t) {
++ndigits;
t >>= PyLong_SHIFT;
}
+
+ /* Construct output value. */
v = _PyLong_New(ndigits);
if (v != NULL) {
digit *p = v->ob_digit;
- Py_SET_SIZE(v, negative ? -ndigits : ndigits);
+ Py_SET_SIZE(v, ival < 0 ? -ndigits : ndigits);
t = abs_ival;
while (t) {
*p++ = (digit)(t & PyLong_MASK);