stl_treemap.iterators

STL-like forward and reverse iterators for tree containers.

  1"""STL-like forward and reverse iterators for tree containers."""
  2
  3from __future__ import annotations
  4
  5from abc import ABC, abstractmethod
  6from typing import Any, Protocol
  7
  8from stl_treemap.tree_node import TreeNode
  9
 10
 11class IterableContainer(Protocol):
 12    """Protocol for containers that support forward and backward node traversal."""
 13
 14    def next(self, node: Any) -> Any:
 15        """Return the node following *node* in forward order."""
 16        ...
 17
 18    def prev(self, node: Any) -> Any:
 19        """Return the node preceding *node* in forward order."""
 20        ...
 21
 22
 23class BaseIterator[K, V, C: IterableContainer](ABC):
 24    """
 25    Base class for STL-like iterators.
 26
 27    References a node and a container. Navigation is achieved by calling
 28    the container's prev() and next() methods.
 29    """
 30
 31    def __init__(self, node: TreeNode[K, V], container: C) -> None:
 32        """
 33        Create an iterator from a node and a container.
 34
 35        Args:
 36            node: Start node.
 37            container: Container to traverse.
 38
 39        """
 40        self._n = node
 41        self._c = container
 42
 43    @abstractmethod
 44    def next(self) -> None:
 45        """Advance to the next node."""
 46
 47    @abstractmethod
 48    def prev(self) -> None:
 49        """Retreat to the previous node."""
 50
 51    def equals(self, rhs: object) -> bool:
 52        """
 53        Check equality of two iterators.
 54
 55        Two iterators are equal when they point to the same node of the same container.
 56
 57        Args:
 58            rhs: Right-hand side iterator.
 59
 60        Returns:
 61            True when both iterators point to the same node of the same container.
 62
 63        Raises:
 64            ValueError: When iterators are of different types.
 65            ValueError: When iterators belong to different containers.
 66
 67        """
 68        if not isinstance(rhs, type(self)):
 69            lhs_class = type(self).__name__
 70            rhs_class = type(rhs).__name__
 71            raise ValueError(f"Can't compare an instance of {lhs_class} with an instance of {rhs_class}")
 72        if self._c is not rhs.container:
 73            raise ValueError("Iterators belong to different containers")
 74        return self._n is rhs.node
 75
 76    @property
 77    def node(self) -> TreeNode[K, V]:
 78        """@private Current node."""
 79        return self._n
 80
 81    @property
 82    def key(self) -> K:
 83        """Key of the current node."""
 84        return self._n.key
 85
 86    @property
 87    def value(self) -> V:
 88        """Value of the current node."""
 89        return self._n.value
 90
 91    @property
 92    def container(self) -> C:
 93        """@private Container that holds the current node."""
 94        return self._c
 95
 96
 97class TreeIterator[K, V, C: IterableContainer](BaseIterator[K, V, C]):
 98    """
 99    STL-like forward iterator.
100
101    More verbose than Python iterators, but allows iteration over any range
102    within the container.
103
104    Example::
105
106        m = TreeMap()
107        it = m.begin()
108        while not it.equals(m.end()):
109            print(f"key: {it.key}, value: {it.value}")
110            it.next()
111    """
112
113    def __init__(self, *args: Any) -> None:
114        """
115        Create a forward iterator.
116
117        Three construction forms are supported:
118
119        1. From a node and container: ``TreeIterator(node, container)``
120        2. Copy of a TreeIterator: ``TreeIterator(other)``
121        3. Convert from ReverseIterator: ``TreeIterator(reverse_iter)``
122
123        Args:
124            *args: Either ``(node, container)`` or a single iterator to copy/convert.
125
126        Raises:
127            ValueError: When arguments are invalid or the source object is unsupported.
128
129        """
130        if len(args) == 2:  # noqa: PLR2004
131            node, container = args
132            super().__init__(node, container)
133        elif len(args) == 1:
134            obj = args[0]
135            if isinstance(obj, TreeIterator):
136                super().__init__(obj._n, obj._c)
137            elif isinstance(obj, ReverseIterator):
138                c = obj._c
139                super().__init__(c.next(obj._n), c)
140            else:
141                raise ValueError(f"Can't create an Iterator from {type(obj).__name__}")
142        else:
143            raise ValueError("Can't create an Iterator with provided parameters")
144
145    def next(self) -> None:
146        """Advance to the next node in the container."""
147        self._n = self._c.next(self._n)
148
149    def prev(self) -> None:
150        """Retreat to the previous node in the container."""
151        self._n = self._c.prev(self._n)
152
153
154class ReverseIterator[K, V, C: IterableContainer](BaseIterator[K, V, C]):
155    """
156    STL-like backward iterator.
157
158    Traverses the container in reverse order: next() moves backward,
159    prev() moves forward.
160
161    Example::
162
163        m = TreeMap()
164        it = m.rbegin()
165        while not it.equals(m.rend()):
166            print(f"key: {it.key}, value: {it.value}")
167            it.next()
168    """
169
170    def __init__(self, *args: Any) -> None:
171        """
172        Create a reverse iterator.
173
174        Three construction forms are supported:
175
176        1. From a node and container: ``ReverseIterator(node, container)``
177        2. Copy of a ReverseIterator: ``ReverseIterator(other)``
178        3. Convert from TreeIterator: ``ReverseIterator(forward_iter)``
179
180        Args:
181            *args: Either ``(node, container)`` or a single iterator to copy/convert.
182
183        Raises:
184            ValueError: When arguments are invalid or the source object is unsupported.
185
186        """
187        if len(args) == 2:  # noqa: PLR2004
188            node, container = args
189            super().__init__(node, container)
190        elif len(args) == 1:
191            obj = args[0]
192            if isinstance(obj, ReverseIterator):
193                super().__init__(obj._n, obj._c)
194            elif isinstance(obj, TreeIterator):
195                c = obj._c
196                super().__init__(c.prev(obj._n), c)
197            else:
198                raise ValueError(f"Can't create an ReverseIterator from {type(obj).__name__}")
199        else:
200            raise ValueError("Can't create a Reverse Iterator with provided parameters")
201
202    def next(self) -> None:
203        """Advance to the previous node in the container (reverse order)."""
204        self._n = self._c.prev(self._n)
205
206    def prev(self) -> None:
207        """Retreat to the next node in the container (reverse order)."""
208        self._n = self._c.next(self._n)
class IterableContainer(typing.Protocol):
12class IterableContainer(Protocol):
13    """Protocol for containers that support forward and backward node traversal."""
14
15    def next(self, node: Any) -> Any:
16        """Return the node following *node* in forward order."""
17        ...
18
19    def prev(self, node: Any) -> Any:
20        """Return the node preceding *node* in forward order."""
21        ...

Protocol for containers that support forward and backward node traversal.

IterableContainer(*args, **kwargs)
1771def _no_init_or_replace_init(self, *args, **kwargs):
1772    cls = type(self)
1773
1774    if cls._is_protocol:
1775        raise TypeError('Protocols cannot be instantiated')
1776
1777    # Already using a custom `__init__`. No need to calculate correct
1778    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1779    if cls.__init__ is not _no_init_or_replace_init:
1780        return
1781
1782    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1783    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1784    # searches for a proper new `__init__` in the MRO. The new `__init__`
1785    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1786    # instantiation of the protocol subclass will thus use the new
1787    # `__init__` and no longer call `_no_init_or_replace_init`.
1788    for base in cls.__mro__:
1789        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1790        if init is not _no_init_or_replace_init:
1791            cls.__init__ = init
1792            break
1793    else:
1794        # should not happen
1795        cls.__init__ = object.__init__
1796
1797    cls.__init__(self, *args, **kwargs)
def next(self, node: Any) -> Any:
15    def next(self, node: Any) -> Any:
16        """Return the node following *node* in forward order."""
17        ...

Return the node following node in forward order.

def prev(self, node: Any) -> Any:
19    def prev(self, node: Any) -> Any:
20        """Return the node preceding *node* in forward order."""
21        ...

Return the node preceding node in forward order.

class BaseIterator(abc.ABC, typing.Generic[K, V, C]):
24class BaseIterator[K, V, C: IterableContainer](ABC):
25    """
26    Base class for STL-like iterators.
27
28    References a node and a container. Navigation is achieved by calling
29    the container's prev() and next() methods.
30    """
31
32    def __init__(self, node: TreeNode[K, V], container: C) -> None:
33        """
34        Create an iterator from a node and a container.
35
36        Args:
37            node: Start node.
38            container: Container to traverse.
39
40        """
41        self._n = node
42        self._c = container
43
44    @abstractmethod
45    def next(self) -> None:
46        """Advance to the next node."""
47
48    @abstractmethod
49    def prev(self) -> None:
50        """Retreat to the previous node."""
51
52    def equals(self, rhs: object) -> bool:
53        """
54        Check equality of two iterators.
55
56        Two iterators are equal when they point to the same node of the same container.
57
58        Args:
59            rhs: Right-hand side iterator.
60
61        Returns:
62            True when both iterators point to the same node of the same container.
63
64        Raises:
65            ValueError: When iterators are of different types.
66            ValueError: When iterators belong to different containers.
67
68        """
69        if not isinstance(rhs, type(self)):
70            lhs_class = type(self).__name__
71            rhs_class = type(rhs).__name__
72            raise ValueError(f"Can't compare an instance of {lhs_class} with an instance of {rhs_class}")
73        if self._c is not rhs.container:
74            raise ValueError("Iterators belong to different containers")
75        return self._n is rhs.node
76
77    @property
78    def node(self) -> TreeNode[K, V]:
79        """@private Current node."""
80        return self._n
81
82    @property
83    def key(self) -> K:
84        """Key of the current node."""
85        return self._n.key
86
87    @property
88    def value(self) -> V:
89        """Value of the current node."""
90        return self._n.value
91
92    @property
93    def container(self) -> C:
94        """@private Container that holds the current node."""
95        return self._c

Base class for STL-like iterators.

References a node and a container. Navigation is achieved by calling the container's prev() and next() methods.

BaseIterator(node: 'TreeNode[K, V]', container: 'C')
32    def __init__(self, node: TreeNode[K, V], container: C) -> None:
33        """
34        Create an iterator from a node and a container.
35
36        Args:
37            node: Start node.
38            container: Container to traverse.
39
40        """
41        self._n = node
42        self._c = container

Create an iterator from a node and a container.

Args: node: Start node. container: Container to traverse.

@abstractmethod
def next(self) -> None:
44    @abstractmethod
45    def next(self) -> None:
46        """Advance to the next node."""

Advance to the next node.

@abstractmethod
def prev(self) -> None:
48    @abstractmethod
49    def prev(self) -> None:
50        """Retreat to the previous node."""

Retreat to the previous node.

def equals(self, rhs: object) -> bool:
52    def equals(self, rhs: object) -> bool:
53        """
54        Check equality of two iterators.
55
56        Two iterators are equal when they point to the same node of the same container.
57
58        Args:
59            rhs: Right-hand side iterator.
60
61        Returns:
62            True when both iterators point to the same node of the same container.
63
64        Raises:
65            ValueError: When iterators are of different types.
66            ValueError: When iterators belong to different containers.
67
68        """
69        if not isinstance(rhs, type(self)):
70            lhs_class = type(self).__name__
71            rhs_class = type(rhs).__name__
72            raise ValueError(f"Can't compare an instance of {lhs_class} with an instance of {rhs_class}")
73        if self._c is not rhs.container:
74            raise ValueError("Iterators belong to different containers")
75        return self._n is rhs.node

Check equality of two iterators.

Two iterators are equal when they point to the same node of the same container.

Args: rhs: Right-hand side iterator.

Returns: True when both iterators point to the same node of the same container.

Raises: ValueError: When iterators are of different types. ValueError: When iterators belong to different containers.

key: 'K'
82    @property
83    def key(self) -> K:
84        """Key of the current node."""
85        return self._n.key

Key of the current node.

value: 'V'
87    @property
88    def value(self) -> V:
89        """Value of the current node."""
90        return self._n.value

Value of the current node.

class TreeIterator(stl_treemap.iterators.BaseIterator[K, V, C], typing.Generic[K, V, C]):
 98class TreeIterator[K, V, C: IterableContainer](BaseIterator[K, V, C]):
 99    """
100    STL-like forward iterator.
101
102    More verbose than Python iterators, but allows iteration over any range
103    within the container.
104
105    Example::
106
107        m = TreeMap()
108        it = m.begin()
109        while not it.equals(m.end()):
110            print(f"key: {it.key}, value: {it.value}")
111            it.next()
112    """
113
114    def __init__(self, *args: Any) -> None:
115        """
116        Create a forward iterator.
117
118        Three construction forms are supported:
119
120        1. From a node and container: ``TreeIterator(node, container)``
121        2. Copy of a TreeIterator: ``TreeIterator(other)``
122        3. Convert from ReverseIterator: ``TreeIterator(reverse_iter)``
123
124        Args:
125            *args: Either ``(node, container)`` or a single iterator to copy/convert.
126
127        Raises:
128            ValueError: When arguments are invalid or the source object is unsupported.
129
130        """
131        if len(args) == 2:  # noqa: PLR2004
132            node, container = args
133            super().__init__(node, container)
134        elif len(args) == 1:
135            obj = args[0]
136            if isinstance(obj, TreeIterator):
137                super().__init__(obj._n, obj._c)
138            elif isinstance(obj, ReverseIterator):
139                c = obj._c
140                super().__init__(c.next(obj._n), c)
141            else:
142                raise ValueError(f"Can't create an Iterator from {type(obj).__name__}")
143        else:
144            raise ValueError("Can't create an Iterator with provided parameters")
145
146    def next(self) -> None:
147        """Advance to the next node in the container."""
148        self._n = self._c.next(self._n)
149
150    def prev(self) -> None:
151        """Retreat to the previous node in the container."""
152        self._n = self._c.prev(self._n)

STL-like forward iterator.

More verbose than Python iterators, but allows iteration over any range within the container.

Example::

m = TreeMap()
it = m.begin()
while not it.equals(m.end()):
    print(f"key: {it.key}, value: {it.value}")
    it.next()
TreeIterator(*args: Any)
114    def __init__(self, *args: Any) -> None:
115        """
116        Create a forward iterator.
117
118        Three construction forms are supported:
119
120        1. From a node and container: ``TreeIterator(node, container)``
121        2. Copy of a TreeIterator: ``TreeIterator(other)``
122        3. Convert from ReverseIterator: ``TreeIterator(reverse_iter)``
123
124        Args:
125            *args: Either ``(node, container)`` or a single iterator to copy/convert.
126
127        Raises:
128            ValueError: When arguments are invalid or the source object is unsupported.
129
130        """
131        if len(args) == 2:  # noqa: PLR2004
132            node, container = args
133            super().__init__(node, container)
134        elif len(args) == 1:
135            obj = args[0]
136            if isinstance(obj, TreeIterator):
137                super().__init__(obj._n, obj._c)
138            elif isinstance(obj, ReverseIterator):
139                c = obj._c
140                super().__init__(c.next(obj._n), c)
141            else:
142                raise ValueError(f"Can't create an Iterator from {type(obj).__name__}")
143        else:
144            raise ValueError("Can't create an Iterator with provided parameters")

Create a forward iterator.

Three construction forms are supported:

  1. From a node and container: TreeIterator(node, container)
  2. Copy of a TreeIterator: TreeIterator(other)
  3. Convert from ReverseIterator: TreeIterator(reverse_iter)

Args: *args: Either (node, container) or a single iterator to copy/convert.

Raises: ValueError: When arguments are invalid or the source object is unsupported.

def next(self) -> None:
146    def next(self) -> None:
147        """Advance to the next node in the container."""
148        self._n = self._c.next(self._n)

Advance to the next node in the container.

def prev(self) -> None:
150    def prev(self) -> None:
151        """Retreat to the previous node in the container."""
152        self._n = self._c.prev(self._n)

Retreat to the previous node in the container.

Inherited Members
BaseIterator
equals
key
value
class ReverseIterator(stl_treemap.iterators.BaseIterator[K, V, C], typing.Generic[K, V, C]):
155class ReverseIterator[K, V, C: IterableContainer](BaseIterator[K, V, C]):
156    """
157    STL-like backward iterator.
158
159    Traverses the container in reverse order: next() moves backward,
160    prev() moves forward.
161
162    Example::
163
164        m = TreeMap()
165        it = m.rbegin()
166        while not it.equals(m.rend()):
167            print(f"key: {it.key}, value: {it.value}")
168            it.next()
169    """
170
171    def __init__(self, *args: Any) -> None:
172        """
173        Create a reverse iterator.
174
175        Three construction forms are supported:
176
177        1. From a node and container: ``ReverseIterator(node, container)``
178        2. Copy of a ReverseIterator: ``ReverseIterator(other)``
179        3. Convert from TreeIterator: ``ReverseIterator(forward_iter)``
180
181        Args:
182            *args: Either ``(node, container)`` or a single iterator to copy/convert.
183
184        Raises:
185            ValueError: When arguments are invalid or the source object is unsupported.
186
187        """
188        if len(args) == 2:  # noqa: PLR2004
189            node, container = args
190            super().__init__(node, container)
191        elif len(args) == 1:
192            obj = args[0]
193            if isinstance(obj, ReverseIterator):
194                super().__init__(obj._n, obj._c)
195            elif isinstance(obj, TreeIterator):
196                c = obj._c
197                super().__init__(c.prev(obj._n), c)
198            else:
199                raise ValueError(f"Can't create an ReverseIterator from {type(obj).__name__}")
200        else:
201            raise ValueError("Can't create a Reverse Iterator with provided parameters")
202
203    def next(self) -> None:
204        """Advance to the previous node in the container (reverse order)."""
205        self._n = self._c.prev(self._n)
206
207    def prev(self) -> None:
208        """Retreat to the next node in the container (reverse order)."""
209        self._n = self._c.next(self._n)

STL-like backward iterator.

Traverses the container in reverse order: next() moves backward, prev() moves forward.

Example::

m = TreeMap()
it = m.rbegin()
while not it.equals(m.rend()):
    print(f"key: {it.key}, value: {it.value}")
    it.next()
ReverseIterator(*args: Any)
171    def __init__(self, *args: Any) -> None:
172        """
173        Create a reverse iterator.
174
175        Three construction forms are supported:
176
177        1. From a node and container: ``ReverseIterator(node, container)``
178        2. Copy of a ReverseIterator: ``ReverseIterator(other)``
179        3. Convert from TreeIterator: ``ReverseIterator(forward_iter)``
180
181        Args:
182            *args: Either ``(node, container)`` or a single iterator to copy/convert.
183
184        Raises:
185            ValueError: When arguments are invalid or the source object is unsupported.
186
187        """
188        if len(args) == 2:  # noqa: PLR2004
189            node, container = args
190            super().__init__(node, container)
191        elif len(args) == 1:
192            obj = args[0]
193            if isinstance(obj, ReverseIterator):
194                super().__init__(obj._n, obj._c)
195            elif isinstance(obj, TreeIterator):
196                c = obj._c
197                super().__init__(c.prev(obj._n), c)
198            else:
199                raise ValueError(f"Can't create an ReverseIterator from {type(obj).__name__}")
200        else:
201            raise ValueError("Can't create a Reverse Iterator with provided parameters")

Create a reverse iterator.

Three construction forms are supported:

  1. From a node and container: ReverseIterator(node, container)
  2. Copy of a ReverseIterator: ReverseIterator(other)
  3. Convert from TreeIterator: ReverseIterator(forward_iter)

Args: *args: Either (node, container) or a single iterator to copy/convert.

Raises: ValueError: When arguments are invalid or the source object is unsupported.

def next(self) -> None:
203    def next(self) -> None:
204        """Advance to the previous node in the container (reverse order)."""
205        self._n = self._c.prev(self._n)

Advance to the previous node in the container (reverse order).

def prev(self) -> None:
207    def prev(self) -> None:
208        """Retreat to the next node in the container (reverse order)."""
209        self._n = self._c.next(self._n)

Retreat to the next node in the container (reverse order).

Inherited Members
BaseIterator
equals
key
value