1 from abc
import abstractmethod
2 from typing
import (TYPE_CHECKING
, AbstractSet
, Any
, Iterable
, Iterator
,
3 Mapping
, MutableSet
, NoReturn
, TypeVar
, Union
)
6 from typing_extensions
import Literal
, Self
, final
12 def __getitem__(self
, v
):
13 if isinstance(v
, tuple):
14 return Union
[tuple(type(i
) for i
in v
)]
21 _T_co
= TypeVar("_T_co", covariant
=True)
37 "trailing_zero_count",
41 # pyright currently doesn't like typing_extensions' definition
42 # -- added to typing in python 3.11
43 def assert_never(arg
):
44 # type: (NoReturn) -> NoReturn
45 raise AssertionError("got to code that's supposed to be unreachable")
48 class OFSet(AbstractSet
[_T_co
]):
49 """ ordered frozen set """
50 __slots__
= "__items",
52 def __init__(self
, items
=()):
53 # type: (Iterable[_T_co]) -> None
54 self
.__items
= {v
: None for v
in items
}
56 def __contains__(self
, x
):
57 return x
in self
.__items
60 return iter(self
.__items
)
63 return len(self
.__items
)
71 return f
"OFSet({list(self)})"
74 class OSet(MutableSet
[_T
]):
75 """ ordered mutable set """
76 __slots__
= "__items",
78 def __init__(self
, items
=()):
79 # type: (Iterable[_T]) -> None
80 self
.__items
= {v
: None for v
in items
}
82 def __contains__(self
, x
):
83 return x
in self
.__items
86 return iter(self
.__items
)
89 return len(self
.__items
)
93 self
.__items
[value
] = None
95 def discard(self
, value
):
97 self
.__items
.pop(value
, None)
102 return f
"OSet({list(self)})"
105 class FMap(Mapping
[_T
, _T_co
]):
106 """ordered frozen hashable mapping"""
107 __slots__
= "__items", "__hash"
109 def __init__(self
, items
=()):
110 # type: (Mapping[_T, _T_co] | Iterable[tuple[_T, _T_co]]) -> None
111 self
.__items
= dict(items
) # type: dict[_T, _T_co]
112 self
.__hash
= None # type: None | int
114 def __getitem__(self
, item
):
115 # type: (_T) -> _T_co
116 return self
.__items
[item
]
119 # type: () -> Iterator[_T]
120 return iter(self
.__items
)
123 return len(self
.__items
)
125 def __eq__(self
, other
):
126 # type: (object) -> bool
127 if isinstance(other
, FMap
):
128 return self
.__items
== other
.__items
129 return super().__eq
__(other
)
132 if self
.__hash
is None:
133 self
.__hash
= hash(frozenset(self
.items()))
137 return f
"FMap({self.__items})"
140 def trailing_zero_count(v
, default
=-1):
141 # type: (int, int) -> int
142 without_bit
= v
& (v
- 1) # clear lowest set bit
143 bit
= v
& ~without_bit
# extract lowest set bit
144 return top_set_bit_index(bit
, default
)
147 def top_set_bit_index(v
, default
=-1):
148 # type: (int, int) -> int
151 return v
.bit_length() - 1
155 # added in cpython 3.10
156 bit_count
= int.bit_count
# type: ignore[attr]
157 except AttributeError:
160 """returns the number of 1 bits in the absolute value of the input"""
161 return bin(abs(v
)).count('1')
164 class BaseBitSet(AbstractSet
[int]):
165 __slots__
= "__bits",
174 def _from_bits(cls
, bits
):
175 # type: (int) -> Self
176 return cls(bits
=bits
)
178 def __init__(self
, items
=(), bits
=0):
179 # type: (Iterable[int], int) -> None
182 raise ValueError("can't store negative integers")
185 raise ValueError("can't store an infinite set")
193 def bits(self
, bits
):
194 # type: (int) -> None
196 raise AttributeError("can't write to frozen bitset's bits")
198 raise ValueError("can't store an infinite set")
201 def __contains__(self
, x
):
202 if isinstance(x
, int) and x
>= 0:
203 return (1 << x
) & self
.bits
!= 0
207 # type: () -> Iterator[int]
210 index
= trailing_zero_count(bits
)
214 def __reversed__(self
):
215 # type: () -> Iterator[int]
218 index
= top_set_bit_index(bits
)
223 return bit_count(self
.bits
)
227 return f
"{self.__class__.__name__}()"
228 if self
.bits
> 0xFFFFFFFF and len(self
) < 10:
230 return f
"{self.__class__.__name__}({v})"
231 return f
"{self.__class__.__name__}(bits={hex(self.bits)})"
233 def __eq__(self
, other
):
234 # type: (object) -> bool
235 if not isinstance(other
, BaseBitSet
):
236 return super().__eq
__(other
)
237 return self
.bits
== other
.bits
239 def __and__(self
, other
):
240 # type: (Iterable[Any]) -> Self
241 if isinstance(other
, BaseBitSet
):
242 return self
._from
_bits
(self
.bits
& other
.bits
)
245 if isinstance(item
, int) and item
>= 0:
247 return self
._from
_bits
(self
.bits
& bits
)
251 def __or__(self
, other
):
252 # type: (Iterable[Any]) -> Self
253 if isinstance(other
, BaseBitSet
):
254 return self
._from
_bits
(self
.bits | other
.bits
)
257 if isinstance(item
, int) and item
>= 0:
259 return self
._from
_bits
(bits
)
263 def __xor__(self
, other
):
264 # type: (Iterable[Any]) -> Self
265 if isinstance(other
, BaseBitSet
):
266 return self
._from
_bits
(self
.bits ^ other
.bits
)
269 if isinstance(item
, int) and item
>= 0:
271 return self
._from
_bits
(bits
)
275 def __sub__(self
, other
):
276 # type: (Iterable[Any]) -> Self
277 if isinstance(other
, BaseBitSet
):
278 return self
._from
_bits
(self
.bits
& ~other
.bits
)
281 if isinstance(item
, int) and item
>= 0:
283 return self
._from
_bits
(bits
)
285 def __rsub__(self
, other
):
286 # type: (Iterable[Any]) -> Self
287 if isinstance(other
, BaseBitSet
):
288 return self
._from
_bits
(~self
.bits
& other
.bits
)
291 if isinstance(item
, int) and item
>= 0:
293 return self
._from
_bits
(~self
.bits
& bits
)
295 def isdisjoint(self
, other
):
296 # type: (Iterable[Any]) -> bool
297 if isinstance(other
, BaseBitSet
):
298 return self
.bits
& other
.bits
== 0
299 return super().isdisjoint(other
)
302 class BitSet(BaseBitSet
, MutableSet
[int]):
303 """Mutable Bit Set"""
311 def add(self
, value
):
312 # type: (int) -> None
314 raise ValueError("can't store negative integers")
315 self
.bits |
= 1 << value
317 def discard(self
, value
):
318 # type: (int) -> None
320 self
.bits
&= ~
(1 << value
)
325 def __ior__(self
, it
):
326 # type: (AbstractSet[Any]) -> Self
327 if isinstance(it
, BaseBitSet
):
330 return super().__ior
__(it
)
332 def __iand__(self
, it
):
333 # type: (AbstractSet[Any]) -> Self
334 if isinstance(it
, BaseBitSet
):
337 return super().__iand
__(it
)
339 def __ixor__(self
, it
):
340 # type: (AbstractSet[Any]) -> Self
341 if isinstance(it
, BaseBitSet
):
344 return super().__ixor
__(it
)
346 def __isub__(self
, it
):
347 # type: (AbstractSet[Any]) -> Self
348 if isinstance(it
, BaseBitSet
):
349 self
.bits
&= ~it
.bits
351 return super().__isub
__(it
)
354 class FBitSet(BaseBitSet
):
364 return super()._hash
()