| |
| import typing as t |
| import weakref |
|
|
|
|
| class Link: |
| """Representation of one item in a doubly-linked list.""" |
|
|
| __slots__ = ("prev", "next", "key", "__weakref__") |
| prev: "Link" |
| next: "Link" |
| key: str |
|
|
|
|
| class OrderedSet(t.MutableSet[str]): |
| """A set that remembers the order in which items were added.""" |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| def __init__(self, iterable: t.Optional[t.Iterable[str]] = None): |
| self.__root = root = Link() |
| root.prev = root.next = root |
| self.__map: t.MutableMapping[str, Link] = {} |
| if iterable is not None: |
| self |= iterable |
|
|
| def __len__(self) -> int: |
| return len(self.__map) |
|
|
| def __contains__(self, key: object) -> bool: |
| return key in self.__map |
|
|
| def add(self, key: str) -> None: |
| |
| if key not in self.__map: |
| self.__map[key] = link = Link() |
| root = self.__root |
| last = root.prev |
| link.prev, link.next, link.key = last, root, key |
| last.next = root.prev = weakref.proxy(link) |
|
|
| def discard(self, key: str) -> None: |
| |
| |
| if key in self.__map: |
| link = self.__map.pop(key) |
| link.prev.next = link.next |
| link.next.prev = link.prev |
|
|
| def __iter__(self) -> t.Generator[str, None, None]: |
| |
| root = self.__root |
| curr = root.next |
| while curr is not root: |
| yield curr.key |
| curr = curr.next |
|
|
| def __reversed__(self) -> t.Generator[str, None, None]: |
| |
| root = self.__root |
| curr = root.prev |
| while curr is not root: |
| yield curr.key |
| curr = curr.prev |
|
|
| def pop(self, last: bool = True) -> str: |
| if not self: |
| raise KeyError("set is empty") |
| key = next(reversed(self)) if last else next(iter(self)) |
| self.discard(key) |
| return key |
|
|
| def __repr__(self) -> str: |
| if not self: |
| return f"{self.__class__.__name__}()" |
| return f"{self.__class__.__name__}({list(self)!r})" |
|
|
| def __str__(self) -> str: |
| return self.__repr__() |
|
|
| def __eq__(self, other: object) -> bool: |
| if isinstance(other, OrderedSet): |
| return len(self) == len(other) and list(self) == list(other) |
| other = t.cast(t.Iterable[str], other) |
| return not self.isdisjoint(other) |
|
|