exonware-xwnode 0.0.1.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- exonware/__init__.py +14 -0
- exonware/xwnode/__init__.py +127 -0
- exonware/xwnode/base.py +676 -0
- exonware/xwnode/config.py +178 -0
- exonware/xwnode/contracts.py +730 -0
- exonware/xwnode/errors.py +503 -0
- exonware/xwnode/facade.py +460 -0
- exonware/xwnode/strategies/__init__.py +158 -0
- exonware/xwnode/strategies/advisor.py +463 -0
- exonware/xwnode/strategies/edges/__init__.py +32 -0
- exonware/xwnode/strategies/edges/adj_list.py +227 -0
- exonware/xwnode/strategies/edges/adj_matrix.py +391 -0
- exonware/xwnode/strategies/edges/base.py +169 -0
- exonware/xwnode/strategies/flyweight.py +328 -0
- exonware/xwnode/strategies/impls/__init__.py +13 -0
- exonware/xwnode/strategies/impls/_base_edge.py +403 -0
- exonware/xwnode/strategies/impls/_base_node.py +307 -0
- exonware/xwnode/strategies/impls/edge_adj_list.py +353 -0
- exonware/xwnode/strategies/impls/edge_adj_matrix.py +445 -0
- exonware/xwnode/strategies/impls/edge_bidir_wrapper.py +455 -0
- exonware/xwnode/strategies/impls/edge_block_adj_matrix.py +539 -0
- exonware/xwnode/strategies/impls/edge_coo.py +533 -0
- exonware/xwnode/strategies/impls/edge_csc.py +447 -0
- exonware/xwnode/strategies/impls/edge_csr.py +492 -0
- exonware/xwnode/strategies/impls/edge_dynamic_adj_list.py +503 -0
- exonware/xwnode/strategies/impls/edge_flow_network.py +555 -0
- exonware/xwnode/strategies/impls/edge_hyperedge_set.py +516 -0
- exonware/xwnode/strategies/impls/edge_neural_graph.py +650 -0
- exonware/xwnode/strategies/impls/edge_octree.py +574 -0
- exonware/xwnode/strategies/impls/edge_property_store.py +655 -0
- exonware/xwnode/strategies/impls/edge_quadtree.py +519 -0
- exonware/xwnode/strategies/impls/edge_rtree.py +820 -0
- exonware/xwnode/strategies/impls/edge_temporal_edgeset.py +558 -0
- exonware/xwnode/strategies/impls/edge_tree_graph_basic.py +271 -0
- exonware/xwnode/strategies/impls/edge_weighted_graph.py +411 -0
- exonware/xwnode/strategies/manager.py +775 -0
- exonware/xwnode/strategies/metrics.py +538 -0
- exonware/xwnode/strategies/migration.py +432 -0
- exonware/xwnode/strategies/nodes/__init__.py +50 -0
- exonware/xwnode/strategies/nodes/_base_node.py +307 -0
- exonware/xwnode/strategies/nodes/adjacency_list.py +267 -0
- exonware/xwnode/strategies/nodes/aho_corasick.py +345 -0
- exonware/xwnode/strategies/nodes/array_list.py +209 -0
- exonware/xwnode/strategies/nodes/base.py +247 -0
- exonware/xwnode/strategies/nodes/deque.py +200 -0
- exonware/xwnode/strategies/nodes/hash_map.py +135 -0
- exonware/xwnode/strategies/nodes/heap.py +307 -0
- exonware/xwnode/strategies/nodes/linked_list.py +232 -0
- exonware/xwnode/strategies/nodes/node_aho_corasick.py +520 -0
- exonware/xwnode/strategies/nodes/node_array_list.py +175 -0
- exonware/xwnode/strategies/nodes/node_avl_tree.py +371 -0
- exonware/xwnode/strategies/nodes/node_b_plus_tree.py +542 -0
- exonware/xwnode/strategies/nodes/node_bitmap.py +420 -0
- exonware/xwnode/strategies/nodes/node_bitset_dynamic.py +513 -0
- exonware/xwnode/strategies/nodes/node_bloom_filter.py +347 -0
- exonware/xwnode/strategies/nodes/node_btree.py +357 -0
- exonware/xwnode/strategies/nodes/node_count_min_sketch.py +470 -0
- exonware/xwnode/strategies/nodes/node_cow_tree.py +473 -0
- exonware/xwnode/strategies/nodes/node_cuckoo_hash.py +392 -0
- exonware/xwnode/strategies/nodes/node_fenwick_tree.py +301 -0
- exonware/xwnode/strategies/nodes/node_hash_map.py +269 -0
- exonware/xwnode/strategies/nodes/node_heap.py +191 -0
- exonware/xwnode/strategies/nodes/node_hyperloglog.py +407 -0
- exonware/xwnode/strategies/nodes/node_linked_list.py +409 -0
- exonware/xwnode/strategies/nodes/node_lsm_tree.py +400 -0
- exonware/xwnode/strategies/nodes/node_ordered_map.py +390 -0
- exonware/xwnode/strategies/nodes/node_ordered_map_balanced.py +565 -0
- exonware/xwnode/strategies/nodes/node_patricia.py +512 -0
- exonware/xwnode/strategies/nodes/node_persistent_tree.py +378 -0
- exonware/xwnode/strategies/nodes/node_radix_trie.py +452 -0
- exonware/xwnode/strategies/nodes/node_red_black_tree.py +497 -0
- exonware/xwnode/strategies/nodes/node_roaring_bitmap.py +570 -0
- exonware/xwnode/strategies/nodes/node_segment_tree.py +289 -0
- exonware/xwnode/strategies/nodes/node_set_hash.py +354 -0
- exonware/xwnode/strategies/nodes/node_set_tree.py +480 -0
- exonware/xwnode/strategies/nodes/node_skip_list.py +316 -0
- exonware/xwnode/strategies/nodes/node_splay_tree.py +393 -0
- exonware/xwnode/strategies/nodes/node_suffix_array.py +487 -0
- exonware/xwnode/strategies/nodes/node_treap.py +387 -0
- exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py +1434 -0
- exonware/xwnode/strategies/nodes/node_trie.py +252 -0
- exonware/xwnode/strategies/nodes/node_union_find.py +187 -0
- exonware/xwnode/strategies/nodes/node_xdata_optimized.py +369 -0
- exonware/xwnode/strategies/nodes/priority_queue.py +209 -0
- exonware/xwnode/strategies/nodes/queue.py +161 -0
- exonware/xwnode/strategies/nodes/sparse_matrix.py +206 -0
- exonware/xwnode/strategies/nodes/stack.py +152 -0
- exonware/xwnode/strategies/nodes/trie.py +274 -0
- exonware/xwnode/strategies/nodes/union_find.py +283 -0
- exonware/xwnode/strategies/pattern_detector.py +603 -0
- exonware/xwnode/strategies/performance_monitor.py +487 -0
- exonware/xwnode/strategies/queries/__init__.py +24 -0
- exonware/xwnode/strategies/queries/base.py +236 -0
- exonware/xwnode/strategies/queries/cql.py +201 -0
- exonware/xwnode/strategies/queries/cypher.py +181 -0
- exonware/xwnode/strategies/queries/datalog.py +70 -0
- exonware/xwnode/strategies/queries/elastic_dsl.py +70 -0
- exonware/xwnode/strategies/queries/eql.py +70 -0
- exonware/xwnode/strategies/queries/flux.py +70 -0
- exonware/xwnode/strategies/queries/gql.py +70 -0
- exonware/xwnode/strategies/queries/graphql.py +240 -0
- exonware/xwnode/strategies/queries/gremlin.py +181 -0
- exonware/xwnode/strategies/queries/hiveql.py +214 -0
- exonware/xwnode/strategies/queries/hql.py +70 -0
- exonware/xwnode/strategies/queries/jmespath.py +219 -0
- exonware/xwnode/strategies/queries/jq.py +66 -0
- exonware/xwnode/strategies/queries/json_query.py +66 -0
- exonware/xwnode/strategies/queries/jsoniq.py +248 -0
- exonware/xwnode/strategies/queries/kql.py +70 -0
- exonware/xwnode/strategies/queries/linq.py +238 -0
- exonware/xwnode/strategies/queries/logql.py +70 -0
- exonware/xwnode/strategies/queries/mql.py +68 -0
- exonware/xwnode/strategies/queries/n1ql.py +210 -0
- exonware/xwnode/strategies/queries/partiql.py +70 -0
- exonware/xwnode/strategies/queries/pig.py +215 -0
- exonware/xwnode/strategies/queries/promql.py +70 -0
- exonware/xwnode/strategies/queries/sparql.py +220 -0
- exonware/xwnode/strategies/queries/sql.py +275 -0
- exonware/xwnode/strategies/queries/xml_query.py +66 -0
- exonware/xwnode/strategies/queries/xpath.py +223 -0
- exonware/xwnode/strategies/queries/xquery.py +258 -0
- exonware/xwnode/strategies/queries/xwnode_executor.py +332 -0
- exonware/xwnode/strategies/queries/xwquery_strategy.py +424 -0
- exonware/xwnode/strategies/registry.py +604 -0
- exonware/xwnode/strategies/simple.py +273 -0
- exonware/xwnode/strategies/utils.py +532 -0
- exonware/xwnode/types.py +912 -0
- exonware/xwnode/version.py +78 -0
- exonware_xwnode-0.0.1.12.dist-info/METADATA +169 -0
- exonware_xwnode-0.0.1.12.dist-info/RECORD +132 -0
- exonware_xwnode-0.0.1.12.dist-info/WHEEL +4 -0
- exonware_xwnode-0.0.1.12.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,409 @@
|
|
1
|
+
"""
|
2
|
+
Linked List Node Strategy Implementation
|
3
|
+
|
4
|
+
This module implements the LINKED_LIST strategy for efficient
|
5
|
+
insertions and deletions with sequential access patterns.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from typing import Any, Iterator, List, Dict, Optional
|
9
|
+
from ._base_node import aNodeStrategy
|
10
|
+
from ...types import NodeMode, NodeTrait
|
11
|
+
|
12
|
+
|
13
|
+
class ListNode:
|
14
|
+
"""Node in the doubly linked list."""
|
15
|
+
|
16
|
+
def __init__(self, key: str, value: Any):
|
17
|
+
self.key = key
|
18
|
+
self.value = value
|
19
|
+
self.prev: Optional['ListNode'] = None
|
20
|
+
self.next: Optional['ListNode'] = None
|
21
|
+
|
22
|
+
|
23
|
+
class xLinkedListStrategy(aNodeStrategy):
|
24
|
+
"""
|
25
|
+
Linked List node strategy for efficient insertions and deletions.
|
26
|
+
|
27
|
+
Provides O(1) insertions/deletions at known positions with
|
28
|
+
sequential access patterns optimized for iteration.
|
29
|
+
"""
|
30
|
+
|
31
|
+
def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
|
32
|
+
"""Initialize the Linked List strategy."""
|
33
|
+
super().__init__(NodeMode.LINKED_LIST, traits, **options)
|
34
|
+
|
35
|
+
self.doubly_linked = options.get('doubly_linked', True)
|
36
|
+
|
37
|
+
# Doubly linked list with sentinel nodes
|
38
|
+
self._head = ListNode("HEAD", None)
|
39
|
+
self._tail = ListNode("TAIL", None)
|
40
|
+
self._head.next = self._tail
|
41
|
+
self._tail.prev = self._head
|
42
|
+
|
43
|
+
# Quick access mapping
|
44
|
+
self._key_to_node: Dict[str, ListNode] = {}
|
45
|
+
self._size = 0
|
46
|
+
|
47
|
+
def get_supported_traits(self) -> NodeTrait:
|
48
|
+
"""Get the traits supported by the linked list strategy."""
|
49
|
+
return (NodeTrait.ORDERED | NodeTrait.INDEXED)
|
50
|
+
|
51
|
+
def _insert_after(self, prev_node: ListNode, key: str, value: Any) -> ListNode:
|
52
|
+
"""Insert new node after given node."""
|
53
|
+
new_node = ListNode(key, value)
|
54
|
+
next_node = prev_node.next
|
55
|
+
|
56
|
+
# Link new node
|
57
|
+
prev_node.next = new_node
|
58
|
+
new_node.prev = prev_node
|
59
|
+
new_node.next = next_node
|
60
|
+
next_node.prev = new_node
|
61
|
+
|
62
|
+
return new_node
|
63
|
+
|
64
|
+
def _remove_node(self, node: ListNode) -> None:
|
65
|
+
"""Remove node from list."""
|
66
|
+
prev_node = node.prev
|
67
|
+
next_node = node.next
|
68
|
+
|
69
|
+
prev_node.next = next_node
|
70
|
+
next_node.prev = prev_node
|
71
|
+
|
72
|
+
# Clear references
|
73
|
+
node.prev = None
|
74
|
+
node.next = None
|
75
|
+
|
76
|
+
def _get_node_at_index(self, index: int) -> Optional[ListNode]:
|
77
|
+
"""Get node at given index."""
|
78
|
+
if index < 0 or index >= self._size:
|
79
|
+
return None
|
80
|
+
|
81
|
+
# Optimize direction based on index
|
82
|
+
if index < self._size // 2:
|
83
|
+
# Search from head
|
84
|
+
current = self._head.next
|
85
|
+
for _ in range(index):
|
86
|
+
current = current.next
|
87
|
+
else:
|
88
|
+
# Search from tail
|
89
|
+
current = self._tail.prev
|
90
|
+
for _ in range(self._size - index - 1):
|
91
|
+
current = current.prev
|
92
|
+
|
93
|
+
return current if current != self._head and current != self._tail else None
|
94
|
+
|
95
|
+
# ============================================================================
|
96
|
+
# CORE OPERATIONS (Key-based interface for compatibility)
|
97
|
+
# ============================================================================
|
98
|
+
|
99
|
+
def put(self, key: Any, value: Any = None) -> None:
|
100
|
+
"""Add/update key-value pair."""
|
101
|
+
key_str = str(key)
|
102
|
+
|
103
|
+
if key_str in self._key_to_node:
|
104
|
+
# Update existing
|
105
|
+
self._key_to_node[key_str].value = value
|
106
|
+
else:
|
107
|
+
# Insert at end
|
108
|
+
new_node = self._insert_after(self._tail.prev, key_str, value)
|
109
|
+
self._key_to_node[key_str] = new_node
|
110
|
+
self._size += 1
|
111
|
+
|
112
|
+
def get(self, key: Any, default: Any = None) -> Any:
|
113
|
+
"""Get value by key."""
|
114
|
+
key_str = str(key)
|
115
|
+
|
116
|
+
if key_str == "list_info":
|
117
|
+
return {
|
118
|
+
'size': self._size,
|
119
|
+
'doubly_linked': self.doubly_linked,
|
120
|
+
'first': self.first(),
|
121
|
+
'last': self.last()
|
122
|
+
}
|
123
|
+
elif key_str.isdigit():
|
124
|
+
# Numeric access by index
|
125
|
+
index = int(key_str)
|
126
|
+
node = self._get_node_at_index(index)
|
127
|
+
return node.value if node else default
|
128
|
+
|
129
|
+
node = self._key_to_node.get(key_str)
|
130
|
+
return node.value if node else default
|
131
|
+
|
132
|
+
def has(self, key: Any) -> bool:
|
133
|
+
"""Check if key exists."""
|
134
|
+
key_str = str(key)
|
135
|
+
|
136
|
+
if key_str == "list_info":
|
137
|
+
return True
|
138
|
+
elif key_str.isdigit():
|
139
|
+
index = int(key_str)
|
140
|
+
return 0 <= index < self._size
|
141
|
+
|
142
|
+
return key_str in self._key_to_node
|
143
|
+
|
144
|
+
def remove(self, key: Any) -> bool:
|
145
|
+
"""Remove key from list."""
|
146
|
+
key_str = str(key)
|
147
|
+
|
148
|
+
if key_str.isdigit():
|
149
|
+
# Remove by index
|
150
|
+
index = int(key_str)
|
151
|
+
node = self._get_node_at_index(index)
|
152
|
+
if node:
|
153
|
+
self._remove_node(node)
|
154
|
+
del self._key_to_node[node.key]
|
155
|
+
self._size -= 1
|
156
|
+
return True
|
157
|
+
return False
|
158
|
+
|
159
|
+
node = self._key_to_node.get(key_str)
|
160
|
+
if node:
|
161
|
+
self._remove_node(node)
|
162
|
+
del self._key_to_node[key_str]
|
163
|
+
self._size -= 1
|
164
|
+
return True
|
165
|
+
|
166
|
+
return False
|
167
|
+
|
168
|
+
def delete(self, key: Any) -> bool:
|
169
|
+
"""Remove key from list (alias for remove)."""
|
170
|
+
return self.remove(key)
|
171
|
+
|
172
|
+
def clear(self) -> None:
|
173
|
+
"""Clear all data."""
|
174
|
+
self._head.next = self._tail
|
175
|
+
self._tail.prev = self._head
|
176
|
+
self._key_to_node.clear()
|
177
|
+
self._size = 0
|
178
|
+
|
179
|
+
def keys(self) -> Iterator[str]:
|
180
|
+
"""Get all keys in insertion order."""
|
181
|
+
current = self._head.next
|
182
|
+
while current != self._tail:
|
183
|
+
yield current.key
|
184
|
+
current = current.next
|
185
|
+
|
186
|
+
def values(self) -> Iterator[Any]:
|
187
|
+
"""Get all values in insertion order."""
|
188
|
+
current = self._head.next
|
189
|
+
while current != self._tail:
|
190
|
+
yield current.value
|
191
|
+
current = current.next
|
192
|
+
|
193
|
+
def items(self) -> Iterator[tuple[str, Any]]:
|
194
|
+
"""Get all key-value pairs in insertion order."""
|
195
|
+
current = self._head.next
|
196
|
+
while current != self._tail:
|
197
|
+
yield (current.key, current.value)
|
198
|
+
current = current.next
|
199
|
+
|
200
|
+
def __len__(self) -> int:
|
201
|
+
"""Get number of elements."""
|
202
|
+
return self._size
|
203
|
+
|
204
|
+
def to_native(self) -> List[Any]:
|
205
|
+
"""Convert to native Python list."""
|
206
|
+
return list(self.values())
|
207
|
+
|
208
|
+
@property
|
209
|
+
def is_list(self) -> bool:
|
210
|
+
"""This is a list strategy."""
|
211
|
+
return True
|
212
|
+
|
213
|
+
@property
|
214
|
+
def is_dict(self) -> bool:
|
215
|
+
"""This also behaves like a dict."""
|
216
|
+
return True
|
217
|
+
|
218
|
+
# ============================================================================
|
219
|
+
# LINKED LIST SPECIFIC OPERATIONS
|
220
|
+
# ============================================================================
|
221
|
+
|
222
|
+
def append(self, value: Any) -> str:
|
223
|
+
"""Append value to end of list."""
|
224
|
+
key = str(self._size)
|
225
|
+
self.put(key, value)
|
226
|
+
return key
|
227
|
+
|
228
|
+
def prepend(self, value: Any) -> str:
|
229
|
+
"""Prepend value to beginning of list."""
|
230
|
+
key = f"prepend_{self._size}"
|
231
|
+
new_node = self._insert_after(self._head, key, value)
|
232
|
+
self._key_to_node[key] = new_node
|
233
|
+
self._size += 1
|
234
|
+
return key
|
235
|
+
|
236
|
+
def insert_at(self, index: int, value: Any) -> str:
|
237
|
+
"""Insert value at specific index."""
|
238
|
+
if index < 0 or index > self._size:
|
239
|
+
raise IndexError(f"Index {index} out of range")
|
240
|
+
|
241
|
+
if index == 0:
|
242
|
+
return self.prepend(value)
|
243
|
+
elif index == self._size:
|
244
|
+
return self.append(value)
|
245
|
+
|
246
|
+
# Find insertion point
|
247
|
+
prev_node = self._get_node_at_index(index - 1)
|
248
|
+
if not prev_node:
|
249
|
+
raise IndexError(f"Cannot find insertion point at index {index}")
|
250
|
+
|
251
|
+
key = f"insert_{index}_{self._size}"
|
252
|
+
new_node = self._insert_after(prev_node, key, value)
|
253
|
+
self._key_to_node[key] = new_node
|
254
|
+
self._size += 1
|
255
|
+
return key
|
256
|
+
|
257
|
+
def pop(self) -> Any:
|
258
|
+
"""Remove and return last element."""
|
259
|
+
if self._size == 0:
|
260
|
+
raise IndexError("pop from empty list")
|
261
|
+
|
262
|
+
last_node = self._tail.prev
|
263
|
+
value = last_node.value
|
264
|
+
self._remove_node(last_node)
|
265
|
+
del self._key_to_node[last_node.key]
|
266
|
+
self._size -= 1
|
267
|
+
return value
|
268
|
+
|
269
|
+
def popleft(self) -> Any:
|
270
|
+
"""Remove and return first element."""
|
271
|
+
if self._size == 0:
|
272
|
+
raise IndexError("popleft from empty list")
|
273
|
+
|
274
|
+
first_node = self._head.next
|
275
|
+
value = first_node.value
|
276
|
+
self._remove_node(first_node)
|
277
|
+
del self._key_to_node[first_node.key]
|
278
|
+
self._size -= 1
|
279
|
+
return value
|
280
|
+
|
281
|
+
def first(self) -> Any:
|
282
|
+
"""Get first element without removing."""
|
283
|
+
if self._size == 0:
|
284
|
+
return None
|
285
|
+
return self._head.next.value
|
286
|
+
|
287
|
+
def last(self) -> Any:
|
288
|
+
"""Get last element without removing."""
|
289
|
+
if self._size == 0:
|
290
|
+
return None
|
291
|
+
return self._tail.prev.value
|
292
|
+
|
293
|
+
def reverse(self) -> None:
|
294
|
+
"""Reverse the list in place."""
|
295
|
+
if self._size <= 1:
|
296
|
+
return
|
297
|
+
|
298
|
+
# Swap all next/prev pointers
|
299
|
+
current = self._head
|
300
|
+
while current:
|
301
|
+
current.next, current.prev = current.prev, current.next
|
302
|
+
current = current.prev # Note: we swapped, so prev is now next
|
303
|
+
|
304
|
+
# Swap head and tail
|
305
|
+
self._head, self._tail = self._tail, self._head
|
306
|
+
|
307
|
+
def get_at_index(self, index: int) -> Any:
|
308
|
+
"""Get value at specific index."""
|
309
|
+
node = self._get_node_at_index(index)
|
310
|
+
if not node:
|
311
|
+
raise IndexError(f"Index {index} out of range")
|
312
|
+
return node.value
|
313
|
+
|
314
|
+
def set_at_index(self, index: int, value: Any) -> None:
|
315
|
+
"""Set value at specific index."""
|
316
|
+
node = self._get_node_at_index(index)
|
317
|
+
if not node:
|
318
|
+
raise IndexError(f"Index {index} out of range")
|
319
|
+
node.value = value
|
320
|
+
|
321
|
+
def find_index(self, value: Any) -> int:
|
322
|
+
"""Find index of first occurrence of value."""
|
323
|
+
current = self._head.next
|
324
|
+
index = 0
|
325
|
+
|
326
|
+
while current != self._tail:
|
327
|
+
if current.value == value:
|
328
|
+
return index
|
329
|
+
current = current.next
|
330
|
+
index += 1
|
331
|
+
|
332
|
+
return -1
|
333
|
+
|
334
|
+
def remove_value(self, value: Any) -> bool:
|
335
|
+
"""Remove first occurrence of value."""
|
336
|
+
current = self._head.next
|
337
|
+
|
338
|
+
while current != self._tail:
|
339
|
+
if current.value == value:
|
340
|
+
self._remove_node(current)
|
341
|
+
del self._key_to_node[current.key]
|
342
|
+
self._size -= 1
|
343
|
+
return True
|
344
|
+
current = current.next
|
345
|
+
|
346
|
+
return False
|
347
|
+
|
348
|
+
def count_value(self, value: Any) -> int:
|
349
|
+
"""Count occurrences of value."""
|
350
|
+
count = 0
|
351
|
+
current = self._head.next
|
352
|
+
|
353
|
+
while current != self._tail:
|
354
|
+
if current.value == value:
|
355
|
+
count += 1
|
356
|
+
current = current.next
|
357
|
+
|
358
|
+
return count
|
359
|
+
|
360
|
+
def to_array(self) -> List[Any]:
|
361
|
+
"""Convert to array representation."""
|
362
|
+
return list(self.values())
|
363
|
+
|
364
|
+
def get_statistics(self) -> Dict[str, Any]:
|
365
|
+
"""Get comprehensive linked list statistics."""
|
366
|
+
return {
|
367
|
+
'size': self._size,
|
368
|
+
'doubly_linked': self.doubly_linked,
|
369
|
+
'first_value': self.first(),
|
370
|
+
'last_value': self.last(),
|
371
|
+
'memory_overhead': self._size * (64 if self.doubly_linked else 32), # Pointer overhead
|
372
|
+
'access_pattern': 'sequential'
|
373
|
+
}
|
374
|
+
|
375
|
+
# ============================================================================
|
376
|
+
# PERFORMANCE CHARACTERISTICS
|
377
|
+
# ============================================================================
|
378
|
+
|
379
|
+
@property
|
380
|
+
def backend_info(self) -> Dict[str, Any]:
|
381
|
+
"""Get backend implementation info."""
|
382
|
+
return {
|
383
|
+
'strategy': 'LINKED_LIST',
|
384
|
+
'backend': f'{"Doubly" if self.doubly_linked else "Singly"} linked list with sentinel nodes',
|
385
|
+
'doubly_linked': self.doubly_linked,
|
386
|
+
'complexity': {
|
387
|
+
'append': 'O(1)',
|
388
|
+
'prepend': 'O(1)',
|
389
|
+
'insert_at': 'O(n)',
|
390
|
+
'remove_at': 'O(n)',
|
391
|
+
'access_by_index': 'O(n)',
|
392
|
+
'search': 'O(n)',
|
393
|
+
'space': 'O(n)'
|
394
|
+
}
|
395
|
+
}
|
396
|
+
|
397
|
+
@property
|
398
|
+
def metrics(self) -> Dict[str, Any]:
|
399
|
+
"""Get performance metrics."""
|
400
|
+
stats = self.get_statistics()
|
401
|
+
|
402
|
+
return {
|
403
|
+
'size': stats['size'],
|
404
|
+
'first_value': str(stats['first_value']) if stats['first_value'] is not None else 'None',
|
405
|
+
'last_value': str(stats['last_value']) if stats['last_value'] is not None else 'None',
|
406
|
+
'doubly_linked': stats['doubly_linked'],
|
407
|
+
'memory_overhead': f"{stats['memory_overhead']} bytes",
|
408
|
+
'access_pattern': stats['access_pattern']
|
409
|
+
}
|