diff options
author | Facundo Batista <facundobatista@gmail.com> | 2008-07-24 18:57:11 (GMT) |
---|---|---|
committer | Facundo Batista <facundobatista@gmail.com> | 2008-07-24 18:57:11 (GMT) |
commit | 6e6f59b1c9fc01d2cf0404c775214819e6f07b34 (patch) | |
tree | ea9e73c3c38651115e4adf5195a5171076482bc8 | |
parent | 00c88f090db65fbe782b46e0ac0b1b08dbb42044 (diff) | |
download | cpython-6e6f59b1c9fc01d2cf0404c775214819e6f07b34.zip cpython-6e6f59b1c9fc01d2cf0404c775214819e6f07b34.tar.gz cpython-6e6f59b1c9fc01d2cf0404c775214819e6f07b34.tar.bz2 |
Optimization to stop creating new small longs and use the
one previously stored. Issue 2417.
-rw-r--r-- | Lib/test/test_long.py | 18 | ||||
-rw-r--r-- | Objects/longobject.c | 50 |
2 files changed, 46 insertions, 22 deletions
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index b00f736..c475878 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -805,6 +805,24 @@ class LongTest(unittest.TestCase): 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(): support.run_unittest(LongTest) diff --git a/Objects/longobject.c b/Objects/longobject.c index 6cea51a..ae62cfd 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -13,6 +13,11 @@ #ifndef NSMALLNEGINTS #define NSMALLNEGINTS 5 #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 /* Small integers are preallocated in this array so that they can be shared. @@ -42,11 +47,23 @@ get_small_int(int ival) return get_small_int(ival); \ } 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 #define CHECK_SMALL_INT(ival) +#define maybe_small_long(val) (val) #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 be a small integer, so negating it must go to PyLong_FromLong */ #define NEGATE(x) \ @@ -68,8 +85,6 @@ get_small_int(int ival) */ #define FIVEARY_CUTOFF 8 -#define ABS(x) ((x) < 0 ? -(x) : (x)) - #undef MIN #undef MAX #define MAX(x, y) ((x) < (y) ? (y) : (x)) @@ -1982,14 +1997,7 @@ digit beyond the first. if (pend) *pend = str; long_normalize(z); - if (ABS(Py_SIZE(z)) <= 1) { - long res = MEDIUM_VALUE(z); - if (-NSMALLPOSINTS <= res && res <= NSMALLPOSINTS) { - Py_DECREF(z); - return PyLong_FromLong(res); - } - } - return (PyObject *) z; + return (PyObject *) maybe_small_long(z); onError: Py_XDECREF(z); @@ -2078,7 +2086,7 @@ long_divrem(PyLongObject *a, PyLongObject *b, NEGATE(z); if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0) NEGATE(*prem); - *pdiv = z; + *pdiv = maybe_small_long(z); return 0; } @@ -2335,7 +2343,7 @@ x_sub(PyLongObject *a, PyLongObject *b) while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i]) ; if (i < 0) - return _PyLong_New(0); + return (PyLongObject *)PyLong_FromLong(0); if (a->ob_digit[i] < b->ob_digit[i]) { sign = -1; { 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; if (asize <= i) { if (asize == 0) - return _PyLong_New(0); + return (PyLongObject *)PyLong_FromLong(0); else return x_mul(a, b); } @@ -3199,7 +3207,7 @@ long_invert(PyLongObject *v) if (x == NULL) return NULL; Py_SIZE(x) = -(Py_SIZE(x)); - return (PyObject *)x; + return (PyObject *)maybe_small_long(x); } static PyObject * @@ -3264,10 +3272,8 @@ long_rshift(PyLongObject *a, PyLongObject *b) } wordshift = shiftby / PyLong_SHIFT; newsize = ABS(Py_SIZE(a)) - wordshift; - if (newsize <= 0) { - z = _PyLong_New(0); - return (PyObject *)z; - } + if (newsize <= 0) + return PyLong_FromLong(0); loshift = shiftby % PyLong_SHIFT; hishift = PyLong_SHIFT - loshift; lomask = ((digit)1 << hishift) - 1; @@ -3286,7 +3292,7 @@ long_rshift(PyLongObject *a, PyLongObject *b) z = long_normalize(z); } rshift_error: - return (PyObject *) z; + return (PyObject *) maybe_small_long(z); } @@ -3342,7 +3348,7 @@ long_lshift(PyObject *v, PyObject *w) assert(!accum); z = long_normalize(z); lshift_error: - return (PyObject *) z; + return (PyObject *) maybe_small_long(z); } @@ -3448,7 +3454,7 @@ long_bitwise(PyLongObject *a, Py_DECREF(b); z = long_normalize(z); if (negz == 0) - return (PyObject *) z; + return (PyObject *) maybe_small_long(z); v = long_invert(z); Py_DECREF(z); return v; |