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)
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.
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)
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.
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.
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.
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()
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:
- From a node and container:
TreeIterator(node, container) - Copy of a TreeIterator:
TreeIterator(other) - 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.
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.
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
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()
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:
- From a node and container:
ReverseIterator(node, container) - Copy of a ReverseIterator:
ReverseIterator(other) - 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.
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).
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).