facundo.batista
2008-07-24 18:57:11 UTC
Author: facundo.batista
Date: Thu Jul 24 20:57:11 2008
New Revision: 65220
Log:
Optimization to stop creating new small longs and use the
one previously stored. Issue 2417.
Modified:
python/branches/py3k/Lib/test/test_long.py
python/branches/py3k/Objects/longobject.c
Modified: python/branches/py3k/Lib/test/test_long.py
==============================================================================
--- python/branches/py3k/Lib/test/test_long.py (original)
+++ python/branches/py3k/Lib/test/test_long.py Thu Jul 24 20:57:11 2008
@@ -805,6 +805,24 @@
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)
Modified: python/branches/py3k/Objects/longobject.c
==============================================================================
--- python/branches/py3k/Objects/longobject.c (original)
+++ python/branches/py3k/Objects/longobject.c Thu Jul 24 20:57:11 2008
@@ -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 @@
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 @@
*/
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
z = long_normalize(z);
}
rshift_error:
- return (PyObject *) z;
+ return (PyObject *) maybe_small_long(z);
}
@@ -3342,7 +3348,7 @@
assert(!accum);
z = long_normalize(z);
lshift_error:
- return (PyObject *) z;
+ return (PyObject *) maybe_small_long(z);
}
@@ -3448,7 +3454,7 @@
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;
Date: Thu Jul 24 20:57:11 2008
New Revision: 65220
Log:
Optimization to stop creating new small longs and use the
one previously stored. Issue 2417.
Modified:
python/branches/py3k/Lib/test/test_long.py
python/branches/py3k/Objects/longobject.c
Modified: python/branches/py3k/Lib/test/test_long.py
==============================================================================
--- python/branches/py3k/Lib/test/test_long.py (original)
+++ python/branches/py3k/Lib/test/test_long.py Thu Jul 24 20:57:11 2008
@@ -805,6 +805,24 @@
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)
Modified: python/branches/py3k/Objects/longobject.c
==============================================================================
--- python/branches/py3k/Objects/longobject.c (original)
+++ python/branches/py3k/Objects/longobject.c Thu Jul 24 20:57:11 2008
@@ -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 @@
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 @@
*/
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
z = long_normalize(z);
}
rshift_error:
- return (PyObject *) z;
+ return (PyObject *) maybe_small_long(z);
}
@@ -3342,7 +3348,7 @@
assert(!accum);
z = long_normalize(z);
lshift_error:
- return (PyObject *) z;
+ return (PyObject *) maybe_small_long(z);
}
@@ -3448,7 +3454,7 @@
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;