1 # Access WeakSet through the weakref module.
2 # This code is separated-out because it is needed
3 # by abc.py to load everything else at startup.
5 from _weakref
import ref
10 class _IterationGuard(object):
11 # This context manager registers itself in the current iterators of the
12 # weak container, such as to delay all removals until the context manager
14 # This technique should be relatively thread-safe (since sets are).
16 def __init__(self
, weakcontainer
):
18 self
.weakcontainer
= ref(weakcontainer
)
21 w
= self
.weakcontainer()
23 w
._iterating
.add(self
)
26 def __exit__(self
, e
, t
, b
):
27 w
= self
.weakcontainer()
35 class WeakSet(object):
36 def __init__(self
, data
=None):
38 def _remove(item
, selfref
=ref(self
)):
42 self
._pending
_removals
.append(item
)
44 self
.data
.discard(item
)
45 self
._remove
= _remove
46 # A list of keys to be removed
47 self
._pending
_removals
= []
48 self
._iterating
= set()
52 def _commit_removals(self
):
53 l
= self
._pending
_removals
54 discard
= self
.data
.discard
59 with
_IterationGuard(self
):
60 for itemref
in self
.data
:
66 return sum(x() is not None for x
in self
.data
)
68 def __contains__(self
, item
):
69 return ref(item
) in self
.data
72 return (self
.__class
__, (list(self
),),
73 getattr(self
, '__dict__', None))
78 if self
._pending
_removals
:
79 self
._commit
_removals
()
80 self
.data
.add(ref(item
, self
._remove
))
83 if self
._pending
_removals
:
84 self
._commit
_removals
()
88 return self
.__class
__(self
)
91 if self
._pending
_removals
:
92 self
._commit
_removals
()
95 itemref
= self
.data
.pop()
97 raise KeyError('pop from empty WeakSet')
102 def remove(self
, item
):
103 if self
._pending
_removals
:
104 self
._commit
_removals
()
105 self
.data
.remove(ref(item
))
107 def discard(self
, item
):
108 if self
._pending
_removals
:
109 self
._commit
_removals
()
110 self
.data
.discard(ref(item
))
112 def update(self
, other
):
113 if self
._pending
_removals
:
114 self
._commit
_removals
()
115 if isinstance(other
, self
.__class
__):
116 self
.data
.update(other
.data
)
118 for element
in other
:
121 def __ior__(self
, other
):
125 # Helper functions for simple delegating methods.
126 def _apply(self
, other
, method
):
127 if not isinstance(other
, self
.__class
__):
128 other
= self
.__class
__(other
)
129 newdata
= method(other
.data
)
130 newset
= self
.__class
__()
131 newset
.data
= newdata
134 def difference(self
, other
):
135 return self
._apply
(other
, self
.data
.difference
)
138 def difference_update(self
, other
):
139 if self
._pending
_removals
:
140 self
._commit
_removals
()
144 self
.data
.difference_update(ref(item
) for item
in other
)
145 def __isub__(self
, other
):
146 if self
._pending
_removals
:
147 self
._commit
_removals
()
151 self
.data
.difference_update(ref(item
) for item
in other
)
154 def intersection(self
, other
):
155 return self
._apply
(other
, self
.data
.intersection
)
156 __and__
= intersection
158 def intersection_update(self
, other
):
159 if self
._pending
_removals
:
160 self
._commit
_removals
()
161 self
.data
.intersection_update(ref(item
) for item
in other
)
162 def __iand__(self
, other
):
163 if self
._pending
_removals
:
164 self
._commit
_removals
()
165 self
.data
.intersection_update(ref(item
) for item
in other
)
168 def issubset(self
, other
):
169 return self
.data
.issubset(ref(item
) for item
in other
)
172 def __le__(self
, other
):
173 return self
.data
<= set(ref(item
) for item
in other
)
175 def issuperset(self
, other
):
176 return self
.data
.issuperset(ref(item
) for item
in other
)
179 def __ge__(self
, other
):
180 return self
.data
>= set(ref(item
) for item
in other
)
182 def __eq__(self
, other
):
183 if not isinstance(other
, self
.__class
__):
184 return NotImplemented
185 return self
.data
== set(ref(item
) for item
in other
)
187 def symmetric_difference(self
, other
):
188 return self
._apply
(other
, self
.data
.symmetric_difference
)
189 __xor__
= symmetric_difference
191 def symmetric_difference_update(self
, other
):
192 if self
._pending
_removals
:
193 self
._commit
_removals
()
197 self
.data
.symmetric_difference_update(ref(item
) for item
in other
)
198 def __ixor__(self
, other
):
199 if self
._pending
_removals
:
200 self
._commit
_removals
()
204 self
.data
.symmetric_difference_update(ref(item
) for item
in other
)
207 def union(self
, other
):
208 return self
._apply
(other
, self
.data
.union
)
211 def isdisjoint(self
, other
):
212 return len(self
.intersection(other
)) == 0