]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-116621: Specialize list.extend for dict items (gh-116888)
authorDonghee Na <donghee.na@python.org>
Tue, 19 Mar 2024 03:18:07 +0000 (12:18 +0900)
committerGitHub <noreply@github.com>
Tue, 19 Mar 2024 03:18:07 +0000 (12:18 +0900)
Objects/listobject.c

index 096043bb3d3c51345588b8c851f62f74baac1e52..fc20a9bff3af470e98e38fc0ddcd83b50c8a3747 100644 (file)
@@ -1289,7 +1289,7 @@ list_extend_set(PyListObject *self, PySetObject *other)
     PyObject **dest = self->ob_item + m;
     while (_PySet_NextEntry((PyObject *)other, &setpos, &key, &hash)) {
         Py_INCREF(key);
-        *dest = key;
+        FT_ATOMIC_STORE_PTR_RELEASE(*dest, key);
         dest++;
     }
     Py_SET_SIZE(self, m + n);
@@ -1312,7 +1312,7 @@ list_extend_dict(PyListObject *self, PyDictObject *dict, int which_item)
     while (_PyDict_Next((PyObject *)dict, &pos, &keyvalue[0], &keyvalue[1], NULL)) {
         PyObject *obj = keyvalue[which_item];
         Py_INCREF(obj);
-        *dest = obj;
+        FT_ATOMIC_STORE_PTR_RELEASE(*dest, obj);
         dest++;
     }
 
@@ -1320,12 +1320,39 @@ list_extend_dict(PyListObject *self, PyDictObject *dict, int which_item)
     return 0;
 }
 
+static int
+list_extend_dictitems(PyListObject *self, PyDictObject *dict)
+{
+    Py_ssize_t m = Py_SIZE(self);
+    Py_ssize_t n = PyDict_GET_SIZE(dict);
+    if (list_resize(self, m + n) < 0) {
+        return -1;
+    }
+
+    PyObject **dest = self->ob_item + m;
+    Py_ssize_t pos = 0;
+    Py_ssize_t i = 0;
+    PyObject *key, *value;
+    while (_PyDict_Next((PyObject *)dict, &pos, &key, &value, NULL)) {
+        PyObject *item = PyTuple_Pack(2, key, value);
+        if (item == NULL) {
+            Py_SET_SIZE(self, m + i);
+            return -1;
+        }
+        FT_ATOMIC_STORE_PTR_RELEASE(*dest, item);
+        dest++;
+        i++;
+    }
+
+    Py_SET_SIZE(self, m + n);
+    return 0;
+}
+
 static int
 _list_extend(PyListObject *self, PyObject *iterable)
 {
     // Special case:
     // lists and tuples which can use PySequence_Fast ops
-    // TODO(@corona10): Add more special cases for other types.
     int res = -1;
     if ((PyObject *)self == iterable) {
         Py_BEGIN_CRITICAL_SECTION(self);
@@ -1359,6 +1386,12 @@ _list_extend(PyListObject *self, PyObject *iterable)
         res = list_extend_dict(self, dict, 1 /*values*/);
         Py_END_CRITICAL_SECTION2();
     }
+    else if (Py_IS_TYPE(iterable, &PyDictItems_Type)) {
+        PyDictObject *dict = ((_PyDictViewObject *)iterable)->dv_dict;
+        Py_BEGIN_CRITICAL_SECTION2(self, dict);
+        res = list_extend_dictitems(self, dict);
+        Py_END_CRITICAL_SECTION2();
+    }
     else {
         Py_BEGIN_CRITICAL_SECTION(self);
         res = list_extend_iter_lock_held(self, iterable);