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.
Files changed (132) hide show
  1. exonware/__init__.py +14 -0
  2. exonware/xwnode/__init__.py +127 -0
  3. exonware/xwnode/base.py +676 -0
  4. exonware/xwnode/config.py +178 -0
  5. exonware/xwnode/contracts.py +730 -0
  6. exonware/xwnode/errors.py +503 -0
  7. exonware/xwnode/facade.py +460 -0
  8. exonware/xwnode/strategies/__init__.py +158 -0
  9. exonware/xwnode/strategies/advisor.py +463 -0
  10. exonware/xwnode/strategies/edges/__init__.py +32 -0
  11. exonware/xwnode/strategies/edges/adj_list.py +227 -0
  12. exonware/xwnode/strategies/edges/adj_matrix.py +391 -0
  13. exonware/xwnode/strategies/edges/base.py +169 -0
  14. exonware/xwnode/strategies/flyweight.py +328 -0
  15. exonware/xwnode/strategies/impls/__init__.py +13 -0
  16. exonware/xwnode/strategies/impls/_base_edge.py +403 -0
  17. exonware/xwnode/strategies/impls/_base_node.py +307 -0
  18. exonware/xwnode/strategies/impls/edge_adj_list.py +353 -0
  19. exonware/xwnode/strategies/impls/edge_adj_matrix.py +445 -0
  20. exonware/xwnode/strategies/impls/edge_bidir_wrapper.py +455 -0
  21. exonware/xwnode/strategies/impls/edge_block_adj_matrix.py +539 -0
  22. exonware/xwnode/strategies/impls/edge_coo.py +533 -0
  23. exonware/xwnode/strategies/impls/edge_csc.py +447 -0
  24. exonware/xwnode/strategies/impls/edge_csr.py +492 -0
  25. exonware/xwnode/strategies/impls/edge_dynamic_adj_list.py +503 -0
  26. exonware/xwnode/strategies/impls/edge_flow_network.py +555 -0
  27. exonware/xwnode/strategies/impls/edge_hyperedge_set.py +516 -0
  28. exonware/xwnode/strategies/impls/edge_neural_graph.py +650 -0
  29. exonware/xwnode/strategies/impls/edge_octree.py +574 -0
  30. exonware/xwnode/strategies/impls/edge_property_store.py +655 -0
  31. exonware/xwnode/strategies/impls/edge_quadtree.py +519 -0
  32. exonware/xwnode/strategies/impls/edge_rtree.py +820 -0
  33. exonware/xwnode/strategies/impls/edge_temporal_edgeset.py +558 -0
  34. exonware/xwnode/strategies/impls/edge_tree_graph_basic.py +271 -0
  35. exonware/xwnode/strategies/impls/edge_weighted_graph.py +411 -0
  36. exonware/xwnode/strategies/manager.py +775 -0
  37. exonware/xwnode/strategies/metrics.py +538 -0
  38. exonware/xwnode/strategies/migration.py +432 -0
  39. exonware/xwnode/strategies/nodes/__init__.py +50 -0
  40. exonware/xwnode/strategies/nodes/_base_node.py +307 -0
  41. exonware/xwnode/strategies/nodes/adjacency_list.py +267 -0
  42. exonware/xwnode/strategies/nodes/aho_corasick.py +345 -0
  43. exonware/xwnode/strategies/nodes/array_list.py +209 -0
  44. exonware/xwnode/strategies/nodes/base.py +247 -0
  45. exonware/xwnode/strategies/nodes/deque.py +200 -0
  46. exonware/xwnode/strategies/nodes/hash_map.py +135 -0
  47. exonware/xwnode/strategies/nodes/heap.py +307 -0
  48. exonware/xwnode/strategies/nodes/linked_list.py +232 -0
  49. exonware/xwnode/strategies/nodes/node_aho_corasick.py +520 -0
  50. exonware/xwnode/strategies/nodes/node_array_list.py +175 -0
  51. exonware/xwnode/strategies/nodes/node_avl_tree.py +371 -0
  52. exonware/xwnode/strategies/nodes/node_b_plus_tree.py +542 -0
  53. exonware/xwnode/strategies/nodes/node_bitmap.py +420 -0
  54. exonware/xwnode/strategies/nodes/node_bitset_dynamic.py +513 -0
  55. exonware/xwnode/strategies/nodes/node_bloom_filter.py +347 -0
  56. exonware/xwnode/strategies/nodes/node_btree.py +357 -0
  57. exonware/xwnode/strategies/nodes/node_count_min_sketch.py +470 -0
  58. exonware/xwnode/strategies/nodes/node_cow_tree.py +473 -0
  59. exonware/xwnode/strategies/nodes/node_cuckoo_hash.py +392 -0
  60. exonware/xwnode/strategies/nodes/node_fenwick_tree.py +301 -0
  61. exonware/xwnode/strategies/nodes/node_hash_map.py +269 -0
  62. exonware/xwnode/strategies/nodes/node_heap.py +191 -0
  63. exonware/xwnode/strategies/nodes/node_hyperloglog.py +407 -0
  64. exonware/xwnode/strategies/nodes/node_linked_list.py +409 -0
  65. exonware/xwnode/strategies/nodes/node_lsm_tree.py +400 -0
  66. exonware/xwnode/strategies/nodes/node_ordered_map.py +390 -0
  67. exonware/xwnode/strategies/nodes/node_ordered_map_balanced.py +565 -0
  68. exonware/xwnode/strategies/nodes/node_patricia.py +512 -0
  69. exonware/xwnode/strategies/nodes/node_persistent_tree.py +378 -0
  70. exonware/xwnode/strategies/nodes/node_radix_trie.py +452 -0
  71. exonware/xwnode/strategies/nodes/node_red_black_tree.py +497 -0
  72. exonware/xwnode/strategies/nodes/node_roaring_bitmap.py +570 -0
  73. exonware/xwnode/strategies/nodes/node_segment_tree.py +289 -0
  74. exonware/xwnode/strategies/nodes/node_set_hash.py +354 -0
  75. exonware/xwnode/strategies/nodes/node_set_tree.py +480 -0
  76. exonware/xwnode/strategies/nodes/node_skip_list.py +316 -0
  77. exonware/xwnode/strategies/nodes/node_splay_tree.py +393 -0
  78. exonware/xwnode/strategies/nodes/node_suffix_array.py +487 -0
  79. exonware/xwnode/strategies/nodes/node_treap.py +387 -0
  80. exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py +1434 -0
  81. exonware/xwnode/strategies/nodes/node_trie.py +252 -0
  82. exonware/xwnode/strategies/nodes/node_union_find.py +187 -0
  83. exonware/xwnode/strategies/nodes/node_xdata_optimized.py +369 -0
  84. exonware/xwnode/strategies/nodes/priority_queue.py +209 -0
  85. exonware/xwnode/strategies/nodes/queue.py +161 -0
  86. exonware/xwnode/strategies/nodes/sparse_matrix.py +206 -0
  87. exonware/xwnode/strategies/nodes/stack.py +152 -0
  88. exonware/xwnode/strategies/nodes/trie.py +274 -0
  89. exonware/xwnode/strategies/nodes/union_find.py +283 -0
  90. exonware/xwnode/strategies/pattern_detector.py +603 -0
  91. exonware/xwnode/strategies/performance_monitor.py +487 -0
  92. exonware/xwnode/strategies/queries/__init__.py +24 -0
  93. exonware/xwnode/strategies/queries/base.py +236 -0
  94. exonware/xwnode/strategies/queries/cql.py +201 -0
  95. exonware/xwnode/strategies/queries/cypher.py +181 -0
  96. exonware/xwnode/strategies/queries/datalog.py +70 -0
  97. exonware/xwnode/strategies/queries/elastic_dsl.py +70 -0
  98. exonware/xwnode/strategies/queries/eql.py +70 -0
  99. exonware/xwnode/strategies/queries/flux.py +70 -0
  100. exonware/xwnode/strategies/queries/gql.py +70 -0
  101. exonware/xwnode/strategies/queries/graphql.py +240 -0
  102. exonware/xwnode/strategies/queries/gremlin.py +181 -0
  103. exonware/xwnode/strategies/queries/hiveql.py +214 -0
  104. exonware/xwnode/strategies/queries/hql.py +70 -0
  105. exonware/xwnode/strategies/queries/jmespath.py +219 -0
  106. exonware/xwnode/strategies/queries/jq.py +66 -0
  107. exonware/xwnode/strategies/queries/json_query.py +66 -0
  108. exonware/xwnode/strategies/queries/jsoniq.py +248 -0
  109. exonware/xwnode/strategies/queries/kql.py +70 -0
  110. exonware/xwnode/strategies/queries/linq.py +238 -0
  111. exonware/xwnode/strategies/queries/logql.py +70 -0
  112. exonware/xwnode/strategies/queries/mql.py +68 -0
  113. exonware/xwnode/strategies/queries/n1ql.py +210 -0
  114. exonware/xwnode/strategies/queries/partiql.py +70 -0
  115. exonware/xwnode/strategies/queries/pig.py +215 -0
  116. exonware/xwnode/strategies/queries/promql.py +70 -0
  117. exonware/xwnode/strategies/queries/sparql.py +220 -0
  118. exonware/xwnode/strategies/queries/sql.py +275 -0
  119. exonware/xwnode/strategies/queries/xml_query.py +66 -0
  120. exonware/xwnode/strategies/queries/xpath.py +223 -0
  121. exonware/xwnode/strategies/queries/xquery.py +258 -0
  122. exonware/xwnode/strategies/queries/xwnode_executor.py +332 -0
  123. exonware/xwnode/strategies/queries/xwquery_strategy.py +424 -0
  124. exonware/xwnode/strategies/registry.py +604 -0
  125. exonware/xwnode/strategies/simple.py +273 -0
  126. exonware/xwnode/strategies/utils.py +532 -0
  127. exonware/xwnode/types.py +912 -0
  128. exonware/xwnode/version.py +78 -0
  129. exonware_xwnode-0.0.1.12.dist-info/METADATA +169 -0
  130. exonware_xwnode-0.0.1.12.dist-info/RECORD +132 -0
  131. exonware_xwnode-0.0.1.12.dist-info/WHEEL +4 -0
  132. exonware_xwnode-0.0.1.12.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,473 @@
1
+ #exonware\xnode\strategies\impls\node_cow_tree.py
2
+ """
3
+ Copy-on-Write Tree Node Strategy Implementation
4
+
5
+ This module implements the COW_TREE strategy for copy-on-write trees with
6
+ atomic snapshots and versioning capabilities.
7
+ """
8
+
9
+ from typing import Any, Iterator, List, Dict, Optional, Tuple, Set
10
+ from .base import ANodeTreeStrategy
11
+ from ...types import NodeMode, NodeTrait
12
+
13
+
14
+ class COWTreeNode:
15
+ """Copy-on-write node in the tree."""
16
+
17
+ def __init__(self, key: str, value: Any = None, left: Optional['COWTreeNode'] = None,
18
+ right: Optional['COWTreeNode'] = None, ref_count: int = 1):
19
+ self.key = key
20
+ self.value = value
21
+ self.left = left
22
+ self.right = right
23
+ self.ref_count = ref_count
24
+ self._frozen = False
25
+ self._hash = None
26
+
27
+ def __hash__(self) -> int:
28
+ """Cache hash for performance."""
29
+ if self._hash is None:
30
+ self._hash = hash((self.key, self.value, id(self.left), id(self.right)))
31
+ return self._hash
32
+
33
+ def __eq__(self, other) -> bool:
34
+ """Structural equality."""
35
+ if not isinstance(other, COWTreeNode):
36
+ return False
37
+ return (self.key == other.key and
38
+ self.value == other.value and
39
+ self.left is other.left and
40
+ self.right is other.right)
41
+
42
+ def increment_ref(self) -> None:
43
+ """Increment reference count."""
44
+ if not self._frozen:
45
+ self.ref_count += 1
46
+
47
+ def decrement_ref(self) -> bool:
48
+ """Decrement reference count, return True if should be deleted."""
49
+ if not self._frozen:
50
+ self.ref_count -= 1
51
+ return self.ref_count <= 0
52
+ return False
53
+
54
+ def freeze(self) -> None:
55
+ """Freeze node to prevent modifications."""
56
+ self._frozen = True
57
+
58
+ def is_shared(self) -> bool:
59
+ """Check if node is shared (ref_count > 1)."""
60
+ return self.ref_count > 1
61
+
62
+
63
+ class COWTreeStrategy(ANodeTreeStrategy):
64
+ """
65
+ Copy-on-write tree node strategy with atomic snapshots.
66
+
67
+ Provides instant snapshots, atomic updates, and versioning through
68
+ copy-on-write semantics with reference counting.
69
+ """
70
+
71
+ def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
72
+ """Initialize the COW tree strategy."""
73
+ super().__init__(NodeMode.COW_TREE, traits, **options)
74
+
75
+ self.case_sensitive = options.get('case_sensitive', True)
76
+ self.balanced = options.get('balanced', True) # Use AVL balancing
77
+ self.auto_snapshot = options.get('auto_snapshot', False)
78
+
79
+ # Core COW tree
80
+ self._root: Optional[COWTreeNode] = None
81
+ self._size = 0
82
+ self._version = 0
83
+ self._snapshots: List['xCOWTreeStrategy'] = []
84
+
85
+ # Statistics
86
+ self._total_copies = 0
87
+ self._total_shares = 0
88
+ self._max_height = 0
89
+ self._snapshot_count = 0
90
+
91
+ def get_supported_traits(self) -> NodeTrait:
92
+ """Get the traits supported by the COW tree strategy."""
93
+ return (NodeTrait.PERSISTENT | NodeTrait.ORDERED | NodeTrait.INDEXED)
94
+
95
+ def _normalize_key(self, key: str) -> str:
96
+ """Normalize key based on case sensitivity."""
97
+ return key if self.case_sensitive else key.lower()
98
+
99
+ def _create_node(self, key: str, value: Any, left: Optional[COWTreeNode] = None,
100
+ right: Optional[COWTreeNode] = None) -> COWTreeNode:
101
+ """Create new node."""
102
+ return COWTreeNode(key, value, left, right)
103
+
104
+ def _copy_node(self, node: COWTreeNode) -> COWTreeNode:
105
+ """Copy node with COW semantics."""
106
+ if not node.is_shared():
107
+ # Node is not shared, can modify in place
108
+ return node
109
+
110
+ # Node is shared, need to copy
111
+ self._total_copies += 1
112
+ new_node = COWTreeNode(node.key, node.value, node.left, node.right)
113
+
114
+ # Increment reference counts for shared children
115
+ if node.left:
116
+ node.left.increment_ref()
117
+ if node.right:
118
+ node.right.increment_ref()
119
+
120
+ return new_node
121
+
122
+ def _get_height(self, node: Optional[COWTreeNode]) -> int:
123
+ """Get height of node."""
124
+ if not node:
125
+ return 0
126
+
127
+ left_height = self._get_height(node.left)
128
+ right_height = self._get_height(node.right)
129
+ return 1 + max(left_height, right_height)
130
+
131
+ def _get_balance(self, node: Optional[COWTreeNode]) -> int:
132
+ """Get balance factor of node."""
133
+ if not node:
134
+ return 0
135
+ return self._get_height(node.left) - self._get_height(node.right)
136
+
137
+ def _rotate_right(self, node: COWTreeNode) -> COWTreeNode:
138
+ """Right rotation for AVL balancing."""
139
+ left = node.left
140
+ if not left:
141
+ return node
142
+
143
+ # Copy nodes if shared
144
+ left = self._copy_node(left)
145
+ node = self._copy_node(node)
146
+
147
+ # Perform rotation
148
+ new_right = self._create_node(node.key, node.value, left.right, node.right)
149
+ new_root = self._create_node(left.key, left.value, left.left, new_right)
150
+
151
+ return new_root
152
+
153
+ def _rotate_left(self, node: COWTreeNode) -> COWTreeNode:
154
+ """Left rotation for AVL balancing."""
155
+ right = node.right
156
+ if not right:
157
+ return node
158
+
159
+ # Copy nodes if shared
160
+ right = self._copy_node(right)
161
+ node = self._copy_node(node)
162
+
163
+ # Perform rotation
164
+ new_left = self._create_node(node.key, node.value, node.left, right.left)
165
+ new_root = self._create_node(right.key, right.value, new_left, right.right)
166
+
167
+ return new_root
168
+
169
+ def _balance_node(self, node: COWTreeNode) -> COWTreeNode:
170
+ """Balance node using AVL rotations."""
171
+ if not self.balanced:
172
+ return node
173
+
174
+ balance = self._get_balance(node)
175
+
176
+ # Left heavy
177
+ if balance > 1:
178
+ if self._get_balance(node.left) < 0:
179
+ # Left-Right case
180
+ new_left = self._rotate_left(node.left)
181
+ new_node = self._create_node(node.key, node.value, new_left, node.right)
182
+ return self._rotate_right(new_node)
183
+ else:
184
+ # Left-Left case
185
+ return self._rotate_right(node)
186
+
187
+ # Right heavy
188
+ if balance < -1:
189
+ if self._get_balance(node.right) > 0:
190
+ # Right-Left case
191
+ new_right = self._rotate_right(node.right)
192
+ new_node = self._create_node(node.key, node.value, node.left, new_right)
193
+ return self._rotate_left(new_node)
194
+ else:
195
+ # Right-Right case
196
+ return self._rotate_left(node)
197
+
198
+ return node
199
+
200
+ def _insert_node(self, node: Optional[COWTreeNode], key: str, value: Any) -> Tuple[Optional[COWTreeNode], bool]:
201
+ """Insert node with COW semantics."""
202
+ if not node:
203
+ new_node = self._create_node(key, value)
204
+ return new_node, True
205
+
206
+ # Copy node if shared
207
+ if node.is_shared():
208
+ node = self._copy_node(node)
209
+
210
+ normalized_key = self._normalize_key(key)
211
+ node_key = self._normalize_key(node.key)
212
+
213
+ if normalized_key < node_key:
214
+ new_left, inserted = self._insert_node(node.left, key, value)
215
+ if inserted or new_left is not node.left:
216
+ new_node = self._create_node(node.key, node.value, new_left, node.right)
217
+ return self._balance_node(new_node), True
218
+ else:
219
+ # Share unchanged node
220
+ self._total_shares += 1
221
+ return node, False
222
+ elif normalized_key > node_key:
223
+ new_right, inserted = self._insert_node(node.right, key, value)
224
+ if inserted or new_right is not node.right:
225
+ new_node = self._create_node(node.key, node.value, node.left, new_right)
226
+ return self._balance_node(new_node), True
227
+ else:
228
+ # Share unchanged node
229
+ self._total_shares += 1
230
+ return node, False
231
+ else:
232
+ # Key exists, update value
233
+ if node.value == value:
234
+ # Share unchanged node
235
+ self._total_shares += 1
236
+ return node, False
237
+ else:
238
+ new_node = self._create_node(node.key, value, node.left, node.right)
239
+ return new_node, False
240
+
241
+ def _find_node(self, node: Optional[COWTreeNode], key: str) -> Optional[COWTreeNode]:
242
+ """Find node by key."""
243
+ if not node:
244
+ return None
245
+
246
+ normalized_key = self._normalize_key(key)
247
+ node_key = self._normalize_key(node.key)
248
+
249
+ if normalized_key < node_key:
250
+ return self._find_node(node.left, key)
251
+ elif normalized_key > node_key:
252
+ return self._find_node(node.right, key)
253
+ else:
254
+ return node
255
+
256
+ def _delete_node(self, node: Optional[COWTreeNode], key: str) -> Tuple[Optional[COWTreeNode], bool]:
257
+ """Delete node with COW semantics."""
258
+ if not node:
259
+ return None, False
260
+
261
+ # Copy node if shared
262
+ if node.is_shared():
263
+ node = self._copy_node(node)
264
+
265
+ normalized_key = self._normalize_key(key)
266
+ node_key = self._normalize_key(node.key)
267
+
268
+ if normalized_key < node_key:
269
+ new_left, deleted = self._delete_node(node.left, key)
270
+ if deleted or new_left is not node.left:
271
+ new_node = self._create_node(node.key, node.value, new_left, node.right)
272
+ return self._balance_node(new_node), True
273
+ else:
274
+ # Share unchanged node
275
+ self._total_shares += 1
276
+ return node, False
277
+ elif normalized_key > node_key:
278
+ new_right, deleted = self._delete_node(node.right, key)
279
+ if deleted or new_right is not node.right:
280
+ new_node = self._create_node(node.key, node.value, node.left, new_right)
281
+ return self._balance_node(new_node), True
282
+ else:
283
+ # Share unchanged node
284
+ self._total_shares += 1
285
+ return node, False
286
+ else:
287
+ # Found node to delete
288
+ if not node.left:
289
+ return node.right, True
290
+ elif not node.right:
291
+ return node.left, True
292
+ else:
293
+ # Node has both children, find successor
294
+ successor = self._find_min(node.right)
295
+ new_right, _ = self._delete_node(node.right, successor.key)
296
+ new_node = self._create_node(successor.key, successor.value, node.left, new_right)
297
+ return self._balance_node(new_node), True
298
+
299
+ def _find_min(self, node: COWTreeNode) -> COWTreeNode:
300
+ """Find minimum node in subtree."""
301
+ while node.left:
302
+ node = node.left
303
+ return node
304
+
305
+ def _inorder_traversal(self, node: Optional[COWTreeNode]) -> Iterator[Tuple[str, Any]]:
306
+ """In-order traversal of tree."""
307
+ if node:
308
+ yield from self._inorder_traversal(node.left)
309
+ yield (node.key, node.value)
310
+ yield from self._inorder_traversal(node.right)
311
+
312
+ def _freeze_tree(self, node: Optional[COWTreeNode]) -> None:
313
+ """Freeze entire tree to prevent modifications."""
314
+ if node:
315
+ node.freeze()
316
+ self._freeze_tree(node.left)
317
+ self._freeze_tree(node.right)
318
+
319
+ # ============================================================================
320
+ # CORE OPERATIONS
321
+ # ============================================================================
322
+
323
+ def put(self, key: Any, value: Any = None) -> None:
324
+ """Store a key-value pair."""
325
+ if not isinstance(key, str):
326
+ key = str(key)
327
+
328
+ new_root, inserted = self._insert_node(self._root, key, value)
329
+ self._root = new_root
330
+
331
+ if inserted:
332
+ self._size += 1
333
+ self._version += 1
334
+
335
+ self._max_height = max(self._max_height, self._get_height(self._root))
336
+
337
+ # Auto-snapshot if enabled
338
+ if self.auto_snapshot and inserted:
339
+ self.snapshot()
340
+
341
+ def get(self, key: Any, default: Any = None) -> Any:
342
+ """Retrieve a value by key."""
343
+ if not isinstance(key, str):
344
+ key = str(key)
345
+
346
+ node = self._find_node(self._root, key)
347
+ return node.value if node else default
348
+
349
+ def delete(self, key: Any) -> bool:
350
+ """Remove a key-value pair."""
351
+ if not isinstance(key, str):
352
+ key = str(key)
353
+
354
+ new_root, deleted = self._delete_node(self._root, key)
355
+ self._root = new_root
356
+
357
+ if deleted:
358
+ self._size -= 1
359
+ self._version += 1
360
+
361
+ return deleted
362
+
363
+ def has(self, key: Any) -> bool:
364
+ """Check if key exists."""
365
+ if not isinstance(key, str):
366
+ key = str(key)
367
+
368
+ return self._find_node(self._root, key) is not None
369
+
370
+ def clear(self) -> None:
371
+ """Clear all data."""
372
+ self._root = None
373
+ self._size = 0
374
+ self._version += 1
375
+
376
+ def size(self) -> int:
377
+ """Get number of key-value pairs."""
378
+ return self._size
379
+
380
+ def is_empty(self) -> bool:
381
+ """Check if tree is empty."""
382
+ return self._root is None
383
+
384
+ # ============================================================================
385
+ # ITERATION
386
+ # ============================================================================
387
+
388
+ def keys(self) -> Iterator[str]:
389
+ """Iterate over keys in sorted order."""
390
+ for key, _ in self._inorder_traversal(self._root):
391
+ yield key
392
+
393
+ def values(self) -> Iterator[Any]:
394
+ """Iterate over values in key order."""
395
+ for _, value in self._inorder_traversal(self._root):
396
+ yield value
397
+
398
+ def items(self) -> Iterator[Tuple[str, Any]]:
399
+ """Iterate over key-value pairs in sorted order."""
400
+ yield from self._inorder_traversal(self._root)
401
+
402
+ def __iter__(self) -> Iterator[str]:
403
+ """Iterate over keys."""
404
+ yield from self.keys()
405
+
406
+ # ============================================================================
407
+ # COW TREE SPECIFIC OPERATIONS
408
+ # ============================================================================
409
+
410
+ def snapshot(self) -> 'xCOWTreeStrategy':
411
+ """Create an atomic snapshot of the current tree."""
412
+ snapshot = xCOWTreeStrategy(self.traits, **self.options)
413
+ snapshot._root = self._root
414
+ snapshot._size = self._size
415
+ snapshot._version = self._version
416
+
417
+ # Increment reference counts for shared nodes
418
+ if self._root:
419
+ self._root.increment_ref()
420
+
421
+ # Freeze the snapshot to prevent modifications
422
+ snapshot._freeze_tree(snapshot._root)
423
+
424
+ self._snapshots.append(snapshot)
425
+ self._snapshot_count += 1
426
+
427
+ return snapshot
428
+
429
+ def restore_snapshot(self, snapshot: 'xCOWTreeStrategy') -> None:
430
+ """Restore from a snapshot."""
431
+ # Decrement reference counts for current tree
432
+ if self._root:
433
+ self._root.decrement_ref()
434
+
435
+ # Copy snapshot state
436
+ self._root = snapshot._root
437
+ self._size = snapshot._size
438
+ self._version = snapshot._version
439
+
440
+ # Increment reference counts for restored tree
441
+ if self._root:
442
+ self._root.increment_ref()
443
+
444
+ def get_snapshots(self) -> List['xCOWTreeStrategy']:
445
+ """Get list of all snapshots."""
446
+ return self._snapshots.copy()
447
+
448
+ def cleanup_snapshots(self) -> int:
449
+ """Clean up old snapshots, return number of snapshots removed."""
450
+ removed = len(self._snapshots)
451
+ self._snapshots.clear()
452
+ self._snapshot_count = 0
453
+ return removed
454
+
455
+ def get_version(self) -> int:
456
+ """Get current version number."""
457
+ return self._version
458
+
459
+ def get_stats(self) -> Dict[str, Any]:
460
+ """Get performance statistics."""
461
+ return {
462
+ 'size': self._size,
463
+ 'height': self._get_height(self._root),
464
+ 'max_height': self._max_height,
465
+ 'version': self._version,
466
+ 'snapshot_count': self._snapshot_count,
467
+ 'total_copies': self._total_copies,
468
+ 'total_shares': self._total_shares,
469
+ 'copy_ratio': self._total_copies / max(1, self._total_shares + self._total_copies),
470
+ 'strategy': 'COW_TREE',
471
+ 'backend': 'Copy-on-write AVL tree with reference counting',
472
+ 'traits': [trait.name for trait in NodeTrait if self.has_trait(trait)]
473
+ }