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,409 @@
1
+ """
2
+ Linked List Node Strategy Implementation
3
+
4
+ This module implements the LINKED_LIST strategy for efficient
5
+ insertions and deletions with sequential access patterns.
6
+ """
7
+
8
+ from typing import Any, Iterator, List, Dict, Optional
9
+ from ._base_node import aNodeStrategy
10
+ from ...types import NodeMode, NodeTrait
11
+
12
+
13
+ class ListNode:
14
+ """Node in the doubly linked list."""
15
+
16
+ def __init__(self, key: str, value: Any):
17
+ self.key = key
18
+ self.value = value
19
+ self.prev: Optional['ListNode'] = None
20
+ self.next: Optional['ListNode'] = None
21
+
22
+
23
+ class xLinkedListStrategy(aNodeStrategy):
24
+ """
25
+ Linked List node strategy for efficient insertions and deletions.
26
+
27
+ Provides O(1) insertions/deletions at known positions with
28
+ sequential access patterns optimized for iteration.
29
+ """
30
+
31
+ def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
32
+ """Initialize the Linked List strategy."""
33
+ super().__init__(NodeMode.LINKED_LIST, traits, **options)
34
+
35
+ self.doubly_linked = options.get('doubly_linked', True)
36
+
37
+ # Doubly linked list with sentinel nodes
38
+ self._head = ListNode("HEAD", None)
39
+ self._tail = ListNode("TAIL", None)
40
+ self._head.next = self._tail
41
+ self._tail.prev = self._head
42
+
43
+ # Quick access mapping
44
+ self._key_to_node: Dict[str, ListNode] = {}
45
+ self._size = 0
46
+
47
+ def get_supported_traits(self) -> NodeTrait:
48
+ """Get the traits supported by the linked list strategy."""
49
+ return (NodeTrait.ORDERED | NodeTrait.INDEXED)
50
+
51
+ def _insert_after(self, prev_node: ListNode, key: str, value: Any) -> ListNode:
52
+ """Insert new node after given node."""
53
+ new_node = ListNode(key, value)
54
+ next_node = prev_node.next
55
+
56
+ # Link new node
57
+ prev_node.next = new_node
58
+ new_node.prev = prev_node
59
+ new_node.next = next_node
60
+ next_node.prev = new_node
61
+
62
+ return new_node
63
+
64
+ def _remove_node(self, node: ListNode) -> None:
65
+ """Remove node from list."""
66
+ prev_node = node.prev
67
+ next_node = node.next
68
+
69
+ prev_node.next = next_node
70
+ next_node.prev = prev_node
71
+
72
+ # Clear references
73
+ node.prev = None
74
+ node.next = None
75
+
76
+ def _get_node_at_index(self, index: int) -> Optional[ListNode]:
77
+ """Get node at given index."""
78
+ if index < 0 or index >= self._size:
79
+ return None
80
+
81
+ # Optimize direction based on index
82
+ if index < self._size // 2:
83
+ # Search from head
84
+ current = self._head.next
85
+ for _ in range(index):
86
+ current = current.next
87
+ else:
88
+ # Search from tail
89
+ current = self._tail.prev
90
+ for _ in range(self._size - index - 1):
91
+ current = current.prev
92
+
93
+ return current if current != self._head and current != self._tail else None
94
+
95
+ # ============================================================================
96
+ # CORE OPERATIONS (Key-based interface for compatibility)
97
+ # ============================================================================
98
+
99
+ def put(self, key: Any, value: Any = None) -> None:
100
+ """Add/update key-value pair."""
101
+ key_str = str(key)
102
+
103
+ if key_str in self._key_to_node:
104
+ # Update existing
105
+ self._key_to_node[key_str].value = value
106
+ else:
107
+ # Insert at end
108
+ new_node = self._insert_after(self._tail.prev, key_str, value)
109
+ self._key_to_node[key_str] = new_node
110
+ self._size += 1
111
+
112
+ def get(self, key: Any, default: Any = None) -> Any:
113
+ """Get value by key."""
114
+ key_str = str(key)
115
+
116
+ if key_str == "list_info":
117
+ return {
118
+ 'size': self._size,
119
+ 'doubly_linked': self.doubly_linked,
120
+ 'first': self.first(),
121
+ 'last': self.last()
122
+ }
123
+ elif key_str.isdigit():
124
+ # Numeric access by index
125
+ index = int(key_str)
126
+ node = self._get_node_at_index(index)
127
+ return node.value if node else default
128
+
129
+ node = self._key_to_node.get(key_str)
130
+ return node.value if node else default
131
+
132
+ def has(self, key: Any) -> bool:
133
+ """Check if key exists."""
134
+ key_str = str(key)
135
+
136
+ if key_str == "list_info":
137
+ return True
138
+ elif key_str.isdigit():
139
+ index = int(key_str)
140
+ return 0 <= index < self._size
141
+
142
+ return key_str in self._key_to_node
143
+
144
+ def remove(self, key: Any) -> bool:
145
+ """Remove key from list."""
146
+ key_str = str(key)
147
+
148
+ if key_str.isdigit():
149
+ # Remove by index
150
+ index = int(key_str)
151
+ node = self._get_node_at_index(index)
152
+ if node:
153
+ self._remove_node(node)
154
+ del self._key_to_node[node.key]
155
+ self._size -= 1
156
+ return True
157
+ return False
158
+
159
+ node = self._key_to_node.get(key_str)
160
+ if node:
161
+ self._remove_node(node)
162
+ del self._key_to_node[key_str]
163
+ self._size -= 1
164
+ return True
165
+
166
+ return False
167
+
168
+ def delete(self, key: Any) -> bool:
169
+ """Remove key from list (alias for remove)."""
170
+ return self.remove(key)
171
+
172
+ def clear(self) -> None:
173
+ """Clear all data."""
174
+ self._head.next = self._tail
175
+ self._tail.prev = self._head
176
+ self._key_to_node.clear()
177
+ self._size = 0
178
+
179
+ def keys(self) -> Iterator[str]:
180
+ """Get all keys in insertion order."""
181
+ current = self._head.next
182
+ while current != self._tail:
183
+ yield current.key
184
+ current = current.next
185
+
186
+ def values(self) -> Iterator[Any]:
187
+ """Get all values in insertion order."""
188
+ current = self._head.next
189
+ while current != self._tail:
190
+ yield current.value
191
+ current = current.next
192
+
193
+ def items(self) -> Iterator[tuple[str, Any]]:
194
+ """Get all key-value pairs in insertion order."""
195
+ current = self._head.next
196
+ while current != self._tail:
197
+ yield (current.key, current.value)
198
+ current = current.next
199
+
200
+ def __len__(self) -> int:
201
+ """Get number of elements."""
202
+ return self._size
203
+
204
+ def to_native(self) -> List[Any]:
205
+ """Convert to native Python list."""
206
+ return list(self.values())
207
+
208
+ @property
209
+ def is_list(self) -> bool:
210
+ """This is a list strategy."""
211
+ return True
212
+
213
+ @property
214
+ def is_dict(self) -> bool:
215
+ """This also behaves like a dict."""
216
+ return True
217
+
218
+ # ============================================================================
219
+ # LINKED LIST SPECIFIC OPERATIONS
220
+ # ============================================================================
221
+
222
+ def append(self, value: Any) -> str:
223
+ """Append value to end of list."""
224
+ key = str(self._size)
225
+ self.put(key, value)
226
+ return key
227
+
228
+ def prepend(self, value: Any) -> str:
229
+ """Prepend value to beginning of list."""
230
+ key = f"prepend_{self._size}"
231
+ new_node = self._insert_after(self._head, key, value)
232
+ self._key_to_node[key] = new_node
233
+ self._size += 1
234
+ return key
235
+
236
+ def insert_at(self, index: int, value: Any) -> str:
237
+ """Insert value at specific index."""
238
+ if index < 0 or index > self._size:
239
+ raise IndexError(f"Index {index} out of range")
240
+
241
+ if index == 0:
242
+ return self.prepend(value)
243
+ elif index == self._size:
244
+ return self.append(value)
245
+
246
+ # Find insertion point
247
+ prev_node = self._get_node_at_index(index - 1)
248
+ if not prev_node:
249
+ raise IndexError(f"Cannot find insertion point at index {index}")
250
+
251
+ key = f"insert_{index}_{self._size}"
252
+ new_node = self._insert_after(prev_node, key, value)
253
+ self._key_to_node[key] = new_node
254
+ self._size += 1
255
+ return key
256
+
257
+ def pop(self) -> Any:
258
+ """Remove and return last element."""
259
+ if self._size == 0:
260
+ raise IndexError("pop from empty list")
261
+
262
+ last_node = self._tail.prev
263
+ value = last_node.value
264
+ self._remove_node(last_node)
265
+ del self._key_to_node[last_node.key]
266
+ self._size -= 1
267
+ return value
268
+
269
+ def popleft(self) -> Any:
270
+ """Remove and return first element."""
271
+ if self._size == 0:
272
+ raise IndexError("popleft from empty list")
273
+
274
+ first_node = self._head.next
275
+ value = first_node.value
276
+ self._remove_node(first_node)
277
+ del self._key_to_node[first_node.key]
278
+ self._size -= 1
279
+ return value
280
+
281
+ def first(self) -> Any:
282
+ """Get first element without removing."""
283
+ if self._size == 0:
284
+ return None
285
+ return self._head.next.value
286
+
287
+ def last(self) -> Any:
288
+ """Get last element without removing."""
289
+ if self._size == 0:
290
+ return None
291
+ return self._tail.prev.value
292
+
293
+ def reverse(self) -> None:
294
+ """Reverse the list in place."""
295
+ if self._size <= 1:
296
+ return
297
+
298
+ # Swap all next/prev pointers
299
+ current = self._head
300
+ while current:
301
+ current.next, current.prev = current.prev, current.next
302
+ current = current.prev # Note: we swapped, so prev is now next
303
+
304
+ # Swap head and tail
305
+ self._head, self._tail = self._tail, self._head
306
+
307
+ def get_at_index(self, index: int) -> Any:
308
+ """Get value at specific index."""
309
+ node = self._get_node_at_index(index)
310
+ if not node:
311
+ raise IndexError(f"Index {index} out of range")
312
+ return node.value
313
+
314
+ def set_at_index(self, index: int, value: Any) -> None:
315
+ """Set value at specific index."""
316
+ node = self._get_node_at_index(index)
317
+ if not node:
318
+ raise IndexError(f"Index {index} out of range")
319
+ node.value = value
320
+
321
+ def find_index(self, value: Any) -> int:
322
+ """Find index of first occurrence of value."""
323
+ current = self._head.next
324
+ index = 0
325
+
326
+ while current != self._tail:
327
+ if current.value == value:
328
+ return index
329
+ current = current.next
330
+ index += 1
331
+
332
+ return -1
333
+
334
+ def remove_value(self, value: Any) -> bool:
335
+ """Remove first occurrence of value."""
336
+ current = self._head.next
337
+
338
+ while current != self._tail:
339
+ if current.value == value:
340
+ self._remove_node(current)
341
+ del self._key_to_node[current.key]
342
+ self._size -= 1
343
+ return True
344
+ current = current.next
345
+
346
+ return False
347
+
348
+ def count_value(self, value: Any) -> int:
349
+ """Count occurrences of value."""
350
+ count = 0
351
+ current = self._head.next
352
+
353
+ while current != self._tail:
354
+ if current.value == value:
355
+ count += 1
356
+ current = current.next
357
+
358
+ return count
359
+
360
+ def to_array(self) -> List[Any]:
361
+ """Convert to array representation."""
362
+ return list(self.values())
363
+
364
+ def get_statistics(self) -> Dict[str, Any]:
365
+ """Get comprehensive linked list statistics."""
366
+ return {
367
+ 'size': self._size,
368
+ 'doubly_linked': self.doubly_linked,
369
+ 'first_value': self.first(),
370
+ 'last_value': self.last(),
371
+ 'memory_overhead': self._size * (64 if self.doubly_linked else 32), # Pointer overhead
372
+ 'access_pattern': 'sequential'
373
+ }
374
+
375
+ # ============================================================================
376
+ # PERFORMANCE CHARACTERISTICS
377
+ # ============================================================================
378
+
379
+ @property
380
+ def backend_info(self) -> Dict[str, Any]:
381
+ """Get backend implementation info."""
382
+ return {
383
+ 'strategy': 'LINKED_LIST',
384
+ 'backend': f'{"Doubly" if self.doubly_linked else "Singly"} linked list with sentinel nodes',
385
+ 'doubly_linked': self.doubly_linked,
386
+ 'complexity': {
387
+ 'append': 'O(1)',
388
+ 'prepend': 'O(1)',
389
+ 'insert_at': 'O(n)',
390
+ 'remove_at': 'O(n)',
391
+ 'access_by_index': 'O(n)',
392
+ 'search': 'O(n)',
393
+ 'space': 'O(n)'
394
+ }
395
+ }
396
+
397
+ @property
398
+ def metrics(self) -> Dict[str, Any]:
399
+ """Get performance metrics."""
400
+ stats = self.get_statistics()
401
+
402
+ return {
403
+ 'size': stats['size'],
404
+ 'first_value': str(stats['first_value']) if stats['first_value'] is not None else 'None',
405
+ 'last_value': str(stats['last_value']) if stats['last_value'] is not None else 'None',
406
+ 'doubly_linked': stats['doubly_linked'],
407
+ 'memory_overhead': f"{stats['memory_overhead']} bytes",
408
+ 'access_pattern': stats['access_pattern']
409
+ }