diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2010-11-30 22:23:20 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2010-11-30 22:23:20 (GMT) |
commit | 715f3cd10d0481a2dd8c1969c4044d068b06cfd5 (patch) | |
tree | a19264728a7400fa860d23fc048c9254d04fbf8d /Objects/setobject.c | |
parent | 697ce959318dab84ec30a9e307e37f17ebcbe224 (diff) | |
download | cpython-715f3cd10d0481a2dd8c1969c4044d068b06cfd5.zip cpython-715f3cd10d0481a2dd8c1969c4044d068b06cfd5.tar.gz cpython-715f3cd10d0481a2dd8c1969c4044d068b06cfd5.tar.bz2 |
Issue #8685: Speed up set difference `a - b` when source set `a` is
much larger than operand `b`. Patch by Andrew Bennetts.
Diffstat (limited to 'Objects/setobject.c')
-rw-r--r-- | Objects/setobject.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/Objects/setobject.c b/Objects/setobject.c index dfafefd..478b5cb 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1525,6 +1525,20 @@ PyDoc_STRVAR(difference_update_doc, "Remove all elements of another set from this set."); static PyObject * +set_copy_and_difference(PySetObject *so, PyObject *other) +{ + PyObject *result; + + result = set_copy(so); + if (result == NULL) + return NULL; + if (set_difference_update_internal((PySetObject *) result, other) != -1) + return result; + Py_DECREF(result); + return NULL; +} + +static PyObject * set_difference(PySetObject *so, PyObject *other) { PyObject *result; @@ -1532,13 +1546,13 @@ set_difference(PySetObject *so, PyObject *other) Py_ssize_t pos = 0; if (!PyAnySet_Check(other) && !PyDict_CheckExact(other)) { - result = set_copy(so); - if (result == NULL) - return NULL; - if (set_difference_update_internal((PySetObject *)result, other) != -1) - return result; - Py_DECREF(result); - return NULL; + return set_copy_and_difference(so, other); + } + + /* If len(so) much more than len(other), it's more efficient to simply copy + * so and then iterate other looking for common elements. */ + if ((PySet_GET_SIZE(so) >> 2) > PyObject_Size(other)) { + return set_copy_and_difference(so, other); } result = make_new_set_basetype(Py_TYPE(so), NULL); @@ -1560,6 +1574,7 @@ set_difference(PySetObject *so, PyObject *other) return result; } + /* Iterate over so, checking for common elements in other. */ while (set_next(so, &pos, &entry)) { int rv = set_contains_entry((PySetObject *)other, entry); if (rv == -1) { |