summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorInada Naoki <songofacandy@gmail.com>2019-11-07 15:59:04 (GMT)
committerGitHub <noreply@github.com>2019-11-07 15:59:04 (GMT)
commit6cbc84fb99acb33dd659d7adb29a20adbe62b74a (patch)
tree227b48a65e2965719fc86a3c5759f04e6a615c85
parentd12d0e7c0fe2b49c40ac4d66365147c619d6c475 (diff)
downloadcpython-6cbc84fb99acb33dd659d7adb29a20adbe62b74a.zip
cpython-6cbc84fb99acb33dd659d7adb29a20adbe62b74a.tar.gz
cpython-6cbc84fb99acb33dd659d7adb29a20adbe62b74a.tar.bz2
bpo-38613: Optimize set operations of dict keys. (GH-16961)
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2019-10-29-15-44-24.bpo-38613.V_R3NC.rst3
-rw-r--r--Objects/dictobject.c54
2 files changed, 36 insertions, 21 deletions
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-10-29-15-44-24.bpo-38613.V_R3NC.rst b/Misc/NEWS.d/next/Core and Builtins/2019-10-29-15-44-24.bpo-38613.V_R3NC.rst
new file mode 100644
index 0000000..c001db6
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-10-29-15-44-24.bpo-38613.V_R3NC.rst
@@ -0,0 +1,3 @@
+Optimized some set operations (e.g. ``|``, ``^``, and ``-``) of
+``dict_keys``. ``d.keys() | other`` was slower than ``set(d) | other`` but
+they are almost same performance for now.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index d909f22..4afa19c 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -4162,17 +4162,34 @@ static PySequenceMethods dictkeys_as_sequence = {
(objobjproc)dictkeys_contains, /* sq_contains */
};
+// Create an set object from dictviews object.
+// Returns a new reference.
+// This utility function is used by set operations.
static PyObject*
-dictviews_sub(PyObject* self, PyObject *other)
+dictviews_to_set(PyObject *self)
{
- PyObject *result = PySet_New(self);
- PyObject *tmp;
- _Py_IDENTIFIER(difference_update);
+ PyObject *left = self;
+ if (PyDictKeys_Check(self)) {
+ // PySet_New() has fast path for the dict object.
+ PyObject *dict = (PyObject *)((_PyDictViewObject *)self)->dv_dict;
+ if (PyDict_CheckExact(dict)) {
+ left = dict;
+ }
+ }
+ return PySet_New(left);
+}
- if (result == NULL)
+static PyObject*
+dictviews_sub(PyObject *self, PyObject *other)
+{
+ PyObject *result = dictviews_to_set(self);
+ if (result == NULL) {
return NULL;
+ }
- tmp = _PyObject_CallMethodIdOneArg(result, &PyId_difference_update, other);
+ _Py_IDENTIFIER(difference_update);
+ PyObject *tmp = _PyObject_CallMethodIdOneArg(
+ result, &PyId_difference_update, other);
if (tmp == NULL) {
Py_DECREF(result);
return NULL;
@@ -4273,34 +4290,29 @@ error:
static PyObject*
dictviews_or(PyObject* self, PyObject *other)
{
- PyObject *result = PySet_New(self);
- PyObject *tmp;
- _Py_IDENTIFIER(update);
-
- if (result == NULL)
+ PyObject *result = dictviews_to_set(self);
+ if (result == NULL) {
return NULL;
+ }
- tmp = _PyObject_CallMethodIdOneArg(result, &PyId_update, other);
- if (tmp == NULL) {
+ if (_PySet_Update(result, other) < 0) {
Py_DECREF(result);
return NULL;
}
-
- Py_DECREF(tmp);
return result;
}
static PyObject*
dictviews_xor(PyObject* self, PyObject *other)
{
- PyObject *result = PySet_New(self);
- PyObject *tmp;
- _Py_IDENTIFIER(symmetric_difference_update);
-
- if (result == NULL)
+ PyObject *result = dictviews_to_set(self);
+ if (result == NULL) {
return NULL;
+ }
- tmp = _PyObject_CallMethodIdOneArg(result, &PyId_symmetric_difference_update, other);
+ _Py_IDENTIFIER(symmetric_difference_update);
+ PyObject *tmp = _PyObject_CallMethodIdOneArg(
+ result, &PyId_symmetric_difference_update, other);
if (tmp == NULL) {
Py_DECREF(result);
return NULL;