Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6e6f59b

Browse files
Optimization to stop creating new small longs and use the
one previously stored. Issue 2417.
1 parent 00c88f0 commit 6e6f59b

2 files changed

Lines changed: 46 additions & 22 deletions

File tree

Lib/test/test_long.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,24 @@ def test_true_division(self):
805805
self.assertRaises(ZeroDivisionError, eval, zero, namespace)
806806

807807

808+
def test_small_ints(self):
809+
for i in range(-5, 257):
810+
self.assertTrue(i is i + 0)
811+
self.assertTrue(i is i * 1)
812+
self.assertTrue(i is i - 0)
813+
self.assertTrue(i is i // 1)
814+
self.assertTrue(i is i & -1)
815+
self.assertTrue(i is i | 0)
816+
self.assertTrue(i is i ^ 0)
817+
self.assertTrue(i is ~~i)
818+
self.assertTrue(i is i**1)
819+
self.assertTrue(i is int(str(i)))
820+
self.assertTrue(i is i<<2>>2, str(i))
821+
# corner cases
822+
i = 1 << 70
823+
self.assertTrue(i - i is 0)
824+
self.assertTrue(0 * i is 0)
825+
808826
def test_main():
809827
support.run_unittest(LongTest)
810828

Objects/longobject.c

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
#ifndef NSMALLNEGINTS
1414
#define NSMALLNEGINTS 5
1515
#endif
16+
17+
#define MEDIUM_VALUE(x) (Py_SIZE(x) < 0 ? -(x)->ob_digit[0] : \
18+
(Py_SIZE(x) == 0 ? 0 : (x)->ob_digit[0]))
19+
#define ABS(x) ((x) < 0 ? -(x) : (x))
20+
1621
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
1722
/* Small integers are preallocated in this array so that they
1823
can be shared.
@@ -42,11 +47,23 @@ get_small_int(int ival)
4247
return get_small_int(ival); \
4348
} while(0)
4449

50+
static PyLongObject *
51+
maybe_small_long(PyLongObject *v)
52+
{
53+
if (v && ABS(Py_SIZE(v)) <= 1) {
54+
int ival = MEDIUM_VALUE(v);
55+
if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
56+
Py_DECREF(v);
57+
return (PyLongObject *)get_small_int(ival);
58+
}
59+
}
60+
return v;
61+
}
4562
#else
4663
#define CHECK_SMALL_INT(ival)
64+
#define maybe_small_long(val) (val)
4765
#endif
4866

49-
#define MEDIUM_VALUE(x) (Py_SIZE(x) < 0 ? -(x)->ob_digit[0] : (Py_SIZE(x) == 0 ? 0 : (x)->ob_digit[0]))
5067
/* If a freshly-allocated long is already shared, it must
5168
be a small integer, so negating it must go to PyLong_FromLong */
5269
#define NEGATE(x) \
@@ -68,8 +85,6 @@ get_small_int(int ival)
6885
*/
6986
#define FIVEARY_CUTOFF 8
7087

71-
#define ABS(x) ((x) < 0 ? -(x) : (x))
72-
7388
#undef MIN
7489
#undef MAX
7590
#define MAX(x, y) ((x) < (y) ? (y) : (x))
@@ -1982,14 +1997,7 @@ digit beyond the first.
19821997
if (pend)
19831998
*pend = str;
19841999
long_normalize(z);
1985-
if (ABS(Py_SIZE(z)) <= 1) {
1986-
long res = MEDIUM_VALUE(z);
1987-
if (-NSMALLPOSINTS <= res && res <= NSMALLPOSINTS) {
1988-
Py_DECREF(z);
1989-
return PyLong_FromLong(res);
1990-
}
1991-
}
1992-
return (PyObject *) z;
2000+
return (PyObject *) maybe_small_long(z);
19932001

19942002
onError:
19952003
Py_XDECREF(z);
@@ -2078,7 +2086,7 @@ long_divrem(PyLongObject *a, PyLongObject *b,
20782086
NEGATE(z);
20792087
if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0)
20802088
NEGATE(*prem);
2081-
*pdiv = z;
2089+
*pdiv = maybe_small_long(z);
20822090
return 0;
20832091
}
20842092

@@ -2335,7 +2343,7 @@ x_sub(PyLongObject *a, PyLongObject *b)
23352343
while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
23362344
;
23372345
if (i < 0)
2338-
return _PyLong_New(0);
2346+
return (PyLongObject *)PyLong_FromLong(0);
23392347
if (a->ob_digit[i] < b->ob_digit[i]) {
23402348
sign = -1;
23412349
{ PyLongObject *temp = a; a = b; b = temp; }
@@ -2588,7 +2596,7 @@ k_mul(PyLongObject *a, PyLongObject *b)
25882596
i = a == b ? KARATSUBA_SQUARE_CUTOFF : KARATSUBA_CUTOFF;
25892597
if (asize <= i) {
25902598
if (asize == 0)
2591-
return _PyLong_New(0);
2599+
return (PyLongObject *)PyLong_FromLong(0);
25922600
else
25932601
return x_mul(a, b);
25942602
}
@@ -3199,7 +3207,7 @@ long_invert(PyLongObject *v)
31993207
if (x == NULL)
32003208
return NULL;
32013209
Py_SIZE(x) = -(Py_SIZE(x));
3202-
return (PyObject *)x;
3210+
return (PyObject *)maybe_small_long(x);
32033211
}
32043212

32053213
static PyObject *
@@ -3264,10 +3272,8 @@ long_rshift(PyLongObject *a, PyLongObject *b)
32643272
}
32653273
wordshift = shiftby / PyLong_SHIFT;
32663274
newsize = ABS(Py_SIZE(a)) - wordshift;
3267-
if (newsize <= 0) {
3268-
z = _PyLong_New(0);
3269-
return (PyObject *)z;
3270-
}
3275+
if (newsize <= 0)
3276+
return PyLong_FromLong(0);
32713277
loshift = shiftby % PyLong_SHIFT;
32723278
hishift = PyLong_SHIFT - loshift;
32733279
lomask = ((digit)1 << hishift) - 1;
@@ -3286,7 +3292,7 @@ long_rshift(PyLongObject *a, PyLongObject *b)
32863292
z = long_normalize(z);
32873293
}
32883294
rshift_error:
3289-
return (PyObject *) z;
3295+
return (PyObject *) maybe_small_long(z);
32903296

32913297
}
32923298

@@ -3342,7 +3348,7 @@ long_lshift(PyObject *v, PyObject *w)
33423348
assert(!accum);
33433349
z = long_normalize(z);
33443350
lshift_error:
3345-
return (PyObject *) z;
3351+
return (PyObject *) maybe_small_long(z);
33463352
}
33473353

33483354

@@ -3448,7 +3454,7 @@ long_bitwise(PyLongObject *a,
34483454
Py_DECREF(b);
34493455
z = long_normalize(z);
34503456
if (negz == 0)
3451-
return (PyObject *) z;
3457+
return (PyObject *) maybe_small_long(z);
34523458
v = long_invert(z);
34533459
Py_DECREF(z);
34543460
return v;

0 commit comments

Comments
 (0)