]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
SF bug 433228: repr(list) woes when len(list) big.
authorTim Peters <tim.peters@gmail.com>
Sat, 16 Jun 2001 05:11:17 +0000 (05:11 +0000)
committerTim Peters <tim.peters@gmail.com>
Sat, 16 Jun 2001 05:11:17 +0000 (05:11 +0000)
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.

Include/stringobject.h
Objects/dictobject.c
Objects/listobject.c
Objects/stringobject.c
Objects/tupleobject.c

index fbcff314d1507bfd4e9d1856cf6656334f9726a8..96f371ee7edf27831717edbb22e666fe69a09059 100644 (file)
@@ -77,6 +77,10 @@ extern DL_IMPORT(void) _Py_ReleaseInternedStrings(void);
 #define PyString_AS_STRING(op) (((PyStringObject *)(op))->ob_sval)
 #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 ----------------------------------------------------- */
 
 /* Create an object by decoding the encoded string s of the
index 21cc6c6ce14b76e063221bc59825be3b2378e3ed..42bfd40213869d167a7ed9897b8e9dbf5053da2d 100644 (file)
@@ -809,42 +809,80 @@ dict_print(register dictobject *mp, register FILE *fp, register int flags)
 static PyObject *
 dict_repr(dictobject *mp)
 {
-       auto PyObject *v;
-       PyObject *sepa, *colon;
-       register int i;
-       register int any;
+       int i, pos;
+       PyObject *s, *temp, *colon = NULL;
+       PyObject *pieces = NULL, *result = NULL;
+       PyObject *key, *value;
 
-       i = Py_ReprEnter((PyObject*)mp);
+       i = Py_ReprEnter((PyObject *)mp);
        if (i != 0) {
-               if (i > 0)
-                       return PyString_FromString("{...}");
-               return NULL;
+               return i > 0 ? PyString_FromString("{...}") : NULL;
        }
 
-       v = PyString_FromString("{");
-       sepa = PyString_FromString(", ");
-       colon = PyString_FromString(": ");
-       any = 0;
-       for (i = 0; i <= mp->ma_mask && v; i++) {
-               dictentry *ep = mp->ma_table + i;
-               PyObject *pvalue = ep->me_value;
-               if (pvalue != NULL) {
-                       /* Prevent PyObject_Repr from deleting value during
-                          key format */
-                       Py_INCREF(pvalue);
-                       if (any++)
-                               PyString_Concat(&v, sepa);
-                       PyString_ConcatAndDel(&v, PyObject_Repr(ep->me_key));
-                       PyString_Concat(&v, colon);
-                       PyString_ConcatAndDel(&v, PyObject_Repr(pvalue));
-                       Py_DECREF(pvalue);
-               }
+       if (mp->ma_used == 0) {
+               result = PyString_FromString("{}");
+               goto Done;
        }
-       PyString_ConcatAndDel(&v, PyString_FromString("}"));
-       Py_ReprLeave((PyObject*)mp);
-       Py_XDECREF(sepa);
+
+       pieces = PyList_New(0);
+       if (pieces == NULL)
+               goto Done;
+
+       colon = PyString_FromString(": ");
+       if (colon == NULL)
+               goto Done;
+
+       /* Do repr() on each key+value pair, and insert ": " between them.
+          Note that repr may mutate the dict. */
+       pos = 0;
+       while (PyDict_Next((PyObject *)mp, &pos, &key, &value)) {
+               int status;
+               /* Prevent repr from deleting value during key format. */
+               Py_INCREF(value);
+               s = PyObject_Repr(key);
+               PyString_Concat(&s, colon);
+               PyString_ConcatAndDel(&s, PyObject_Repr(value));
+               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;
+       }
+
+       /* Add "{}" decorations to the first and last items. */
+       assert(PyList_GET_SIZE(pieces) > 0);
+       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);
-       return v;
+       Py_ReprLeave((PyObject *)mp);
+       return result;
 }
 
 static int
index e595c85082501a0c98b0bcec93a2002bd52e9b8a..6fb3145d362846921b01ffe15e64ac5b184893bf 100644 (file)
@@ -246,26 +246,68 @@ list_print(PyListObject *op, FILE *fp, int flags)
 static PyObject *
 list_repr(PyListObject *v)
 {
-       PyObject *s, *comma;
        int i;
+       PyObject *s, *temp;
+       PyObject *pieces = NULL, *result = NULL;
 
        i = Py_ReprEnter((PyObject*)v);
        if (i != 0) {
-               if (i > 0)
-                       return PyString_FromString("[...]");
-               return NULL;
+               return i > 0 ? PyString_FromString("[...]") : NULL;
        }
-       s = PyString_FromString("[");
-       comma = PyString_FromString(", ");
-       for (i = 0; i < v->ob_size && s != NULL; i++) {
-               if (i > 0)
-                       PyString_Concat(&s, comma);
-               PyString_ConcatAndDel(&s, PyObject_Repr(v->ob_item[i]));
+
+       if (v->ob_size == 0) {
+               result = PyString_FromString("[]");
+               goto Done;
        }
-       Py_XDECREF(comma);
-       PyString_ConcatAndDel(&s, PyString_FromString("]"));
+
+       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("[");
+       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_ReprLeave((PyObject *)v);
-       return s;
+       return result;
 }
 
 static int
index bcf51474ec4d80b8aee5422c137939a1a5a35968..24443d832319b7e2b14ad5a37e1865dff38f59df 100644 (file)
@@ -1031,6 +1031,23 @@ string_join(PyStringObject *self, PyObject *args)
        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
 string_find_internal(PyStringObject *self, PyObject *args, int dir)
 {
index 17ec1a0183b0006c7f2605bf8914421c773aae6a..538cc704d2098784ea4b476d63241c95935a0176 100644 (file)
@@ -184,20 +184,56 @@ tupleprint(PyTupleObject *op, FILE *fp, int flags)
 static PyObject *
 tuplerepr(PyTupleObject *v)
 {
-       PyObject *s, *comma;
-       int i;
+       int i, n;
+       PyObject *s, *temp;
+       PyObject *pieces, *result = NULL;
+
+       n = v->ob_size;
+       if (n == 0)
+               return PyString_FromString("()");
+
+       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);
+       }
+
+       /* Add "()" decorations to the first and last items. */
+       assert(n > 0);
        s = PyString_FromString("(");
-       comma = PyString_FromString(", ");
-       for (i = 0; i < v->ob_size && s != NULL; i++) {
-               if (i > 0)
-                       PyString_Concat(&s, comma);
-               PyString_ConcatAndDel(&s, PyObject_Repr(v->ob_item[i]));
-       }
-       Py_DECREF(comma);
-       if (v->ob_size == 1)
-               PyString_ConcatAndDel(&s, PyString_FromString(","));
-       PyString_ConcatAndDel(&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