]> granicus.if.org Git - python/commitdiff
Optimization to stop creating new small longs and use the
authorFacundo Batista <facundobatista@gmail.com>
Thu, 24 Jul 2008 18:57:11 +0000 (18:57 +0000)
committerFacundo Batista <facundobatista@gmail.com>
Thu, 24 Jul 2008 18:57:11 +0000 (18:57 +0000)
one previously stored. Issue 2417.

Lib/test/test_long.py
Objects/longobject.c

index b00f73606469ae6a56354408ff517727c3569832..c47587888af3a153a26d1709911202bf9ced061a 100644 (file)
@@ -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)
 
index 6cea51a2841cc85a5fbfdfa6b5ed21820d4732af..ae62cfd423f994120dcb3e1e95c19a1ef5320e79 100644 (file)
 #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;