mirror of https://github.com/python/cpython
Issue #5260: Various portability and standards compliance fixes, optimizations
and cleanups in Objects/longobject.c. The most significant change is that longs now use less memory: average savings are 2 bytes per long on 32-bit systems and 6 bytes per long on 64-bit systems. (This memory saving already exists in py3k.)
This commit is contained in:
parent
5b8c701eef
commit
2ffb26fb83
|
@ -19,14 +19,13 @@ extern "C" {
|
|||
long_pow() requires that SHIFT be divisible by 5. */
|
||||
|
||||
typedef unsigned short digit;
|
||||
typedef unsigned int wdigit; /* digit widened to parameter size */
|
||||
#define BASE_TWODIGITS_TYPE long
|
||||
typedef unsigned BASE_TWODIGITS_TYPE twodigits;
|
||||
typedef BASE_TWODIGITS_TYPE stwodigits; /* signed variant of twodigits */
|
||||
|
||||
#define PyLong_SHIFT 15
|
||||
#define PyLong_BASE ((digit)1 << PyLong_SHIFT)
|
||||
#define PyLong_MASK ((int)(PyLong_BASE - 1))
|
||||
#define PyLong_MASK ((digit)(PyLong_BASE - 1))
|
||||
|
||||
/* b/w compatibility with Python 2.5 */
|
||||
#define SHIFT PyLong_SHIFT
|
||||
|
|
|
@ -593,12 +593,12 @@ class SizeofTest(unittest.TestCase):
|
|||
# listreverseiterator (list)
|
||||
check(reversed([]), size(h + 'lP'))
|
||||
# long
|
||||
check(0L, size(vh + 'H') - self.H)
|
||||
check(1L, size(vh + 'H'))
|
||||
check(-1L, size(vh + 'H'))
|
||||
check(32768L, size(vh + 'H') + self.H)
|
||||
check(32768L*32768L-1, size(vh + 'H') + self.H)
|
||||
check(32768L*32768L, size(vh + 'H') + 2*self.H)
|
||||
check(0L, size(vh))
|
||||
check(1L, size(vh) + self.H)
|
||||
check(-1L, size(vh) + self.H)
|
||||
check(32768L, size(vh) + 2*self.H)
|
||||
check(32768L*32768L-1, size(vh) + 2*self.H)
|
||||
check(32768L*32768L, size(vh) + 3*self.H)
|
||||
# module
|
||||
check(unittest, size(h + 'P'))
|
||||
# None
|
||||
|
|
|
@ -12,6 +12,10 @@ What's New in Python 2.7 alpha 1
|
|||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #5260: Long integers now consume less memory: average
|
||||
saving is 2 bytes per long on a 32-bit system and 6 bytes per long
|
||||
on a 64-bit system.
|
||||
|
||||
- Issue #5186: Reduce hash collisions for objects with no __hash__ method by
|
||||
rotating the object pointer by 4 bits to the right.
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "longintrepr.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* For long multiplication, use the O(N**2) school algorithm unless
|
||||
* both operands contain more than KARATSUBA_CUTOFF digits (this
|
||||
|
@ -30,12 +31,6 @@
|
|||
#define MAX(x, y) ((x) < (y) ? (y) : (x))
|
||||
#define MIN(x, y) ((x) > (y) ? (y) : (x))
|
||||
|
||||
/* Forward */
|
||||
static PyLongObject *long_normalize(PyLongObject *);
|
||||
static PyLongObject *mul1(PyLongObject *, wdigit);
|
||||
static PyLongObject *muladd1(PyLongObject *, wdigit, wdigit);
|
||||
static PyLongObject *divrem1(PyLongObject *, digit, digit *);
|
||||
|
||||
#define SIGCHECK(PyTryBlock) \
|
||||
if (--_Py_Ticker < 0) { \
|
||||
_Py_Ticker = _Py_CheckInterval; \
|
||||
|
@ -62,16 +57,20 @@ long_normalize(register PyLongObject *v)
|
|||
/* Allocate a new long int object with size digits.
|
||||
Return NULL and set exception if we run out of memory. */
|
||||
|
||||
#define MAX_LONG_DIGITS \
|
||||
((PY_SSIZE_T_MAX - offsetof(PyLongObject, ob_digit))/sizeof(digit))
|
||||
|
||||
PyLongObject *
|
||||
_PyLong_New(Py_ssize_t size)
|
||||
{
|
||||
if (size > PY_SSIZE_T_MAX) {
|
||||
PyErr_NoMemory();
|
||||
if (size > MAX_LONG_DIGITS) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"too many digits in integer");
|
||||
return NULL;
|
||||
}
|
||||
/* coverity[ampersand_in_size] */
|
||||
/* XXX(nnorwitz): This can overflow --
|
||||
PyObject_NEW_VAR / _PyObject_VAR_SIZE need to detect overflow */
|
||||
/* XXX(nnorwitz): PyObject_NEW_VAR / _PyObject_VAR_SIZE need to detect
|
||||
overflow */
|
||||
return PyObject_NEW_VAR(PyLongObject, &PyLong_Type, size);
|
||||
}
|
||||
|
||||
|
@ -197,8 +196,8 @@ PyLong_FromDouble(double dval)
|
|||
return NULL;
|
||||
frac = ldexp(frac, (expo-1) % PyLong_SHIFT + 1);
|
||||
for (i = ndig; --i >= 0; ) {
|
||||
long bits = (long)frac;
|
||||
v->ob_digit[i] = (digit) bits;
|
||||
digit bits = (digit)frac;
|
||||
v->ob_digit[i] = bits;
|
||||
frac = frac - (double)bits;
|
||||
frac = ldexp(frac, PyLong_SHIFT);
|
||||
}
|
||||
|
@ -438,9 +437,9 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n,
|
|||
int incr; /* direction to move pstartbyte */
|
||||
const unsigned char* pendbyte; /* MSB of bytes */
|
||||
size_t numsignificantbytes; /* number of bytes that matter */
|
||||
size_t ndigits; /* number of Python long digits */
|
||||
Py_ssize_t ndigits; /* number of Python long digits */
|
||||
PyLongObject* v; /* result */
|
||||
int idigit = 0; /* next free index in v->ob_digit */
|
||||
Py_ssize_t idigit = 0; /* next free index in v->ob_digit */
|
||||
|
||||
if (n == 0)
|
||||
return PyLong_FromLong(0L);
|
||||
|
@ -483,12 +482,16 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n,
|
|||
}
|
||||
|
||||
/* How many Python long digits do we need? We have
|
||||
8*numsignificantbytes bits, and each Python long digit has PyLong_SHIFT
|
||||
bits, so it's the ceiling of the quotient. */
|
||||
8*numsignificantbytes bits, and each Python long digit has
|
||||
PyLong_SHIFT bits, so it's the ceiling of the quotient. */
|
||||
/* catch overflow before it happens */
|
||||
if (numsignificantbytes > (PY_SSIZE_T_MAX - PyLong_SHIFT) / 8) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"byte array too long to convert to int");
|
||||
return NULL;
|
||||
}
|
||||
ndigits = (numsignificantbytes * 8 + PyLong_SHIFT - 1) / PyLong_SHIFT;
|
||||
if (ndigits > (size_t)INT_MAX)
|
||||
return PyErr_NoMemory();
|
||||
v = _PyLong_New((int)ndigits);
|
||||
v = _PyLong_New(ndigits);
|
||||
if (v == NULL)
|
||||
return NULL;
|
||||
|
||||
|
@ -517,8 +520,9 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n,
|
|||
accumbits += 8;
|
||||
if (accumbits >= PyLong_SHIFT) {
|
||||
/* There's enough to fill a Python digit. */
|
||||
assert(idigit < (int)ndigits);
|
||||
v->ob_digit[idigit] = (digit)(accum & PyLong_MASK);
|
||||
assert(idigit < ndigits);
|
||||
v->ob_digit[idigit] = (digit)(accum &
|
||||
PyLong_MASK);
|
||||
++idigit;
|
||||
accum >>= PyLong_SHIFT;
|
||||
accumbits -= PyLong_SHIFT;
|
||||
|
@ -527,7 +531,7 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n,
|
|||
}
|
||||
assert(accumbits < PyLong_SHIFT);
|
||||
if (accumbits) {
|
||||
assert(idigit < (int)ndigits);
|
||||
assert(idigit < ndigits);
|
||||
v->ob_digit[idigit] = (digit)accum;
|
||||
++idigit;
|
||||
}
|
||||
|
@ -1124,19 +1128,11 @@ v_isub(digit *x, Py_ssize_t m, digit *y, Py_ssize_t n)
|
|||
/* Multiply by a single digit, ignoring the sign. */
|
||||
|
||||
static PyLongObject *
|
||||
mul1(PyLongObject *a, wdigit n)
|
||||
{
|
||||
return muladd1(a, n, (digit)0);
|
||||
}
|
||||
|
||||
/* Multiply by a single digit and add a single digit, ignoring the sign. */
|
||||
|
||||
static PyLongObject *
|
||||
muladd1(PyLongObject *a, wdigit n, wdigit extra)
|
||||
mul1(PyLongObject *a, digit n)
|
||||
{
|
||||
Py_ssize_t size_a = ABS(Py_SIZE(a));
|
||||
PyLongObject *z = _PyLong_New(size_a+1);
|
||||
twodigits carry = extra;
|
||||
twodigits carry = 0;
|
||||
Py_ssize_t i;
|
||||
|
||||
if (z == NULL)
|
||||
|
@ -1757,8 +1753,6 @@ PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base)
|
|||
static PyLongObject *x_divrem
|
||||
(PyLongObject *, PyLongObject *, PyLongObject **);
|
||||
static PyObject *long_long(PyObject *v);
|
||||
static int long_divrem(PyLongObject *, PyLongObject *,
|
||||
PyLongObject **, PyLongObject **);
|
||||
|
||||
/* Long division with remainder, top-level routine */
|
||||
|
||||
|
@ -1976,14 +1970,12 @@ long_hash(PyLongObject *v)
|
|||
sign = -1;
|
||||
i = -(i);
|
||||
}
|
||||
#define LONG_BIT_PyLong_SHIFT (8*sizeof(long) - PyLong_SHIFT)
|
||||
/* The following loop produces a C unsigned long x such that x is
|
||||
congruent to the absolute value of v modulo ULONG_MAX. The
|
||||
resulting x is nonzero if and only if v is. */
|
||||
while (--i >= 0) {
|
||||
/* Force a native long #-bits (32 or 64) circular shift */
|
||||
x = ((x << PyLong_SHIFT) & ~PyLong_MASK) |
|
||||
((x >> LONG_BIT_PyLong_SHIFT) & PyLong_MASK);
|
||||
x = (x >> (8*SIZEOF_LONG-PyLong_SHIFT)) | (x << PyLong_SHIFT);
|
||||
x += v->ob_digit[i];
|
||||
/* If the addition above overflowed we compensate by
|
||||
incrementing. This preserves the value modulo
|
||||
|
@ -1991,11 +1983,10 @@ long_hash(PyLongObject *v)
|
|||
if (x < v->ob_digit[i])
|
||||
x++;
|
||||
}
|
||||
#undef LONG_BIT_PyLong_SHIFT
|
||||
x = x * sign;
|
||||
if (x == -1)
|
||||
x = -2;
|
||||
return x;
|
||||
if (x == (unsigned long)-1)
|
||||
x = (unsigned long)-2;
|
||||
return (long)x;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3337,7 +3328,7 @@ long_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
/* Since PyLong_FromString doesn't have a length parameter,
|
||||
* check here for possible NULs in the string. */
|
||||
char *string = PyString_AS_STRING(x);
|
||||
if (strlen(string) != PyString_Size(x)) {
|
||||
if (strlen(string) != (size_t)PyString_Size(x)) {
|
||||
/* create a repr() of the input string,
|
||||
* just like PyLong_FromString does. */
|
||||
PyObject *srepr;
|
||||
|
@ -3443,9 +3434,7 @@ long_sizeof(PyLongObject *v)
|
|||
{
|
||||
Py_ssize_t res;
|
||||
|
||||
res = v->ob_type->tp_basicsize;
|
||||
if (v->ob_size != 0)
|
||||
res += abs(v->ob_size) * sizeof(digit);
|
||||
res = v->ob_type->tp_basicsize + ABS(Py_SIZE(v))*sizeof(digit);
|
||||
return PyInt_FromSsize_t(res);
|
||||
}
|
||||
|
||||
|
@ -3619,7 +3608,7 @@ PyTypeObject PyLong_Type = {
|
|||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0, /* ob_size */
|
||||
"long", /* tp_name */
|
||||
sizeof(PyLongObject) - sizeof(digit), /* tp_basicsize */
|
||||
offsetof(PyLongObject, ob_digit), /* tp_basicsize */
|
||||
sizeof(digit), /* tp_itemsize */
|
||||
long_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
|
|
Loading…
Reference in New Issue