summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/lib/libstdtypes.tex120
-rw-r--r--Include/setobject.h2
-rw-r--r--Lib/test/test_set.py73
-rw-r--r--Objects/setobject.c285
4 files changed, 328 insertions, 152 deletions
diff --git a/Doc/lib/libstdtypes.tex b/Doc/lib/libstdtypes.tex
index 917ca4b..4eb4595 100644
--- a/Doc/lib/libstdtypes.tex
+++ b/Doc/lib/libstdtypes.tex
@@ -1071,6 +1071,126 @@ Notes:
\versionadded{2.4}
\end{description}
+\subsection{Set Types \label{types-set}}
+\obindex{set}
+
+A \dfn{set} object is an unordered collection of immutable values.
+Common uses include membership testing, removing duplicates from a sequence,
+and computing mathematical operations such as intersection, union, difference,
+and symmetric difference.
+\versionadded{2.4}
+
+Like other collections, sets support \code{\var{x} in \var{set}},
+\code{len(\var{set})}, and \code{for \var{x} in \var{set}}. Being an
+unordered collection, sets do not record element position or order of
+insertion. Accordingly, sets do not support indexing, slicing, or
+other sequence-like behavior.
+
+There are currently two builtin set types, \class{set} and \class{frozenset}.
+The \class{set} type is mutable --- the contents can be changed using methods
+like \method{add()} and \method{remove()}. Since it is mutable, it has no
+hash value and cannot be used as either a dictionary key or as an element of
+another set. The \class{frozenset} type is immutable and hashable --- its
+contents cannot be altered after is created; however, it can be used as
+a dictionary key or as an element of another set.
+
+Instances of \class{set} and \class{frozenset} provide the following operations:
+
+\begin{tableiii}{c|c|l}{code}{Operation}{Equivalent}{Result}
+ \lineiii{len(\var{s})}{}{cardinality of set \var{s}}
+
+ \hline
+ \lineiii{\var{x} in \var{s}}{}
+ {test \var{x} for membership in \var{s}}
+ \lineiii{\var{x} not in \var{s}}{}
+ {test \var{x} for non-membership in \var{s}}
+ \lineiii{\var{s}.issubset(\var{t})}{\code{\var{s} <= \var{t}}}
+ {test whether every element in \var{s} is in \var{t}}
+ \lineiii{\var{s}.issuperset(\var{t})}{\code{\var{s} >= \var{t}}}
+ {test whether every element in \var{t} is in \var{s}}
+
+ \hline
+ \lineiii{\var{s}.union(\var{t})}{\var{s} | \var{t}}
+ {new set with elements from both \var{s} and \var{t}}
+ \lineiii{\var{s}.intersection(\var{t})}{\var{s} \&\ \var{t}}
+ {new set with elements common to \var{s} and \var{t}}
+ \lineiii{\var{s}.difference(\var{t})}{\var{s} - \var{t}}
+ {new set with elements in \var{s} but not in \var{t}}
+ \lineiii{\var{s}.symmetric_difference(\var{t})}{\var{s} \^\ \var{t}}
+ {new set with elements in either \var{s} or \var{t} but not both}
+ \lineiii{\var{s}.copy()}{}
+ {new set with a shallow copy of \var{s}}
+\end{tableiii}
+
+Note, the non-operator versions of \method{union()}, \method{intersection()},
+\method{difference()}, and \method{symmetric_difference()},
+\method{issubset()}, and \method{issuperset()} methods will accept any
+iterable as an argument. In contrast, their operator based counterparts
+require their arguments to be sets. This precludes error-prone constructions
+like \code{set('abc') \&\ 'cbs'} in favor of the more readable
+\code{set('abc').intersection('cbs')}.
+
+Both \class{set} and \class{frozenset} support set to set comparisons.
+Two sets are equal if and only if every element of each set is contained in
+the other (each is a subset of the other).
+A set is less than another set if and only if the first set is a proper
+subset of the second set (is a subset, but is not equal).
+A set is greater than another set if and only if the first set is a proper
+superset of the second set (is a superset, but is not equal).
+
+The subset and equality comparisons do not generalize to a complete
+ordering function. For example, any two disjoint sets are not equal and
+are not subsets of each other, so \emph{all} of the following return
+\code{False}: \code{\var{a}<\var{b}}, \code{\var{a}==\var{b}}, or
+\code{\var{a}>\var{b}}.
+Accordingly, sets do not implement the \method{__cmp__} method.
+
+Since sets only define partial ordering (subset relationships), the output
+of the \method{list.sort()} method is undefined for lists of sets.
+
+For convenience in implementing sets of sets, the \method{__contains__()},
+\method{remove()}, and \method{discard()} methods automatically match
+instances of the \class{set} class their \class{frozenset} counterparts
+inside a set. For example, \code{set('abc') in set([frozenset('abc')])}
+returns \code{True}.
+
+The following table lists operations available for \class{set}
+that do not apply to immutable instances of \class{frozenset}:
+
+\begin{tableiii}{c|c|l}{code}{Operation}{Equivalent}{Result}
+ \lineiii{\var{s}.update(\var{t})}
+ {\var{s} |= \var{t}}
+ {return set \var{s} with elements added from \var{t}}
+ \lineiii{\var{s}.intersection_update(\var{t})}
+ {\var{s} \&= \var{t}}
+ {return set \var{s} keeping only elements also found in \var{t}}
+ \lineiii{\var{s}.difference_update(\var{t})}
+ {\var{s} -= \var{t}}
+ {return set \var{s} after removing elements found in \var{t}}
+ \lineiii{\var{s}.symmetric_difference_update(\var{t})}
+ {\var{s} \textasciicircum= \var{t}}
+ {return set \var{s} with elements from \var{s} or \var{t}
+ but not both}
+
+ \hline
+ \lineiii{\var{s}.add(\var{x})}{}
+ {add element \var{x} to set \var{s}}
+ \lineiii{\var{s}.remove(\var{x})}{}
+ {remove \var{x} from set \var{s}; raises KeyError if not present}
+ \lineiii{\var{s}.discard(\var{x})}{}
+ {removes \var{x} from set \var{s} if present}
+ \lineiii{\var{s}.pop()}{}
+ {remove and return an arbitrary element from \var{s}; raises
+ \exception{KeyError} if empty}
+ \lineiii{\var{s}.clear()}{}
+ {remove all elements from set \var{s}}
+\end{tableiii}
+
+Note, the non-operator versions of the \method{update()},
+\method{intersection_update()}, \method{difference_update()}, and
+\method{symmetric_difference_update()} methods will accept any iterable
+as an argument.
+
\subsection{Mapping Types \label{typesmapping}}
\obindex{mapping}
diff --git a/Include/setobject.h b/Include/setobject.h
index 6289f9c..267e3b0 100644
--- a/Include/setobject.h
+++ b/Include/setobject.h
@@ -20,7 +20,7 @@ typedef struct {
PyAPI_DATA(PyTypeObject) PySet_Type;
PyAPI_DATA(PyTypeObject) PyFrozenSet_Type;
-
+#define PyFrozenSet_CheckExact(ob) ((ob)->ob_type == &PyFrozenSet_Type)
#define PyAnySet_Check(ob) \
((ob)->ob_type == &PySet_Type || (ob)->ob_type == &PyFrozenSet_Type || \
PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \
diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py
index 939e490..f3cdc17 100644
--- a/Lib/test/test_set.py
+++ b/Lib/test/test_set.py
@@ -46,6 +46,11 @@ class TestJointOps(unittest.TestCase):
self.assertEqual(type(u), self.thetype)
self.assertRaises(PassThru, self.s.union, check_pass_thru())
self.assertRaises(TypeError, self.s.union, [[]])
+ for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+ self.assertEqual(self.thetype('abcba').union(C('cdc')), set('abcd'))
+ self.assertEqual(self.thetype('abcba').union(C('efgfe')), set('abcefg'))
+ self.assertEqual(self.thetype('abcba').union(C('ccb')), set('abc'))
+ self.assertEqual(self.thetype('abcba').union(C('ef')), set('abcef'))
def test_or(self):
i = self.s.union(self.otherword)
@@ -65,6 +70,11 @@ class TestJointOps(unittest.TestCase):
self.assertEqual(self.s, self.thetype(self.word))
self.assertEqual(type(i), self.thetype)
self.assertRaises(PassThru, self.s.intersection, check_pass_thru())
+ for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+ self.assertEqual(self.thetype('abcba').intersection(C('cdc')), set('cc'))
+ self.assertEqual(self.thetype('abcba').intersection(C('efgfe')), set(''))
+ self.assertEqual(self.thetype('abcba').intersection(C('ccb')), set('bc'))
+ self.assertEqual(self.thetype('abcba').intersection(C('ef')), set(''))
def test_and(self):
i = self.s.intersection(self.otherword)
@@ -85,6 +95,11 @@ class TestJointOps(unittest.TestCase):
self.assertEqual(type(i), self.thetype)
self.assertRaises(PassThru, self.s.difference, check_pass_thru())
self.assertRaises(TypeError, self.s.difference, [[]])
+ for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+ self.assertEqual(self.thetype('abcba').difference(C('cdc')), set('ab'))
+ self.assertEqual(self.thetype('abcba').difference(C('efgfe')), set('abc'))
+ self.assertEqual(self.thetype('abcba').difference(C('ccb')), set('a'))
+ self.assertEqual(self.thetype('abcba').difference(C('ef')), set('abc'))
def test_sub(self):
i = self.s.difference(self.otherword)
@@ -105,6 +120,11 @@ class TestJointOps(unittest.TestCase):
self.assertEqual(type(i), self.thetype)
self.assertRaises(PassThru, self.s.symmetric_difference, check_pass_thru())
self.assertRaises(TypeError, self.s.symmetric_difference, [[]])
+ for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+ self.assertEqual(self.thetype('abcba').symmetric_difference(C('cdc')), set('abd'))
+ self.assertEqual(self.thetype('abcba').symmetric_difference(C('efgfe')), set('abcefg'))
+ self.assertEqual(self.thetype('abcba').symmetric_difference(C('ccb')), set('a'))
+ self.assertEqual(self.thetype('abcba').symmetric_difference(C('ef')), set('abcef'))
def test_xor(self):
i = self.s.symmetric_difference(self.otherword)
@@ -191,7 +211,8 @@ class TestSet(TestJointOps):
def test_clear(self):
self.s.clear()
- self.assertEqual(self.s, set([]))
+ self.assertEqual(self.s, set())
+ self.assertEqual(len(self.s), 0)
def test_copy(self):
dup = self.s.copy()
@@ -201,6 +222,9 @@ class TestSet(TestJointOps):
def test_add(self):
self.s.add('Q')
self.assert_('Q' in self.s)
+ dup = self.s.copy()
+ self.s.add('Q')
+ self.assertEqual(self.s, dup)
self.assertRaises(TypeError, self.s.add, [])
def test_remove(self):
@@ -231,13 +255,18 @@ class TestSet(TestJointOps):
self.assert_(elem not in self.s)
self.assertRaises(KeyError, self.s.pop)
- def test_union_update(self):
- retval = self.s.union_update(self.otherword)
+ def test_update(self):
+ retval = self.s.update(self.otherword)
self.assertEqual(retval, None)
for c in (self.word + self.otherword):
self.assert_(c in self.s)
- self.assertRaises(PassThru, self.s.union_update, check_pass_thru())
- self.assertRaises(TypeError, self.s.union_update, [[]])
+ self.assertRaises(PassThru, self.s.update, check_pass_thru())
+ self.assertRaises(TypeError, self.s.update, [[]])
+ for p, q in (('cdc', 'abcd'), ('efgfe', 'abcefg'), ('ccb', 'abc'), ('ef', 'abcef')):
+ for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+ s = self.thetype('abcba')
+ self.assertEqual(s.update(C(p)), None)
+ self.assertEqual(s, set(q))
def test_ior(self):
self.s |= set(self.otherword)
@@ -254,6 +283,11 @@ class TestSet(TestJointOps):
self.assert_(c not in self.s)
self.assertRaises(PassThru, self.s.intersection_update, check_pass_thru())
self.assertRaises(TypeError, self.s.intersection_update, [[]])
+ for p, q in (('cdc', 'c'), ('efgfe', ''), ('ccb', 'bc'), ('ef', '')):
+ for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+ s = self.thetype('abcba')
+ self.assertEqual(s.intersection_update(C(p)), None)
+ self.assertEqual(s, set(q))
def test_iand(self):
self.s &= set(self.otherword)
@@ -273,6 +307,12 @@ class TestSet(TestJointOps):
self.assert_(c not in self.s)
self.assertRaises(PassThru, self.s.difference_update, check_pass_thru())
self.assertRaises(TypeError, self.s.difference_update, [[]])
+ self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])
+ for p, q in (('cdc', 'ab'), ('efgfe', 'abc'), ('ccb', 'a'), ('ef', 'abc')):
+ for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+ s = self.thetype('abcba')
+ self.assertEqual(s.difference_update(C(p)), None)
+ self.assertEqual(s, set(q))
def test_isub(self):
self.s -= set(self.otherword)
@@ -292,6 +332,11 @@ class TestSet(TestJointOps):
self.assert_(c not in self.s)
self.assertRaises(PassThru, self.s.symmetric_difference_update, check_pass_thru())
self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])
+ for p, q in (('cdc', 'abd'), ('efgfe', 'abcefg'), ('ccb', 'a'), ('ef', 'abcef')):
+ for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
+ s = self.thetype('abcba')
+ self.assertEqual(s.symmetric_difference_update(C(p)), None)
+ self.assertEqual(s, set(q))
def test_ixor(self):
self.s ^= set(self.otherword)
@@ -635,7 +680,7 @@ class TestUpdateOps(unittest.TestCase):
self.assertEqual(self.set, set([2, 4, 6, 8]))
def test_union_method_call(self):
- self.set.union_update(set([3, 4, 5]))
+ self.set.update(set([3, 4, 5]))
self.assertEqual(self.set, set([2, 3, 4, 5, 6]))
def test_intersection_subset(self):
@@ -761,15 +806,15 @@ class TestMutate(unittest.TestCase):
self.failUnless(v in popped)
def test_update_empty_tuple(self):
- self.set.union_update(())
+ self.set.update(())
self.assertEqual(self.set, set(self.values))
def test_update_unit_tuple_overlap(self):
- self.set.union_update(("a",))
+ self.set.update(("a",))
self.assertEqual(self.set, set(self.values))
def test_update_unit_tuple_non_overlap(self):
- self.set.union_update(("a", "z"))
+ self.set.update(("a", "z"))
self.assertEqual(self.set, set(self.values + ["z"]))
#==============================================================================
@@ -872,7 +917,7 @@ class TestOnlySetsInBinaryOps(unittest.TestCase):
self.assertRaises(TypeError, lambda: self.other > self.set)
self.assertRaises(TypeError, lambda: self.other >= self.set)
- def test_union_update_operator(self):
+ def test_update_operator(self):
try:
self.set |= self.other
except TypeError:
@@ -880,11 +925,11 @@ class TestOnlySetsInBinaryOps(unittest.TestCase):
else:
self.fail("expected TypeError")
- def test_union_update(self):
+ def test_update(self):
if self.otherIsIterable:
- self.set.union_update(self.other)
+ self.set.update(self.other)
else:
- self.assertRaises(TypeError, self.set.union_update, self.other)
+ self.assertRaises(TypeError, self.set.update, self.other)
def test_union(self):
self.assertRaises(TypeError, lambda: self.set | self.other)
@@ -1215,7 +1260,7 @@ class TestVariousIteratorArgs(unittest.TestCase):
def test_inplace_methods(self):
for data in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5), 'december'):
- for methname in ('union_update', 'intersection_update',
+ for methname in ('update', 'intersection_update',
'difference_update', 'symmetric_difference_update'):
for g in (G, I, Ig, S, L, R):
s = set('january')
diff --git a/Objects/setobject.c b/Objects/setobject.c
index fab07fb..01f0588 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -12,48 +12,44 @@
static PyObject *
make_new_set(PyTypeObject *type, PyObject *iterable)
{
- PyObject *data;
+ PyObject *data = NULL;
PyObject *it = NULL;
PyObject *item;
- PySetObject *so;
+ PySetObject *so = NULL;
/* Get iterator. */
if (iterable != NULL) {
it = PyObject_GetIter(iterable);
if (it == NULL)
- return NULL;
+ goto done;
}
data = PyDict_New();
- if (data == NULL) {
- Py_DECREF(it);
- return NULL;
- }
+ if (data == NULL)
+ goto done;
while (it != NULL && (item = PyIter_Next(it)) != NULL) {
if (PyDict_SetItem(data, item, Py_True) == -1) {
- Py_DECREF(it);
- Py_DECREF(data);
Py_DECREF(item);
- return NULL;
+ goto done;
}
Py_DECREF(item);
}
- Py_XDECREF(it);
- if (PyErr_Occurred()) {
- Py_DECREF(data);
- return NULL;
- }
+ if (PyErr_Occurred())
+ goto done;
/* create PySetObject structure */
so = (PySetObject *)type->tp_alloc(type, 0);
- if (so == NULL) {
- Py_DECREF(data);
- return NULL;
- }
+ if (so == NULL)
+ goto done;
+
+ Py_INCREF(data);
so->data = data;
so->hash = -1;
+done:
+ Py_XDECREF(data);
+ Py_XDECREF(it);
return (PyObject *)so;
}
@@ -64,7 +60,7 @@ frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable))
return NULL;
- if (iterable != NULL && iterable->ob_type == &PyFrozenSet_Type) {
+ if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) {
Py_INCREF(iterable);
return iterable;
}
@@ -161,7 +157,7 @@ set_copy(PySetObject *so)
static PyObject *
frozenset_copy(PySetObject *so)
{
- if (so->ob_type == &PyFrozenSet_Type) {
+ if (PyFrozenSet_CheckExact(so)) {
Py_INCREF(so);
return (PyObject *)so;
}
@@ -171,52 +167,6 @@ frozenset_copy(PySetObject *so)
PyDoc_STRVAR(copy_doc, "Return a shallow copy of a set.");
static PyObject *
-set_union(PySetObject *so, PyObject *other)
-{
- PySetObject *result;
- PyObject *item, *data, *it;
-
- result = (PySetObject *)set_copy(so);
- if (result == NULL)
- return NULL;
-
- if (PyAnySet_Check(other)) {
- if (PyDict_Merge(result->data, ((PySetObject *)other)->data, 0) == -1) {
- Py_DECREF(result);
- return NULL;
- }
- return (PyObject *)result;
- }
-
- it = PyObject_GetIter(other);
- if (it == NULL) {
- Py_DECREF(result);
- return NULL;
- }
- data = result->data;
- while ((item = PyIter_Next(it)) != NULL) {
- if (PyDict_SetItem(data, item, Py_True) == -1) {
- Py_DECREF(it);
- Py_DECREF(result);
- Py_DECREF(item);
- return NULL;
- }
- Py_DECREF(item);
- }
- Py_DECREF(it);
- if (PyErr_Occurred()) {
- Py_DECREF(result);
- return NULL;
- }
- return (PyObject *)result;
-}
-
-PyDoc_STRVAR(union_doc,
- "Return the union of two sets as a new set.\n\
-\n\
-(i.e. all elements that are in either set.)");
-
-static PyObject *
set_union_update(PySetObject *so, PyObject *other)
{
PyObject *item, *data, *it;
@@ -224,8 +174,7 @@ set_union_update(PySetObject *so, PyObject *other)
if (PyAnySet_Check(other)) {
if (PyDict_Merge(so->data, ((PySetObject *)other)->data, 0) == -1)
return NULL;
- Py_INCREF(so);
- return (PyObject *)so;
+ Py_RETURN_NONE;
}
it = PyObject_GetIter(other);
@@ -251,6 +200,29 @@ PyDoc_STRVAR(union_update_doc,
"Update a set with the union of itself and another.");
static PyObject *
+set_union(PySetObject *so, PyObject *other)
+{
+ PySetObject *result;
+ PyObject *rv;
+
+ result = (PySetObject *)set_copy(so);
+ if (result == NULL)
+ return NULL;
+ rv = set_union_update(result, other);
+ if (rv == NULL) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ Py_DECREF(rv);
+ return (PyObject *)result;
+}
+
+PyDoc_STRVAR(union_doc,
+ "Return the union of two sets as a new set.\n\
+\n\
+(i.e. all elements that are in either set.)");
+
+static PyObject *
set_or(PySetObject *so, PyObject *other)
{
if (!PyAnySet_Check(so) || !PyAnySet_Check(other)) {
@@ -286,15 +258,25 @@ set_intersection(PySetObject *so, PyObject *other)
result = (PySetObject *)make_new_set(so->ob_type, NULL);
if (result == NULL)
return NULL;
-
+ tgtdata = result->data;
+ selfdata = so->data;
+
+ if (PyAnySet_Check(other) &&
+ PyDict_Size(((PySetObject *)other)->data) > PyDict_Size(selfdata)) {
+ selfdata = ((PySetObject *)other)->data;
+ other = (PyObject *)so;
+ } else if (PyDict_Check(other) &&
+ PyDict_Size(other) > PyDict_Size(selfdata)) {
+ selfdata = other;
+ other = so->data;
+ }
+
it = PyObject_GetIter(other);
if (it == NULL) {
Py_DECREF(result);
return NULL;
}
- selfdata = so->data;
- tgtdata = result->data;
while ((item = PyIter_Next(it)) != NULL) {
if (PySequence_Contains(selfdata, item)) {
if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
@@ -390,27 +372,39 @@ set_iand(PySetObject *so, PyObject *other)
static PyObject *
set_difference(PySetObject *so, PyObject *other)
{
- PySetObject *result;
- PyObject *item, *tgtdata, *it;
+ PySetObject *result, *otherset=NULL;
+ PyObject *item, *otherdata, *tgtdata, *it;
- result = (PySetObject *)set_copy(so);
+ result = (PySetObject *)make_new_set(so->ob_type, NULL);
if (result == NULL)
return NULL;
-
- it = PyObject_GetIter(other);
+ tgtdata = result->data;
+
+ if (PyDict_Check(other))
+ otherdata = other;
+ else if (PyAnySet_Check(other))
+ otherdata = ((PySetObject *)other)->data;
+ else {
+ otherset = (PySetObject *)make_new_set(so->ob_type, other);
+ if (otherset == NULL) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ otherdata = otherset->data;
+ }
+
+ it = PyObject_GetIter(so->data);
if (it == NULL) {
+ Py_XDECREF(otherset);
Py_DECREF(result);
return NULL;
}
- tgtdata = result->data;
while ((item = PyIter_Next(it)) != NULL) {
- if (PyDict_DelItem(tgtdata, item) == -1) {
- if (PyErr_ExceptionMatches(PyExc_KeyError))
- PyErr_Clear();
- else {
+ if (!PySequence_Contains(otherdata, item)) {
+ if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
+ Py_XDECREF(otherset);
Py_DECREF(it);
- Py_DECREF(result);
Py_DECREF(item);
return NULL;
}
@@ -418,6 +412,7 @@ set_difference(PySetObject *so, PyObject *other)
Py_DECREF(item);
}
Py_DECREF(it);
+ Py_XDECREF(otherset);
if (PyErr_Occurred()) {
Py_DECREF(result);
return NULL;
@@ -489,99 +484,112 @@ set_isub(PySetObject *so, PyObject *other)
}
static PyObject *
-set_symmetric_difference(PySetObject *so, PyObject *other)
+set_symmetric_difference_update(PySetObject *so, PyObject *other)
{
- PySetObject *result, *otherset=NULL;
- PyObject *item, *selfdata, *otherdata, *tgtdata, *it;
+ PyObject *item, *selfdata, *it, *otherdata;
+ PySetObject *otherset = NULL;
selfdata = so->data;
- result = (PySetObject *)set_copy(so);
- if (result == NULL)
- return NULL;
- tgtdata = result->data;
-
if (PyDict_Check(other))
otherdata = other;
else if (PyAnySet_Check(other))
otherdata = ((PySetObject *)other)->data;
else {
otherset = (PySetObject *)make_new_set(so->ob_type, other);
- if (otherset == NULL) {
- Py_DECREF(result);
+ if (otherset == NULL)
return NULL;
- }
otherdata = otherset->data;
- }
+ }
it = PyObject_GetIter(otherdata);
- if (it == NULL) {
- Py_XDECREF(otherset);
- Py_DECREF(result);
+ if (it == NULL)
return NULL;
- }
while ((item = PyIter_Next(it)) != NULL) {
- if (PyDict_DelItem(tgtdata, item) == -1) {
- PyErr_Clear();
- if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
+ if (PySequence_Contains(selfdata, item)) {
+ if (PyDict_DelItem(selfdata, item) == -1) {
+ Py_XDECREF(otherset);
Py_DECREF(it);
+ Py_DECREF(item);
+ return NULL;
+ }
+ } else {
+ if (PyDict_SetItem(selfdata, item, Py_True) == -1) {
Py_XDECREF(otherset);
- Py_DECREF(result);
+ Py_DECREF(it);
Py_DECREF(item);
return NULL;
- }
+ }
}
Py_DECREF(item);
}
- Py_DECREF(it);
Py_XDECREF(otherset);
- if (PyErr_Occurred()) {
- Py_DECREF(result);
+ Py_DECREF(it);
+ if (PyErr_Occurred())
return NULL;
- }
- return (PyObject *)result;
+ Py_RETURN_NONE;
}
-PyDoc_STRVAR(symmetric_difference_doc,
-"Return the symmetric difference of two sets as a new set.\n\
-\n\
-(i.e. all elements that are in exactly one of the sets.)");
+PyDoc_STRVAR(symmetric_difference_update_doc,
+"Update a set with the symmetric difference of itself and another.");
static PyObject *
-set_symmetric_difference_update(PySetObject *so, PyObject *other)
+set_symmetric_difference(PySetObject *so, PyObject *other)
{
- PyObject *item, *selfdata, *it, *otherdata;
- PySetObject *otherset = NULL;
-
- selfdata = so->data;
+ PySetObject *result;
+ PyObject *item, *selfdata, *otherdata, *tgtdata, *it, *rv, *otherset;
if (PyDict_Check(other))
otherdata = other;
else if (PyAnySet_Check(other))
otherdata = ((PySetObject *)other)->data;
else {
- otherset = (PySetObject *)make_new_set(so->ob_type, other);
+ otherset = make_new_set(so->ob_type, other);
if (otherset == NULL)
return NULL;
- otherdata = otherset->data;
- }
+ rv = set_symmetric_difference_update((PySetObject *)otherset, (PyObject *)so);
+ if (rv == NULL)
+ return NULL;
+ Py_DECREF(rv);
+ return otherset;
+ }
- it = PyObject_GetIter(otherdata);
- if (it == NULL)
+ result = (PySetObject *)make_new_set(so->ob_type, NULL);
+ if (result == NULL)
return NULL;
+ tgtdata = result->data;
+ selfdata = so->data;
+ it = PyObject_GetIter(otherdata);
+ if (it == NULL) {
+ Py_DECREF(result);
+ return NULL;
+ }
while ((item = PyIter_Next(it)) != NULL) {
- if (PySequence_Contains(selfdata, item)) {
- if (PyDict_DelItem(selfdata, item) == -1) {
- Py_XDECREF(otherset);
+ if (!PySequence_Contains(selfdata, item)) {
+ if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
Py_DECREF(it);
Py_DECREF(item);
return NULL;
}
- } else {
- if (PyDict_SetItem(selfdata, item, Py_True) == -1) {
- Py_XDECREF(otherset);
+ }
+ Py_DECREF(item);
+ }
+ Py_DECREF(it);
+ if (PyErr_Occurred()) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ it = PyObject_GetIter(selfdata);
+ if (it == NULL) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ while ((item = PyIter_Next(it)) != NULL) {
+ if (!PySequence_Contains(otherdata, item)) {
+ if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
Py_DECREF(it);
Py_DECREF(item);
return NULL;
@@ -589,15 +597,19 @@ set_symmetric_difference_update(PySetObject *so, PyObject *other)
}
Py_DECREF(item);
}
- Py_XDECREF(otherset);
Py_DECREF(it);
- if (PyErr_Occurred())
+ if (PyErr_Occurred()) {
+ Py_DECREF(result);
return NULL;
- Py_RETURN_NONE;
+ }
+
+ return (PyObject *)result;
}
-PyDoc_STRVAR(symmetric_difference_update_doc,
-"Update a set with the symmetric difference of itself and another.");
+PyDoc_STRVAR(symmetric_difference_doc,
+"Return the symmetric difference of two sets as a new set.\n\
+\n\
+(i.e. all elements that are in exactly one of the sets.)");
static PyObject *
set_xor(PySetObject *so, PyObject *other)
@@ -1012,7 +1024,7 @@ static PyMethodDef set_methods[] = {
symmetric_difference_update_doc},
{"union", (PyCFunction)set_union, METH_O,
union_doc},
- {"union_update",(PyCFunction)set_union_update, METH_O,
+ {"update", (PyCFunction)set_union_update, METH_O,
union_update_doc},
{NULL, NULL} /* sentinel */
};
@@ -1159,8 +1171,7 @@ PyTypeObject PyFrozenSet_Type = {
0, /* ob_size */
"frozenset", /* tp_name */
sizeof(PySetObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
+ 0, /* tp_itemsize */ /* methods */
(destructor)set_dealloc, /* tp_dealloc */
(printfunc)set_tp_print, /* tp_print */
0, /* tp_getattr */