exonware-xwnode 0.0.1.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- exonware/__init__.py +14 -0
- exonware/xwnode/__init__.py +127 -0
- exonware/xwnode/base.py +676 -0
- exonware/xwnode/config.py +178 -0
- exonware/xwnode/contracts.py +730 -0
- exonware/xwnode/errors.py +503 -0
- exonware/xwnode/facade.py +460 -0
- exonware/xwnode/strategies/__init__.py +158 -0
- exonware/xwnode/strategies/advisor.py +463 -0
- exonware/xwnode/strategies/edges/__init__.py +32 -0
- exonware/xwnode/strategies/edges/adj_list.py +227 -0
- exonware/xwnode/strategies/edges/adj_matrix.py +391 -0
- exonware/xwnode/strategies/edges/base.py +169 -0
- exonware/xwnode/strategies/flyweight.py +328 -0
- exonware/xwnode/strategies/impls/__init__.py +13 -0
- exonware/xwnode/strategies/impls/_base_edge.py +403 -0
- exonware/xwnode/strategies/impls/_base_node.py +307 -0
- exonware/xwnode/strategies/impls/edge_adj_list.py +353 -0
- exonware/xwnode/strategies/impls/edge_adj_matrix.py +445 -0
- exonware/xwnode/strategies/impls/edge_bidir_wrapper.py +455 -0
- exonware/xwnode/strategies/impls/edge_block_adj_matrix.py +539 -0
- exonware/xwnode/strategies/impls/edge_coo.py +533 -0
- exonware/xwnode/strategies/impls/edge_csc.py +447 -0
- exonware/xwnode/strategies/impls/edge_csr.py +492 -0
- exonware/xwnode/strategies/impls/edge_dynamic_adj_list.py +503 -0
- exonware/xwnode/strategies/impls/edge_flow_network.py +555 -0
- exonware/xwnode/strategies/impls/edge_hyperedge_set.py +516 -0
- exonware/xwnode/strategies/impls/edge_neural_graph.py +650 -0
- exonware/xwnode/strategies/impls/edge_octree.py +574 -0
- exonware/xwnode/strategies/impls/edge_property_store.py +655 -0
- exonware/xwnode/strategies/impls/edge_quadtree.py +519 -0
- exonware/xwnode/strategies/impls/edge_rtree.py +820 -0
- exonware/xwnode/strategies/impls/edge_temporal_edgeset.py +558 -0
- exonware/xwnode/strategies/impls/edge_tree_graph_basic.py +271 -0
- exonware/xwnode/strategies/impls/edge_weighted_graph.py +411 -0
- exonware/xwnode/strategies/manager.py +775 -0
- exonware/xwnode/strategies/metrics.py +538 -0
- exonware/xwnode/strategies/migration.py +432 -0
- exonware/xwnode/strategies/nodes/__init__.py +50 -0
- exonware/xwnode/strategies/nodes/_base_node.py +307 -0
- exonware/xwnode/strategies/nodes/adjacency_list.py +267 -0
- exonware/xwnode/strategies/nodes/aho_corasick.py +345 -0
- exonware/xwnode/strategies/nodes/array_list.py +209 -0
- exonware/xwnode/strategies/nodes/base.py +247 -0
- exonware/xwnode/strategies/nodes/deque.py +200 -0
- exonware/xwnode/strategies/nodes/hash_map.py +135 -0
- exonware/xwnode/strategies/nodes/heap.py +307 -0
- exonware/xwnode/strategies/nodes/linked_list.py +232 -0
- exonware/xwnode/strategies/nodes/node_aho_corasick.py +520 -0
- exonware/xwnode/strategies/nodes/node_array_list.py +175 -0
- exonware/xwnode/strategies/nodes/node_avl_tree.py +371 -0
- exonware/xwnode/strategies/nodes/node_b_plus_tree.py +542 -0
- exonware/xwnode/strategies/nodes/node_bitmap.py +420 -0
- exonware/xwnode/strategies/nodes/node_bitset_dynamic.py +513 -0
- exonware/xwnode/strategies/nodes/node_bloom_filter.py +347 -0
- exonware/xwnode/strategies/nodes/node_btree.py +357 -0
- exonware/xwnode/strategies/nodes/node_count_min_sketch.py +470 -0
- exonware/xwnode/strategies/nodes/node_cow_tree.py +473 -0
- exonware/xwnode/strategies/nodes/node_cuckoo_hash.py +392 -0
- exonware/xwnode/strategies/nodes/node_fenwick_tree.py +301 -0
- exonware/xwnode/strategies/nodes/node_hash_map.py +269 -0
- exonware/xwnode/strategies/nodes/node_heap.py +191 -0
- exonware/xwnode/strategies/nodes/node_hyperloglog.py +407 -0
- exonware/xwnode/strategies/nodes/node_linked_list.py +409 -0
- exonware/xwnode/strategies/nodes/node_lsm_tree.py +400 -0
- exonware/xwnode/strategies/nodes/node_ordered_map.py +390 -0
- exonware/xwnode/strategies/nodes/node_ordered_map_balanced.py +565 -0
- exonware/xwnode/strategies/nodes/node_patricia.py +512 -0
- exonware/xwnode/strategies/nodes/node_persistent_tree.py +378 -0
- exonware/xwnode/strategies/nodes/node_radix_trie.py +452 -0
- exonware/xwnode/strategies/nodes/node_red_black_tree.py +497 -0
- exonware/xwnode/strategies/nodes/node_roaring_bitmap.py +570 -0
- exonware/xwnode/strategies/nodes/node_segment_tree.py +289 -0
- exonware/xwnode/strategies/nodes/node_set_hash.py +354 -0
- exonware/xwnode/strategies/nodes/node_set_tree.py +480 -0
- exonware/xwnode/strategies/nodes/node_skip_list.py +316 -0
- exonware/xwnode/strategies/nodes/node_splay_tree.py +393 -0
- exonware/xwnode/strategies/nodes/node_suffix_array.py +487 -0
- exonware/xwnode/strategies/nodes/node_treap.py +387 -0
- exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py +1434 -0
- exonware/xwnode/strategies/nodes/node_trie.py +252 -0
- exonware/xwnode/strategies/nodes/node_union_find.py +187 -0
- exonware/xwnode/strategies/nodes/node_xdata_optimized.py +369 -0
- exonware/xwnode/strategies/nodes/priority_queue.py +209 -0
- exonware/xwnode/strategies/nodes/queue.py +161 -0
- exonware/xwnode/strategies/nodes/sparse_matrix.py +206 -0
- exonware/xwnode/strategies/nodes/stack.py +152 -0
- exonware/xwnode/strategies/nodes/trie.py +274 -0
- exonware/xwnode/strategies/nodes/union_find.py +283 -0
- exonware/xwnode/strategies/pattern_detector.py +603 -0
- exonware/xwnode/strategies/performance_monitor.py +487 -0
- exonware/xwnode/strategies/queries/__init__.py +24 -0
- exonware/xwnode/strategies/queries/base.py +236 -0
- exonware/xwnode/strategies/queries/cql.py +201 -0
- exonware/xwnode/strategies/queries/cypher.py +181 -0
- exonware/xwnode/strategies/queries/datalog.py +70 -0
- exonware/xwnode/strategies/queries/elastic_dsl.py +70 -0
- exonware/xwnode/strategies/queries/eql.py +70 -0
- exonware/xwnode/strategies/queries/flux.py +70 -0
- exonware/xwnode/strategies/queries/gql.py +70 -0
- exonware/xwnode/strategies/queries/graphql.py +240 -0
- exonware/xwnode/strategies/queries/gremlin.py +181 -0
- exonware/xwnode/strategies/queries/hiveql.py +214 -0
- exonware/xwnode/strategies/queries/hql.py +70 -0
- exonware/xwnode/strategies/queries/jmespath.py +219 -0
- exonware/xwnode/strategies/queries/jq.py +66 -0
- exonware/xwnode/strategies/queries/json_query.py +66 -0
- exonware/xwnode/strategies/queries/jsoniq.py +248 -0
- exonware/xwnode/strategies/queries/kql.py +70 -0
- exonware/xwnode/strategies/queries/linq.py +238 -0
- exonware/xwnode/strategies/queries/logql.py +70 -0
- exonware/xwnode/strategies/queries/mql.py +68 -0
- exonware/xwnode/strategies/queries/n1ql.py +210 -0
- exonware/xwnode/strategies/queries/partiql.py +70 -0
- exonware/xwnode/strategies/queries/pig.py +215 -0
- exonware/xwnode/strategies/queries/promql.py +70 -0
- exonware/xwnode/strategies/queries/sparql.py +220 -0
- exonware/xwnode/strategies/queries/sql.py +275 -0
- exonware/xwnode/strategies/queries/xml_query.py +66 -0
- exonware/xwnode/strategies/queries/xpath.py +223 -0
- exonware/xwnode/strategies/queries/xquery.py +258 -0
- exonware/xwnode/strategies/queries/xwnode_executor.py +332 -0
- exonware/xwnode/strategies/queries/xwquery_strategy.py +424 -0
- exonware/xwnode/strategies/registry.py +604 -0
- exonware/xwnode/strategies/simple.py +273 -0
- exonware/xwnode/strategies/utils.py +532 -0
- exonware/xwnode/types.py +912 -0
- exonware/xwnode/version.py +78 -0
- exonware_xwnode-0.0.1.12.dist-info/METADATA +169 -0
- exonware_xwnode-0.0.1.12.dist-info/RECORD +132 -0
- exonware_xwnode-0.0.1.12.dist-info/WHEEL +4 -0
- exonware_xwnode-0.0.1.12.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,378 @@
|
|
1
|
+
#exonware\xnode\strategies\impls\node_persistent_tree.py
|
2
|
+
"""
|
3
|
+
Persistent Tree Node Strategy Implementation
|
4
|
+
|
5
|
+
This module implements the PERSISTENT_TREE strategy for immutable functional
|
6
|
+
trees with structural sharing and lock-free concurrency.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from typing import Any, Iterator, List, Dict, Optional, Tuple
|
10
|
+
from .base import ANodeTreeStrategy
|
11
|
+
from ...types import NodeMode, NodeTrait
|
12
|
+
|
13
|
+
|
14
|
+
class PersistentTreeNode:
|
15
|
+
"""Immutable node in the persistent tree."""
|
16
|
+
|
17
|
+
def __init__(self, key: str, value: Any = None, left: Optional['PersistentTreeNode'] = None,
|
18
|
+
right: Optional['PersistentTreeNode'] = None, height: int = 1):
|
19
|
+
self.key = key
|
20
|
+
self.value = value
|
21
|
+
self.left = left
|
22
|
+
self.right = right
|
23
|
+
self.height = height
|
24
|
+
self._hash = None
|
25
|
+
|
26
|
+
def __hash__(self) -> int:
|
27
|
+
"""Cache hash for performance."""
|
28
|
+
if self._hash is None:
|
29
|
+
self._hash = hash((self.key, self.value, id(self.left), id(self.right)))
|
30
|
+
return self._hash
|
31
|
+
|
32
|
+
def __eq__(self, other) -> bool:
|
33
|
+
"""Structural equality."""
|
34
|
+
if not isinstance(other, PersistentTreeNode):
|
35
|
+
return False
|
36
|
+
return (self.key == other.key and
|
37
|
+
self.value == other.value and
|
38
|
+
self.left is other.left and
|
39
|
+
self.right is other.right)
|
40
|
+
|
41
|
+
|
42
|
+
class PersistentTreeStrategy(ANodeTreeStrategy):
|
43
|
+
"""
|
44
|
+
Persistent tree node strategy for immutable functional trees.
|
45
|
+
|
46
|
+
Provides lock-free concurrency through immutability and structural sharing.
|
47
|
+
Each operation returns a new tree while sharing unchanged nodes.
|
48
|
+
"""
|
49
|
+
|
50
|
+
def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
|
51
|
+
"""Initialize the persistent tree strategy."""
|
52
|
+
super().__init__(NodeMode.PERSISTENT_TREE, traits, **options)
|
53
|
+
|
54
|
+
self.case_sensitive = options.get('case_sensitive', True)
|
55
|
+
self.balanced = options.get('balanced', True) # Use AVL balancing
|
56
|
+
|
57
|
+
# Core persistent tree
|
58
|
+
self._root: Optional[PersistentTreeNode] = None
|
59
|
+
self._size = 0
|
60
|
+
self._version = 0
|
61
|
+
|
62
|
+
# Statistics
|
63
|
+
self._total_allocations = 0
|
64
|
+
self._total_shares = 0
|
65
|
+
self._max_height = 0
|
66
|
+
|
67
|
+
def get_supported_traits(self) -> NodeTrait:
|
68
|
+
"""Get the traits supported by the persistent tree strategy."""
|
69
|
+
return (NodeTrait.PERSISTENT | NodeTrait.ORDERED | NodeTrait.INDEXED)
|
70
|
+
|
71
|
+
def _normalize_key(self, key: str) -> str:
|
72
|
+
"""Normalize key based on case sensitivity."""
|
73
|
+
return key if self.case_sensitive else key.lower()
|
74
|
+
|
75
|
+
def _create_node(self, key: str, value: Any, left: Optional[PersistentTreeNode] = None,
|
76
|
+
right: Optional[PersistentTreeNode] = None) -> PersistentTreeNode:
|
77
|
+
"""Create new node with structural sharing."""
|
78
|
+
self._total_allocations += 1
|
79
|
+
height = 1 + max(
|
80
|
+
left.height if left else 0,
|
81
|
+
right.height if right else 0
|
82
|
+
)
|
83
|
+
return PersistentTreeNode(key, value, left, right, height)
|
84
|
+
|
85
|
+
def _get_height(self, node: Optional[PersistentTreeNode]) -> int:
|
86
|
+
"""Get height of node."""
|
87
|
+
return node.height if node else 0
|
88
|
+
|
89
|
+
def _get_balance(self, node: Optional[PersistentTreeNode]) -> int:
|
90
|
+
"""Get balance factor of node."""
|
91
|
+
if not node:
|
92
|
+
return 0
|
93
|
+
return self._get_height(node.left) - self._get_height(node.right)
|
94
|
+
|
95
|
+
def _rotate_right(self, node: PersistentTreeNode) -> PersistentTreeNode:
|
96
|
+
"""Right rotation for AVL balancing."""
|
97
|
+
left = node.left
|
98
|
+
if not left:
|
99
|
+
return node
|
100
|
+
|
101
|
+
# Create new nodes with structural sharing
|
102
|
+
new_right = self._create_node(node.key, node.value, left.right, node.right)
|
103
|
+
new_root = self._create_node(left.key, left.value, left.left, new_right)
|
104
|
+
|
105
|
+
return new_root
|
106
|
+
|
107
|
+
def _rotate_left(self, node: PersistentTreeNode) -> PersistentTreeNode:
|
108
|
+
"""Left rotation for AVL balancing."""
|
109
|
+
right = node.right
|
110
|
+
if not right:
|
111
|
+
return node
|
112
|
+
|
113
|
+
# Create new nodes with structural sharing
|
114
|
+
new_left = self._create_node(node.key, node.value, node.left, right.left)
|
115
|
+
new_root = self._create_node(right.key, right.value, new_left, right.right)
|
116
|
+
|
117
|
+
return new_root
|
118
|
+
|
119
|
+
def _balance_node(self, node: PersistentTreeNode) -> PersistentTreeNode:
|
120
|
+
"""Balance node using AVL rotations."""
|
121
|
+
if not self.balanced:
|
122
|
+
return node
|
123
|
+
|
124
|
+
balance = self._get_balance(node)
|
125
|
+
|
126
|
+
# Left heavy
|
127
|
+
if balance > 1:
|
128
|
+
if self._get_balance(node.left) < 0:
|
129
|
+
# Left-Right case
|
130
|
+
new_left = self._rotate_left(node.left)
|
131
|
+
new_node = self._create_node(node.key, node.value, new_left, node.right)
|
132
|
+
return self._rotate_right(new_node)
|
133
|
+
else:
|
134
|
+
# Left-Left case
|
135
|
+
return self._rotate_right(node)
|
136
|
+
|
137
|
+
# Right heavy
|
138
|
+
if balance < -1:
|
139
|
+
if self._get_balance(node.right) > 0:
|
140
|
+
# Right-Left case
|
141
|
+
new_right = self._rotate_right(node.right)
|
142
|
+
new_node = self._create_node(node.key, node.value, node.left, new_right)
|
143
|
+
return self._rotate_left(new_node)
|
144
|
+
else:
|
145
|
+
# Right-Right case
|
146
|
+
return self._rotate_left(node)
|
147
|
+
|
148
|
+
return node
|
149
|
+
|
150
|
+
def _insert_node(self, node: Optional[PersistentTreeNode], key: str, value: Any) -> Tuple[PersistentTreeNode, bool]:
|
151
|
+
"""Insert node with structural sharing."""
|
152
|
+
if not node:
|
153
|
+
new_node = self._create_node(key, value)
|
154
|
+
return new_node, True
|
155
|
+
|
156
|
+
normalized_key = self._normalize_key(key)
|
157
|
+
node_key = self._normalize_key(node.key)
|
158
|
+
|
159
|
+
if normalized_key < node_key:
|
160
|
+
new_left, inserted = self._insert_node(node.left, key, value)
|
161
|
+
if inserted:
|
162
|
+
new_node = self._create_node(node.key, node.value, new_left, node.right)
|
163
|
+
return self._balance_node(new_node), True
|
164
|
+
else:
|
165
|
+
# Share unchanged node
|
166
|
+
self._total_shares += 1
|
167
|
+
return node, False
|
168
|
+
elif normalized_key > node_key:
|
169
|
+
new_right, inserted = self._insert_node(node.right, key, value)
|
170
|
+
if inserted:
|
171
|
+
new_node = self._create_node(node.key, node.value, node.left, new_right)
|
172
|
+
return self._balance_node(new_node), True
|
173
|
+
else:
|
174
|
+
# Share unchanged node
|
175
|
+
self._total_shares += 1
|
176
|
+
return node, False
|
177
|
+
else:
|
178
|
+
# Key exists, update value
|
179
|
+
if node.value == value:
|
180
|
+
# Share unchanged node
|
181
|
+
self._total_shares += 1
|
182
|
+
return node, False
|
183
|
+
else:
|
184
|
+
new_node = self._create_node(node.key, value, node.left, node.right)
|
185
|
+
return new_node, False
|
186
|
+
|
187
|
+
def _find_node(self, node: Optional[PersistentTreeNode], key: str) -> Optional[PersistentTreeNode]:
|
188
|
+
"""Find node by key."""
|
189
|
+
if not node:
|
190
|
+
return None
|
191
|
+
|
192
|
+
normalized_key = self._normalize_key(key)
|
193
|
+
node_key = self._normalize_key(node.key)
|
194
|
+
|
195
|
+
if normalized_key < node_key:
|
196
|
+
return self._find_node(node.left, key)
|
197
|
+
elif normalized_key > node_key:
|
198
|
+
return self._find_node(node.right, key)
|
199
|
+
else:
|
200
|
+
return node
|
201
|
+
|
202
|
+
def _delete_node(self, node: Optional[PersistentTreeNode], key: str) -> Tuple[Optional[PersistentTreeNode], bool]:
|
203
|
+
"""Delete node with structural sharing."""
|
204
|
+
if not node:
|
205
|
+
return None, False
|
206
|
+
|
207
|
+
normalized_key = self._normalize_key(key)
|
208
|
+
node_key = self._normalize_key(node.key)
|
209
|
+
|
210
|
+
if normalized_key < node_key:
|
211
|
+
new_left, deleted = self._delete_node(node.left, key)
|
212
|
+
if deleted:
|
213
|
+
new_node = self._create_node(node.key, node.value, new_left, node.right)
|
214
|
+
return self._balance_node(new_node), True
|
215
|
+
else:
|
216
|
+
# Share unchanged node
|
217
|
+
self._total_shares += 1
|
218
|
+
return node, False
|
219
|
+
elif normalized_key > node_key:
|
220
|
+
new_right, deleted = self._delete_node(node.right, key)
|
221
|
+
if deleted:
|
222
|
+
new_node = self._create_node(node.key, node.value, node.left, new_right)
|
223
|
+
return self._balance_node(new_node), True
|
224
|
+
else:
|
225
|
+
# Share unchanged node
|
226
|
+
self._total_shares += 1
|
227
|
+
return node, False
|
228
|
+
else:
|
229
|
+
# Found node to delete
|
230
|
+
if not node.left:
|
231
|
+
return node.right, True
|
232
|
+
elif not node.right:
|
233
|
+
return node.left, True
|
234
|
+
else:
|
235
|
+
# Node has both children, find successor
|
236
|
+
successor = self._find_min(node.right)
|
237
|
+
new_right, _ = self._delete_node(node.right, successor.key)
|
238
|
+
new_node = self._create_node(successor.key, successor.value, node.left, new_right)
|
239
|
+
return self._balance_node(new_node), True
|
240
|
+
|
241
|
+
def _find_min(self, node: PersistentTreeNode) -> PersistentTreeNode:
|
242
|
+
"""Find minimum node in subtree."""
|
243
|
+
while node.left:
|
244
|
+
node = node.left
|
245
|
+
return node
|
246
|
+
|
247
|
+
def _inorder_traversal(self, node: Optional[PersistentTreeNode]) -> Iterator[Tuple[str, Any]]:
|
248
|
+
"""In-order traversal of tree."""
|
249
|
+
if node:
|
250
|
+
yield from self._inorder_traversal(node.left)
|
251
|
+
yield (node.key, node.value)
|
252
|
+
yield from self._inorder_traversal(node.right)
|
253
|
+
|
254
|
+
# ============================================================================
|
255
|
+
# CORE OPERATIONS
|
256
|
+
# ============================================================================
|
257
|
+
|
258
|
+
def put(self, key: Any, value: Any = None) -> None:
|
259
|
+
"""Store a key-value pair, returning new tree."""
|
260
|
+
if not isinstance(key, str):
|
261
|
+
key = str(key)
|
262
|
+
|
263
|
+
new_root, inserted = self._insert_node(self._root, key, value)
|
264
|
+
self._root = new_root
|
265
|
+
|
266
|
+
if inserted:
|
267
|
+
self._size += 1
|
268
|
+
self._version += 1
|
269
|
+
|
270
|
+
self._max_height = max(self._max_height, self._get_height(self._root))
|
271
|
+
|
272
|
+
def get(self, key: Any, default: Any = None) -> Any:
|
273
|
+
"""Retrieve a value by key."""
|
274
|
+
if not isinstance(key, str):
|
275
|
+
key = str(key)
|
276
|
+
|
277
|
+
node = self._find_node(self._root, key)
|
278
|
+
return node.value if node else default
|
279
|
+
|
280
|
+
def delete(self, key: Any) -> bool:
|
281
|
+
"""Remove a key-value pair."""
|
282
|
+
if not isinstance(key, str):
|
283
|
+
key = str(key)
|
284
|
+
|
285
|
+
new_root, deleted = self._delete_node(self._root, key)
|
286
|
+
self._root = new_root
|
287
|
+
|
288
|
+
if deleted:
|
289
|
+
self._size -= 1
|
290
|
+
self._version += 1
|
291
|
+
|
292
|
+
return deleted
|
293
|
+
|
294
|
+
def has(self, key: Any) -> bool:
|
295
|
+
"""Check if key exists."""
|
296
|
+
if not isinstance(key, str):
|
297
|
+
key = str(key)
|
298
|
+
|
299
|
+
return self._find_node(self._root, key) is not None
|
300
|
+
|
301
|
+
def clear(self) -> None:
|
302
|
+
"""Clear all data."""
|
303
|
+
self._root = None
|
304
|
+
self._size = 0
|
305
|
+
self._version += 1
|
306
|
+
|
307
|
+
def size(self) -> int:
|
308
|
+
"""Get number of key-value pairs."""
|
309
|
+
return self._size
|
310
|
+
|
311
|
+
def is_empty(self) -> bool:
|
312
|
+
"""Check if tree is empty."""
|
313
|
+
return self._root is None
|
314
|
+
|
315
|
+
# ============================================================================
|
316
|
+
# ITERATION
|
317
|
+
# ============================================================================
|
318
|
+
|
319
|
+
def keys(self) -> Iterator[str]:
|
320
|
+
"""Iterate over keys in sorted order."""
|
321
|
+
for key, _ in self._inorder_traversal(self._root):
|
322
|
+
yield key
|
323
|
+
|
324
|
+
def values(self) -> Iterator[Any]:
|
325
|
+
"""Iterate over values in key order."""
|
326
|
+
for _, value in self._inorder_traversal(self._root):
|
327
|
+
yield value
|
328
|
+
|
329
|
+
def items(self) -> Iterator[Tuple[str, Any]]:
|
330
|
+
"""Iterate over key-value pairs in sorted order."""
|
331
|
+
yield from self._inorder_traversal(self._root)
|
332
|
+
|
333
|
+
def __iter__(self) -> Iterator[str]:
|
334
|
+
"""Iterate over keys."""
|
335
|
+
yield from self.keys()
|
336
|
+
|
337
|
+
# ============================================================================
|
338
|
+
# PERSISTENT TREE SPECIFIC OPERATIONS
|
339
|
+
# ============================================================================
|
340
|
+
|
341
|
+
def snapshot(self) -> 'xPersistentTreeStrategy':
|
342
|
+
"""Create a snapshot of the current tree."""
|
343
|
+
snapshot = xPersistentTreeStrategy(self.traits, **self.options)
|
344
|
+
snapshot._root = self._root # Share root (structural sharing)
|
345
|
+
snapshot._size = self._size
|
346
|
+
snapshot._version = self._version
|
347
|
+
return snapshot
|
348
|
+
|
349
|
+
def merge(self, other: 'xPersistentTreeStrategy') -> 'xPersistentTreeStrategy':
|
350
|
+
"""Merge with another persistent tree."""
|
351
|
+
result = xPersistentTreeStrategy(self.traits, **self.options)
|
352
|
+
|
353
|
+
# Copy all items from both trees
|
354
|
+
for key, value in self.items():
|
355
|
+
result.put(key, value)
|
356
|
+
for key, value in other.items():
|
357
|
+
result.put(key, value)
|
358
|
+
|
359
|
+
return result
|
360
|
+
|
361
|
+
def get_version(self) -> int:
|
362
|
+
"""Get current version number."""
|
363
|
+
return self._version
|
364
|
+
|
365
|
+
def get_stats(self) -> Dict[str, Any]:
|
366
|
+
"""Get performance statistics."""
|
367
|
+
return {
|
368
|
+
'size': self._size,
|
369
|
+
'height': self._get_height(self._root),
|
370
|
+
'max_height': self._max_height,
|
371
|
+
'version': self._version,
|
372
|
+
'total_allocations': self._total_allocations,
|
373
|
+
'total_shares': self._total_shares,
|
374
|
+
'sharing_ratio': self._total_shares / max(1, self._total_allocations),
|
375
|
+
'strategy': 'PERSISTENT_TREE',
|
376
|
+
'backend': 'Immutable AVL tree with structural sharing',
|
377
|
+
'traits': [trait.name for trait in NodeTrait if self.has_trait(trait)]
|
378
|
+
}
|