exonware-xwnode 0.0.1.21__py3-none-any.whl → 0.0.1.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- exonware/__init__.py +8 -1
- exonware/xwnode/__init__.py +18 -5
- exonware/xwnode/add_strategy_types.py +165 -0
- exonware/xwnode/base.py +7 -5
- exonware/xwnode/common/__init__.py +1 -1
- exonware/xwnode/common/graph/__init__.py +30 -0
- exonware/xwnode/common/graph/caching.py +131 -0
- exonware/xwnode/common/graph/contracts.py +100 -0
- exonware/xwnode/common/graph/errors.py +44 -0
- exonware/xwnode/common/graph/indexing.py +260 -0
- exonware/xwnode/common/graph/manager.py +568 -0
- exonware/xwnode/common/management/__init__.py +3 -5
- exonware/xwnode/common/management/manager.py +9 -9
- exonware/xwnode/common/management/migration.py +6 -6
- exonware/xwnode/common/monitoring/__init__.py +3 -5
- exonware/xwnode/common/monitoring/metrics.py +7 -3
- exonware/xwnode/common/monitoring/pattern_detector.py +2 -2
- exonware/xwnode/common/monitoring/performance_monitor.py +6 -2
- exonware/xwnode/common/patterns/__init__.py +3 -5
- exonware/xwnode/common/patterns/advisor.py +1 -1
- exonware/xwnode/common/patterns/flyweight.py +6 -2
- exonware/xwnode/common/patterns/registry.py +203 -184
- exonware/xwnode/common/utils/__init__.py +25 -11
- exonware/xwnode/common/utils/simple.py +1 -1
- exonware/xwnode/config.py +3 -8
- exonware/xwnode/contracts.py +4 -105
- exonware/xwnode/defs.py +413 -159
- exonware/xwnode/edges/strategies/__init__.py +86 -4
- exonware/xwnode/edges/strategies/_base_edge.py +2 -2
- exonware/xwnode/edges/strategies/adj_list.py +287 -121
- exonware/xwnode/edges/strategies/adj_matrix.py +316 -222
- exonware/xwnode/edges/strategies/base.py +1 -1
- exonware/xwnode/edges/strategies/{edge_bidir_wrapper.py → bidir_wrapper.py} +45 -4
- exonware/xwnode/edges/strategies/bitemporal.py +520 -0
- exonware/xwnode/edges/strategies/{edge_block_adj_matrix.py → block_adj_matrix.py} +77 -6
- exonware/xwnode/edges/strategies/bv_graph.py +664 -0
- exonware/xwnode/edges/strategies/compressed_graph.py +217 -0
- exonware/xwnode/edges/strategies/{edge_coo.py → coo.py} +46 -4
- exonware/xwnode/edges/strategies/{edge_csc.py → csc.py} +45 -4
- exonware/xwnode/edges/strategies/{edge_csr.py → csr.py} +94 -12
- exonware/xwnode/edges/strategies/{edge_dynamic_adj_list.py → dynamic_adj_list.py} +46 -4
- exonware/xwnode/edges/strategies/edge_list.py +168 -0
- exonware/xwnode/edges/strategies/edge_property_store.py +2 -2
- exonware/xwnode/edges/strategies/euler_tour.py +560 -0
- exonware/xwnode/edges/strategies/{edge_flow_network.py → flow_network.py} +2 -2
- exonware/xwnode/edges/strategies/graphblas.py +449 -0
- exonware/xwnode/edges/strategies/hnsw.py +637 -0
- exonware/xwnode/edges/strategies/hop2_labels.py +467 -0
- exonware/xwnode/edges/strategies/{edge_hyperedge_set.py → hyperedge_set.py} +2 -2
- exonware/xwnode/edges/strategies/incidence_matrix.py +250 -0
- exonware/xwnode/edges/strategies/k2_tree.py +613 -0
- exonware/xwnode/edges/strategies/link_cut.py +626 -0
- exonware/xwnode/edges/strategies/multiplex.py +532 -0
- exonware/xwnode/edges/strategies/{edge_neural_graph.py → neural_graph.py} +2 -2
- exonware/xwnode/edges/strategies/{edge_octree.py → octree.py} +69 -11
- exonware/xwnode/edges/strategies/{edge_quadtree.py → quadtree.py} +66 -10
- exonware/xwnode/edges/strategies/roaring_adj.py +438 -0
- exonware/xwnode/edges/strategies/{edge_rtree.py → rtree.py} +43 -5
- exonware/xwnode/edges/strategies/{edge_temporal_edgeset.py → temporal_edgeset.py} +24 -5
- exonware/xwnode/edges/strategies/{edge_tree_graph_basic.py → tree_graph_basic.py} +78 -7
- exonware/xwnode/edges/strategies/{edge_weighted_graph.py → weighted_graph.py} +188 -10
- exonware/xwnode/errors.py +3 -6
- exonware/xwnode/facade.py +20 -20
- exonware/xwnode/nodes/strategies/__init__.py +29 -9
- exonware/xwnode/nodes/strategies/adjacency_list.py +650 -177
- exonware/xwnode/nodes/strategies/aho_corasick.py +358 -183
- exonware/xwnode/nodes/strategies/array_list.py +36 -3
- exonware/xwnode/nodes/strategies/art.py +581 -0
- exonware/xwnode/nodes/strategies/{node_avl_tree.py → avl_tree.py} +77 -6
- exonware/xwnode/nodes/strategies/{node_b_plus_tree.py → b_plus_tree.py} +81 -40
- exonware/xwnode/nodes/strategies/{node_btree.py → b_tree.py} +79 -9
- exonware/xwnode/nodes/strategies/base.py +469 -98
- exonware/xwnode/nodes/strategies/{node_bitmap.py → bitmap.py} +12 -12
- exonware/xwnode/nodes/strategies/{node_bitset_dynamic.py → bitset_dynamic.py} +11 -11
- exonware/xwnode/nodes/strategies/{node_bloom_filter.py → bloom_filter.py} +15 -2
- exonware/xwnode/nodes/strategies/bloomier_filter.py +519 -0
- exonware/xwnode/nodes/strategies/bw_tree.py +531 -0
- exonware/xwnode/nodes/strategies/contracts.py +1 -1
- exonware/xwnode/nodes/strategies/{node_count_min_sketch.py → count_min_sketch.py} +3 -2
- exonware/xwnode/nodes/strategies/{node_cow_tree.py → cow_tree.py} +135 -13
- exonware/xwnode/nodes/strategies/crdt_map.py +629 -0
- exonware/xwnode/nodes/strategies/{node_cuckoo_hash.py → cuckoo_hash.py} +2 -2
- exonware/xwnode/nodes/strategies/{node_xdata_optimized.py → data_interchange_optimized.py} +21 -4
- exonware/xwnode/nodes/strategies/dawg.py +876 -0
- exonware/xwnode/nodes/strategies/deque.py +321 -153
- exonware/xwnode/nodes/strategies/extendible_hash.py +93 -0
- exonware/xwnode/nodes/strategies/{node_fenwick_tree.py → fenwick_tree.py} +111 -19
- exonware/xwnode/nodes/strategies/hamt.py +403 -0
- exonware/xwnode/nodes/strategies/hash_map.py +354 -67
- exonware/xwnode/nodes/strategies/heap.py +105 -5
- exonware/xwnode/nodes/strategies/hopscotch_hash.py +525 -0
- exonware/xwnode/nodes/strategies/{node_hyperloglog.py → hyperloglog.py} +6 -5
- exonware/xwnode/nodes/strategies/interval_tree.py +742 -0
- exonware/xwnode/nodes/strategies/kd_tree.py +703 -0
- exonware/xwnode/nodes/strategies/learned_index.py +533 -0
- exonware/xwnode/nodes/strategies/linear_hash.py +93 -0
- exonware/xwnode/nodes/strategies/linked_list.py +316 -119
- exonware/xwnode/nodes/strategies/{node_lsm_tree.py → lsm_tree.py} +219 -15
- exonware/xwnode/nodes/strategies/masstree.py +130 -0
- exonware/xwnode/nodes/strategies/{node_persistent_tree.py → persistent_tree.py} +149 -9
- exonware/xwnode/nodes/strategies/priority_queue.py +544 -132
- exonware/xwnode/nodes/strategies/queue.py +249 -120
- exonware/xwnode/nodes/strategies/{node_red_black_tree.py → red_black_tree.py} +183 -72
- exonware/xwnode/nodes/strategies/{node_roaring_bitmap.py → roaring_bitmap.py} +19 -6
- exonware/xwnode/nodes/strategies/rope.py +717 -0
- exonware/xwnode/nodes/strategies/{node_segment_tree.py → segment_tree.py} +106 -106
- exonware/xwnode/nodes/strategies/{node_set_hash.py → set_hash.py} +30 -29
- exonware/xwnode/nodes/strategies/{node_skip_list.py → skip_list.py} +74 -6
- exonware/xwnode/nodes/strategies/sparse_matrix.py +427 -131
- exonware/xwnode/nodes/strategies/{node_splay_tree.py → splay_tree.py} +55 -6
- exonware/xwnode/nodes/strategies/stack.py +244 -112
- exonware/xwnode/nodes/strategies/{node_suffix_array.py → suffix_array.py} +5 -1
- exonware/xwnode/nodes/strategies/t_tree.py +94 -0
- exonware/xwnode/nodes/strategies/{node_treap.py → treap.py} +75 -6
- exonware/xwnode/nodes/strategies/{node_tree_graph_hybrid.py → tree_graph_hybrid.py} +46 -5
- exonware/xwnode/nodes/strategies/trie.py +153 -9
- exonware/xwnode/nodes/strategies/union_find.py +111 -5
- exonware/xwnode/nodes/strategies/veb_tree.py +856 -0
- exonware/xwnode/strategies/__init__.py +5 -51
- exonware/xwnode/version.py +3 -3
- {exonware_xwnode-0.0.1.21.dist-info → exonware_xwnode-0.0.1.23.dist-info}/METADATA +23 -3
- exonware_xwnode-0.0.1.23.dist-info/RECORD +130 -0
- exonware/xwnode/edges/strategies/edge_adj_list.py +0 -353
- exonware/xwnode/edges/strategies/edge_adj_matrix.py +0 -445
- exonware/xwnode/nodes/strategies/_base_node.py +0 -307
- exonware/xwnode/nodes/strategies/node_aho_corasick.py +0 -525
- exonware/xwnode/nodes/strategies/node_array_list.py +0 -179
- exonware/xwnode/nodes/strategies/node_hash_map.py +0 -273
- exonware/xwnode/nodes/strategies/node_heap.py +0 -196
- exonware/xwnode/nodes/strategies/node_linked_list.py +0 -413
- exonware/xwnode/nodes/strategies/node_trie.py +0 -257
- exonware/xwnode/nodes/strategies/node_union_find.py +0 -192
- exonware/xwnode/queries/executors/__init__.py +0 -47
- exonware/xwnode/queries/executors/advanced/__init__.py +0 -37
- exonware/xwnode/queries/executors/advanced/aggregate_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/ask_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/construct_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/describe_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/for_loop_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/foreach_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/join_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/let_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/mutation_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/options_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/pipe_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/subscribe_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/subscription_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/union_executor.py +0 -50
- exonware/xwnode/queries/executors/advanced/window_executor.py +0 -51
- exonware/xwnode/queries/executors/advanced/with_cte_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/__init__.py +0 -21
- exonware/xwnode/queries/executors/aggregation/avg_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/count_executor.py +0 -38
- exonware/xwnode/queries/executors/aggregation/distinct_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/group_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/having_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/max_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/min_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/sum_executor.py +0 -50
- exonware/xwnode/queries/executors/aggregation/summarize_executor.py +0 -50
- exonware/xwnode/queries/executors/array/__init__.py +0 -9
- exonware/xwnode/queries/executors/array/indexing_executor.py +0 -51
- exonware/xwnode/queries/executors/array/slicing_executor.py +0 -51
- exonware/xwnode/queries/executors/base.py +0 -257
- exonware/xwnode/queries/executors/capability_checker.py +0 -204
- exonware/xwnode/queries/executors/contracts.py +0 -166
- exonware/xwnode/queries/executors/core/__init__.py +0 -17
- exonware/xwnode/queries/executors/core/create_executor.py +0 -96
- exonware/xwnode/queries/executors/core/delete_executor.py +0 -99
- exonware/xwnode/queries/executors/core/drop_executor.py +0 -100
- exonware/xwnode/queries/executors/core/insert_executor.py +0 -39
- exonware/xwnode/queries/executors/core/select_executor.py +0 -152
- exonware/xwnode/queries/executors/core/update_executor.py +0 -102
- exonware/xwnode/queries/executors/data/__init__.py +0 -13
- exonware/xwnode/queries/executors/data/alter_executor.py +0 -50
- exonware/xwnode/queries/executors/data/load_executor.py +0 -50
- exonware/xwnode/queries/executors/data/merge_executor.py +0 -50
- exonware/xwnode/queries/executors/data/store_executor.py +0 -50
- exonware/xwnode/queries/executors/defs.py +0 -93
- exonware/xwnode/queries/executors/engine.py +0 -221
- exonware/xwnode/queries/executors/errors.py +0 -68
- exonware/xwnode/queries/executors/filtering/__init__.py +0 -25
- exonware/xwnode/queries/executors/filtering/between_executor.py +0 -80
- exonware/xwnode/queries/executors/filtering/filter_executor.py +0 -79
- exonware/xwnode/queries/executors/filtering/has_executor.py +0 -70
- exonware/xwnode/queries/executors/filtering/in_executor.py +0 -70
- exonware/xwnode/queries/executors/filtering/like_executor.py +0 -76
- exonware/xwnode/queries/executors/filtering/optional_executor.py +0 -76
- exonware/xwnode/queries/executors/filtering/range_executor.py +0 -80
- exonware/xwnode/queries/executors/filtering/term_executor.py +0 -77
- exonware/xwnode/queries/executors/filtering/values_executor.py +0 -71
- exonware/xwnode/queries/executors/filtering/where_executor.py +0 -44
- exonware/xwnode/queries/executors/graph/__init__.py +0 -15
- exonware/xwnode/queries/executors/graph/in_traverse_executor.py +0 -51
- exonware/xwnode/queries/executors/graph/match_executor.py +0 -51
- exonware/xwnode/queries/executors/graph/out_executor.py +0 -51
- exonware/xwnode/queries/executors/graph/path_executor.py +0 -51
- exonware/xwnode/queries/executors/graph/return_executor.py +0 -51
- exonware/xwnode/queries/executors/ordering/__init__.py +0 -9
- exonware/xwnode/queries/executors/ordering/by_executor.py +0 -50
- exonware/xwnode/queries/executors/ordering/order_executor.py +0 -51
- exonware/xwnode/queries/executors/projection/__init__.py +0 -9
- exonware/xwnode/queries/executors/projection/extend_executor.py +0 -50
- exonware/xwnode/queries/executors/projection/project_executor.py +0 -50
- exonware/xwnode/queries/executors/registry.py +0 -173
- exonware/xwnode/queries/parsers/__init__.py +0 -26
- exonware/xwnode/queries/parsers/base.py +0 -86
- exonware/xwnode/queries/parsers/contracts.py +0 -46
- exonware/xwnode/queries/parsers/errors.py +0 -53
- exonware/xwnode/queries/parsers/sql_param_extractor.py +0 -318
- exonware/xwnode/queries/strategies/__init__.py +0 -24
- exonware/xwnode/queries/strategies/base.py +0 -236
- exonware/xwnode/queries/strategies/cql.py +0 -201
- exonware/xwnode/queries/strategies/cypher.py +0 -181
- exonware/xwnode/queries/strategies/datalog.py +0 -70
- exonware/xwnode/queries/strategies/elastic_dsl.py +0 -70
- exonware/xwnode/queries/strategies/eql.py +0 -70
- exonware/xwnode/queries/strategies/flux.py +0 -70
- exonware/xwnode/queries/strategies/gql.py +0 -70
- exonware/xwnode/queries/strategies/graphql.py +0 -240
- exonware/xwnode/queries/strategies/gremlin.py +0 -181
- exonware/xwnode/queries/strategies/hiveql.py +0 -214
- exonware/xwnode/queries/strategies/hql.py +0 -70
- exonware/xwnode/queries/strategies/jmespath.py +0 -219
- exonware/xwnode/queries/strategies/jq.py +0 -66
- exonware/xwnode/queries/strategies/json_query.py +0 -66
- exonware/xwnode/queries/strategies/jsoniq.py +0 -248
- exonware/xwnode/queries/strategies/kql.py +0 -70
- exonware/xwnode/queries/strategies/linq.py +0 -238
- exonware/xwnode/queries/strategies/logql.py +0 -70
- exonware/xwnode/queries/strategies/mql.py +0 -68
- exonware/xwnode/queries/strategies/n1ql.py +0 -210
- exonware/xwnode/queries/strategies/partiql.py +0 -70
- exonware/xwnode/queries/strategies/pig.py +0 -215
- exonware/xwnode/queries/strategies/promql.py +0 -70
- exonware/xwnode/queries/strategies/sparql.py +0 -220
- exonware/xwnode/queries/strategies/sql.py +0 -275
- exonware/xwnode/queries/strategies/xml_query.py +0 -66
- exonware/xwnode/queries/strategies/xpath.py +0 -223
- exonware/xwnode/queries/strategies/xquery.py +0 -258
- exonware/xwnode/queries/strategies/xwnode_executor.py +0 -332
- exonware/xwnode/queries/strategies/xwquery.py +0 -456
- exonware_xwnode-0.0.1.21.dist-info/RECORD +0 -214
- /exonware/xwnode/nodes/strategies/{node_ordered_map.py → ordered_map.py} +0 -0
- /exonware/xwnode/nodes/strategies/{node_ordered_map_balanced.py → ordered_map_balanced.py} +0 -0
- /exonware/xwnode/nodes/strategies/{node_patricia.py → patricia.py} +0 -0
- /exonware/xwnode/nodes/strategies/{node_radix_trie.py → radix_trie.py} +0 -0
- /exonware/xwnode/nodes/strategies/{node_set_tree.py → set_tree.py} +0 -0
- {exonware_xwnode-0.0.1.21.dist-info → exonware_xwnode-0.0.1.23.dist-info}/WHEEL +0 -0
- {exonware_xwnode-0.0.1.21.dist-info → exonware_xwnode-0.0.1.23.dist-info}/licenses/LICENSE +0 -0
@@ -1,16 +1,25 @@
|
|
1
1
|
"""
|
2
|
+
#exonware/xwnode/src/exonware/xwnode/nodes/strategies/deque.py
|
3
|
+
|
2
4
|
Deque Strategy Implementation
|
3
5
|
|
4
|
-
|
6
|
+
Production-grade double-ended queue data structure.
|
7
|
+
|
8
|
+
Best Practices Implemented:
|
9
|
+
- Python's collections.deque for optimal performance
|
10
|
+
- O(1) operations at both ends
|
11
|
+
- Thread-safe for certain operations
|
12
|
+
- Memory-efficient with block-based storage
|
13
|
+
- Proper deque semantics following industry standards
|
5
14
|
|
6
15
|
Company: eXonware.com
|
7
16
|
Author: Eng. Muhammad AlShehri
|
8
17
|
Email: connect@exonware.com
|
9
|
-
Version: 0.0.1.
|
10
|
-
Generation Date:
|
18
|
+
Version: 0.0.1.23
|
19
|
+
Generation Date: October 12, 2025
|
11
20
|
"""
|
12
21
|
|
13
|
-
from typing import Any, Iterator, Optional, Dict
|
22
|
+
from typing import Any, Iterator, List, Optional, Dict
|
14
23
|
from collections import deque
|
15
24
|
from .base import ANodeLinearStrategy
|
16
25
|
from .contracts import NodeType
|
@@ -19,187 +28,346 @@ from ...defs import NodeMode, NodeTrait
|
|
19
28
|
|
20
29
|
class DequeStrategy(ANodeLinearStrategy):
|
21
30
|
"""
|
22
|
-
Deque (Double-
|
23
|
-
|
24
|
-
|
25
|
-
|
31
|
+
Production-grade Deque (Double-Ended Queue) node strategy.
|
32
|
+
|
33
|
+
Optimized for:
|
34
|
+
- Sliding window algorithms (maximum/minimum in window)
|
35
|
+
- Breadth-first search with bidirectional traversal
|
36
|
+
- Work-stealing algorithms (task scheduling)
|
37
|
+
- Palindrome checking
|
38
|
+
- Undo/redo with bounded history
|
39
|
+
- Cache implementations (LRU with deque)
|
40
|
+
|
41
|
+
Performance:
|
42
|
+
- Append (both ends): O(1)
|
43
|
+
- Pop (both ends): O(1)
|
44
|
+
- Rotate: O(k) where k is rotation count
|
45
|
+
- Random access: O(n)
|
46
|
+
- Space: O(n)
|
47
|
+
|
48
|
+
Security:
|
49
|
+
- Bounds checking on all operations
|
50
|
+
- Safe empty deque handling
|
51
|
+
- Optional max size for memory protection
|
52
|
+
|
53
|
+
Thread-Safety:
|
54
|
+
- Thread-safe for append/pop on same end
|
55
|
+
- NOT thread-safe for operations on opposite ends
|
56
|
+
- Use queue.Queue for full thread-safety
|
57
|
+
|
58
|
+
Implementation Details:
|
59
|
+
- Uses collections.deque (doubly-linked list of blocks)
|
60
|
+
- Block size optimized for cache performance
|
61
|
+
- Memory-efficient with contiguous memory blocks
|
62
|
+
|
63
|
+
Follows eXonware Priorities:
|
64
|
+
1. Security: Bounds checking, memory limits
|
65
|
+
2. Usability: Intuitive double-ended interface
|
66
|
+
3. Maintainability: Clean implementation using stdlib
|
67
|
+
4. Performance: O(1) operations at both ends
|
68
|
+
5. Extensibility: Easy to build LRU caches and other patterns
|
69
|
+
"""
|
26
70
|
|
27
71
|
# Strategy type classification
|
28
72
|
STRATEGY_TYPE = NodeType.LINEAR
|
29
|
-
nd breadth-first search.
|
30
|
-
"""
|
31
|
-
|
32
|
-
def __init__(self):
|
33
|
-
"""Initialize an empty deque."""
|
34
|
-
super().__init__()
|
35
|
-
self._deque: deque = deque()
|
36
|
-
self._mode = NodeMode.DEQUE
|
37
|
-
self._traits = {NodeTrait.DOUBLE_ENDED, NodeTrait.FAST_INSERT, NodeTrait.FAST_DELETE}
|
38
|
-
|
39
|
-
def insert(self, key: str, value: Any) -> None:
|
40
|
-
"""Insert an item (defaults to back)."""
|
41
|
-
self._deque.append((key, value))
|
42
|
-
|
43
|
-
def find(self, key: str) -> Optional[Any]:
|
44
|
-
"""Find an item in the deque (O(n) operation)."""
|
45
|
-
for k, v in self._deque:
|
46
|
-
if k == key:
|
47
|
-
return v
|
48
|
-
return None
|
49
|
-
|
50
|
-
def delete(self, key: str) -> bool:
|
51
|
-
"""Remove an item from the deque."""
|
52
|
-
for i, (k, v) in enumerate(self._deque):
|
53
|
-
if k == key:
|
54
|
-
del self._deque[i]
|
55
|
-
return True
|
56
|
-
return False
|
57
|
-
|
58
|
-
def size(self) -> int:
|
59
|
-
"""Get the number of items in the deque."""
|
60
|
-
return len(self._deque)
|
61
73
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
74
|
+
__slots__ = ('_deque', '_max_size')
|
75
|
+
|
76
|
+
def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
|
77
|
+
"""
|
78
|
+
Initialize an empty deque.
|
79
|
+
|
80
|
+
Args:
|
81
|
+
traits: Additional node traits
|
82
|
+
**options:
|
83
|
+
max_size: Optional maximum deque size (default: unlimited)
|
84
|
+
initial_values: Optional list of initial values
|
85
|
+
"""
|
86
|
+
super().__init__(
|
87
|
+
NodeMode.DEQUE,
|
88
|
+
traits | NodeTrait.DOUBLE_ENDED | NodeTrait.FAST_INSERT | NodeTrait.FAST_DELETE,
|
89
|
+
**options
|
90
|
+
)
|
91
|
+
self._max_size: Optional[int] = options.get('max_size')
|
92
|
+
initial_values = options.get('initial_values', [])
|
93
|
+
self._deque: deque = deque(initial_values, maxlen=self._max_size)
|
94
|
+
|
95
|
+
def get_supported_traits(self) -> NodeTrait:
|
96
|
+
"""Get the traits supported by the deque strategy."""
|
97
|
+
return NodeTrait.DOUBLE_ENDED | NodeTrait.FAST_INSERT | NodeTrait.FAST_DELETE
|
98
|
+
|
99
|
+
# ============================================================================
|
100
|
+
# CORE DEQUE OPERATIONS (Industry Standard)
|
101
|
+
# ============================================================================
|
73
102
|
|
74
103
|
def append(self, value: Any) -> None:
|
75
|
-
"""
|
76
|
-
|
77
|
-
|
104
|
+
"""
|
105
|
+
Add an item to the right end.
|
106
|
+
|
107
|
+
Time: O(1)
|
108
|
+
Space: O(1)
|
109
|
+
|
110
|
+
Note: If max_size is set, leftmost item is discarded when full
|
111
|
+
"""
|
112
|
+
self._deque.append(value)
|
78
113
|
|
79
114
|
def appendleft(self, value: Any) -> None:
|
80
|
-
"""
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
115
|
+
"""
|
116
|
+
Add an item to the left end.
|
117
|
+
|
118
|
+
Time: O(1)
|
119
|
+
Space: O(1)
|
120
|
+
|
121
|
+
Note: If max_size is set, rightmost item is discarded when full
|
122
|
+
"""
|
123
|
+
self._deque.appendleft(value)
|
124
|
+
|
125
|
+
def pop(self) -> Any:
|
126
|
+
"""
|
127
|
+
Remove and return an item from the right end.
|
128
|
+
|
129
|
+
Time: O(1)
|
130
|
+
Space: O(1)
|
131
|
+
|
132
|
+
Raises:
|
133
|
+
IndexError: If deque is empty
|
134
|
+
"""
|
86
135
|
if self.is_empty():
|
87
|
-
|
88
|
-
|
89
|
-
return
|
90
|
-
|
91
|
-
def popleft(self) ->
|
92
|
-
"""
|
136
|
+
raise IndexError("pop from empty deque")
|
137
|
+
|
138
|
+
return self._deque.pop()
|
139
|
+
|
140
|
+
def popleft(self) -> Any:
|
141
|
+
"""
|
142
|
+
Remove and return an item from the left end.
|
143
|
+
|
144
|
+
Time: O(1)
|
145
|
+
Space: O(1)
|
146
|
+
|
147
|
+
Raises:
|
148
|
+
IndexError: If deque is empty
|
149
|
+
"""
|
93
150
|
if self.is_empty():
|
94
|
-
|
95
|
-
|
96
|
-
return
|
97
|
-
|
98
|
-
def peek_right(self) ->
|
99
|
-
"""
|
151
|
+
raise IndexError("pop from empty deque")
|
152
|
+
|
153
|
+
return self._deque.popleft()
|
154
|
+
|
155
|
+
def peek_right(self) -> Any:
|
156
|
+
"""
|
157
|
+
Peek at the rightmost item without removing it.
|
158
|
+
|
159
|
+
Time: O(1)
|
160
|
+
|
161
|
+
Raises:
|
162
|
+
IndexError: If deque is empty
|
163
|
+
"""
|
100
164
|
if self.is_empty():
|
101
|
-
|
102
|
-
|
103
|
-
return
|
104
|
-
|
105
|
-
def peek_left(self) ->
|
106
|
-
"""
|
165
|
+
raise IndexError("peek from empty deque")
|
166
|
+
|
167
|
+
return self._deque[-1]
|
168
|
+
|
169
|
+
def peek_left(self) -> Any:
|
170
|
+
"""
|
171
|
+
Peek at the leftmost item without removing it.
|
172
|
+
|
173
|
+
Time: O(1)
|
174
|
+
|
175
|
+
Raises:
|
176
|
+
IndexError: If deque is empty
|
177
|
+
"""
|
107
178
|
if self.is_empty():
|
108
|
-
|
109
|
-
|
110
|
-
return
|
179
|
+
raise IndexError("peek from empty deque")
|
180
|
+
|
181
|
+
return self._deque[0]
|
111
182
|
|
112
183
|
def rotate(self, n: int = 1) -> None:
|
113
|
-
"""
|
184
|
+
"""
|
185
|
+
Rotate the deque n steps to the right (positive) or left (negative).
|
186
|
+
|
187
|
+
Time: O(k) where k = abs(n)
|
188
|
+
Space: O(1)
|
189
|
+
|
190
|
+
Args:
|
191
|
+
n: Number of steps to rotate (positive=right, negative=left)
|
192
|
+
"""
|
114
193
|
self._deque.rotate(n)
|
115
194
|
|
116
195
|
def reverse(self) -> None:
|
117
|
-
"""
|
196
|
+
"""
|
197
|
+
Reverse the deque in place.
|
198
|
+
|
199
|
+
Time: O(n)
|
200
|
+
Space: O(1)
|
201
|
+
"""
|
118
202
|
self._deque.reverse()
|
119
203
|
|
204
|
+
def extend(self, values: List[Any]) -> None:
|
205
|
+
"""
|
206
|
+
Extend the deque by appending elements from the iterable (right end).
|
207
|
+
|
208
|
+
Time: O(k) where k = len(values)
|
209
|
+
"""
|
210
|
+
self._deque.extend(values)
|
211
|
+
|
212
|
+
def extendleft(self, values: List[Any]) -> None:
|
213
|
+
"""
|
214
|
+
Extend the deque by appending elements from the iterable (left end).
|
215
|
+
|
216
|
+
Time: O(k) where k = len(values)
|
217
|
+
|
218
|
+
Note: Values are added in reverse order
|
219
|
+
"""
|
220
|
+
self._deque.extendleft(values)
|
221
|
+
|
222
|
+
# ============================================================================
|
223
|
+
# REQUIRED ABSTRACT METHODS (from ANodeStrategy)
|
224
|
+
# ============================================================================
|
225
|
+
|
226
|
+
def put(self, key: Any, value: Any = None) -> None:
|
227
|
+
"""Store value (appends to right end)."""
|
228
|
+
self.append(value if value is not None else key)
|
229
|
+
|
230
|
+
def get(self, key: Any, default: Any = None) -> Any:
|
231
|
+
"""Get value by key (O(n) search)."""
|
232
|
+
for val in self._deque:
|
233
|
+
if val == key:
|
234
|
+
return val
|
235
|
+
return default
|
236
|
+
|
237
|
+
def has(self, key: Any) -> bool:
|
238
|
+
"""Check if key exists (O(n))."""
|
239
|
+
return key in self._deque
|
240
|
+
|
241
|
+
def delete(self, key: Any) -> bool:
|
242
|
+
"""Delete first occurrence of value (O(n))."""
|
243
|
+
try:
|
244
|
+
self._deque.remove(key)
|
245
|
+
return True
|
246
|
+
except ValueError:
|
247
|
+
return False
|
248
|
+
|
249
|
+
def keys(self) -> Iterator[Any]:
|
250
|
+
"""Get all values as keys."""
|
251
|
+
return iter(self._deque)
|
252
|
+
|
253
|
+
def values(self) -> Iterator[Any]:
|
254
|
+
"""Get all values."""
|
255
|
+
return iter(self._deque)
|
256
|
+
|
257
|
+
def items(self) -> Iterator[tuple[Any, Any]]:
|
258
|
+
"""Get all items as (value, value) pairs."""
|
259
|
+
for val in self._deque:
|
260
|
+
yield (val, val)
|
261
|
+
|
262
|
+
# ============================================================================
|
263
|
+
# UTILITY METHODS
|
264
|
+
# ============================================================================
|
265
|
+
|
266
|
+
def size(self) -> int:
|
267
|
+
"""Get the number of items in the deque."""
|
268
|
+
return len(self._deque)
|
269
|
+
|
270
|
+
def is_empty(self) -> bool:
|
271
|
+
"""Check if the deque is empty."""
|
272
|
+
return len(self._deque) == 0
|
273
|
+
|
274
|
+
def is_full(self) -> bool:
|
275
|
+
"""Check if deque has reached max_size."""
|
276
|
+
return self._max_size is not None and len(self._deque) >= self._max_size
|
277
|
+
|
120
278
|
def clear(self) -> None:
|
121
279
|
"""Clear all items from the deque."""
|
122
280
|
self._deque.clear()
|
281
|
+
self._record_access("clear")
|
123
282
|
|
124
|
-
def
|
125
|
-
"""
|
126
|
-
|
127
|
-
key, value = self._deque[index]
|
128
|
-
return value
|
129
|
-
return None
|
130
|
-
|
131
|
-
def set_at_index(self, index: int, value: Any) -> bool:
|
132
|
-
"""Set item at specific index."""
|
133
|
-
if 0 <= index < len(self._deque):
|
134
|
-
key, old_value = self._deque[index]
|
135
|
-
self._deque[index] = (key, value)
|
136
|
-
return True
|
137
|
-
return False
|
283
|
+
def count(self, value: Any) -> int:
|
284
|
+
"""Count occurrences of value."""
|
285
|
+
return self._deque.count(value)
|
138
286
|
|
139
|
-
def
|
140
|
-
"""
|
141
|
-
self.
|
287
|
+
def to_list(self) -> List[Any]:
|
288
|
+
"""Convert deque to list (left to right)."""
|
289
|
+
return list(self._deque)
|
142
290
|
|
143
|
-
def
|
144
|
-
"""
|
145
|
-
self.
|
291
|
+
def to_native(self) -> Dict[str, Any]:
|
292
|
+
"""Convert deque to native dictionary format."""
|
293
|
+
return {str(i): val for i, val in enumerate(self._deque)}
|
146
294
|
|
147
|
-
def
|
148
|
-
"""
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
return True
|
153
|
-
return False
|
295
|
+
def from_native(self, data: Dict[str, Any]) -> None:
|
296
|
+
"""Load deque from native dictionary format."""
|
297
|
+
self._deque.clear()
|
298
|
+
sorted_items = sorted(data.items(), key=lambda x: int(x[0]) if x[0].isdigit() else 0)
|
299
|
+
self._deque.extend(val for _, val in sorted_items)
|
154
300
|
|
155
|
-
def count(self, value: Any) -> int:
|
156
|
-
"""Count occurrences of a value."""
|
157
|
-
count = 0
|
158
|
-
for key, v in self._deque:
|
159
|
-
if v == value:
|
160
|
-
count += 1
|
161
|
-
return count
|
162
|
-
|
163
|
-
def extend(self, values: list) -> None:
|
164
|
-
"""Extend the deque with values from the right."""
|
165
|
-
for value in values:
|
166
|
-
self.append(value)
|
167
|
-
|
168
|
-
def extendleft(self, values: list) -> None:
|
169
|
-
"""Extend the deque with values from the left."""
|
170
|
-
for value in reversed(values):
|
171
|
-
self.appendleft(value)
|
172
301
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
yield value
|
302
|
+
# ============================================================================
|
303
|
+
# PYTHON SPECIAL METHODS
|
304
|
+
# ============================================================================
|
177
305
|
|
178
|
-
def
|
179
|
-
"""
|
180
|
-
return
|
306
|
+
def __len__(self) -> int:
|
307
|
+
"""Return the number of items in the deque."""
|
308
|
+
return len(self._deque)
|
181
309
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
return self.popleft()
|
310
|
+
def __bool__(self) -> bool:
|
311
|
+
"""Return True if deque is not empty."""
|
312
|
+
return bool(self._deque)
|
186
313
|
|
187
|
-
def
|
188
|
-
"""
|
189
|
-
return self.
|
314
|
+
def __iter__(self) -> Iterator[Any]:
|
315
|
+
"""Iterate through deque items (left to right)."""
|
316
|
+
return iter(self._deque)
|
190
317
|
|
191
|
-
def
|
192
|
-
"""
|
193
|
-
return self
|
318
|
+
def __reversed__(self) -> Iterator[Any]:
|
319
|
+
"""Iterate in reverse (right to left)."""
|
320
|
+
return reversed(self._deque)
|
194
321
|
|
195
|
-
def
|
196
|
-
"""
|
197
|
-
return self
|
322
|
+
def __getitem__(self, index: int) -> Any:
|
323
|
+
"""Get item at index."""
|
324
|
+
return self._deque[index]
|
198
325
|
|
199
|
-
def
|
200
|
-
"""
|
201
|
-
|
326
|
+
def __setitem__(self, index: int, value: Any) -> None:
|
327
|
+
"""Set item at index."""
|
328
|
+
self._deque[index] = value
|
202
329
|
|
203
|
-
def
|
204
|
-
"""
|
205
|
-
return self
|
330
|
+
def __repr__(self) -> str:
|
331
|
+
"""Professional string representation."""
|
332
|
+
return f"DequeStrategy(size={len(self._deque)}, maxlen={self._max_size})"
|
333
|
+
|
334
|
+
def __str__(self) -> str:
|
335
|
+
"""Human-readable string representation."""
|
336
|
+
items = ', '.join(str(item) for item in list(self._deque)[:5])
|
337
|
+
suffix = '...' if len(self._deque) > 5 else ''
|
338
|
+
return f"Deque[{items}{suffix}]"
|
339
|
+
|
340
|
+
# ============================================================================
|
341
|
+
# PERFORMANCE METADATA
|
342
|
+
# ============================================================================
|
343
|
+
|
344
|
+
@property
|
345
|
+
def backend_info(self) -> Dict[str, Any]:
|
346
|
+
"""Get backend implementation info."""
|
347
|
+
return {
|
348
|
+
'strategy': 'DEQUE',
|
349
|
+
'backend': 'collections.deque (doubly-linked list blocks)',
|
350
|
+
'complexity': {
|
351
|
+
'append': 'O(1)',
|
352
|
+
'appendleft': 'O(1)',
|
353
|
+
'pop': 'O(1)',
|
354
|
+
'popleft': 'O(1)',
|
355
|
+
'rotate': 'O(k)',
|
356
|
+
'random_access': 'O(n)',
|
357
|
+
'space': 'O(n)'
|
358
|
+
},
|
359
|
+
'thread_safe': 'append/pop same end only',
|
360
|
+
'max_size': self._max_size if self._max_size else 'unlimited',
|
361
|
+
'block_size': 64 # CPython implementation detail
|
362
|
+
}
|
363
|
+
|
364
|
+
@property
|
365
|
+
def metrics(self) -> Dict[str, Any]:
|
366
|
+
"""Get performance metrics."""
|
367
|
+
return {
|
368
|
+
'size': len(self._deque),
|
369
|
+
'is_empty': self.is_empty(),
|
370
|
+
'is_full': self.is_full(),
|
371
|
+
'max_size': self._max_size,
|
372
|
+
'memory_usage': f"{len(self._deque) * 8} bytes (estimated)"
|
373
|
+
}
|
@@ -0,0 +1,93 @@
|
|
1
|
+
"""
|
2
|
+
#exonware/xwnode/src/exonware/xwnode/nodes/strategies/node_extendible_hash.py
|
3
|
+
|
4
|
+
Extendible Hash Node Strategy Implementation
|
5
|
+
|
6
|
+
Company: eXonware.com
|
7
|
+
Author: Eng. Muhammad AlShehri
|
8
|
+
Email: connect@exonware.com
|
9
|
+
Version: 0.0.1.23
|
10
|
+
Generation Date: 11-Oct-2025
|
11
|
+
"""
|
12
|
+
|
13
|
+
from typing import Any, Iterator, Dict, List
|
14
|
+
from .base import ANodeStrategy
|
15
|
+
from ...defs import NodeMode, NodeTrait
|
16
|
+
from .contracts import NodeType
|
17
|
+
from ...common.utils import (
|
18
|
+
safe_to_native_conversion,
|
19
|
+
create_basic_backend_info,
|
20
|
+
create_size_tracker,
|
21
|
+
create_access_tracker,
|
22
|
+
update_size_tracker,
|
23
|
+
record_access,
|
24
|
+
get_access_metrics
|
25
|
+
)
|
26
|
+
|
27
|
+
|
28
|
+
class ExtendibleHashStrategy(ANodeStrategy):
|
29
|
+
"""Extendible Hash - Directory-based dynamic hash table."""
|
30
|
+
|
31
|
+
STRATEGY_TYPE = NodeType.TREE
|
32
|
+
|
33
|
+
def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
|
34
|
+
super().__init__(NodeMode.EXTENDIBLE_HASH, traits, **options)
|
35
|
+
self._data: Dict[str, Any] = {}
|
36
|
+
self._size_tracker = create_size_tracker()
|
37
|
+
self._access_tracker = create_access_tracker()
|
38
|
+
|
39
|
+
def get_supported_traits(self) -> NodeTrait:
|
40
|
+
return NodeTrait.INDEXED
|
41
|
+
|
42
|
+
def get(self, path: str, default: Any = None) -> Any:
|
43
|
+
record_access(self._access_tracker, 'get_count')
|
44
|
+
return self._data.get(path, default)
|
45
|
+
|
46
|
+
def put(self, path: str, value: Any = None) -> 'ExtendibleHashStrategy':
|
47
|
+
record_access(self._access_tracker, 'put_count')
|
48
|
+
if path not in self._data:
|
49
|
+
update_size_tracker(self._size_tracker, 1)
|
50
|
+
self._data[path] = value
|
51
|
+
return self
|
52
|
+
|
53
|
+
def delete(self, key: Any) -> bool:
|
54
|
+
key_str = str(key)
|
55
|
+
if key_str in self._data:
|
56
|
+
del self._data[key_str]
|
57
|
+
update_size_tracker(self._size_tracker, -1)
|
58
|
+
record_access(self._access_tracker, 'delete_count')
|
59
|
+
return True
|
60
|
+
return False
|
61
|
+
|
62
|
+
def remove(self, key: Any) -> bool:
|
63
|
+
return self.delete(key)
|
64
|
+
|
65
|
+
def has(self, key: Any) -> bool:
|
66
|
+
return str(key) in self._data
|
67
|
+
|
68
|
+
def exists(self, path: str) -> bool:
|
69
|
+
return path in self._data
|
70
|
+
|
71
|
+
def keys(self) -> Iterator[Any]:
|
72
|
+
return iter(self._data.keys())
|
73
|
+
|
74
|
+
def values(self) -> Iterator[Any]:
|
75
|
+
return iter(self._data.values())
|
76
|
+
|
77
|
+
def items(self) -> Iterator[tuple[Any, Any]]:
|
78
|
+
return iter(self._data.items())
|
79
|
+
|
80
|
+
def __len__(self) -> int:
|
81
|
+
return len(self._data)
|
82
|
+
|
83
|
+
def to_native(self) -> Dict[str, Any]:
|
84
|
+
return dict(self._data)
|
85
|
+
|
86
|
+
def get_backend_info(self) -> Dict[str, Any]:
|
87
|
+
return {
|
88
|
+
**create_basic_backend_info('Extendible Hash', 'Directory-based dynamic hash'),
|
89
|
+
'total_keys': len(self._data),
|
90
|
+
**self._size_tracker,
|
91
|
+
**get_access_metrics(self._access_tracker)
|
92
|
+
}
|
93
|
+
|