diff -r 35289291a2e6 Objects/longobject.c --- a/Objects/longobject.c Mon Sep 24 23:19:17 2012 +0200 +++ b/Objects/longobject.c Tue Sep 25 00:53:29 2012 +0200 @@ -23,12 +23,22 @@ #define ABS(x) ((x) < 0 ? -(x) : (x)) #if NSMALLNEGINTS + NSMALLPOSINTS > 0 +typedef struct { + PyLongObject base; + /* cache result of long_to_decimal_string */ + PyObject *str; +} _PySmallIntObject; + /* Small integers are preallocated in this array so that they can be shared. The integers that are preallocated are those in the range -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive). */ -static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; +static _PySmallIntObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; + +#define IS_SMALL_INT(ob) (&small_ints[0] <= (_PySmallIntObject*)(ob) \ + && (_PySmallIntObject*)(ob) < &small_ints[NSMALLNEGINTS + NSMALLPOSINTS]) + #ifdef COUNT_ALLOCS Py_ssize_t quick_int_allocs, quick_neg_int_allocs; #endif @@ -1550,6 +1560,9 @@ divrem1(PyLongObject *a, digit n, digit string. (Return value is non-shared so that callers can modify the returned value if necessary.) */ +static PyObject * +long_to_decimal_string(PyObject *ob); + static int long_to_decimal_string_internal(PyObject *aa, PyObject **p_output, @@ -1567,6 +1580,17 @@ long_to_decimal_string_internal(PyObject PyErr_BadInternalCall(); return -1; } + + if (writer != NULL && IS_SMALL_INT(aa)) { + int err; + str = long_to_decimal_string(aa); + if (str == NULL) + return -1; + err = _PyUnicodeWriter_WriteStr(writer, str); + Py_DECREF(str); + return err; + } + size_a = ABS(Py_SIZE(a)); negative = Py_SIZE(a) < 0; @@ -1701,18 +1725,40 @@ long_to_decimal_string_internal(PyObject } else { assert(_PyUnicode_CheckConsistency(str, 1)); - *p_output = (PyObject *)str; + *p_output = str; } return 0; } static PyObject * -long_to_decimal_string(PyObject *aa) +long_to_decimal_string(PyObject *ob) { - PyObject *v; - if (long_to_decimal_string_internal(aa, &v, NULL) == -1) - return NULL; - return v; + PyObject *str; + + if (!IS_SMALL_INT(ob)) { + if (long_to_decimal_string_internal(ob, &str, NULL) == -1) + return NULL; + } + else { + _PySmallIntObject *small = (_PySmallIntObject *)ob; + if (small->str == NULL) { + int ival = (int)(small - small_ints) - NSMALLNEGINTS; + if (0 <= ival && ival <= 9) { + /* call PyUnicode_FromOrdinal() to get Unicode singletons */ + str = PyUnicode_FromOrdinal('0' + ival); + } + else { + if (long_to_decimal_string_internal(ob, &str, NULL) == -1) + return NULL; + } + small->str = str; + } + else { + str = small->str; + } + Py_INCREF(str); + } + return str; } /* Convert a long int object to a string, using a given conversion base, @@ -4982,10 +5028,12 @@ int { #if NSMALLNEGINTS + NSMALLPOSINTS > 0 int ival, size; - PyLongObject *v = small_ints; - - for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++, v++) { + _PySmallIntObject *small = small_ints; + PyLongObject *v; + + for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++, small++) { size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1); + v = &small->base; if (Py_TYPE(v) == &PyLong_Type) { /* The element is already initialized, most likely * the Python interpreter was initialized before. @@ -5007,6 +5055,7 @@ int } Py_SIZE(v) = size; v->ob_digit[0] = abs(ival); + ((_PySmallIntObject *)v)->str = NULL; } #endif /* initialize int_info */ @@ -5024,7 +5073,7 @@ PyLong_Fini(void) reinitializations will fail. */ #if NSMALLNEGINTS + NSMALLPOSINTS > 0 int i; - PyLongObject *v = small_ints; + _PySmallIntObject *v = small_ints; for (i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++, v++) { _Py_DEC_REFTOTAL; _Py_ForgetReference((PyObject*)v); diff -r 35289291a2e6 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Mon Sep 24 23:19:17 2012 +0200 +++ b/Objects/unicodeobject.c Tue Sep 25 00:53:29 2012 +0200 @@ -13290,7 +13290,6 @@ formatlong(PyObject *val, int flags, int switch (type) { case 'd': case 'u': - /* Special-case boolean: we want 0/1 */ if (PyBool_Check(val)) result = PyNumber_ToBase(val, 10); else @@ -13311,15 +13310,9 @@ formatlong(PyObject *val, int flags, int if (!result) return NULL; - assert(unicode_modifiable(result)); assert(PyUnicode_IS_READY(result)); assert(PyUnicode_IS_ASCII(result)); - /* To modify the string in-place, there can only be one reference. */ - if (Py_REFCNT(result) != 1) { - PyErr_BadInternalCall(); - return NULL; - } buf = PyUnicode_DATA(result); llen = PyUnicode_GET_LENGTH(result); if (llen > INT_MAX) { @@ -13328,11 +13321,31 @@ formatlong(PyObject *val, int flags, int return NULL; } len = (int)llen; + sign = buf[0] == '-'; numnondigits += sign; numdigits = len - numnondigits; assert(numdigits > 0); + if (((flags & F_ALT) != 0 || !(type == 'o' || type == 'x' || type == 'X')) + && (prec <= numdigits) + && (type != 'X')) + return result; + + if (Py_REFCNT(result) != 1) { + PyObject *copy = _PyUnicode_Copy(result); + Py_DECREF(result); + if (!copy) + return NULL; + result = copy; + + assert(PyUnicode_IS_READY(result)); + assert(PyUnicode_IS_ASCII(result)); + } + + /* To modify the string in-place, there can only be one reference. */ + assert(unicode_modifiable(result)); + /* Get rid of base marker unless F_ALT */ if (((flags & F_ALT) == 0 && (type == 'o' || type == 'x' || type == 'X'))) {