Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Lib/test/test_dictviews.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,27 @@ def test_keys_set_operations(self):
d1 = {'a': 1, 'b': 2}
d2 = {'b': 3, 'c': 2}
d3 = {'d': 4, 'e': 5}
d4 = {'d': 4}

class CustomSet(set):
def intersection(self, other):
return CustomSet(super().intersection(other))

self.assertEqual(d1.keys() & d1.keys(), {'a', 'b'})
self.assertEqual(d1.keys() & d2.keys(), {'b'})
self.assertEqual(d1.keys() & d3.keys(), set())
self.assertEqual(d1.keys() & set(d1.keys()), {'a', 'b'})
self.assertEqual(d1.keys() & set(d2.keys()), {'b'})
self.assertEqual(d1.keys() & set(d3.keys()), set())
self.assertEqual(d1.keys() & tuple(d1.keys()), {'a', 'b'})
self.assertEqual(d3.keys() & d4.keys(), {'d'})
self.assertEqual(d4.keys() & d3.keys(), {'d'})
self.assertEqual(d4.keys() & set(d3.keys()), {'d'})
self.assertIsInstance(d4.keys() & frozenset(d3.keys()), set)
self.assertIsInstance(frozenset(d3.keys()) & d4.keys(), set)
self.assertIs(type(d4.keys() & CustomSet(d3.keys())), set)
self.assertIs(type(d1.keys() & []), set)
self.assertIs(type([] & d1.keys()), set)

self.assertEqual(d1.keys() | d1.keys(), {'a', 'b'})
self.assertEqual(d1.keys() | d2.keys(), {'a', 'b', 'c'})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve speed of dictview intersection by directly using set intersection
logic. Patch by David Su.
81 changes: 77 additions & 4 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Comment thread
rhettinger marked this conversation as resolved.
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)) {
Comment thread
rhettinger marked this conversation as resolved.
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*
Expand Down