Optimization to stop creating new small longs and use the

one previously stored. Issue 2417.
This commit is contained in:
Facundo Batista 2008-07-24 18:57:11 +00:00
parent 00c88f090d
commit 6e6f59b1c9
2 changed files with 46 additions and 22 deletions

View File

@ -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)

View File

@ -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;