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