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