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,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
+ }