mirror of https://github.com/python/cpython
Optimization to stop creating new small longs and use the
one previously stored. Issue 2417.
This commit is contained in:
parent
00c88f090d
commit
6e6f59b1c9
|
@ -805,6 +805,24 @@ class LongTest(unittest.TestCase):
|
||||||
self.assertRaises(ZeroDivisionError, eval, zero, namespace)
|
self.assertRaises(ZeroDivisionError, eval, zero, namespace)
|
||||||
|
|
||||||
|
|
||||||
|
def test_small_ints(self):
|
||||||
|
for i in range(-5, 257):
|
||||||
|
self.assertTrue(i is i + 0)
|
||||||
|
self.assertTrue(i is i * 1)
|
||||||
|
self.assertTrue(i is i - 0)
|
||||||
|
self.assertTrue(i is i // 1)
|
||||||
|
self.assertTrue(i is i & -1)
|
||||||
|
self.assertTrue(i is i | 0)
|
||||||
|
self.assertTrue(i is i ^ 0)
|
||||||
|
self.assertTrue(i is ~~i)
|
||||||
|
self.assertTrue(i is i**1)
|
||||||
|
self.assertTrue(i is int(str(i)))
|
||||||
|
self.assertTrue(i is i<<2>>2, str(i))
|
||||||
|
# corner cases
|
||||||
|
i = 1 << 70
|
||||||
|
self.assertTrue(i - i is 0)
|
||||||
|
self.assertTrue(0 * i is 0)
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
support.run_unittest(LongTest)
|
support.run_unittest(LongTest)
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,11 @@
|
||||||
#ifndef NSMALLNEGINTS
|
#ifndef NSMALLNEGINTS
|
||||||
#define NSMALLNEGINTS 5
|
#define NSMALLNEGINTS 5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MEDIUM_VALUE(x) (Py_SIZE(x) < 0 ? -(x)->ob_digit[0] : \
|
||||||
|
(Py_SIZE(x) == 0 ? 0 : (x)->ob_digit[0]))
|
||||||
|
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
||||||
|
|
||||||
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
|
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
|
||||||
/* Small integers are preallocated in this array so that they
|
/* Small integers are preallocated in this array so that they
|
||||||
can be shared.
|
can be shared.
|
||||||
|
@ -42,11 +47,23 @@ get_small_int(int ival)
|
||||||
return get_small_int(ival); \
|
return get_small_int(ival); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
static PyLongObject *
|
||||||
|
maybe_small_long(PyLongObject *v)
|
||||||
|
{
|
||||||
|
if (v && ABS(Py_SIZE(v)) <= 1) {
|
||||||
|
int ival = MEDIUM_VALUE(v);
|
||||||
|
if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
|
||||||
|
Py_DECREF(v);
|
||||||
|
return (PyLongObject *)get_small_int(ival);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#define CHECK_SMALL_INT(ival)
|
#define CHECK_SMALL_INT(ival)
|
||||||
|
#define maybe_small_long(val) (val)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MEDIUM_VALUE(x) (Py_SIZE(x) < 0 ? -(x)->ob_digit[0] : (Py_SIZE(x) == 0 ? 0 : (x)->ob_digit[0]))
|
|
||||||
/* If a freshly-allocated long is already shared, it must
|
/* If a freshly-allocated long is already shared, it must
|
||||||
be a small integer, so negating it must go to PyLong_FromLong */
|
be a small integer, so negating it must go to PyLong_FromLong */
|
||||||
#define NEGATE(x) \
|
#define NEGATE(x) \
|
||||||
|
@ -68,8 +85,6 @@ get_small_int(int ival)
|
||||||
*/
|
*/
|
||||||
#define FIVEARY_CUTOFF 8
|
#define FIVEARY_CUTOFF 8
|
||||||
|
|
||||||
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
|
||||||
|
|
||||||
#undef MIN
|
#undef MIN
|
||||||
#undef MAX
|
#undef MAX
|
||||||
#define MAX(x, y) ((x) < (y) ? (y) : (x))
|
#define MAX(x, y) ((x) < (y) ? (y) : (x))
|
||||||
|
@ -1982,14 +1997,7 @@ digit beyond the first.
|
||||||
if (pend)
|
if (pend)
|
||||||
*pend = str;
|
*pend = str;
|
||||||
long_normalize(z);
|
long_normalize(z);
|
||||||
if (ABS(Py_SIZE(z)) <= 1) {
|
return (PyObject *) maybe_small_long(z);
|
||||||
long res = MEDIUM_VALUE(z);
|
|
||||||
if (-NSMALLPOSINTS <= res && res <= NSMALLPOSINTS) {
|
|
||||||
Py_DECREF(z);
|
|
||||||
return PyLong_FromLong(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (PyObject *) z;
|
|
||||||
|
|
||||||
onError:
|
onError:
|
||||||
Py_XDECREF(z);
|
Py_XDECREF(z);
|
||||||
|
@ -2078,7 +2086,7 @@ long_divrem(PyLongObject *a, PyLongObject *b,
|
||||||
NEGATE(z);
|
NEGATE(z);
|
||||||
if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0)
|
if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0)
|
||||||
NEGATE(*prem);
|
NEGATE(*prem);
|
||||||
*pdiv = z;
|
*pdiv = maybe_small_long(z);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2335,7 +2343,7 @@ x_sub(PyLongObject *a, PyLongObject *b)
|
||||||
while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
|
while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
|
||||||
;
|
;
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
return _PyLong_New(0);
|
return (PyLongObject *)PyLong_FromLong(0);
|
||||||
if (a->ob_digit[i] < b->ob_digit[i]) {
|
if (a->ob_digit[i] < b->ob_digit[i]) {
|
||||||
sign = -1;
|
sign = -1;
|
||||||
{ PyLongObject *temp = a; a = b; b = temp; }
|
{ PyLongObject *temp = a; a = b; b = temp; }
|
||||||
|
@ -2588,7 +2596,7 @@ k_mul(PyLongObject *a, PyLongObject *b)
|
||||||
i = a == b ? KARATSUBA_SQUARE_CUTOFF : KARATSUBA_CUTOFF;
|
i = a == b ? KARATSUBA_SQUARE_CUTOFF : KARATSUBA_CUTOFF;
|
||||||
if (asize <= i) {
|
if (asize <= i) {
|
||||||
if (asize == 0)
|
if (asize == 0)
|
||||||
return _PyLong_New(0);
|
return (PyLongObject *)PyLong_FromLong(0);
|
||||||
else
|
else
|
||||||
return x_mul(a, b);
|
return x_mul(a, b);
|
||||||
}
|
}
|
||||||
|
@ -3199,7 +3207,7 @@ long_invert(PyLongObject *v)
|
||||||
if (x == NULL)
|
if (x == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_SIZE(x) = -(Py_SIZE(x));
|
Py_SIZE(x) = -(Py_SIZE(x));
|
||||||
return (PyObject *)x;
|
return (PyObject *)maybe_small_long(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -3264,10 +3272,8 @@ long_rshift(PyLongObject *a, PyLongObject *b)
|
||||||
}
|
}
|
||||||
wordshift = shiftby / PyLong_SHIFT;
|
wordshift = shiftby / PyLong_SHIFT;
|
||||||
newsize = ABS(Py_SIZE(a)) - wordshift;
|
newsize = ABS(Py_SIZE(a)) - wordshift;
|
||||||
if (newsize <= 0) {
|
if (newsize <= 0)
|
||||||
z = _PyLong_New(0);
|
return PyLong_FromLong(0);
|
||||||
return (PyObject *)z;
|
|
||||||
}
|
|
||||||
loshift = shiftby % PyLong_SHIFT;
|
loshift = shiftby % PyLong_SHIFT;
|
||||||
hishift = PyLong_SHIFT - loshift;
|
hishift = PyLong_SHIFT - loshift;
|
||||||
lomask = ((digit)1 << hishift) - 1;
|
lomask = ((digit)1 << hishift) - 1;
|
||||||
|
@ -3286,7 +3292,7 @@ long_rshift(PyLongObject *a, PyLongObject *b)
|
||||||
z = long_normalize(z);
|
z = long_normalize(z);
|
||||||
}
|
}
|
||||||
rshift_error:
|
rshift_error:
|
||||||
return (PyObject *) z;
|
return (PyObject *) maybe_small_long(z);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3342,7 +3348,7 @@ long_lshift(PyObject *v, PyObject *w)
|
||||||
assert(!accum);
|
assert(!accum);
|
||||||
z = long_normalize(z);
|
z = long_normalize(z);
|
||||||
lshift_error:
|
lshift_error:
|
||||||
return (PyObject *) z;
|
return (PyObject *) maybe_small_long(z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3448,7 +3454,7 @@ long_bitwise(PyLongObject *a,
|
||||||
Py_DECREF(b);
|
Py_DECREF(b);
|
||||||
z = long_normalize(z);
|
z = long_normalize(z);
|
||||||
if (negz == 0)
|
if (negz == 0)
|
||||||
return (PyObject *) z;
|
return (PyObject *) maybe_small_long(z);
|
||||||
v = long_invert(z);
|
v = long_invert(z);
|
||||||
Py_DECREF(z);
|
Py_DECREF(z);
|
||||||
return v;
|
return v;
|
||||||
|
|
Loading…
Reference in New Issue