diff options
author | Forest Gregg <fgregg@users.noreply.github.com> | 2019-08-26 07:17:43 (GMT) |
---|---|---|
committer | Raymond Hettinger <rhettinger@users.noreply.github.com> | 2019-08-26 07:17:43 (GMT) |
commit | 998cf1f03a61de8a0cd3811faa97973d4022bc55 (patch) | |
tree | 1536d878a50a5b365154b72d15d88c805773326f /Objects/dictobject.c | |
parent | c3ea41e9bf100a5396b851488c3efe208e5e2179 (diff) | |
download | cpython-998cf1f03a61de8a0cd3811faa97973d4022bc55.zip cpython-998cf1f03a61de8a0cd3811faa97973d4022bc55.tar.gz cpython-998cf1f03a61de8a0cd3811faa97973d4022bc55.tar.bz2 |
bpo-27575: port set intersection logic into dictview intersection (GH-7696)
Diffstat (limited to 'Objects/dictobject.c')
-rw-r--r-- | Objects/dictobject.c | 81 |
1 files changed, 77 insertions, 4 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c index f168ad5..fec3a87 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -4169,24 +4169,97 @@ dictviews_sub(PyObject* self, PyObject *other) return result; } -PyObject* +static int +dictitems_contains(_PyDictViewObject *dv, PyObject *obj); + +PyObject * _PyDictView_Intersect(PyObject* self, PyObject *other) { - PyObject *result = PySet_New(self); + PyObject *result; + PyObject *it; + PyObject *key; + Py_ssize_t len_self; + int rv; + int (*dict_contains)(_PyDictViewObject *, PyObject *); PyObject *tmp; - _Py_IDENTIFIER(intersection_update); + /* Python interpreter swaps parameters when dict view + is on right side of & */ + if (!PyDictViewSet_Check(self)) { + PyObject *tmp = other; + other = self; + self = tmp; + } + + len_self = dictview_len((_PyDictViewObject *)self); + + /* if other is a set and self is smaller than other, + reuse set intersection logic */ + if (Py_TYPE(other) == &PySet_Type && len_self <= PyObject_Size(other)) { + _Py_IDENTIFIER(intersection); + return _PyObject_CallMethodIdObjArgs(other, &PyId_intersection, self, NULL); + } + + /* if other is another dict view, and it is bigger than self, + swap them */ + if (PyDictViewSet_Check(other)) { + Py_ssize_t len_other = dictview_len((_PyDictViewObject *)other); + if (len_other > len_self) { + PyObject *tmp = other; + other = self; + self = tmp; + } + } + + /* at this point, two things should be true + 1. self is a dictview + 2. if other is a dictview then it is smaller than self */ + result = PySet_New(NULL); if (result == NULL) return NULL; + it = PyObject_GetIter(other); + + _Py_IDENTIFIER(intersection_update); tmp = _PyObject_CallMethodIdOneArg(result, &PyId_intersection_update, other); if (tmp == NULL) { Py_DECREF(result); return NULL; } - Py_DECREF(tmp); + + if (PyDictKeys_Check(self)) { + dict_contains = dictkeys_contains; + } + /* else PyDictItems_Check(self) */ + else { + dict_contains = dictitems_contains; + } + + while ((key = PyIter_Next(it)) != NULL) { + rv = dict_contains((_PyDictViewObject *)self, key); + if (rv < 0) { + goto error; + } + if (rv) { + if (PySet_Add(result, key)) { + goto error; + } + } + Py_DECREF(key); + } + Py_DECREF(it); + if (PyErr_Occurred()) { + Py_DECREF(result); + return NULL; + } return result; + +error: + Py_DECREF(it); + Py_DECREF(result); + Py_DECREF(key); + return NULL; } static PyObject* |