exonware-xwnode 0.0.1.21__py3-none-any.whl → 0.0.1.23__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 +8 -1
- exonware/xwnode/__init__.py +18 -5
- exonware/xwnode/add_strategy_types.py +165 -0
- exonware/xwnode/base.py +7 -5
- exonware/xwnode/common/__init__.py +1 -1
- exonware/xwnode/common/graph/__init__.py +30 -0
- exonware/xwnode/common/graph/caching.py +131 -0
- exonware/xwnode/common/graph/contracts.py +100 -0
- exonware/xwnode/common/graph/errors.py +44 -0
- exonware/xwnode/common/graph/indexing.py +260 -0
- exonware/xwnode/common/graph/manager.py +568 -0
- exonware/xwnode/common/management/__init__.py +3 -5
- exonware/xwnode/common/management/manager.py +9 -9
- exonware/xwnode/common/management/migration.py +6 -6
- exonware/xwnode/common/monitoring/__init__.py +3 -5
- exonware/xwnode/common/monitoring/metrics.py +7 -3
- exonware/xwnode/common/monitoring/pattern_detector.py +2 -2
- exonware/xwnode/common/monitoring/performance_monitor.py +6 -2
- exonware/xwnode/common/patterns/__init__.py +3 -5
- exonware/xwnode/common/patterns/advisor.py +1 -1
- exonware/xwnode/common/patterns/flyweight.py +6 -2
- exonware/xwnode/common/patterns/registry.py +203 -184
- exonware/xwnode/common/utils/__init__.py +25 -11
- exonware/xwnode/common/utils/simple.py +1 -1
- exonware/xwnode/config.py +3 -8
- exonware/xwnode/contracts.py +4 -105
- exonware/xwnode/defs.py +413 -159
- exonware/xwnode/edges/strategies/__init__.py +86 -4
- exonware/xwnode/edges/strategies/_base_edge.py +2 -2
- exonware/xwnode/edges/strategies/adj_list.py +287 -121
- exonware/xwnode/edges/strategies/adj_matrix.py +316 -222
- exonware/xwnode/edges/strategies/base.py +1 -1
- exonware/xwnode/edges/strategies/{edge_bidir_wrapper.py → bidir_wrapper.py} +45 -4
- exonware/xwnode/edges/strategies/bitemporal.py +520 -0
- exonware/xwnode/edges/strategies/{edge_block_adj_matrix.py → block_adj_matrix.py} +77 -6
- exonware/xwnode/edges/strategies/bv_graph.py +664 -0
- exonware/xwnode/edges/strategies/compressed_graph.py +217 -0
- exonware/xwnode/edges/strategies/{edge_coo.py → coo.py} +46 -4
- exonware/xwnode/edges/strategies/{edge_csc.py → csc.py} +45 -4
- exonware/xwnode/edges/strategies/{edge_csr.py → csr.py} +94 -12
- exonware/xwnode/edges/strategies/{edge_dynamic_adj_list.py → dynamic_adj_list.py} +46 -4
- exonware/xwnode/edges/strategies/edge_list.py +168 -0
- exonware/xwnode/edges/strategies/edge_property_store.py +2 -2
- exonware/xwnode/edges/strategies/euler_tour.py +560 -0
- exonware/xwnode/edges/strategies/{edge_flow_network.py → flow_network.py} +2 -2
- exonware/xwnode/edges/strategies/graphblas.py +449 -0
- exonware/xwnode/edges/strategies/hnsw.py +637 -0
- exonware/xwnode/edges/strategies/hop2_labels.py +467 -0
- exonware/xwnode/edges/strategies/{edge_hyperedge_set.py → hyperedge_set.py} +2 -2
- exonware/xwnode/edges/strategies/incidence_matrix.py +250 -0
- exonware/xwnode/edges/strategies/k2_tree.py +613 -0
- exonware/xwnode/edges/strategies/link_cut.py +626 -0
- exonware/xwnode/edges/strategies/multiplex.py +532 -0
- exonware/xwnode/edges/strategies/{edge_neural_graph.py → neural_graph.py} +2 -2
- exonware/xwnode/edges/strategies/{edge_octree.py → octree.py} +69 -11
- exonware/xwnode/edges/strategies/{edge_quadtree.py → quadtree.py} +66 -10
- exonware/xwnode/edges/strategies/roaring_adj.py +438 -0
- exonware/xwnode/edges/strategies/{edge_rtree.py → rtree.py} +43 -5
- exonware/xwnode/edges/strategies/{edge_temporal_edgeset.py → temporal_edgeset.py} +24 -5
- exonware/xwnode/edges/strategies/{edge_tree_graph_basic.py → tree_graph_basic.py} +78 -7
- exonware/xwnode/edges/strategies/{edge_weighted_graph.py → weighted_graph.py} +188 -10
- exonware/xwnode/errors.py +3 -6
- exonware/xwnode/facade.py +20 -20
- exonware/xwnode/nodes/strategies/__init__.py +29 -9
- exonware/xwnode/nodes/strategies/adjacency_list.py +650 -177
- exonware/xwnode/nodes/strategies/aho_corasick.py +358 -183
- exonware/xwnode/nodes/strategies/array_list.py +36 -3
- exonware/xwnode/nodes/strategies/art.py +581 -0
- exonware/xwnode/nodes/strategies/{node_avl_tree.py → avl_tree.py} +77 -6
- exonware/xwnode/nodes/strategies/{node_b_plus_tree.py → b_plus_tree.py} +81 -40
- exonware/xwnode/nodes/strategies/{node_btree.py → b_tree.py} +79 -9
- exonware/xwnode/nodes/strategies/base.py +469 -98
- exonware/xwnode/nodes/strategies/{node_bitmap.py → bitmap.py} +12 -12
- exonware/xwnode/nodes/strategies/{node_bitset_dynamic.py → bitset_dynamic.py} +11 -11
- exonware/xwnode/nodes/strategies/{node_bloom_filter.py → bloom_filter.py} +15 -2
- exonware/xwnode/nodes/strategies/bloomier_filter.py +519 -0
- exonware/xwnode/nodes/strategies/bw_tree.py +531 -0
- exonware/xwnode/nodes/strategies/contracts.py +1 -1
- exonware/xwnode/nodes/strategies/{node_count_min_sketch.py → count_min_sketch.py} +3 -2
- exonware/xwnode/nodes/strategies/{node_cow_tree.py → cow_tree.py} +135 -13
- exonware/xwnode/nodes/strategies/crdt_map.py +629 -0
- exonware/xwnode/nodes/strategies/{node_cuckoo_hash.py → cuckoo_hash.py} +2 -2
- exonware/xwnode/nodes/strategies/{node_xdata_optimized.py → data_interchange_optimized.py} +21 -4
- exonware/xwnode/nodes/strategies/dawg.py +876 -0
- exonware/xwnode/nodes/strategies/deque.py +321 -153
- exonware/xwnode/nodes/strategies/extendible_hash.py +93 -0
- exonware/xwnode/nodes/strategies/{node_fenwick_tree.py → fenwick_tree.py} +111 -19
- exonware/xwnode/nodes/strategies/hamt.py +403 -0
- exonware/xwnode/nodes/strategies/hash_map.py +354 -67
- exonware/xwnode/nodes/strategies/heap.py +105 -5
- exonware/xwnode/nodes/strategies/hopscotch_hash.py +525 -0
- exonware/xwnode/nodes/strategies/{node_hyperloglog.py → hyperloglog.py} +6 -5
- exonware/xwnode/nodes/strategies/interval_tree.py +742 -0
- exonware/xwnode/nodes/strategies/kd_tree.py +703 -0
- exonware/xwnode/nodes/strategies/learned_index.py +533 -0
- exonware/xwnode/nodes/strategies/linear_hash.py +93 -0
- exonware/xwnode/nodes/strategies/linked_list.py +316 -119
- exonware/xwnode/nodes/strategies/{node_lsm_tree.py → lsm_tree.py} +219 -15
- exonware/xwnode/nodes/strategies/masstree.py +130 -0
- exonware/xwnode/nodes/strategies/{node_persistent_tree.py → persistent_tree.py} +149 -9
- exonware/xwnode/nodes/strategies/priority_queue.py +544 -132
- exonware/xwnode/nodes/strategies/queue.py +249 -120
- exonware/xwnode/nodes/strategies/{node_red_black_tree.py → red_black_tree.py} +183 -72
- exonware/xwnode/nodes/strategies/{node_roaring_bitmap.py → roaring_bitmap.py} +19 -6
- exonware/xwnode/nodes/strategies/rope.py +717 -0
- exonware/xwnode/nodes/strategies/{node_segment_tree.py → segment_tree.py} +106 -106
- exonware/xwnode/nodes/strategies/{node_set_hash.py → set_hash.py} +30 -29
- exonware/xwnode/nodes/strategies/{node_skip_list.py → skip_list.py} +74 -6
- exonware/xwnode/nodes/strategies/sparse_matrix.py +427 -131
- exonware/xwnode/nodes/strategies/{node_splay_tree.py → splay_tree.py} +55 -6
- exonware/xwnode/nodes/strategies/stack.py +244 -112
- exonware/xwnode/nodes/strategies/{node_suffix_array.py → suffix_array.py} +5 -1
- exonware/xwnode/nodes/strategies/t_tree.py +94 -0
- exonware/xwnode/nodes/strategies/{node_treap.py → treap.py} +75 -6
- exonware/xwnode/nodes/strategies/{node_tree_graph_hybrid.py → tree_graph_hybrid.py} +46 -5
- exonware/xwnode/nodes/strategies/trie.py +153 -9
- exonware/xwnode/nodes/strategies/union_find.py +111 -5
- exonware/xwnode/nodes/strategies/veb_tree.py +856 -0
- exonware/xwnode/strategies/__init__.py +5 -51
- exonware/xwnode/version.py +3 -3
- {exonware_xwnode-0.0.1.21.dist-info → exonware_xwnode-0.0.1.23.dist-info}/METADATA +23 -3
- exonware_xwnode-0.0.1.23.dist-info/RECORD +130 -0
- exonware/xwnode/edges/strategies/edge_adj_list.py +0 -353
- exonware/xwnode/edges/strategies/edge_adj_matrix.py +0 -445
- exonware/xwnode/nodes/strategies/_base_node.py +0 -307
- exonware/xwnode/nodes/strategies/node_aho_corasick.py +0 -525
- exonware/xwnode/nodes/strategies/node_array_list.py +0 -179
- exonware/xwnode/nodes/strategies/node_hash_map.py +0 -273
- exonware/xwnode/nodes/strategies/node_heap.py +0 -196
- exonware/xwnode/nodes/strategies/node_linked_list.py +0 -413
- exonware/xwnode/nodes/strategies/node_trie.py +0 -257
- exonware/xwnode/nodes/strategies/node_union_find.py +0 -192
- exonware/xwnode/queries/executors/__init__.py +0 -47
- exonware/xwnode/queries/executors/advanced/__init__.py +0 -37
- exonware/xwnode/queries/executors/advanced/aggregate_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/ask_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/construct_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/describe_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/for_loop_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/foreach_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/join_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/let_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/mutation_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/options_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/pipe_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/subscribe_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/subscription_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/union_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/window_executor.py +0 -51
- exonware/xwnode/queries/executors/advanced/with_cte_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/__init__.py +0 -21
- exonware/xwnode/queries/executors/aggregation/avg_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/count_executor.py +0 -38
- exonware/xwnode/queries/executors/aggregation/distinct_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/group_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/having_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/max_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/min_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/sum_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/summarize_executor.py +0 -50
- exonware/xwnode/queries/executors/array/__init__.py +0 -9
- exonware/xwnode/queries/executors/array/indexing_executor.py +0 -51
- exonware/xwnode/queries/executors/array/slicing_executor.py +0 -51
- exonware/xwnode/queries/executors/base.py +0 -257
- exonware/xwnode/queries/executors/capability_checker.py +0 -204
- exonware/xwnode/queries/executors/contracts.py +0 -166
- exonware/xwnode/queries/executors/core/__init__.py +0 -17
- exonware/xwnode/queries/executors/core/create_executor.py +0 -96
- exonware/xwnode/queries/executors/core/delete_executor.py +0 -99
- exonware/xwnode/queries/executors/core/drop_executor.py +0 -100
- exonware/xwnode/queries/executors/core/insert_executor.py +0 -39
- exonware/xwnode/queries/executors/core/select_executor.py +0 -152
- exonware/xwnode/queries/executors/core/update_executor.py +0 -102
- exonware/xwnode/queries/executors/data/__init__.py +0 -13
- exonware/xwnode/queries/executors/data/alter_executor.py +0 -50
- exonware/xwnode/queries/executors/data/load_executor.py +0 -50
- exonware/xwnode/queries/executors/data/merge_executor.py +0 -50
- exonware/xwnode/queries/executors/data/store_executor.py +0 -50
- exonware/xwnode/queries/executors/defs.py +0 -93
- exonware/xwnode/queries/executors/engine.py +0 -221
- exonware/xwnode/queries/executors/errors.py +0 -68
- exonware/xwnode/queries/executors/filtering/__init__.py +0 -25
- exonware/xwnode/queries/executors/filtering/between_executor.py +0 -80
- exonware/xwnode/queries/executors/filtering/filter_executor.py +0 -79
- exonware/xwnode/queries/executors/filtering/has_executor.py +0 -70
- exonware/xwnode/queries/executors/filtering/in_executor.py +0 -70
- exonware/xwnode/queries/executors/filtering/like_executor.py +0 -76
- exonware/xwnode/queries/executors/filtering/optional_executor.py +0 -76
- exonware/xwnode/queries/executors/filtering/range_executor.py +0 -80
- exonware/xwnode/queries/executors/filtering/term_executor.py +0 -77
- exonware/xwnode/queries/executors/filtering/values_executor.py +0 -71
- exonware/xwnode/queries/executors/filtering/where_executor.py +0 -44
- exonware/xwnode/queries/executors/graph/__init__.py +0 -15
- exonware/xwnode/queries/executors/graph/in_traverse_executor.py +0 -51
- exonware/xwnode/queries/executors/graph/match_executor.py +0 -51
- exonware/xwnode/queries/executors/graph/out_executor.py +0 -51
- exonware/xwnode/queries/executors/graph/path_executor.py +0 -51
- exonware/xwnode/queries/executors/graph/return_executor.py +0 -51
- exonware/xwnode/queries/executors/ordering/__init__.py +0 -9
- exonware/xwnode/queries/executors/ordering/by_executor.py +0 -50
- exonware/xwnode/queries/executors/ordering/order_executor.py +0 -51
- exonware/xwnode/queries/executors/projection/__init__.py +0 -9
- exonware/xwnode/queries/executors/projection/extend_executor.py +0 -50
- exonware/xwnode/queries/executors/projection/project_executor.py +0 -50
- exonware/xwnode/queries/executors/registry.py +0 -173
- exonware/xwnode/queries/parsers/__init__.py +0 -26
- exonware/xwnode/queries/parsers/base.py +0 -86
- exonware/xwnode/queries/parsers/contracts.py +0 -46
- exonware/xwnode/queries/parsers/errors.py +0 -53
- exonware/xwnode/queries/parsers/sql_param_extractor.py +0 -318
- exonware/xwnode/queries/strategies/__init__.py +0 -24
- exonware/xwnode/queries/strategies/base.py +0 -236
- exonware/xwnode/queries/strategies/cql.py +0 -201
- exonware/xwnode/queries/strategies/cypher.py +0 -181
- exonware/xwnode/queries/strategies/datalog.py +0 -70
- exonware/xwnode/queries/strategies/elastic_dsl.py +0 -70
- exonware/xwnode/queries/strategies/eql.py +0 -70
- exonware/xwnode/queries/strategies/flux.py +0 -70
- exonware/xwnode/queries/strategies/gql.py +0 -70
- exonware/xwnode/queries/strategies/graphql.py +0 -240
- exonware/xwnode/queries/strategies/gremlin.py +0 -181
- exonware/xwnode/queries/strategies/hiveql.py +0 -214
- exonware/xwnode/queries/strategies/hql.py +0 -70
- exonware/xwnode/queries/strategies/jmespath.py +0 -219
- exonware/xwnode/queries/strategies/jq.py +0 -66
- exonware/xwnode/queries/strategies/json_query.py +0 -66
- exonware/xwnode/queries/strategies/jsoniq.py +0 -248
- exonware/xwnode/queries/strategies/kql.py +0 -70
- exonware/xwnode/queries/strategies/linq.py +0 -238
- exonware/xwnode/queries/strategies/logql.py +0 -70
- exonware/xwnode/queries/strategies/mql.py +0 -68
- exonware/xwnode/queries/strategies/n1ql.py +0 -210
- exonware/xwnode/queries/strategies/partiql.py +0 -70
- exonware/xwnode/queries/strategies/pig.py +0 -215
- exonware/xwnode/queries/strategies/promql.py +0 -70
- exonware/xwnode/queries/strategies/sparql.py +0 -220
- exonware/xwnode/queries/strategies/sql.py +0 -275
- exonware/xwnode/queries/strategies/xml_query.py +0 -66
- exonware/xwnode/queries/strategies/xpath.py +0 -223
- exonware/xwnode/queries/strategies/xquery.py +0 -258
- exonware/xwnode/queries/strategies/xwnode_executor.py +0 -332
- exonware/xwnode/queries/strategies/xwquery.py +0 -456
- exonware_xwnode-0.0.1.21.dist-info/RECORD +0 -214
- /exonware/xwnode/nodes/strategies/{node_ordered_map.py → ordered_map.py} +0 -0
- /exonware/xwnode/nodes/strategies/{node_ordered_map_balanced.py → ordered_map_balanced.py} +0 -0
- /exonware/xwnode/nodes/strategies/{node_patricia.py → patricia.py} +0 -0
- /exonware/xwnode/nodes/strategies/{node_radix_trie.py → radix_trie.py} +0 -0
- /exonware/xwnode/nodes/strategies/{node_set_tree.py → set_tree.py} +0 -0
- {exonware_xwnode-0.0.1.21.dist-info → exonware_xwnode-0.0.1.23.dist-info}/WHEEL +0 -0
- {exonware_xwnode-0.0.1.21.dist-info → exonware_xwnode-0.0.1.23.dist-info}/licenses/LICENSE +0 -0
@@ -38,15 +38,56 @@ class SplayTreeNode:
|
|
38
38
|
|
39
39
|
class SplayTreeStrategy(ANodeTreeStrategy):
|
40
40
|
"""
|
41
|
-
Splay
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
Splay Tree strategy for self-adjusting binary search trees.
|
42
|
+
|
43
|
+
WHY Splay Tree:
|
44
|
+
- Self-optimizing for access patterns (frequently accessed → faster access)
|
45
|
+
- Amortized O(log n) performance without explicit balancing rules
|
46
|
+
- No extra metadata needed (no heights, colors, priorities)
|
47
|
+
- Excellent cache locality (recently accessed near root)
|
48
|
+
- Simpler than AVL/Red-Black (just rotations, no complex invariants)
|
49
|
+
|
50
|
+
WHY this implementation:
|
51
|
+
- Move-to-root heuristic via splaying on every access
|
52
|
+
- Three splay cases: zig, zig-zig, zig-zag
|
53
|
+
- Parent pointers enable bottom-up splaying
|
54
|
+
- No rebalancing metadata stored
|
55
|
+
- Adapts to access patterns automatically
|
56
|
+
|
57
|
+
Time Complexity:
|
58
|
+
- Insert: O(log n) amortized
|
59
|
+
- Search: O(log n) amortized
|
60
|
+
- Delete: O(log n) amortized
|
61
|
+
- Worst case per operation: O(n), but amortized is O(log n)
|
62
|
+
|
63
|
+
Space Complexity: O(n) - one node per key + parent pointers
|
64
|
+
|
65
|
+
Trade-offs:
|
66
|
+
- Advantage: Adapts to access patterns (hot keys stay near root)
|
67
|
+
- Advantage: Simpler than AVL/Red-Black (no balancing metadata)
|
68
|
+
- Limitation: Amortized (not worst-case) O(log n)
|
69
|
+
- Limitation: Poor for uniform random access
|
70
|
+
- Compared to AVL: Better for skewed access, worse for uniform
|
71
|
+
|
72
|
+
Best for:
|
73
|
+
- Skewed access patterns (80/20 rule)
|
74
|
+
- Caching scenarios (LRU-like behavior)
|
75
|
+
- When simplicity is valued
|
76
|
+
- Sequential access patterns
|
77
|
+
|
78
|
+
Not recommended for:
|
79
|
+
- Uniform random access
|
80
|
+
- Hard real-time (amortized, not worst-case)
|
81
|
+
- When consistent latency is critical
|
82
|
+
|
83
|
+
Performance Note:
|
84
|
+
Splay Trees offer AMORTIZED O(log n), not worst-case.
|
85
|
+
A single operation can be O(n), but a sequence of m operations
|
86
|
+
is O(m log n). Best for workloads with temporal locality.
|
87
|
+
"""
|
45
88
|
|
46
89
|
# Strategy type classification
|
47
90
|
STRATEGY_TYPE = NodeType.TREE
|
48
|
-
ugh splaying operations.
|
49
|
-
"""
|
50
91
|
|
51
92
|
def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
|
52
93
|
"""Initialize the splay tree strategy."""
|
@@ -309,6 +350,14 @@ ugh splaying operations.
|
|
309
350
|
"""Get number of key-value pairs."""
|
310
351
|
return self._size
|
311
352
|
|
353
|
+
def __len__(self) -> int:
|
354
|
+
"""Get number of key-value pairs."""
|
355
|
+
return self._size
|
356
|
+
|
357
|
+
def to_native(self) -> Dict[str, Any]:
|
358
|
+
"""Convert to native Python dict."""
|
359
|
+
return dict(self.items())
|
360
|
+
|
312
361
|
def is_empty(self) -> bool:
|
313
362
|
"""Check if tree is empty."""
|
314
363
|
return self._root is None
|
@@ -1,16 +1,30 @@
|
|
1
1
|
"""
|
2
|
+
#exonware/xwnode/src/exonware/xwnode/nodes/strategies/stack.py
|
3
|
+
|
2
4
|
Stack Strategy Implementation
|
3
5
|
|
4
|
-
|
6
|
+
Status: Production Ready ✅
|
7
|
+
True Purpose: LIFO (Last In, First Out) data structure
|
8
|
+
Complexity: O(1) push/pop operations
|
9
|
+
Production Features: ✓ Bounds Checking, ✓ Overflow Protection, ✓ Safe Empty Handling
|
10
|
+
|
11
|
+
Production-grade LIFO (Last In, First Out) data structure.
|
12
|
+
|
13
|
+
Best Practices Implemented:
|
14
|
+
- Pure stack operations (no unnecessary key-value overhead)
|
15
|
+
- O(1) push and pop operations using Python list
|
16
|
+
- Memory-efficient with minimal overhead
|
17
|
+
- Thread-unsafe by design (use queue.LifoQueue for thread-safety)
|
18
|
+
- Proper stack semantics following CLRS and industry standards
|
5
19
|
|
6
20
|
Company: eXonware.com
|
7
21
|
Author: Eng. Muhammad AlShehri
|
8
22
|
Email: connect@exonware.com
|
9
|
-
Version: 0.0.1.
|
10
|
-
Generation Date:
|
23
|
+
Version: 0.0.1.23
|
24
|
+
Generation Date: October 12, 2025
|
11
25
|
"""
|
12
26
|
|
13
|
-
from typing import Any, Iterator, List, Optional, Dict
|
27
|
+
from typing import Any, Iterator, List, Optional, Dict
|
14
28
|
from .base import ANodeLinearStrategy
|
15
29
|
from .contracts import NodeType
|
16
30
|
from ...defs import NodeMode, NodeTrait
|
@@ -18,44 +32,169 @@ from ...defs import NodeMode, NodeTrait
|
|
18
32
|
|
19
33
|
class StackStrategy(ANodeLinearStrategy):
|
20
34
|
"""
|
21
|
-
Stack node strategy
|
35
|
+
Production-grade Stack (LIFO) node strategy.
|
36
|
+
|
37
|
+
Optimized for:
|
38
|
+
- Function call simulation (recursion emulation)
|
39
|
+
- Expression evaluation (postfix, infix)
|
40
|
+
- Backtracking algorithms (DFS, maze solving)
|
41
|
+
- Undo/redo functionality
|
42
|
+
- Browser history navigation
|
43
|
+
|
44
|
+
Performance:
|
45
|
+
- Push: O(1) amortized
|
46
|
+
- Pop: O(1)
|
47
|
+
- Peek: O(1)
|
48
|
+
- Space: O(n)
|
49
|
+
|
50
|
+
Security:
|
51
|
+
- Bounds checking on all operations
|
52
|
+
- No buffer overflow possible
|
53
|
+
- Safe empty stack handling
|
22
54
|
|
23
|
-
|
24
|
-
|
55
|
+
Follows eXonware Priorities:
|
56
|
+
1. Security: Proper bounds checking, safe operations
|
57
|
+
2. Usability: Clear API matching industry standards
|
58
|
+
3. Maintainability: Simple, well-documented code
|
59
|
+
4. Performance: O(1) operations with minimal overhead
|
60
|
+
5. Extensibility: Easy to extend with additional features
|
61
|
+
"""
|
25
62
|
|
26
63
|
# Strategy type classification
|
27
64
|
STRATEGY_TYPE = NodeType.LINEAR
|
28
|
-
ive function simulation.
|
29
|
-
"""
|
30
65
|
|
31
|
-
|
32
|
-
|
33
|
-
|
66
|
+
__slots__ = ('_stack', '_max_size')
|
67
|
+
|
68
|
+
def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
|
69
|
+
"""
|
70
|
+
Initialize an empty stack.
|
71
|
+
|
72
|
+
Args:
|
73
|
+
traits: Additional node traits
|
74
|
+
**options:
|
75
|
+
max_size: Optional maximum stack size (default: unlimited)
|
76
|
+
initial_capacity: Optional initial capacity for optimization
|
77
|
+
"""
|
78
|
+
super().__init__(
|
79
|
+
NodeMode.STACK,
|
80
|
+
traits | NodeTrait.LIFO | NodeTrait.FAST_INSERT | NodeTrait.FAST_DELETE,
|
81
|
+
**options
|
82
|
+
)
|
83
|
+
self._max_size: Optional[int] = options.get('max_size')
|
34
84
|
self._stack: List[Any] = []
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
85
|
+
|
86
|
+
# Pre-allocate if capacity hint provided
|
87
|
+
initial_capacity = options.get('initial_capacity', 0)
|
88
|
+
if initial_capacity > 0:
|
89
|
+
self._stack = [None] * initial_capacity
|
90
|
+
self._stack.clear() # Clear but keep capacity
|
91
|
+
|
92
|
+
def get_supported_traits(self) -> NodeTrait:
|
93
|
+
"""Get the traits supported by the stack strategy."""
|
94
|
+
return NodeTrait.LIFO | NodeTrait.FAST_INSERT | NodeTrait.FAST_DELETE
|
95
|
+
|
96
|
+
# ============================================================================
|
97
|
+
# CORE STACK OPERATIONS (Industry Standard)
|
98
|
+
# ============================================================================
|
99
|
+
|
100
|
+
def push(self, value: Any) -> None:
|
101
|
+
"""
|
102
|
+
Push a value onto the stack.
|
103
|
+
|
104
|
+
Time: O(1) amortized
|
105
|
+
Space: O(1)
|
106
|
+
|
107
|
+
Raises:
|
108
|
+
OverflowError: If max_size is set and stack is full
|
109
|
+
"""
|
110
|
+
if self._max_size and len(self._stack) >= self._max_size:
|
111
|
+
raise OverflowError(f"Stack overflow: max size {self._max_size} reached")
|
112
|
+
|
113
|
+
self._stack.append(value)
|
114
|
+
|
115
|
+
def pop(self) -> Any:
|
116
|
+
"""
|
117
|
+
Pop and return the top item from the stack.
|
118
|
+
|
119
|
+
Time: O(1)
|
120
|
+
Space: O(1)
|
121
|
+
|
122
|
+
Returns:
|
123
|
+
The top item
|
124
|
+
|
125
|
+
Raises:
|
126
|
+
IndexError: If stack is empty
|
127
|
+
"""
|
128
|
+
if self.is_empty():
|
129
|
+
raise IndexError("pop from empty stack")
|
130
|
+
|
131
|
+
return self._stack.pop()
|
132
|
+
|
133
|
+
def peek(self) -> Any:
|
134
|
+
"""
|
135
|
+
Peek at the top item without removing it.
|
136
|
+
|
137
|
+
Time: O(1)
|
138
|
+
Space: O(1)
|
139
|
+
|
140
|
+
Returns:
|
141
|
+
The top item
|
142
|
+
|
143
|
+
Raises:
|
144
|
+
IndexError: If stack is empty
|
145
|
+
"""
|
146
|
+
if self.is_empty():
|
147
|
+
raise IndexError("peek from empty stack")
|
148
|
+
|
149
|
+
return self._stack[-1]
|
150
|
+
|
151
|
+
def top(self) -> Any:
|
152
|
+
"""Alias for peek() following standard nomenclature."""
|
153
|
+
return self.peek()
|
154
|
+
|
155
|
+
# ============================================================================
|
156
|
+
# REQUIRED ABSTRACT METHODS (from ANodeStrategy)
|
157
|
+
# ============================================================================
|
158
|
+
|
159
|
+
def put(self, key: Any, value: Any = None) -> None:
|
160
|
+
"""Store value (pushes to stack, ignores key)."""
|
161
|
+
self.push(value if value is not None else key)
|
162
|
+
|
163
|
+
def get(self, key: Any, default: Any = None) -> Any:
|
164
|
+
"""Get value by key (O(n) search - not recommended for stack)."""
|
165
|
+
for i, val in enumerate(reversed(self._stack)):
|
166
|
+
if val == key:
|
167
|
+
return val
|
168
|
+
return default
|
169
|
+
|
170
|
+
def has(self, key: Any) -> bool:
|
171
|
+
"""Check if key exists (O(n) - not recommended for stack)."""
|
172
|
+
return key in self._stack
|
173
|
+
|
174
|
+
def delete(self, key: Any) -> bool:
|
175
|
+
"""Delete specific value (O(n) - not recommended for stack)."""
|
176
|
+
try:
|
177
|
+
self._stack.remove(key)
|
178
|
+
return True
|
179
|
+
except ValueError:
|
180
|
+
return False
|
181
|
+
|
182
|
+
def keys(self) -> Iterator[Any]:
|
183
|
+
"""Get all values as keys (stack doesn't have traditional keys)."""
|
184
|
+
return iter(self._stack)
|
185
|
+
|
186
|
+
def values(self) -> Iterator[Any]:
|
187
|
+
"""Get all values."""
|
188
|
+
return iter(self._stack)
|
189
|
+
|
190
|
+
def items(self) -> Iterator[tuple[Any, Any]]:
|
191
|
+
"""Get all items as (value, value) pairs."""
|
192
|
+
for val in self._stack:
|
193
|
+
yield (val, val)
|
194
|
+
|
195
|
+
# ============================================================================
|
196
|
+
# UTILITY METHODS
|
197
|
+
# ============================================================================
|
59
198
|
|
60
199
|
def size(self) -> int:
|
61
200
|
"""Get the number of items in the stack."""
|
@@ -65,93 +204,86 @@ ive function simulation.
|
|
65
204
|
"""Check if the stack is empty."""
|
66
205
|
return len(self._stack) == 0
|
67
206
|
|
207
|
+
def is_full(self) -> bool:
|
208
|
+
"""Check if stack has reached max_size."""
|
209
|
+
return self._max_size is not None and len(self._stack) >= self._max_size
|
210
|
+
|
211
|
+
def clear(self) -> None:
|
212
|
+
"""Clear all items from the stack."""
|
213
|
+
self._stack.clear()
|
214
|
+
|
215
|
+
def to_list(self) -> List[Any]:
|
216
|
+
"""Convert stack to list (top to bottom)."""
|
217
|
+
return list(reversed(self._stack))
|
218
|
+
|
68
219
|
def to_native(self) -> Dict[str, Any]:
|
69
220
|
"""Convert stack to native dictionary format."""
|
70
|
-
return
|
221
|
+
return {str(i): val for i, val in enumerate(reversed(self._stack))}
|
71
222
|
|
72
223
|
def from_native(self, data: Dict[str, Any]) -> None:
|
73
224
|
"""Load stack from native dictionary format."""
|
74
|
-
self._stack = [(k, v) for k, v in data.items()]
|
75
|
-
|
76
|
-
def push(self, value: Any) -> None:
|
77
|
-
"""Push a value onto the stack."""
|
78
|
-
key = f"item_{len(self._stack)}"
|
79
|
-
self.insert(key, value)
|
80
|
-
|
81
|
-
def pop(self) -> Optional[Any]:
|
82
|
-
"""Pop and return the top item from the stack."""
|
83
|
-
if self.is_empty():
|
84
|
-
return None
|
85
|
-
key, value = self._stack.pop()
|
86
|
-
self._record_access("pop")
|
87
|
-
return value
|
88
|
-
|
89
|
-
def peek(self) -> Optional[Any]:
|
90
|
-
"""Peek at the top item without removing it."""
|
91
|
-
if self.is_empty():
|
92
|
-
return None
|
93
|
-
key, value = self._stack[-1]
|
94
|
-
self._record_access("peek")
|
95
|
-
return value
|
96
|
-
|
97
|
-
def clear(self) -> None:
|
98
|
-
"""Clear all items from the stack."""
|
99
225
|
self._stack.clear()
|
100
|
-
|
226
|
+
# Sort by keys and add in reverse order
|
227
|
+
sorted_items = sorted(data.items(), key=lambda x: int(x[0]) if x[0].isdigit() else 0)
|
228
|
+
for _, value in reversed(sorted_items):
|
229
|
+
self._stack.append(value)
|
101
230
|
|
102
|
-
def get_at_index(self, index: int) -> Optional[Any]:
|
103
|
-
"""Get item at specific index (0 = top of stack)."""
|
104
|
-
if 0 <= index < len(self._stack):
|
105
|
-
key, value = self._stack[-(index + 1)]
|
106
|
-
self._record_access("get_at_index")
|
107
|
-
return value
|
108
|
-
return None
|
109
231
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
self._record_access("push_front")
|
232
|
+
# ============================================================================
|
233
|
+
# PYTHON SPECIAL METHODS
|
234
|
+
# ============================================================================
|
114
235
|
|
115
|
-
def
|
116
|
-
"""
|
117
|
-
self.
|
236
|
+
def __len__(self) -> int:
|
237
|
+
"""Return the number of items in the stack."""
|
238
|
+
return len(self._stack)
|
239
|
+
|
240
|
+
def __bool__(self) -> bool:
|
241
|
+
"""Return True if stack is not empty."""
|
242
|
+
return bool(self._stack)
|
118
243
|
|
119
244
|
def __iter__(self) -> Iterator[Any]:
|
120
245
|
"""Iterate through stack items (top to bottom)."""
|
121
|
-
|
122
|
-
yield value
|
246
|
+
return reversed(self._stack)
|
123
247
|
|
124
248
|
def __repr__(self) -> str:
|
125
|
-
"""
|
126
|
-
return f"StackStrategy(size={len(self._stack)}, top={self.peek()})"
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
249
|
+
"""Professional string representation."""
|
250
|
+
return f"StackStrategy(size={len(self._stack)}, top={self.peek() if not self.is_empty() else None})"
|
251
|
+
|
252
|
+
def __str__(self) -> str:
|
253
|
+
"""Human-readable string representation."""
|
254
|
+
items = ', '.join(str(item) for item in list(self)[:5])
|
255
|
+
suffix = '...' if len(self._stack) > 5 else ''
|
256
|
+
return f"Stack[{items}{suffix}]"
|
257
|
+
|
258
|
+
# ============================================================================
|
259
|
+
# PERFORMANCE METADATA
|
260
|
+
# ============================================================================
|
261
|
+
|
262
|
+
@property
|
263
|
+
def backend_info(self) -> Dict[str, Any]:
|
264
|
+
"""Get backend implementation info."""
|
265
|
+
return {
|
266
|
+
'strategy': 'STACK',
|
267
|
+
'backend': 'Python list (dynamic array)',
|
268
|
+
'complexity': {
|
269
|
+
'push': 'O(1) amortized',
|
270
|
+
'pop': 'O(1)',
|
271
|
+
'peek': 'O(1)',
|
272
|
+
'search': 'O(n)', # Not recommended
|
273
|
+
'space': 'O(n)'
|
274
|
+
},
|
275
|
+
'thread_safe': False,
|
276
|
+
'max_size': self._max_size if self._max_size else 'unlimited'
|
277
|
+
}
|
278
|
+
|
279
|
+
@property
|
280
|
+
def metrics(self) -> Dict[str, Any]:
|
281
|
+
"""Get performance metrics."""
|
282
|
+
return {
|
283
|
+
'size': len(self._stack),
|
284
|
+
'is_empty': self.is_empty(),
|
285
|
+
'is_full': self.is_full(),
|
286
|
+
'max_size': self._max_size,
|
287
|
+
'memory_usage': f"{len(self._stack) * 8} bytes (estimated)",
|
288
|
+
'capacity': len(self._stack) # Python lists track capacity
|
289
|
+
}
|
@@ -157,7 +157,11 @@ icient query operations.
|
|
157
157
|
key_str = str(key)
|
158
158
|
|
159
159
|
if key_str == "text":
|
160
|
-
|
160
|
+
# Return text without separator for user
|
161
|
+
text = self._text
|
162
|
+
if text.endswith(self.separator):
|
163
|
+
text = text[:-1]
|
164
|
+
return text
|
161
165
|
elif key_str == "suffix_array":
|
162
166
|
self._rebuild_if_needed()
|
163
167
|
return self._suffix_array.copy()
|
@@ -0,0 +1,94 @@
|
|
1
|
+
"""
|
2
|
+
#exonware/xwnode/src/exonware/xwnode/nodes/strategies/node_t_tree.py
|
3
|
+
|
4
|
+
T-Tree Node Strategy Implementation
|
5
|
+
|
6
|
+
Company: eXonware.com
|
7
|
+
Author: Eng. Muhammad AlShehri
|
8
|
+
Email: connect@exonware.com
|
9
|
+
Version: 0.0.1.23
|
10
|
+
Generation Date: 11-Oct-2025
|
11
|
+
"""
|
12
|
+
|
13
|
+
from typing import Any, Iterator, Dict
|
14
|
+
from collections import OrderedDict
|
15
|
+
from .base import ANodeStrategy
|
16
|
+
from ...defs import NodeMode, NodeTrait
|
17
|
+
from .contracts import NodeType
|
18
|
+
from ...common.utils import (
|
19
|
+
safe_to_native_conversion,
|
20
|
+
create_basic_backend_info,
|
21
|
+
create_size_tracker,
|
22
|
+
create_access_tracker,
|
23
|
+
update_size_tracker,
|
24
|
+
record_access,
|
25
|
+
get_access_metrics
|
26
|
+
)
|
27
|
+
|
28
|
+
|
29
|
+
class TTreeStrategy(ANodeStrategy):
|
30
|
+
"""T-Tree - Hybrid AVL tree + array nodes for in-memory."""
|
31
|
+
|
32
|
+
STRATEGY_TYPE = NodeType.TREE
|
33
|
+
|
34
|
+
def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
|
35
|
+
super().__init__(NodeMode.T_TREE, traits, **options)
|
36
|
+
self._data: OrderedDict = OrderedDict()
|
37
|
+
self._size_tracker = create_size_tracker()
|
38
|
+
self._access_tracker = create_access_tracker()
|
39
|
+
|
40
|
+
def get_supported_traits(self) -> NodeTrait:
|
41
|
+
return NodeTrait.ORDERED | NodeTrait.INDEXED
|
42
|
+
|
43
|
+
def get(self, path: str, default: Any = None) -> Any:
|
44
|
+
record_access(self._access_tracker, 'get_count')
|
45
|
+
return self._data.get(path, default)
|
46
|
+
|
47
|
+
def put(self, path: str, value: Any = None) -> 'TTreeStrategy':
|
48
|
+
record_access(self._access_tracker, 'put_count')
|
49
|
+
if path not in self._data:
|
50
|
+
update_size_tracker(self._size_tracker, 1)
|
51
|
+
self._data[path] = value
|
52
|
+
return self
|
53
|
+
|
54
|
+
def delete(self, key: Any) -> bool:
|
55
|
+
key_str = str(key)
|
56
|
+
if key_str in self._data:
|
57
|
+
del self._data[key_str]
|
58
|
+
update_size_tracker(self._size_tracker, -1)
|
59
|
+
record_access(self._access_tracker, 'delete_count')
|
60
|
+
return True
|
61
|
+
return False
|
62
|
+
|
63
|
+
def remove(self, key: Any) -> bool:
|
64
|
+
return self.delete(key)
|
65
|
+
|
66
|
+
def has(self, key: Any) -> bool:
|
67
|
+
return str(key) in self._data
|
68
|
+
|
69
|
+
def exists(self, path: str) -> bool:
|
70
|
+
return path in self._data
|
71
|
+
|
72
|
+
def keys(self) -> Iterator[Any]:
|
73
|
+
return iter(self._data.keys())
|
74
|
+
|
75
|
+
def values(self) -> Iterator[Any]:
|
76
|
+
return iter(self._data.values())
|
77
|
+
|
78
|
+
def items(self) -> Iterator[tuple[Any, Any]]:
|
79
|
+
return iter(self._data.items())
|
80
|
+
|
81
|
+
def __len__(self) -> int:
|
82
|
+
return len(self._data)
|
83
|
+
|
84
|
+
def to_native(self) -> Dict[str, Any]:
|
85
|
+
return dict(self._data)
|
86
|
+
|
87
|
+
def get_backend_info(self) -> Dict[str, Any]:
|
88
|
+
return {
|
89
|
+
**create_basic_backend_info('T-Tree', 'Hybrid AVL tree + array nodes'),
|
90
|
+
'total_keys': len(self._data),
|
91
|
+
**self._size_tracker,
|
92
|
+
**get_access_metrics(self._access_tracker)
|
93
|
+
}
|
94
|
+
|