mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
SF bug 433228: repr(list) woes when len(list) big.
Gave Python linear-time repr() implementations for dicts, lists, strings. This means, e.g., that repr(range(50000)) is no longer 50x slower than pprint.pprint() in 2.2 <wink>. I don't consider this a bugfix candidate, as it's a performance boost. Added _PyString_Join() to the internal string API. If we want that in the public API, fine, but then it requires runtime error checks instead of asserts.
This commit is contained in:
parent
239508cd10
commit
a7259597f1
5 changed files with 193 additions and 56 deletions
|
@ -77,6 +77,10 @@ extern DL_IMPORT(void) _Py_ReleaseInternedStrings(void);
|
||||||
#define PyString_AS_STRING(op) (((PyStringObject *)(op))->ob_sval)
|
#define PyString_AS_STRING(op) (((PyStringObject *)(op))->ob_sval)
|
||||||
#define PyString_GET_SIZE(op) (((PyStringObject *)(op))->ob_size)
|
#define PyString_GET_SIZE(op) (((PyStringObject *)(op))->ob_size)
|
||||||
|
|
||||||
|
/* _PyString_Join(sep, x) is like sep.join(x). sep must be PyStringObject*,
|
||||||
|
x must be an iterable object. */
|
||||||
|
extern DL_IMPORT(PyObject *) _PyString_Join(PyObject *sep, PyObject *x);
|
||||||
|
|
||||||
/* --- Generic Codecs ----------------------------------------------------- */
|
/* --- Generic Codecs ----------------------------------------------------- */
|
||||||
|
|
||||||
/* Create an object by decoding the encoded string s of the
|
/* Create an object by decoding the encoded string s of the
|
||||||
|
|
|
@ -809,42 +809,80 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dict_repr(dictobject *mp)
|
dict_repr(dictobject *mp)
|
||||||
{
|
{
|
||||||
auto PyObject *v;
|
int i, pos;
|
||||||
PyObject *sepa, *colon;
|
PyObject *s, *temp, *colon = NULL;
|
||||||
register int i;
|
PyObject *pieces = NULL, *result = NULL;
|
||||||
register int any;
|
PyObject *key, *value;
|
||||||
|
|
||||||
i = Py_ReprEnter((PyObject*)mp);
|
i = Py_ReprEnter((PyObject *)mp);
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
if (i > 0)
|
return i > 0 ? PyString_FromString("{...}") : NULL;
|
||||||
return PyString_FromString("{...}");
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v = PyString_FromString("{");
|
if (mp->ma_used == 0) {
|
||||||
sepa = PyString_FromString(", ");
|
result = PyString_FromString("{}");
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
pieces = PyList_New(0);
|
||||||
|
if (pieces == NULL)
|
||||||
|
goto Done;
|
||||||
|
|
||||||
colon = PyString_FromString(": ");
|
colon = PyString_FromString(": ");
|
||||||
any = 0;
|
if (colon == NULL)
|
||||||
for (i = 0; i <= mp->ma_mask && v; i++) {
|
goto Done;
|
||||||
dictentry *ep = mp->ma_table + i;
|
|
||||||
PyObject *pvalue = ep->me_value;
|
/* Do repr() on each key+value pair, and insert ": " between them.
|
||||||
if (pvalue != NULL) {
|
Note that repr may mutate the dict. */
|
||||||
/* Prevent PyObject_Repr from deleting value during
|
pos = 0;
|
||||||
key format */
|
while (PyDict_Next((PyObject *)mp, &pos, &key, &value)) {
|
||||||
Py_INCREF(pvalue);
|
int status;
|
||||||
if (any++)
|
/* Prevent repr from deleting value during key format. */
|
||||||
PyString_Concat(&v, sepa);
|
Py_INCREF(value);
|
||||||
PyString_ConcatAndDel(&v, PyObject_Repr(ep->me_key));
|
s = PyObject_Repr(key);
|
||||||
PyString_Concat(&v, colon);
|
PyString_Concat(&s, colon);
|
||||||
PyString_ConcatAndDel(&v, PyObject_Repr(pvalue));
|
PyString_ConcatAndDel(&s, PyObject_Repr(value));
|
||||||
Py_DECREF(pvalue);
|
Py_DECREF(value);
|
||||||
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
status = PyList_Append(pieces, s);
|
||||||
|
Py_DECREF(s); /* append created a new ref */
|
||||||
|
if (status < 0)
|
||||||
|
goto Done;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
PyString_ConcatAndDel(&v, PyString_FromString("}"));
|
/* Add "{}" decorations to the first and last items. */
|
||||||
Py_ReprLeave((PyObject*)mp);
|
assert(PyList_GET_SIZE(pieces) > 0);
|
||||||
Py_XDECREF(sepa);
|
s = PyString_FromString("{");
|
||||||
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
temp = PyList_GET_ITEM(pieces, 0);
|
||||||
|
PyString_ConcatAndDel(&s, temp);
|
||||||
|
PyList_SET_ITEM(pieces, 0, s);
|
||||||
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
|
||||||
|
s = PyString_FromString("}");
|
||||||
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1);
|
||||||
|
PyString_ConcatAndDel(&temp, s);
|
||||||
|
PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1, temp);
|
||||||
|
if (temp == NULL)
|
||||||
|
goto Done;
|
||||||
|
|
||||||
|
/* Paste them all together with ", " between. */
|
||||||
|
s = PyString_FromString(", ");
|
||||||
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
result = _PyString_Join(s, pieces);
|
||||||
|
Py_DECREF(s);
|
||||||
|
|
||||||
|
Done:
|
||||||
|
Py_XDECREF(pieces);
|
||||||
Py_XDECREF(colon);
|
Py_XDECREF(colon);
|
||||||
return v;
|
Py_ReprLeave((PyObject *)mp);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -246,26 +246,68 @@ list_print(PyListObject *op, FILE *fp, int flags)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
list_repr(PyListObject *v)
|
list_repr(PyListObject *v)
|
||||||
{
|
{
|
||||||
PyObject *s, *comma;
|
|
||||||
int i;
|
int i;
|
||||||
|
PyObject *s, *temp;
|
||||||
|
PyObject *pieces = NULL, *result = NULL;
|
||||||
|
|
||||||
i = Py_ReprEnter((PyObject*)v);
|
i = Py_ReprEnter((PyObject*)v);
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
if (i > 0)
|
return i > 0 ? PyString_FromString("[...]") : NULL;
|
||||||
return PyString_FromString("[...]");
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (v->ob_size == 0) {
|
||||||
|
result = PyString_FromString("[]");
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
pieces = PyList_New(0);
|
||||||
|
if (pieces == NULL)
|
||||||
|
goto Done;
|
||||||
|
|
||||||
|
/* 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 < v->ob_size; ++i) {
|
||||||
|
int status;
|
||||||
|
s = PyObject_Repr(v->ob_item[i]);
|
||||||
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
status = PyList_Append(pieces, s);
|
||||||
|
Py_DECREF(s); /* append created a new ref */
|
||||||
|
if (status < 0)
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add "[]" decorations to the first and last items. */
|
||||||
|
assert(PyList_GET_SIZE(pieces) > 0);
|
||||||
s = PyString_FromString("[");
|
s = PyString_FromString("[");
|
||||||
comma = PyString_FromString(", ");
|
if (s == NULL)
|
||||||
for (i = 0; i < v->ob_size && s != NULL; i++) {
|
goto Done;
|
||||||
if (i > 0)
|
temp = PyList_GET_ITEM(pieces, 0);
|
||||||
PyString_Concat(&s, comma);
|
PyString_ConcatAndDel(&s, temp);
|
||||||
PyString_ConcatAndDel(&s, PyObject_Repr(v->ob_item[i]));
|
PyList_SET_ITEM(pieces, 0, s);
|
||||||
}
|
if (s == NULL)
|
||||||
Py_XDECREF(comma);
|
goto Done;
|
||||||
PyString_ConcatAndDel(&s, PyString_FromString("]"));
|
|
||||||
|
s = PyString_FromString("]");
|
||||||
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1);
|
||||||
|
PyString_ConcatAndDel(&temp, s);
|
||||||
|
PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1, temp);
|
||||||
|
if (temp == NULL)
|
||||||
|
goto Done;
|
||||||
|
|
||||||
|
/* Paste them all together with ", " between. */
|
||||||
|
s = PyString_FromString(", ");
|
||||||
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
result = _PyString_Join(s, pieces);
|
||||||
|
Py_DECREF(s);
|
||||||
|
|
||||||
|
Done:
|
||||||
|
Py_XDECREF(pieces);
|
||||||
Py_ReprLeave((PyObject *)v);
|
Py_ReprLeave((PyObject *)v);
|
||||||
return s;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -1031,6 +1031,23 @@ string_join(PyStringObject *self, PyObject *args)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *_PyString_Join(PyObject *sep, PyObject *x)
|
||||||
|
{
|
||||||
|
PyObject* args;
|
||||||
|
PyObject* result = NULL;
|
||||||
|
|
||||||
|
assert(sep != NULL && PyString_Check(sep));
|
||||||
|
assert(x != NULL);
|
||||||
|
args = PyTuple_New(1);
|
||||||
|
if (args != NULL) {
|
||||||
|
Py_INCREF(x);
|
||||||
|
PyTuple_SET_ITEM(args, 0, x);
|
||||||
|
result = string_join((PyStringObject *)sep, args);
|
||||||
|
Py_DECREF(args);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static long
|
static long
|
||||||
string_find_internal(PyStringObject *self, PyObject *args, int dir)
|
string_find_internal(PyStringObject *self, PyObject *args, int dir)
|
||||||
{
|
{
|
||||||
|
|
|
@ -184,20 +184,56 @@ tupleprint(PyTupleObject *op, FILE *fp, int flags)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
tuplerepr(PyTupleObject *v)
|
tuplerepr(PyTupleObject *v)
|
||||||
{
|
{
|
||||||
PyObject *s, *comma;
|
int i, n;
|
||||||
int i;
|
PyObject *s, *temp;
|
||||||
s = PyString_FromString("(");
|
PyObject *pieces, *result = NULL;
|
||||||
comma = PyString_FromString(", ");
|
|
||||||
for (i = 0; i < v->ob_size && s != NULL; i++) {
|
n = v->ob_size;
|
||||||
if (i > 0)
|
if (n == 0)
|
||||||
PyString_Concat(&s, comma);
|
return PyString_FromString("()");
|
||||||
PyString_ConcatAndDel(&s, PyObject_Repr(v->ob_item[i]));
|
|
||||||
|
pieces = PyTuple_New(n);
|
||||||
|
if (pieces == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Do repr() on each element. */
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
s = PyObject_Repr(v->ob_item[i]);
|
||||||
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
PyTuple_SET_ITEM(pieces, i, s);
|
||||||
}
|
}
|
||||||
Py_DECREF(comma);
|
|
||||||
if (v->ob_size == 1)
|
/* Add "()" decorations to the first and last items. */
|
||||||
PyString_ConcatAndDel(&s, PyString_FromString(","));
|
assert(n > 0);
|
||||||
PyString_ConcatAndDel(&s, PyString_FromString(")"));
|
s = PyString_FromString("(");
|
||||||
return s;
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
temp = PyTuple_GET_ITEM(pieces, 0);
|
||||||
|
PyString_ConcatAndDel(&s, temp);
|
||||||
|
PyTuple_SET_ITEM(pieces, 0, s);
|
||||||
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
|
||||||
|
s = PyString_FromString(n == 1 ? ",)" : ")");
|
||||||
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
temp = PyTuple_GET_ITEM(pieces, n-1);
|
||||||
|
PyString_ConcatAndDel(&temp, s);
|
||||||
|
PyTuple_SET_ITEM(pieces, n-1, temp);
|
||||||
|
if (temp == NULL)
|
||||||
|
goto Done;
|
||||||
|
|
||||||
|
/* Paste them all together with ", " between. */
|
||||||
|
s = PyString_FromString(", ");
|
||||||
|
if (s == NULL)
|
||||||
|
goto Done;
|
||||||
|
result = _PyString_Join(s, pieces);
|
||||||
|
Py_DECREF(s);
|
||||||
|
|
||||||
|
Done:
|
||||||
|
Py_DECREF(pieces);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long
|
static long
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue