diff -r b0eb26a44aff Include/dictobject.h --- a/Include/dictobject.h Tue Nov 19 13:18:45 2013 +0100 +++ b/Include/dictobject.h Tue Nov 19 13:54:28 2013 +0100 @@ -77,9 +77,11 @@ PyAPI_FUNC(int) _PyDict_Contains(PyObjec PyAPI_FUNC(PyObject *) _PyDict_NewPresized(Py_ssize_t minused); PyAPI_FUNC(void) _PyDict_MaybeUntrack(PyObject *mp); PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp); -Py_ssize_t _PyDict_KeysSize(PyDictKeysObject *keys); +PyAPI_FUNC(Py_ssize_t) _PyDict_KeysSize(PyDictKeysObject *keys); #define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL) +PyAPI_FUNC(int) _PyDict_ReprWriter(_PyUnicodeWriter *writer, PyObject *mp); + PyAPI_FUNC(int) PyDict_ClearFreeList(void); #endif diff -r b0eb26a44aff Include/listobject.h --- a/Include/listobject.h Tue Nov 19 13:18:45 2013 +0100 +++ b/Include/listobject.h Tue Nov 19 13:54:28 2013 +0100 @@ -62,6 +62,7 @@ PyAPI_FUNC(int) PyList_Reverse(PyObject PyAPI_FUNC(PyObject *) PyList_AsTuple(PyObject *); #ifndef Py_LIMITED_API PyAPI_FUNC(PyObject *) _PyList_Extend(PyListObject *, PyObject *); +PyAPI_FUNC(int) _PyList_ReprWriter(_PyUnicodeWriter *writer, PyObject *v); PyAPI_FUNC(int) PyList_ClearFreeList(void); PyAPI_FUNC(void) _PyList_DebugMallocStats(FILE *out); diff -r b0eb26a44aff Include/tupleobject.h --- a/Include/tupleobject.h Tue Nov 19 13:18:45 2013 +0100 +++ b/Include/tupleobject.h Tue Nov 19 13:54:28 2013 +0100 @@ -60,6 +60,8 @@ PyAPI_FUNC(void) _PyTuple_MaybeUntrack(P /* Macro, *only* to be used to fill in brand new tuples */ #define PyTuple_SET_ITEM(op, i, v) (((PyTupleObject *)(op))->ob_item[i] = v) + +PyAPI_FUNC(int) _PyTuple_ReprWriter(_PyUnicodeWriter *writer, PyObject *v); #endif PyAPI_FUNC(int) PyTuple_ClearFreeList(void); diff -r b0eb26a44aff Include/unicodeobject.h --- a/Include/unicodeobject.h Tue Nov 19 13:18:45 2013 +0100 +++ b/Include/unicodeobject.h Tue Nov 19 13:54:28 2013 +0100 @@ -987,6 +987,11 @@ PyAPI_FUNC(PyObject *) /* Deallocate memory of a writer (clear its internal buffer). */ PyAPI_FUNC(void) _PyUnicodeWriter_Dealloc(_PyUnicodeWriter *writer); + +PyAPI_FUNC(int) _PyUnicode_ReprWriter(_PyUnicodeWriter *writer, PyObject *obj); + +PyAPI_FUNC(int) _PyObject_ReprWriter(_PyUnicodeWriter *writer, + PyObject *v); #endif #ifndef Py_LIMITED_API diff -r b0eb26a44aff Objects/dictobject.c --- a/Objects/dictobject.c Tue Nov 19 13:18:45 2013 +0100 +++ b/Objects/dictobject.c Tue Nov 19 13:54:28 2013 +0100 @@ -1393,87 +1393,86 @@ dict_dealloc(PyDictObject *mp) } -static PyObject * -dict_repr(PyDictObject *mp) +int +_PyDict_ReprWriter(_PyUnicodeWriter *writer, PyObject *v) { + PyDictObject *mp = (PyDictObject *)v; Py_ssize_t i; PyObject *key = NULL, *value = NULL; - _PyUnicodeWriter writer; int first; - i = Py_ReprEnter((PyObject *)mp); - if (i != 0) { - return i > 0 ? PyUnicode_FromString("{...}") : NULL; + i = Py_ReprEnter(v); + if (i < 0) + return -1; + if (i > 0) + return _PyUnicodeWriter_WriteASCIIString(writer, "{...}", 5); + + if (mp->ma_used == 0) { + Py_ReprLeave(v); + return _PyUnicodeWriter_WriteASCIIString(writer, "{}", 2); } - if (mp->ma_used == 0) { - Py_ReprLeave((PyObject *)mp); - return PyUnicode_FromString("{}"); - } - - _PyUnicodeWriter_Init(&writer); - writer.overallocate = 1; + writer->overallocate = 1; /* "{" + "1: 2" + ", 3: 4" * (len - 1) + "}" */ - writer.min_length = 1 + 4 + (2 + 4) * (mp->ma_used - 1) + 1; - - if (_PyUnicodeWriter_WriteChar(&writer, '{') < 0) + writer->min_length += 1 + 4 + (2 + 4) * (mp->ma_used - 1) + 1; + + if (_PyUnicodeWriter_WriteChar(writer, '{') < 0) goto error; /* Do repr() on each key+value pair, and insert ": " between them. Note that repr may mutate the dict. */ i = 0; first = 1; - while (PyDict_Next((PyObject *)mp, &i, &key, &value)) { - PyObject *s; - int res; - + while (PyDict_Next(v, &i, &key, &value)) { /* Prevent repr from deleting key or value during key format. */ Py_INCREF(key); Py_INCREF(value); if (!first) { - if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) + if (_PyUnicodeWriter_WriteASCIIString(writer, ", ", 2) < 0) goto error; } first = 0; - s = PyObject_Repr(key); - if (s == NULL) + if (_PyObject_ReprWriter(writer, key) < 0) goto error; - res = _PyUnicodeWriter_WriteStr(&writer, s); - Py_DECREF(s); - if (res < 0) + + if (_PyUnicodeWriter_WriteASCIIString(writer, ": ", 2) < 0) goto error; - if (_PyUnicodeWriter_WriteASCIIString(&writer, ": ", 2) < 0) - goto error; - - s = PyObject_Repr(value); - if (s == NULL) - goto error; - res = _PyUnicodeWriter_WriteStr(&writer, s); - Py_DECREF(s); - if (res < 0) + if (_PyObject_ReprWriter(writer, value) < 0) goto error; Py_CLEAR(key); Py_CLEAR(value); } - writer.overallocate = 0; - if (_PyUnicodeWriter_WriteChar(&writer, '}') < 0) + /* writer->overallocate = 0; */ + if (_PyUnicodeWriter_WriteChar(writer, '}') < 0) goto error; - Py_ReprLeave((PyObject *)mp); - - return _PyUnicodeWriter_Finish(&writer); + Py_ReprLeave(v); + + return 0; error: - Py_ReprLeave((PyObject *)mp); - _PyUnicodeWriter_Dealloc(&writer); + Py_ReprLeave(v); Py_XDECREF(key); Py_XDECREF(value); - return NULL; + return -1; +} + +static PyObject * +dict_repr(PyObject *v) +{ + _PyUnicodeWriter writer; + + _PyUnicodeWriter_Init(&writer); + if (_PyDict_ReprWriter(&writer, v) < 0) { + _PyUnicodeWriter_Dealloc(&writer); + return NULL; + } + return _PyUnicodeWriter_Finish(&writer); } static Py_ssize_t @@ -2649,7 +2648,7 @@ PyTypeObject PyDict_Type = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - (reprfunc)dict_repr, /* tp_repr */ + dict_repr, /* tp_repr */ 0, /* tp_as_number */ &dict_as_sequence, /* tp_as_sequence */ &dict_as_mapping, /* tp_as_mapping */ diff -r b0eb26a44aff Objects/listobject.c --- a/Objects/listobject.c Tue Nov 19 13:18:45 2013 +0100 +++ b/Objects/listobject.c Tue Nov 19 13:54:28 2013 +0100 @@ -334,63 +334,71 @@ list_dealloc(PyListObject *op) Py_TRASHCAN_SAFE_END(op) } -static PyObject * -list_repr(PyListObject *v) +int +_PyList_ReprWriter(_PyUnicodeWriter *writer, PyObject *v) { + PyListObject *list = (PyListObject *)v; Py_ssize_t i; - PyObject *s; - _PyUnicodeWriter writer; + + i = Py_ReprEnter(v); + if (i < 0) + return -1; + if (i > 0) + return _PyUnicodeWriter_WriteASCIIString(writer, "[...]", 5); if (Py_SIZE(v) == 0) { - return PyUnicode_FromString("[]"); + Py_ReprLeave(v); + return _PyUnicodeWriter_WriteASCIIString(writer, "[]", 2); } - i = Py_ReprEnter((PyObject*)v); - if (i != 0) { - return i > 0 ? PyUnicode_FromString("[...]") : NULL; - } + writer->overallocate = 1; + /* "[" + "1" + ", 2" * (len - 1) + "]" */ + writer->min_length += 1 + 1 + (2 + 1) * (Py_SIZE(v) - 1) + 1; - _PyUnicodeWriter_Init(&writer); - writer.overallocate = 1; - /* "[" + "1" + ", 2" * (len - 1) + "]" */ - writer.min_length = 1 + 1 + (2 + 1) * (Py_SIZE(v) - 1) + 1; - - if (_PyUnicodeWriter_WriteChar(&writer, '[') < 0) + if (_PyUnicodeWriter_WriteChar(writer, '[') < 0) goto error; /* Do repr() on each element. Note that this may mutate the list, so must refetch the list size on each iteration. */ for (i = 0; i < Py_SIZE(v); ++i) { + int res; + if (i > 0) { - if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) + if (_PyUnicodeWriter_WriteASCIIString(writer, ", ", 2) < 0) goto error; } if (Py_EnterRecursiveCall(" while getting the repr of a list")) goto error; - s = PyObject_Repr(v->ob_item[i]); + res = _PyObject_ReprWriter(writer, list->ob_item[i]); Py_LeaveRecursiveCall(); - if (s == NULL) + if (res < 0) goto error; - - if (_PyUnicodeWriter_WriteStr(&writer, s) < 0) { - Py_DECREF(s); - goto error; - } - Py_DECREF(s); } - writer.overallocate = 0; - if (_PyUnicodeWriter_WriteChar(&writer, ']') < 0) + /* writer->overallocate = 0; */ + if (_PyUnicodeWriter_WriteChar(writer, ']') < 0) goto error; - Py_ReprLeave((PyObject *)v); - return _PyUnicodeWriter_Finish(&writer); + Py_ReprLeave(v); + return 0; error: - _PyUnicodeWriter_Dealloc(&writer); - Py_ReprLeave((PyObject *)v); - return NULL; + Py_ReprLeave(v); + return -1; +} + +static PyObject * +list_repr(PyObject *v) +{ + _PyUnicodeWriter writer; + + _PyUnicodeWriter_Init(&writer); + if (_PyList_ReprWriter(&writer, v) < 0) { + _PyUnicodeWriter_Dealloc(&writer); + return NULL; + } + return _PyUnicodeWriter_Finish(&writer); } static Py_ssize_t @@ -2629,7 +2637,7 @@ PyTypeObject PyList_Type = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - (reprfunc)list_repr, /* tp_repr */ + list_repr, /* tp_repr */ 0, /* tp_as_number */ &list_as_sequence, /* tp_as_sequence */ &list_as_mapping, /* tp_as_mapping */ diff -r b0eb26a44aff Objects/object.c --- a/Objects/object.c Tue Nov 19 13:18:45 2013 +0100 +++ b/Objects/object.c Tue Nov 19 13:54:28 2013 +0100 @@ -480,6 +480,41 @@ PyObject_Repr(PyObject *v) return res; } +int +_PyObject_ReprWriter(_PyUnicodeWriter *writer, PyObject *v) +{ + PyObject *str; + + if (PyLong_CheckExact(v)) { + return _PyLong_FormatWriter(writer, v, 10, 0); + } + if (PyUnicode_CheckExact(v)) { + return _PyUnicode_ReprWriter(writer, v); + } + if (PyList_CheckExact(v)) { + return _PyList_ReprWriter(writer, v); + } + if (PyTuple_CheckExact(v)) { + return _PyTuple_ReprWriter(writer, v); + } + if (PyList_CheckExact(v)) { + return _PyList_ReprWriter(writer, v); + } + if (PyDict_CheckExact(v)) { + return _PyDict_ReprWriter(writer, v); + } + + str = PyObject_Repr(v); + if (str == NULL) + return -1; + if (_PyUnicodeWriter_WriteStr(writer, str) < 0) { + Py_DECREF(str); + return -1; + } + Py_DECREF(str); + return 0; +} + PyObject * PyObject_Str(PyObject *v) { diff -r b0eb26a44aff Objects/tupleobject.c --- a/Objects/tupleobject.c Tue Nov 19 13:18:45 2013 +0100 +++ b/Objects/tupleobject.c Tue Nov 19 13:54:28 2013 +0100 @@ -251,79 +251,87 @@ done: Py_TRASHCAN_SAFE_END(op) } -static PyObject * -tuplerepr(PyTupleObject *v) +int +_PyTuple_ReprWriter(_PyUnicodeWriter *writer, PyObject *v) { + PyTupleObject *tuple = (PyTupleObject *)v; Py_ssize_t i, n; - _PyUnicodeWriter writer; - - n = Py_SIZE(v); - if (n == 0) - return PyUnicode_FromString("()"); /* While not mutable, it is still possible to end up with a cycle in a tuple through an object that stores itself within a tuple (and thus infinitely asks for the repr of itself). This should only be possible within a type. */ - i = Py_ReprEnter((PyObject *)v); - if (i != 0) { - return i > 0 ? PyUnicode_FromString("(...)") : NULL; + i = Py_ReprEnter(v); + if (i < 0) + return -1; + if (i > 0) + return _PyUnicodeWriter_WriteASCIIString(writer, "(...)", 5); + + n = Py_SIZE(v); + if (n == 0) { + Py_ReprLeave(v); + return _PyUnicodeWriter_WriteASCIIString(writer, "()", 2); } - _PyUnicodeWriter_Init(&writer); - writer.overallocate = 1; + writer->overallocate = 1; if (Py_SIZE(v) > 1) { /* "(" + "1" + ", 2" * (len - 1) + ")" */ - writer.min_length = 1 + 1 + (2 + 1) * (Py_SIZE(v) - 1) + 1; + writer->min_length += 1 + 1 + (2 + 1) * (Py_SIZE(v) - 1) + 1; } else { /* "(1,)" */ - writer.min_length = 4; + writer->min_length += 4; } - if (_PyUnicodeWriter_WriteChar(&writer, '(') < 0) + if (_PyUnicodeWriter_WriteChar(writer, '(') < 0) goto error; /* Do repr() on each element. */ for (i = 0; i < n; ++i) { - PyObject *s; + int res; if (i > 0) { - if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) + if (_PyUnicodeWriter_WriteASCIIString(writer, ", ", 2) < 0) goto error; } if (Py_EnterRecursiveCall(" while getting the repr of a tuple")) goto error; - s = PyObject_Repr(v->ob_item[i]); + res = _PyObject_ReprWriter(writer, tuple->ob_item[i]); Py_LeaveRecursiveCall(); - if (s == NULL) + if (res < 0) goto error; - - if (_PyUnicodeWriter_WriteStr(&writer, s) < 0) { - Py_DECREF(s); - goto error; - } - Py_DECREF(s); } - writer.overallocate = 0; + /* writer->overallocate = 0; */ if (n > 1) { - if (_PyUnicodeWriter_WriteChar(&writer, ')') < 0) + if (_PyUnicodeWriter_WriteChar(writer, ')') < 0) goto error; } else { - if (_PyUnicodeWriter_WriteASCIIString(&writer, ",)", 2) < 0) + if (_PyUnicodeWriter_WriteASCIIString(writer, ",)", 2) < 0) goto error; } - Py_ReprLeave((PyObject *)v); - return _PyUnicodeWriter_Finish(&writer); + Py_ReprLeave(v); + return 0; error: - _PyUnicodeWriter_Dealloc(&writer); - Py_ReprLeave((PyObject *)v); - return NULL; + Py_ReprLeave(v); + return -1; +} + +static PyObject * +tuplerepr(PyObject *v) +{ + _PyUnicodeWriter writer; + + _PyUnicodeWriter_Init(&writer); + if (_PyTuple_ReprWriter(&writer, v) < 0) { + _PyUnicodeWriter_Dealloc(&writer); + return NULL; + } + return _PyUnicodeWriter_Finish(&writer); } /* The addend 82520, was selected from the range(0, 1000000) for @@ -803,7 +811,7 @@ PyTypeObject PyTuple_Type = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - (reprfunc)tuplerepr, /* tp_repr */ + tuplerepr, /* tp_repr */ 0, /* tp_as_number */ &tuple_as_sequence, /* tp_as_sequence */ &tuple_as_mapping, /* tp_as_mapping */ diff -r b0eb26a44aff Objects/unicodeobject.c --- a/Objects/unicodeobject.c Tue Nov 19 13:18:45 2013 +0100 +++ b/Objects/unicodeobject.c Tue Nov 19 13:54:28 2013 +0100 @@ -2665,14 +2665,21 @@ unicode_fromformat_arg(_PyUnicodeWriter PyObject *obj = va_arg(*vargs, PyObject *); PyObject *repr; assert(obj); - repr = PyObject_Repr(obj); - if (!repr) - return NULL; - if (unicode_fromformat_write_str(writer, repr, width, precision) == -1) { + + if (width == -1 && precision == -1) { + if (_PyObject_ReprWriter(writer, obj) < 0) + return NULL; + } + else { + repr = PyObject_Repr(obj); + if (!repr) + return NULL; + if (unicode_fromformat_write_str(writer, repr, width, precision) == -1) { + Py_DECREF(repr); + return NULL; + } Py_DECREF(repr); - return NULL; - } - Py_DECREF(repr); + } break; } @@ -12334,10 +12341,9 @@ unicode_replace(PyObject *self, PyObject return result; } -static PyObject * -unicode_repr(PyObject *unicode) -{ - PyObject *repr; +int +_PyUnicode_ReprWriter(_PyUnicodeWriter *writer, PyObject *unicode) +{ Py_ssize_t isize; Py_ssize_t osize, squote, dquote, i, o; Py_UCS4 max, quote; @@ -12345,7 +12351,7 @@ unicode_repr(PyObject *unicode) void *idata, *odata; if (PyUnicode_READY(unicode) == -1) - return NULL; + return -1; isize = PyUnicode_GET_LENGTH(unicode); idata = PyUnicode_DATA(unicode); @@ -12395,21 +12401,23 @@ unicode_repr(PyObject *unicode) } osize += 2; /* quotes */ - repr = PyUnicode_New(osize, max); - if (repr == NULL) - return NULL; - okind = PyUnicode_KIND(repr); - odata = PyUnicode_DATA(repr); - - PyUnicode_WRITE(okind, odata, 0, quote); - PyUnicode_WRITE(okind, odata, osize-1, quote); + writer->overallocate = 1; + if (_PyUnicodeWriter_Prepare(writer, osize, max) < 0) + return -1; + + PyUnicode_WRITE(writer->kind, writer->data, writer->pos, quote); + PyUnicode_WRITE(writer->kind, writer->data, writer->pos+osize-1, quote); if (unchanged) { - _PyUnicode_FastCopyCharacters(repr, 1, + _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos + 1, unicode, 0, isize); } else { - for (i = 0, o = 1; i < isize; i++) { + okind = writer->kind; + odata = writer->data; + o = writer->pos + 1; + + for (i = 0; i < isize; i++) { Py_UCS4 ch = PyUnicode_READ(ikind, idata, i); /* Escape quotes and backslashes */ @@ -12487,9 +12495,23 @@ unicode_repr(PyObject *unicode) } } } + writer->pos += osize; + /* Closing quote already added at the beginning */ - assert(_PyUnicode_CheckConsistency(repr, 1)); - return repr; + return 0; +} + +static PyObject * +unicode_repr(PyObject *unicode) +{ + _PyUnicodeWriter writer; + + _PyUnicodeWriter_Init(&writer); + if (_PyUnicode_ReprWriter(&writer, unicode) < 0) { + _PyUnicodeWriter_Dealloc(&writer); + return NULL; + } + return _PyUnicodeWriter_Finish(&writer); } PyDoc_STRVAR(rfind__doc__, @@ -14384,6 +14406,12 @@ unicode_format_arg_format(struct unicode *p_str = v; Py_INCREF(*p_str); } + else if (arg->ch == 'r' && arg->width == -1 && arg->prec == -1) { + /* Fast path */ + if (_PyObject_ReprWriter(writer, v) == -1) + return -1; + return 1; + } else { if (arg->ch == 's') *p_str = PyObject_Str(v);