r51562 - in python/branches/int_unification: Objects/longobject.c Objects/stringobject.c Python/ceval.c
Author: martin.v.loewis Date: Thu Aug 24 19:42:10 2006 New Revision: 51562 Modified: python/branches/int_unification/Objects/longobject.c python/branches/int_unification/Objects/stringobject.c python/branches/int_unification/Python/ceval.c Log: Special-case more single-digit operations. Avoid modifying singleton values. Fix index computation. Modified: python/branches/int_unification/Objects/longobject.c ============================================================================== --- python/branches/int_unification/Objects/longobject.c (original) +++ python/branches/int_unification/Objects/longobject.c Thu Aug 24 19:42:10 2006 @@ -48,6 +48,14 @@ #define CHECK_SMALL_INT(ival) #endif +#define MEDIUM_VALUE(x) ((x)->ob_size < 0 ? -(x)->ob_digit[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) \ + do if ((x)->ob_refcnt == 1) (x)->ob_size = -(x)->ob_size; \ + else { PyObject* tmp=PyInt_FromLong(-MEDIUM_VALUE(x)); \ + Py_DECREF(x); (x) = (PyLongObject*)tmp; } \ + while(0) /* For long multiplication, use the O(N**2) school algorithm unless * both operands contain more than KARATSUBA_CUTOFF digits (this * being an internal Python long digit, in base BASE). @@ -105,11 +113,18 @@ PyLongObject * _PyLong_New(Py_ssize_t size) { + PyLongObject *result; if (size > PY_SSIZE_T_MAX) { PyErr_NoMemory(); return NULL; } - return PyObject_NEW_VAR(PyLongObject, &PyLong_Type, size); + result = PyObject_MALLOC(sizeof(PyLongObject) + + (size-1)*sizeof(digit)); + if (!result) { + PyErr_NoMemory(); + return NULL; + } + return (PyLongObject*)PyObject_INIT_VAR(result, &PyLong_Type, size); } PyObject * @@ -155,7 +170,7 @@ if (ival < BASE) { /* Fast path for single-digits ints */ - v = PyObject_NEW_VAR(PyLongObject, &PyLong_Type, 1); + v = _PyLong_New(1); if (v) { v->ob_size = negative ? -1 : 1; v->ob_digit[0] = ival; @@ -291,6 +306,11 @@ v = (PyLongObject *)vv; i = v->ob_size; + switch (i) { + case -1: return -v->ob_digit[0]; + case 0: return 0; + case 1: return v->ob_digit[0]; + } sign = 1; x = 0; if (i < 0) { @@ -353,6 +373,11 @@ } v = (PyLongObject *)vv; i = v->ob_size; + switch (i) { + case -1: return -v->ob_digit[0]; + case 0: return 0; + case 1: return v->ob_digit[0]; + } sign = 1; x = 0; if (i < 0) { @@ -402,6 +427,10 @@ "can't convert negative value to unsigned long"); return (unsigned long) -1; } + switch (i) { + case 0: return 0; + case 1: return v->ob_digit[0]; + } while (--i >= 0) { prev = x; x = (x << SHIFT) + v->ob_digit[i]; @@ -436,6 +465,10 @@ "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]; + } while (--i >= 0) { prev = x; x = (x << SHIFT) + v->ob_digit[i]; @@ -465,6 +498,10 @@ } v = (PyLongObject *)vv; i = v->ob_size; + switch (i) { + case 0: return 0; + case 1: return v->ob_digit[0]; + } sign = 1; x = 0; if (i < 0) { @@ -1014,6 +1051,7 @@ PY_LONG_LONG PyLong_AsLongLong(PyObject *vv) { + PyLongObject *v; PY_LONG_LONG bytes; int one = 1; int res; @@ -1043,6 +1081,12 @@ return -1; } + v = (PyLongObject*)vv; + switch(v->ob_size) { + case -1: return -v->ob_digit[0]; + case 0: return 0; + case 1: return v->ob_digit[0]; + } res = _PyLong_AsByteArray( (PyLongObject *)vv, (unsigned char *)&bytes, SIZEOF_LONG_LONG, IS_LITTLE_ENDIAN, 1); @@ -1060,6 +1104,7 @@ unsigned PY_LONG_LONG PyLong_AsUnsignedLongLong(PyObject *vv) { + PyLongObject *v; unsigned PY_LONG_LONG bytes; int one = 1; int res; @@ -1069,6 +1114,12 @@ return (unsigned PY_LONG_LONG)-1; } + v = (PyLongObject*)vv; + switch(v->ob_size) { + case 0: return 0; + case 1: return v->ob_digit[0]; + } + res = _PyLong_AsByteArray( (PyLongObject *)vv, (unsigned char *)&bytes, SIZEOF_LONG_LONG, IS_LITTLE_ENDIAN, 0); @@ -1096,6 +1147,10 @@ return (unsigned long) -1; } v = (PyLongObject *)vv; + switch(v->ob_size) { + case 0: return 0; + case 1: return v->ob_digit[0]; + } i = v->ob_size; sign = 1; x = 0; @@ -1816,7 +1871,7 @@ (size_a == size_b && a->ob_digit[size_a-1] < b->ob_digit[size_b-1])) { /* |a| < |b|. */ - *pdiv = _PyLong_New(0); + *pdiv = (PyLongObject*)PyLong_FromLong(0); Py_INCREF(a); *prem = (PyLongObject *) a; return 0; @@ -1838,9 +1893,9 @@ the remainder r has the sign of a, so a = b*z + r. */ if ((a->ob_size < 0) != (b->ob_size < 0)) - z->ob_size = -(z->ob_size); + NEGATE(z); if (a->ob_size < 0 && (*prem)->ob_size != 0) - (*prem)->ob_size = -((*prem)->ob_size); + NEGATE(*prem); *pdiv = z; return 0; } @@ -1996,6 +2051,11 @@ same value hash to the same value, otherwise comparisons of mapping keys will turn out weird */ i = v->ob_size; + 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[1]; + } sign = 1; x = 0; if (i < 0) { @@ -2101,7 +2161,7 @@ } assert(borrow == 0); if (sign < 0) - z->ob_size = -(z->ob_size); + NEGATE(z); return long_normalize(z); } @@ -2112,6 +2172,9 @@ CONVERT_BINOP((PyObject *)v, (PyObject *)w, &a, &b); + if (ABS(a->ob_size) <= 1 && ABS(b->ob_size) <= 1) + return PyInt_FromLong(MEDIUM_VALUE(a) + + MEDIUM_VALUE(b)); if (a->ob_size < 0) { if (b->ob_size < 0) { z = x_add(a, b); @@ -2139,6 +2202,8 @@ CONVERT_BINOP((PyObject *)v, (PyObject *)w, &a, &b); + if (ABS(a->ob_size) <= 1 && ABS(b->ob_size) <= 1) + return PyLong_FromLong(MEDIUM_VALUE(a)-MEDIUM_VALUE(b)); if (a->ob_size < 0) { if (b->ob_size < 0) z = x_sub(a, b); @@ -2568,10 +2633,13 @@ return Py_NotImplemented; } + if (ABS(v->ob_size) <= 1 && ABS(w->ob_size) <= 1) + return PyLong_FromLong(MEDIUM_VALUE(v)*MEDIUM_VALUE(w)); + z = k_mul(a, b); /* Negate if exactly one of the inputs is negative. */ if (((a->ob_size ^ b->ob_size) < 0) && z) - z->ob_size = -(z->ob_size); + NEGATE(z); Py_DECREF(a); Py_DECREF(b); return (PyObject *)z; @@ -2810,7 +2878,7 @@ Py_DECREF(c); c = temp; temp = NULL; - c->ob_size = - c->ob_size; + NEGATE(c); } /* if modulus == 1: @@ -2931,6 +2999,8 @@ /* Implement ~x as -(x+1) */ PyLongObject *x; PyLongObject *w; + if (ABS(v->ob_size) <=1) + return PyLong_FromLong(-(MEDIUM_VALUE(v)+1)); w = (PyLongObject *)PyLong_FromLong(1L); if (w == NULL) return NULL; @@ -2957,11 +3027,8 @@ long_neg(PyLongObject *v) { PyLongObject *z; - if (v->ob_size == 0 && PyLong_CheckExact(v)) { - /* -0 == 0 */ - Py_INCREF(v); - return (PyObject *) v; - } + if (ABS(v->ob_size) <= 1) + return PyLong_FromLong(-MEDIUM_VALUE(v)); z = (PyLongObject *)_PyLong_Copy(v); if (z != NULL) z->ob_size = -(v->ob_size); @@ -3085,7 +3152,7 @@ if (z == NULL) goto lshift_error; if (a->ob_size < 0) - z->ob_size = -(z->ob_size); + NEGATE(z); for (i = 0; i < wordshift; i++) z->ob_digit[i] = 0; accum = 0; Modified: python/branches/int_unification/Objects/stringobject.c ============================================================================== --- python/branches/int_unification/Objects/stringobject.c (original) +++ python/branches/int_unification/Objects/stringobject.c Thu Aug 24 19:42:10 2006 @@ -4206,6 +4206,14 @@ int numdigits; /* len == numnondigits + numdigits */ int numnondigits = 0; + /* Avoid exceeding SSIZE_T_MAX */ + if (prec > PY_SSIZE_T_MAX-3) { + PyErr_SetString(PyExc_OverflowError, + "precision too large"); + return NULL; + } + + switch (type) { case 'd': case 'u': Modified: python/branches/int_unification/Python/ceval.c ============================================================================== --- python/branches/int_unification/Python/ceval.c (original) +++ python/branches/int_unification/Python/ceval.c Thu Aug 24 19:42:10 2006 @@ -3819,7 +3819,7 @@ { if (v != NULL) { Py_ssize_t x; - if (PyInt_Check(v)) { + if (PyInt_CheckExact(v)) { /* XXX(nnorwitz): I think PyInt_AS_LONG is correct, however, it looks like it should be AsSsize_t. There should be a comment here explaining why.
participants (1)
-
martin.v.loewis