Index: Include/longintrepr.h =================================================================== --- Include/longintrepr.h (révision 67111) +++ Include/longintrepr.h (copie de travail) @@ -19,6 +19,7 @@ long_pow() requires that SHIFT be divisible by 5. */ typedef unsigned short digit; +typedef int sdigit; typedef unsigned int wdigit; /* digit widened to parameter size */ #define BASE_TWODIGITS_TYPE long typedef unsigned BASE_TWODIGITS_TYPE twodigits; @@ -57,6 +58,30 @@ /* Return a copy of src. */ PyAPI_FUNC(PyObject *) _PyLong_Copy(PyLongObject *src); +/* Sign of a PyLong: + * - negative value if x is negative + * - zero is value is zero + * - positive value if x is positive + * + * Eg. "if (PyLong_SIGN(x) < 0) ..." */ +#define PyLong_SIGN(x) Py_SIZE(x) + +/* True if x equals 0 */ +#define PyLong_EQUALS_ZERO(x) (PyLong_SIGN(x) == 0) + +/* True if x fits in a integer (fits in a digit or sdigit): + * x has 0 or 1 digits */ +#define PyLong_FITS_INT(x) (-1 <= Py_SIZE(x) && Py_SIZE(x) <= 1) + +/* Get the value as a small integer (type sdigit). + * The result is only valid if PyLong_FITS_INT(x). */ +#define PyLong_GET_INT(x) \ + ((PyLong_SIGN(x) < 0) ? -(sdigit)(x)->ob_digit[0] : \ + (PyLong_EQUALS_ZERO(x) ? (sdigit)0 : (sdigit)(x)->ob_digit[0])) + +/* Number of digits (in base PyLong_BASE) */ +#define PyLong_NDIGITS(x) ((Py_SIZE(x) < 0)? -Py_SIZE(x) : Py_SIZE(x)) + #ifdef __cplusplus } #endif Index: Objects/longobject.c =================================================================== --- Objects/longobject.c (révision 67111) +++ Objects/longobject.c (copie de travail) @@ -14,10 +14,23 @@ #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)) +/* Optimize version of the following instructions: + * ndigits = PyLong_NDIGITS(x); + * sign = (PyLong_SIGN(x) < 0) ? -1 : 1 + */ +#define PyLong_GET_NDIGITS_SIGN(x,ndigits,sign) \ + do { \ + ndigits = Py_SIZE(v); \ + if (ndigits < 0) { \ + ndigits = -ndigits; \ + sign = -1; \ + } else { \ + sign = 1; \ + } \ + } while (0) + #if NSMALLNEGINTS + NSMALLPOSINTS > 0 /* Small integers are preallocated in this array so that they can be shared. @@ -50,8 +63,8 @@ static PyLongObject * maybe_small_long(PyLongObject *v) { - if (v && ABS(Py_SIZE(v)) <= 1) { - int ival = MEDIUM_VALUE(v); + if (v && PyLong_FITS_INT(v)) { + sdigit ival = PyLong_GET_INT(v); if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { Py_DECREF(v); return (PyLongObject *)get_small_int(ival); @@ -68,7 +81,7 @@ be a small integer, so negating it must go to PyLong_FromLong */ #define NEGATE(x) \ do if (Py_REFCNT(x) == 1) Py_SIZE(x) = -Py_SIZE(x); \ - else { PyObject* tmp=PyLong_FromLong(-MEDIUM_VALUE(x)); \ + else { PyObject* tmp=PyLong_FromLong(-PyLong_GET_INT(x)); \ Py_DECREF(x); (x) = (PyLongObject*)tmp; } \ while(0) /* For long multiplication, use the O(N**2) school algorithm unless @@ -109,13 +122,13 @@ static PyLongObject * long_normalize(register PyLongObject *v) { - Py_ssize_t j = ABS(Py_SIZE(v)); + Py_ssize_t j = PyLong_NDIGITS(v); Py_ssize_t i = j; while (i > 0 && v->ob_digit[i-1] == 0) --i; if (i != j) - Py_SIZE(v) = (Py_SIZE(v) < 0) ? -(i) : i; + Py_SIZE(v) = (PyLong_SIGN(v) < 0) ? -(i) : i; return v; } @@ -151,20 +164,15 @@ Py_ssize_t i; assert(src != NULL); - i = Py_SIZE(src); - if (i < 0) - i = -(i); - if (i < 2) { - int ival = src->ob_digit[0]; - if (Py_SIZE(src) < 0) - ival = -ival; + if (PyLong_FITS_INT(src)) { + sdigit ival = PyLong_GET_INT(src); CHECK_SMALL_INT(ival); } + i = PyLong_NDIGITS(src); result = _PyLong_New(i); if (result != NULL) { Py_SIZE(result) = Py_SIZE(src); - while (--i >= 0) - result->ob_digit[i] = src->ob_digit[i]; + memcpy(result->ob_digit, src->ob_digit, i * sizeof(digit)); } return (PyObject *)result; } @@ -355,32 +363,18 @@ } } - res = -1; v = (PyLongObject *)vv; - i = Py_SIZE(v); - - switch (i) { - case -1: - res = -v->ob_digit[0]; - break; - case 0: - res = 0; - break; - case 1: - res = v->ob_digit[0]; - break; - default: - sign = 1; + if (PyLong_FITS_INT(v)) { + res = (long) PyLong_GET_INT(v); + } else { + PyLong_GET_NDIGITS_SIGN(v, i, sign); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) + v->ob_digit[i]; if ((x >> PyLong_SHIFT) != prev) { - *overflow = Py_SIZE(v) > 0 ? 1 : -1; + *overflow = sign; + res = -1; goto exit; } } @@ -394,8 +388,8 @@ res = LONG_MIN; } else { - *overflow = Py_SIZE(v) > 0 ? 1 : -1; - /* res is already set to -1 */ + res = -1; + *overflow = sign; } } exit: @@ -434,18 +428,11 @@ return -1; } v = (PyLongObject *)vv; - i = Py_SIZE(v); - switch (i) { - case -1: return -v->ob_digit[0]; - case 0: return 0; - case 1: return v->ob_digit[0]; + if (PyLong_FITS_INT(v)) { + return (Py_ssize_t) PyLong_GET_INT(v); } - sign = 1; + PyLong_GET_NDIGITS_SIGN(v, i, sign); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) + v->ob_digit[i]; @@ -484,17 +471,15 @@ return (unsigned long) -1; } v = (PyLongObject *)vv; - i = Py_SIZE(v); - x = 0; - if (i < 0) { + if (PyLong_SIGN(v) < 0) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to unsigned int"); return (unsigned long) -1; } - switch (i) { - case 0: return 0; - case 1: return v->ob_digit[0]; - } + if (PyLong_FITS_INT(v)) + return (unsigned long) PyLong_GET_INT(v); + x = 0; + i = PyLong_NDIGITS(v); while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) + v->ob_digit[i]; @@ -522,17 +507,15 @@ return (unsigned long) -1; } v = (PyLongObject *)vv; - i = Py_SIZE(v); - x = 0; - if (i < 0) { + if (PyLong_SIGN(v) < 0) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to size_t"); return (size_t) -1; } - switch (i) { - case 0: return 0; - case 1: return v->ob_digit[0]; - } + if (PyLong_FITS_INT(v)) + return (size_t) PyLong_GET_INT(v); + x = 0; + i = PyLong_NDIGITS(v); while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) + v->ob_digit[i]; @@ -561,17 +544,10 @@ return (unsigned long) -1; } v = (PyLongObject *)vv; - i = Py_SIZE(v); - switch (i) { - case 0: return 0; - case 1: return v->ob_digit[0]; - } - sign = 1; + if (PyLong_FITS_INT(v)) + return (unsigned long) PyLong_GET_INT(v); + PyLong_GET_NDIGITS_SIGN(v, i, sign); x = 0; - if (i < 0) { - sign = -1; - i = -i; - } while (--i >= 0) { x = (x << PyLong_SHIFT) + v->ob_digit[i]; } @@ -621,7 +597,8 @@ assert(v != NULL); assert(PyLong_Check(v)); - return Py_SIZE(v) == 0 ? 0 : (Py_SIZE(v) < 0 ? -1 : 1); + return PyLong_EQUALS_ZERO(v) ? 0 + : (PyLong_SIGN(v) > 0 ? 1 : -1); } size_t @@ -633,7 +610,7 @@ assert(v != NULL); assert(PyLong_Check(v)); - ndigits = ABS(Py_SIZE(v)); + ndigits = PyLong_NDIGITS(v); assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0); if (ndigits > 0) { digit msd = v->ob_digit[ndigits - 1]; @@ -926,16 +903,11 @@ return -1; } v = (PyLongObject *)vv; - i = Py_SIZE(v); - sign = 1; - if (i < 0) { - sign = -1; - i = -(i); - } - else if (i == 0) { + if (PyLong_EQUALS_ZERO(v)) { *exponent = 0; return 0.0; } + PyLong_GET_NDIGITS_SIGN(x, i, sign); --i; x = (double)v->ob_digit[i]; nbitsneeded = NBITS_WANTED - 1; @@ -1297,13 +1269,8 @@ case 0: return 0; case 1: return v->ob_digit[0]; } - i = Py_SIZE(v); - sign = 1; + PyLong_GET_NDIGITS_SIGN(v, i, sign); x = 0; - if (i < 0) { - sign = -1; - i = -i; - } while (--i >= 0) { x = (x << PyLong_SHIFT) + v->ob_digit[i]; } @@ -1419,7 +1386,7 @@ static PyLongObject * muladd1(PyLongObject *a, wdigit n, wdigit extra) { - Py_ssize_t size_a = ABS(Py_SIZE(a)); + Py_ssize_t size_a = PyLong_NDIGITS(a); PyLongObject *z = _PyLong_New(size_a+1); twodigits carry = extra; Py_ssize_t i; @@ -1465,7 +1432,7 @@ static PyLongObject * divrem1(PyLongObject *a, digit n, digit *prem) { - const Py_ssize_t size = ABS(Py_SIZE(a)); + const Py_ssize_t size = PyLong_NDIGITS(a); PyLongObject *z; assert(n > 0 && n <= PyLong_MASK); @@ -1496,7 +1463,7 @@ return NULL; } assert(base >= 2 && base <= 36); - size_a = ABS(Py_SIZE(a)); + size_a = PyLong_NDIGITS(a); /* Compute a rough upper bound for the length of the string */ i = base; @@ -2045,7 +2012,7 @@ long_divrem(PyLongObject *a, PyLongObject *b, PyLongObject **pdiv, PyLongObject **prem) { - Py_ssize_t size_a = ABS(Py_SIZE(a)), size_b = ABS(Py_SIZE(b)); + Py_ssize_t size_a = PyLong_NDIGITS(a), size_b = PyLong_NDIGITS(b); PyLongObject *z; if (size_b == 0) { @@ -2097,7 +2064,7 @@ static PyLongObject * x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) { - Py_ssize_t size_v = ABS(Py_SIZE(v1)), size_w = ABS(Py_SIZE(w1)); + Py_ssize_t size_v = PyLong_NDIGITS(v1), size_w = PyLong_NDIGITS(w1); digit d = (digit) ((twodigits)PyLong_BASE / (w1->ob_digit[size_w-1] + 1)); PyLongObject *v = mul1(v1, d); PyLongObject *w = mul1(w1, d); @@ -2112,9 +2079,9 @@ assert(size_v >= size_w && size_w > 1); /* Assert checks by div() */ assert(Py_REFCNT(v) == 1); /* Since v will be used as accumulator! */ - assert(size_w == ABS(Py_SIZE(w))); /* That's how d was calculated */ + assert(size_w == PyLong_NDIGITS(w)); /* That's how d was calculated */ - size_v = ABS(Py_SIZE(v)); + size_v = PyLong_NDIGITS(v); k = size_v - size_w; a = _PyLong_New(k + 1); @@ -2212,13 +2179,10 @@ Py_ssize_t sign; if (Py_SIZE(a) != Py_SIZE(b)) { - if (ABS(Py_SIZE(a)) == 0 && ABS(Py_SIZE(b)) == 0) - sign = 0; - else sign = Py_SIZE(a) - Py_SIZE(b); } else { - Py_ssize_t i = ABS(Py_SIZE(a)); + Py_ssize_t i = PyLong_NDIGITS(a); while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i]) ; if (i < 0) @@ -2252,18 +2216,14 @@ /* This is designed so that Python ints and longs with the same value hash to the same value, otherwise comparisons of mapping keys will turn out weird */ - i = Py_SIZE(v); - switch(i) { - case -1: return v->ob_digit[0]==1 ? -2 : -v->ob_digit[0]; - case 0: return 0; - case 1: return v->ob_digit[0]; + if (PyLong_FITS_INT(v)) { + x = PyLong_GET_INT(v); + if (x == -1) + x = -2; + return x; } - sign = 1; + PyLong_GET_NDIGITS_SIGN(v, i, sign); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } #define LONG_BIT_PyLong_SHIFT (8*sizeof(long) - PyLong_SHIFT) /* The following loop produces a C long x such that (unsigned long)x is congruent to the absolute value of v modulo ULONG_MAX. The @@ -2291,7 +2251,7 @@ static PyLongObject * x_add(PyLongObject *a, PyLongObject *b) { - Py_ssize_t size_a = ABS(Py_SIZE(a)), size_b = ABS(Py_SIZE(b)); + Py_ssize_t size_a = PyLong_NDIGITS(a), size_b = PyLong_NDIGITS(b); PyLongObject *z; int i; digit carry = 0; @@ -2325,7 +2285,7 @@ static PyLongObject * x_sub(PyLongObject *a, PyLongObject *b) { - Py_ssize_t size_a = ABS(Py_SIZE(a)), size_b = ABS(Py_SIZE(b)); + Py_ssize_t size_a = PyLong_NDIGITS(a), size_b = PyLong_NDIGITS(b); PyLongObject *z; Py_ssize_t i; int sign = 1; @@ -2382,10 +2342,9 @@ CHECK_BINOP(a, b); - if (ABS(Py_SIZE(a)) <= 1 && ABS(Py_SIZE(b)) <= 1) { - PyObject *result = PyLong_FromLong(MEDIUM_VALUE(a) + - MEDIUM_VALUE(b)); - return result; + if (PyLong_FITS_INT(a) && PyLong_FITS_INT(b)) { + sdigit sum = PyLong_GET_INT(a) + PyLong_GET_INT(b); + return PyLong_FromLong(sum); } if (Py_SIZE(a) < 0) { if (Py_SIZE(b) < 0) { @@ -2412,10 +2371,9 @@ CHECK_BINOP(a, b); - if (ABS(Py_SIZE(a)) <= 1 && ABS(Py_SIZE(b)) <= 1) { - PyObject* r; - r = PyLong_FromLong(MEDIUM_VALUE(a)-MEDIUM_VALUE(b)); - return r; + if (PyLong_FITS_INT(a) && PyLong_FITS_INT(b)) { + sdigit diff = PyLong_GET_INT(a) - PyLong_GET_INT(b); + return PyLong_FromLong(diff); } if (Py_SIZE(a) < 0) { if (Py_SIZE(b) < 0) @@ -2441,8 +2399,8 @@ x_mul(PyLongObject *a, PyLongObject *b) { PyLongObject *z; - Py_ssize_t size_a = ABS(Py_SIZE(a)); - Py_ssize_t size_b = ABS(Py_SIZE(b)); + Py_ssize_t size_a = PyLong_NDIGITS(a); + Py_ssize_t size_b = PyLong_NDIGITS(b); Py_ssize_t i; z = _PyLong_New(size_a + size_b); @@ -2533,7 +2491,7 @@ { PyLongObject *hi, *lo; Py_ssize_t size_lo, size_hi; - const Py_ssize_t size_n = ABS(Py_SIZE(n)); + const Py_ssize_t size_n = PyLong_NDIGITS(n); size_lo = MIN(size_n, size); size_hi = size_n - size_lo; @@ -2562,8 +2520,8 @@ static PyLongObject * k_mul(PyLongObject *a, PyLongObject *b) { - Py_ssize_t asize = ABS(Py_SIZE(a)); - Py_ssize_t bsize = ABS(Py_SIZE(b)); + Py_ssize_t asize = PyLong_NDIGITS(a); + Py_ssize_t bsize = PyLong_NDIGITS(b); PyLongObject *ah = NULL; PyLongObject *al = NULL; PyLongObject *bh = NULL; @@ -2783,8 +2741,8 @@ static PyLongObject * k_lopsided_mul(PyLongObject *a, PyLongObject *b) { - const Py_ssize_t asize = ABS(Py_SIZE(a)); - Py_ssize_t bsize = ABS(Py_SIZE(b)); + const Py_ssize_t asize = PyLong_NDIGITS(a); + Py_ssize_t bsize = PyLong_NDIGITS(b); Py_ssize_t nbdone; /* # of b digits already multiplied */ PyLongObject *ret; PyLongObject *bslice = NULL; @@ -2841,10 +2799,10 @@ CHECK_BINOP(a, b); - if (ABS(Py_SIZE(a)) <= 1 && ABS(Py_SIZE(b)) <= 1) { - PyObject *r; - r = PyLong_FromLong(MEDIUM_VALUE(a)*MEDIUM_VALUE(b)); - return r; + if (PyLong_FITS_INT(a) && PyLong_FITS_INT(b)) { + stwodigits product = PyLong_GET_INT(a); + product *= PyLong_GET_INT(b); + return PyLong_FromLong(product); } z = k_mul(a, b); @@ -3199,8 +3157,11 @@ /* Implement ~x as -(x+1) */ PyLongObject *x; PyLongObject *w; - if (ABS(Py_SIZE(v)) <=1) - return PyLong_FromLong(-(MEDIUM_VALUE(v)+1)); + if (PyLong_FITS_INT(v)) { + sdigit invert = PyLong_GET_INT(v); + invert = -(invert + 1); + return PyLong_FromLong(invert); + } w = (PyLongObject *)PyLong_FromLong(1L); if (w == NULL) return NULL; @@ -3216,8 +3177,11 @@ long_neg(PyLongObject *v) { PyLongObject *z; - if (ABS(Py_SIZE(v)) <= 1) - return PyLong_FromLong(-MEDIUM_VALUE(v)); + if (PyLong_FITS_INT(v)) { + sdigit neg = PyLong_GET_INT(v); + neg = -neg; + return PyLong_FromLong(neg); + } z = (PyLongObject *)_PyLong_Copy(v); if (z != NULL) Py_SIZE(z) = -(Py_SIZE(v)); @@ -3236,7 +3200,7 @@ static int long_bool(PyLongObject *v) { - return ABS(Py_SIZE(v)) != 0; + return !PyLong_EQUALS_ZERO(v); } static PyObject * Index: Modules/mathmodule.c =================================================================== --- Modules/mathmodule.c (révision 67111) +++ Modules/mathmodule.c (copie de travail) @@ -709,7 +709,7 @@ exp = PyLong_AsLong(oexp); if (exp == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - if (Py_SIZE(oexp) < 0) { + if (PyLong_SIGN(oexp) < 0) { exp = LONG_MIN; } else {