| 582 | |
| 583 | # Based on http://code.activestate.com/recipes/576694/. |
| 584 | class OrderedSet(MutableSet): # noqa: PLW1641 |
| 585 | # TODO (cclauss): Fix eq-without-hash ruff rule PLW1641 |
| 586 | def __init__(self, iterable=None): |
| 587 | self.end = end = [] |
| 588 | end += [None, end, end] # sentinel node for doubly linked list |
| 589 | self.map = {} # key --> [key, prev, next] |
| 590 | if iterable is not None: |
| 591 | self |= iterable |
| 592 | |
| 593 | def __len__(self): |
| 594 | return len(self.map) |
| 595 | |
| 596 | def __contains__(self, key): |
| 597 | return key in self.map |
| 598 | |
| 599 | def add(self, key): |
| 600 | if key not in self.map: |
| 601 | end = self.end |
| 602 | curr = end[1] |
| 603 | curr[2] = end[1] = self.map[key] = [key, curr, end] |
| 604 | |
| 605 | def discard(self, key): |
| 606 | if key in self.map: |
| 607 | key, prev_item, next_item = self.map.pop(key) |
| 608 | prev_item[2] = next_item |
| 609 | next_item[1] = prev_item |
| 610 | |
| 611 | def __iter__(self): |
| 612 | end = self.end |
| 613 | curr = end[2] |
| 614 | while curr is not end: |
| 615 | yield curr[0] |
| 616 | curr = curr[2] |
| 617 | |
| 618 | def __reversed__(self): |
| 619 | end = self.end |
| 620 | curr = end[1] |
| 621 | while curr is not end: |
| 622 | yield curr[0] |
| 623 | curr = curr[1] |
| 624 | |
| 625 | # The second argument is an addition that causes a pylint warning. |
| 626 | def pop(self, last=True): # pylint: disable=W0221 |
| 627 | if not self: |
| 628 | raise KeyError("set is empty") |
| 629 | key = self.end[1][0] if last else self.end[2][0] |
| 630 | self.discard(key) |
| 631 | return key |
| 632 | |
| 633 | def __repr__(self): |
| 634 | if not self: |
| 635 | return f"{self.__class__.__name__}()" |
| 636 | return f"{self.__class__.__name__}({list(self)!r})" |
| 637 | |
| 638 | def __eq__(self, other): |
| 639 | if isinstance(other, OrderedSet): |
| 640 | return len(self) == len(other) and list(self) == list(other) |
| 641 | return set(self) == set(other) |
no outgoing calls
no test coverage detected