]> granicus.if.org Git - python/commitdiff
Issue #25869: Optimized deepcopying ElementTree; it is now 20 times faster.
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 21 Dec 2015 10:57:27 +0000 (12:57 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Mon, 21 Dec 2015 10:57:27 +0000 (12:57 +0200)
Misc/NEWS
Modules/_elementtree.c

index 6dc02e3bf3ff9f861c3d9875584a6cb00e85f798..ff1beefaf9283d2bd51354478d0882d64666e74d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -115,6 +115,8 @@ Core and Builtins
 Library
 -------
 
+- Issue #25869: Optimized deepcopying ElementTree; it is now 20 times faster.
+
 - Issue #25873: Optimized iterating ElementTree.  Iterating elements
   Element.iter() is now 40% faster, iterating text Element.itertext()
   is now up to 2.5 times faster.
index ad3e45c3d8beece6524887594bceb659c7e0b685..5908c725e13928289175d36f1e778b1eae70b7e3 100644 (file)
@@ -128,30 +128,6 @@ elementtree_free(void *m)
 
 /* helpers */
 
-LOCAL(PyObject*)
-deepcopy(PyObject* object, PyObject* memo)
-{
-    /* do a deep copy of the given object */
-    PyObject* args;
-    PyObject* result;
-    elementtreestate *st = ET_STATE_GLOBAL;
-
-    if (!st->deepcopy_obj) {
-        PyErr_SetString(
-            PyExc_RuntimeError,
-            "deepcopy helper not found"
-            );
-        return NULL;
-    }
-
-    args = PyTuple_Pack(2, object, memo);
-    if (!args)
-        return NULL;
-    result = PyObject_CallObject(st->deepcopy_obj, args);
-    Py_DECREF(args);
-    return result;
-}
-
 LOCAL(PyObject*)
 list_join(PyObject* list)
 {
@@ -748,6 +724,9 @@ _elementtree_Element___copy___impl(ElementObject *self)
     return (PyObject*) element;
 }
 
+/* Helper for a deep copy. */
+LOCAL(PyObject *) deepcopy(PyObject *, PyObject *);
+
 /*[clinic input]
 _elementtree.Element.__deepcopy__
 
@@ -838,6 +817,57 @@ _elementtree_Element___deepcopy__(ElementObject *self, PyObject *memo)
     return NULL;
 }
 
+LOCAL(PyObject *)
+deepcopy(PyObject *object, PyObject *memo)
+{
+    /* do a deep copy of the given object */
+    PyObject *args;
+    PyObject *result;
+    elementtreestate *st;
+
+    /* Fast paths */
+    if (object == Py_None || PyUnicode_CheckExact(object)) {
+        Py_INCREF(object);
+        return object;
+    }
+
+    if (Py_REFCNT(object) == 1) {
+        if (PyDict_CheckExact(object)) {
+            PyObject *key, *value;
+            Py_ssize_t pos = 0;
+            int simple = 1;
+            while (PyDict_Next(object, &pos, &key, &value)) {
+                if (!PyUnicode_CheckExact(key) || !PyUnicode_CheckExact(value)) {
+                    simple = 0;
+                    break;
+                }
+            }
+            if (simple)
+                return PyDict_Copy(object);
+            /* Fall through to general case */
+        }
+        else if (Element_CheckExact(object)) {
+            return _elementtree_Element___deepcopy__((ElementObject *)object, memo);
+        }
+    }
+
+    /* General case */
+    st = ET_STATE_GLOBAL;
+    if (!st->deepcopy_obj) {
+        PyErr_SetString(PyExc_RuntimeError,
+                        "deepcopy helper not found");
+        return NULL;
+    }
+
+    args = PyTuple_Pack(2, object, memo);
+    if (!args)
+        return NULL;
+    result = PyObject_CallObject(st->deepcopy_obj, args);
+    Py_DECREF(args);
+    return result;
+}
+
+
 /*[clinic input]
 _elementtree.Element.__sizeof__ -> Py_ssize_t