Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pyrsistent/_pset.py: 59%
92 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-01 06:54 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-01 06:54 +0000
1from collections.abc import Set, Hashable
2import sys
3from pyrsistent._pmap import pmap
6class PSet(object):
7 """
8 Persistent set implementation. Built on top of the persistent map. The set supports all operations
9 in the Set protocol and is Hashable.
11 Do not instantiate directly, instead use the factory functions :py:func:`s` or :py:func:`pset`
12 to create an instance.
14 Random access and insert is log32(n) where n is the size of the set.
16 Some examples:
18 >>> s = pset([1, 2, 3, 1])
19 >>> s2 = s.add(4)
20 >>> s3 = s2.remove(2)
21 >>> s
22 pset([1, 2, 3])
23 >>> s2
24 pset([1, 2, 3, 4])
25 >>> s3
26 pset([1, 3, 4])
27 """
28 __slots__ = ('_map', '__weakref__')
30 def __new__(cls, m):
31 self = super(PSet, cls).__new__(cls)
32 self._map = m
33 return self
35 def __contains__(self, element):
36 return element in self._map
38 def __iter__(self):
39 return iter(self._map)
41 def __len__(self):
42 return len(self._map)
44 def __repr__(self):
45 if not self:
46 return 'p' + str(set(self))
48 return 'pset([{0}])'.format(str(set(self))[1:-1])
50 def __str__(self):
51 return self.__repr__()
53 def __hash__(self):
54 return hash(self._map)
56 def __reduce__(self):
57 # Pickling support
58 return pset, (list(self),)
60 @classmethod
61 def _from_iterable(cls, it, pre_size=8):
62 return PSet(pmap(dict((k, True) for k in it), pre_size=pre_size))
64 def add(self, element):
65 """
66 Return a new PSet with element added
68 >>> s1 = s(1, 2)
69 >>> s1.add(3)
70 pset([1, 2, 3])
71 """
72 return self.evolver().add(element).persistent()
74 def update(self, iterable):
75 """
76 Return a new PSet with elements in iterable added
78 >>> s1 = s(1, 2)
79 >>> s1.update([3, 4, 4])
80 pset([1, 2, 3, 4])
81 """
82 e = self.evolver()
83 for element in iterable:
84 e.add(element)
86 return e.persistent()
88 def remove(self, element):
89 """
90 Return a new PSet with element removed. Raises KeyError if element is not present.
92 >>> s1 = s(1, 2)
93 >>> s1.remove(2)
94 pset([1])
95 """
96 if element in self._map:
97 return self.evolver().remove(element).persistent()
99 raise KeyError("Element '%s' not present in PSet" % repr(element))
101 def discard(self, element):
102 """
103 Return a new PSet with element removed. Returns itself if element is not present.
104 """
105 if element in self._map:
106 return self.evolver().remove(element).persistent()
108 return self
110 class _Evolver(object):
111 __slots__ = ('_original_pset', '_pmap_evolver')
113 def __init__(self, original_pset):
114 self._original_pset = original_pset
115 self._pmap_evolver = original_pset._map.evolver()
117 def add(self, element):
118 self._pmap_evolver[element] = True
119 return self
121 def remove(self, element):
122 del self._pmap_evolver[element]
123 return self
125 def is_dirty(self):
126 return self._pmap_evolver.is_dirty()
128 def persistent(self):
129 if not self.is_dirty():
130 return self._original_pset
132 return PSet(self._pmap_evolver.persistent())
134 def __len__(self):
135 return len(self._pmap_evolver)
137 def copy(self):
138 return self
140 def evolver(self):
141 """
142 Create a new evolver for this pset. For a discussion on evolvers in general see the
143 documentation for the pvector evolver.
145 Create the evolver and perform various mutating updates to it:
147 >>> s1 = s(1, 2, 3)
148 >>> e = s1.evolver()
149 >>> _ = e.add(4)
150 >>> len(e)
151 4
152 >>> _ = e.remove(1)
154 The underlying pset remains the same:
156 >>> s1
157 pset([1, 2, 3])
159 The changes are kept in the evolver. An updated pmap can be created using the
160 persistent() function on the evolver.
162 >>> s2 = e.persistent()
163 >>> s2
164 pset([2, 3, 4])
166 The new pset will share data with the original pset in the same way that would have
167 been done if only using operations on the pset.
168 """
169 return PSet._Evolver(self)
171 # All the operations and comparisons you would expect on a set.
172 #
173 # This is not very beautiful. If we avoid inheriting from PSet we can use the
174 # __slots__ concepts (which requires a new style class) and hopefully save some memory.
175 __le__ = Set.__le__
176 __lt__ = Set.__lt__
177 __gt__ = Set.__gt__
178 __ge__ = Set.__ge__
179 __eq__ = Set.__eq__
180 __ne__ = Set.__ne__
182 __and__ = Set.__and__
183 __or__ = Set.__or__
184 __sub__ = Set.__sub__
185 __xor__ = Set.__xor__
187 issubset = __le__
188 issuperset = __ge__
189 union = __or__
190 intersection = __and__
191 difference = __sub__
192 symmetric_difference = __xor__
194 isdisjoint = Set.isdisjoint
196Set.register(PSet)
197Hashable.register(PSet)
199_EMPTY_PSET = PSet(pmap())
202def pset(iterable=(), pre_size=8):
203 """
204 Creates a persistent set from iterable. Optionally takes a sizing parameter equivalent to that
205 used for :py:func:`pmap`.
207 >>> s1 = pset([1, 2, 3, 2])
208 >>> s1
209 pset([1, 2, 3])
210 """
211 if not iterable:
212 return _EMPTY_PSET
214 return PSet._from_iterable(iterable, pre_size=pre_size)
217def s(*elements):
218 """
219 Create a persistent set.
221 Takes an arbitrary number of arguments to insert into the new set.
223 >>> s1 = s(1, 2, 3, 2)
224 >>> s1
225 pset([1, 2, 3])
226 """
227 return pset(elements)