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.
Files changed (132) hide show
  1. exonware/__init__.py +14 -0
  2. exonware/xwnode/__init__.py +127 -0
  3. exonware/xwnode/base.py +676 -0
  4. exonware/xwnode/config.py +178 -0
  5. exonware/xwnode/contracts.py +730 -0
  6. exonware/xwnode/errors.py +503 -0
  7. exonware/xwnode/facade.py +460 -0
  8. exonware/xwnode/strategies/__init__.py +158 -0
  9. exonware/xwnode/strategies/advisor.py +463 -0
  10. exonware/xwnode/strategies/edges/__init__.py +32 -0
  11. exonware/xwnode/strategies/edges/adj_list.py +227 -0
  12. exonware/xwnode/strategies/edges/adj_matrix.py +391 -0
  13. exonware/xwnode/strategies/edges/base.py +169 -0
  14. exonware/xwnode/strategies/flyweight.py +328 -0
  15. exonware/xwnode/strategies/impls/__init__.py +13 -0
  16. exonware/xwnode/strategies/impls/_base_edge.py +403 -0
  17. exonware/xwnode/strategies/impls/_base_node.py +307 -0
  18. exonware/xwnode/strategies/impls/edge_adj_list.py +353 -0
  19. exonware/xwnode/strategies/impls/edge_adj_matrix.py +445 -0
  20. exonware/xwnode/strategies/impls/edge_bidir_wrapper.py +455 -0
  21. exonware/xwnode/strategies/impls/edge_block_adj_matrix.py +539 -0
  22. exonware/xwnode/strategies/impls/edge_coo.py +533 -0
  23. exonware/xwnode/strategies/impls/edge_csc.py +447 -0
  24. exonware/xwnode/strategies/impls/edge_csr.py +492 -0
  25. exonware/xwnode/strategies/impls/edge_dynamic_adj_list.py +503 -0
  26. exonware/xwnode/strategies/impls/edge_flow_network.py +555 -0
  27. exonware/xwnode/strategies/impls/edge_hyperedge_set.py +516 -0
  28. exonware/xwnode/strategies/impls/edge_neural_graph.py +650 -0
  29. exonware/xwnode/strategies/impls/edge_octree.py +574 -0
  30. exonware/xwnode/strategies/impls/edge_property_store.py +655 -0
  31. exonware/xwnode/strategies/impls/edge_quadtree.py +519 -0
  32. exonware/xwnode/strategies/impls/edge_rtree.py +820 -0
  33. exonware/xwnode/strategies/impls/edge_temporal_edgeset.py +558 -0
  34. exonware/xwnode/strategies/impls/edge_tree_graph_basic.py +271 -0
  35. exonware/xwnode/strategies/impls/edge_weighted_graph.py +411 -0
  36. exonware/xwnode/strategies/manager.py +775 -0
  37. exonware/xwnode/strategies/metrics.py +538 -0
  38. exonware/xwnode/strategies/migration.py +432 -0
  39. exonware/xwnode/strategies/nodes/__init__.py +50 -0
  40. exonware/xwnode/strategies/nodes/_base_node.py +307 -0
  41. exonware/xwnode/strategies/nodes/adjacency_list.py +267 -0
  42. exonware/xwnode/strategies/nodes/aho_corasick.py +345 -0
  43. exonware/xwnode/strategies/nodes/array_list.py +209 -0
  44. exonware/xwnode/strategies/nodes/base.py +247 -0
  45. exonware/xwnode/strategies/nodes/deque.py +200 -0
  46. exonware/xwnode/strategies/nodes/hash_map.py +135 -0
  47. exonware/xwnode/strategies/nodes/heap.py +307 -0
  48. exonware/xwnode/strategies/nodes/linked_list.py +232 -0
  49. exonware/xwnode/strategies/nodes/node_aho_corasick.py +520 -0
  50. exonware/xwnode/strategies/nodes/node_array_list.py +175 -0
  51. exonware/xwnode/strategies/nodes/node_avl_tree.py +371 -0
  52. exonware/xwnode/strategies/nodes/node_b_plus_tree.py +542 -0
  53. exonware/xwnode/strategies/nodes/node_bitmap.py +420 -0
  54. exonware/xwnode/strategies/nodes/node_bitset_dynamic.py +513 -0
  55. exonware/xwnode/strategies/nodes/node_bloom_filter.py +347 -0
  56. exonware/xwnode/strategies/nodes/node_btree.py +357 -0
  57. exonware/xwnode/strategies/nodes/node_count_min_sketch.py +470 -0
  58. exonware/xwnode/strategies/nodes/node_cow_tree.py +473 -0
  59. exonware/xwnode/strategies/nodes/node_cuckoo_hash.py +392 -0
  60. exonware/xwnode/strategies/nodes/node_fenwick_tree.py +301 -0
  61. exonware/xwnode/strategies/nodes/node_hash_map.py +269 -0
  62. exonware/xwnode/strategies/nodes/node_heap.py +191 -0
  63. exonware/xwnode/strategies/nodes/node_hyperloglog.py +407 -0
  64. exonware/xwnode/strategies/nodes/node_linked_list.py +409 -0
  65. exonware/xwnode/strategies/nodes/node_lsm_tree.py +400 -0
  66. exonware/xwnode/strategies/nodes/node_ordered_map.py +390 -0
  67. exonware/xwnode/strategies/nodes/node_ordered_map_balanced.py +565 -0
  68. exonware/xwnode/strategies/nodes/node_patricia.py +512 -0
  69. exonware/xwnode/strategies/nodes/node_persistent_tree.py +378 -0
  70. exonware/xwnode/strategies/nodes/node_radix_trie.py +452 -0
  71. exonware/xwnode/strategies/nodes/node_red_black_tree.py +497 -0
  72. exonware/xwnode/strategies/nodes/node_roaring_bitmap.py +570 -0
  73. exonware/xwnode/strategies/nodes/node_segment_tree.py +289 -0
  74. exonware/xwnode/strategies/nodes/node_set_hash.py +354 -0
  75. exonware/xwnode/strategies/nodes/node_set_tree.py +480 -0
  76. exonware/xwnode/strategies/nodes/node_skip_list.py +316 -0
  77. exonware/xwnode/strategies/nodes/node_splay_tree.py +393 -0
  78. exonware/xwnode/strategies/nodes/node_suffix_array.py +487 -0
  79. exonware/xwnode/strategies/nodes/node_treap.py +387 -0
  80. exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py +1434 -0
  81. exonware/xwnode/strategies/nodes/node_trie.py +252 -0
  82. exonware/xwnode/strategies/nodes/node_union_find.py +187 -0
  83. exonware/xwnode/strategies/nodes/node_xdata_optimized.py +369 -0
  84. exonware/xwnode/strategies/nodes/priority_queue.py +209 -0
  85. exonware/xwnode/strategies/nodes/queue.py +161 -0
  86. exonware/xwnode/strategies/nodes/sparse_matrix.py +206 -0
  87. exonware/xwnode/strategies/nodes/stack.py +152 -0
  88. exonware/xwnode/strategies/nodes/trie.py +274 -0
  89. exonware/xwnode/strategies/nodes/union_find.py +283 -0
  90. exonware/xwnode/strategies/pattern_detector.py +603 -0
  91. exonware/xwnode/strategies/performance_monitor.py +487 -0
  92. exonware/xwnode/strategies/queries/__init__.py +24 -0
  93. exonware/xwnode/strategies/queries/base.py +236 -0
  94. exonware/xwnode/strategies/queries/cql.py +201 -0
  95. exonware/xwnode/strategies/queries/cypher.py +181 -0
  96. exonware/xwnode/strategies/queries/datalog.py +70 -0
  97. exonware/xwnode/strategies/queries/elastic_dsl.py +70 -0
  98. exonware/xwnode/strategies/queries/eql.py +70 -0
  99. exonware/xwnode/strategies/queries/flux.py +70 -0
  100. exonware/xwnode/strategies/queries/gql.py +70 -0
  101. exonware/xwnode/strategies/queries/graphql.py +240 -0
  102. exonware/xwnode/strategies/queries/gremlin.py +181 -0
  103. exonware/xwnode/strategies/queries/hiveql.py +214 -0
  104. exonware/xwnode/strategies/queries/hql.py +70 -0
  105. exonware/xwnode/strategies/queries/jmespath.py +219 -0
  106. exonware/xwnode/strategies/queries/jq.py +66 -0
  107. exonware/xwnode/strategies/queries/json_query.py +66 -0
  108. exonware/xwnode/strategies/queries/jsoniq.py +248 -0
  109. exonware/xwnode/strategies/queries/kql.py +70 -0
  110. exonware/xwnode/strategies/queries/linq.py +238 -0
  111. exonware/xwnode/strategies/queries/logql.py +70 -0
  112. exonware/xwnode/strategies/queries/mql.py +68 -0
  113. exonware/xwnode/strategies/queries/n1ql.py +210 -0
  114. exonware/xwnode/strategies/queries/partiql.py +70 -0
  115. exonware/xwnode/strategies/queries/pig.py +215 -0
  116. exonware/xwnode/strategies/queries/promql.py +70 -0
  117. exonware/xwnode/strategies/queries/sparql.py +220 -0
  118. exonware/xwnode/strategies/queries/sql.py +275 -0
  119. exonware/xwnode/strategies/queries/xml_query.py +66 -0
  120. exonware/xwnode/strategies/queries/xpath.py +223 -0
  121. exonware/xwnode/strategies/queries/xquery.py +258 -0
  122. exonware/xwnode/strategies/queries/xwnode_executor.py +332 -0
  123. exonware/xwnode/strategies/queries/xwquery_strategy.py +424 -0
  124. exonware/xwnode/strategies/registry.py +604 -0
  125. exonware/xwnode/strategies/simple.py +273 -0
  126. exonware/xwnode/strategies/utils.py +532 -0
  127. exonware/xwnode/types.py +912 -0
  128. exonware/xwnode/version.py +78 -0
  129. exonware_xwnode-0.0.1.12.dist-info/METADATA +169 -0
  130. exonware_xwnode-0.0.1.12.dist-info/RECORD +132 -0
  131. exonware_xwnode-0.0.1.12.dist-info/WHEEL +4 -0
  132. exonware_xwnode-0.0.1.12.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Edge Strategy Base Classes
4
+
5
+ This module defines the abstract base classes for all edge strategy implementations:
6
+ - AEdgeStrategy: Base strategy for all edge implementations
7
+ - ALinearEdgeStrategy: Linear edge capabilities (sequential connections)
8
+ - ATreeEdgeStrategy: Tree edge capabilities (hierarchical connections)
9
+ - AGraphEdgeStrategy: Graph edge capabilities (network connections)
10
+
11
+ Company: eXonware.com
12
+ Author: Eng. Muhammad AlShehri
13
+ Email: connect@exonware.com
14
+ Version: 0.0.1.12
15
+ Generation Date: January 2, 2025
16
+ """
17
+
18
+ from abc import ABC, abstractmethod
19
+ from typing import Any, Optional, List, Dict, Tuple
20
+
21
+ from ...contracts import iEdgeStrategy
22
+ from ...errors import XWNodeTypeError, XWNodeValueError
23
+
24
+
25
+ class AEdgeStrategy(ABC):
26
+ """Base strategy for all edge implementations."""
27
+
28
+ def __init__(self, **options):
29
+ """Initialize edge strategy."""
30
+ self._options = options
31
+ self._mode = options.get('mode', 'AUTO')
32
+ self._traits = options.get('traits', None)
33
+
34
+ @abstractmethod
35
+ def add_edge(self, from_node: Any, to_node: Any, **kwargs) -> None:
36
+ """Add edge between nodes."""
37
+ pass
38
+
39
+ @abstractmethod
40
+ def remove_edge(self, from_node: Any, to_node: Any) -> bool:
41
+ """Remove edge between nodes."""
42
+ pass
43
+
44
+ @abstractmethod
45
+ def has_edge(self, from_node: Any, to_node: Any) -> bool:
46
+ """Check if edge exists."""
47
+ pass
48
+
49
+ @abstractmethod
50
+ def get_edge_count(self) -> int:
51
+ """Get total number of edges."""
52
+ pass
53
+
54
+ @abstractmethod
55
+ def get_vertex_count(self) -> int:
56
+ """Get total number of vertices."""
57
+ pass
58
+
59
+ def get_mode(self) -> str:
60
+ """Get strategy mode."""
61
+ return self._mode
62
+
63
+ def get_traits(self):
64
+ """Get strategy traits."""
65
+ return self._traits
66
+
67
+
68
+ class ALinearEdgeStrategy(AEdgeStrategy):
69
+ """Linear edge capabilities (sequential connections)."""
70
+
71
+ def get_next(self, node: Any) -> Optional[Any]:
72
+ """Get next node in sequence."""
73
+ raise NotImplementedError("Subclasses must implement get_next")
74
+
75
+ def get_previous(self, node: Any) -> Optional[Any]:
76
+ """Get previous node in sequence."""
77
+ raise NotImplementedError("Subclasses must implement get_previous")
78
+
79
+ def get_first(self) -> Optional[Any]:
80
+ """Get first node in sequence."""
81
+ raise NotImplementedError("Subclasses must implement get_first")
82
+
83
+ def get_last(self) -> Optional[Any]:
84
+ """Get last node in sequence."""
85
+ raise NotImplementedError("Subclasses must implement get_last")
86
+
87
+ def insert_after(self, node: Any, new_node: Any) -> None:
88
+ """Insert new node after specified node."""
89
+ raise NotImplementedError("Subclasses must implement insert_after")
90
+
91
+ def insert_before(self, node: Any, new_node: Any) -> None:
92
+ """Insert new node before specified node."""
93
+ raise NotImplementedError("Subclasses must implement insert_before")
94
+
95
+
96
+ class ATreeEdgeStrategy(AEdgeStrategy):
97
+ """Tree edge capabilities (hierarchical connections)."""
98
+
99
+ def get_parent(self, node: Any) -> Optional[Any]:
100
+ """Get parent node."""
101
+ raise NotImplementedError("Subclasses must implement get_parent")
102
+
103
+ def get_children(self, node: Any) -> List[Any]:
104
+ """Get child nodes."""
105
+ raise NotImplementedError("Subclasses must implement get_children")
106
+
107
+ def get_siblings(self, node: Any) -> List[Any]:
108
+ """Get sibling nodes."""
109
+ raise NotImplementedError("Subclasses must implement get_siblings")
110
+
111
+ def get_root(self) -> Optional[Any]:
112
+ """Get root node."""
113
+ raise NotImplementedError("Subclasses must implement get_root")
114
+
115
+ def get_leaves(self) -> List[Any]:
116
+ """Get leaf nodes."""
117
+ raise NotImplementedError("Subclasses must implement get_leaves")
118
+
119
+ def get_depth(self, node: Any) -> int:
120
+ """Get depth of node."""
121
+ raise NotImplementedError("Subclasses must implement get_depth")
122
+
123
+ def get_height(self) -> int:
124
+ """Get height of tree."""
125
+ raise NotImplementedError("Subclasses must implement get_height")
126
+
127
+ def is_ancestor(self, ancestor: Any, descendant: Any) -> bool:
128
+ """Check if one node is ancestor of another."""
129
+ raise NotImplementedError("Subclasses must implement is_ancestor")
130
+
131
+
132
+ class AGraphEdgeStrategy(AEdgeStrategy):
133
+ """Graph edge capabilities (network connections)."""
134
+
135
+ def get_neighbors(self, node: Any) -> List[Any]:
136
+ """Get all neighboring nodes."""
137
+ raise NotImplementedError("Subclasses must implement get_neighbors")
138
+
139
+ def get_edge_weight(self, from_node: Any, to_node: Any) -> float:
140
+ """Get edge weight."""
141
+ raise NotImplementedError("Subclasses must implement get_edge_weight")
142
+
143
+ def set_edge_weight(self, from_node: Any, to_node: Any, weight: float) -> None:
144
+ """Set edge weight."""
145
+ raise NotImplementedError("Subclasses must implement set_edge_weight")
146
+
147
+ def find_shortest_path(self, start: Any, end: Any) -> List[Any]:
148
+ """Find shortest path between nodes."""
149
+ raise NotImplementedError("Subclasses must implement find_shortest_path")
150
+
151
+ def find_all_paths(self, start: Any, end: Any) -> List[List[Any]]:
152
+ """Find all paths between nodes."""
153
+ raise NotImplementedError("Subclasses must implement find_all_paths")
154
+
155
+ def get_connected_components(self) -> List[List[Any]]:
156
+ """Get all connected components."""
157
+ raise NotImplementedError("Subclasses must implement get_connected_components")
158
+
159
+ def is_connected(self, start: Any, end: Any) -> bool:
160
+ """Check if two nodes are connected."""
161
+ raise NotImplementedError("Subclasses must implement is_connected")
162
+
163
+ def get_degree(self, node: Any) -> int:
164
+ """Get degree of node."""
165
+ raise NotImplementedError("Subclasses must implement get_degree")
166
+
167
+ def is_cyclic(self) -> bool:
168
+ """Check if graph contains cycles."""
169
+ raise NotImplementedError("Subclasses must implement is_cyclic")
@@ -0,0 +1,328 @@
1
+ #!/usr/bin/env python3
2
+ #exonware/xwnode/src/exonware/xwnode/strategies/flyweight.py
3
+ """
4
+ Strategy Flyweight Pattern Implementation
5
+
6
+ Optimizes memory usage by sharing strategy instances with identical configurations.
7
+ This prevents creating multiple instances of the same strategy type with the same
8
+ configuration, which is especially important for high-throughput applications.
9
+
10
+ Company: eXonware.com
11
+ Author: Eng. Muhammad AlShehri
12
+ Email: connect@exonware.com
13
+ Version: 0.0.1.12
14
+ Generation Date: 07-Sep-2025
15
+ """
16
+
17
+ import threading
18
+ import hashlib
19
+ import json
20
+ from typing import Any, Dict, Hashable, Optional, Type, TypeVar, Union
21
+ from weakref import WeakValueDictionary
22
+ from exonware.xwsystem import get_logger
23
+
24
+ logger = get_logger(__name__)
25
+
26
+ from ..types import NodeMode, EdgeMode, NodeTrait, EdgeTrait
27
+ from .nodes.base import ANodeStrategy
28
+ from .edges.base import AEdgeStrategy
29
+
30
+
31
+ T = TypeVar('T', bound=Union[ANodeStrategy, AEdgeStrategy])
32
+
33
+
34
+ class StrategyFlyweight:
35
+ """
36
+ Flyweight factory for strategy instances.
37
+
38
+ Manages shared strategy instances to reduce memory footprint and
39
+ improve performance by avoiding redundant object creation.
40
+ """
41
+
42
+ def __init__(self):
43
+ """Initialize the flyweight factory."""
44
+ self._node_instances: WeakValueDictionary[str, ANodeStrategy] = WeakValueDictionary()
45
+ self._edge_instances: WeakValueDictionary[str, AEdgeStrategy] = WeakValueDictionary()
46
+ self._lock = threading.RLock()
47
+ self._stats = {
48
+ 'node_created': 0,
49
+ 'node_reused': 0,
50
+ 'edge_created': 0,
51
+ 'edge_reused': 0,
52
+ 'cache_hits': 0,
53
+ 'cache_misses': 0,
54
+ 'memory_saved_instances': 0
55
+ }
56
+
57
+ def get_node_strategy(
58
+ self,
59
+ strategy_class: Type[T],
60
+ mode: NodeMode,
61
+ traits: NodeTrait = NodeTrait.NONE,
62
+ **config: Any
63
+ ) -> T:
64
+ """
65
+ Get a node strategy instance, creating or reusing based on configuration.
66
+
67
+ Args:
68
+ strategy_class: The strategy class to instantiate
69
+ mode: Node mode for the strategy
70
+ traits: Node traits for the strategy
71
+ **config: Configuration parameters for the strategy
72
+
73
+ Returns:
74
+ Shared strategy instance
75
+ """
76
+ # Create a hashable key from the class and configuration
77
+ cache_key = self._create_node_cache_key(strategy_class, mode, traits, config)
78
+
79
+ with self._lock:
80
+ # Check if we already have this instance
81
+ if cache_key in self._node_instances:
82
+ self._stats['cache_hits'] += 1
83
+ self._stats['node_reused'] += 1
84
+ self._stats['memory_saved_instances'] += 1
85
+ logger.debug(f"♻️ Reusing node strategy: {strategy_class.__name__}")
86
+ return self._node_instances[cache_key]
87
+
88
+ # Create new instance
89
+ self._stats['cache_misses'] += 1
90
+ self._stats['node_created'] += 1
91
+
92
+ try:
93
+ instance = strategy_class(traits=traits, mode=mode, **config)
94
+ self._node_instances[cache_key] = instance
95
+ logger.debug(f"🆕 Created new node strategy: {strategy_class.__name__}")
96
+ return instance
97
+
98
+ except Exception as e:
99
+ logger.error(f"❌ Failed to create {strategy_class.__name__} instance: {e}")
100
+ raise
101
+
102
+ def get_edge_strategy(
103
+ self,
104
+ strategy_class: Type[T],
105
+ mode: EdgeMode,
106
+ traits: EdgeTrait = EdgeTrait.NONE,
107
+ **config: Any
108
+ ) -> T:
109
+ """
110
+ Get an edge strategy instance, creating or reusing based on configuration.
111
+
112
+ Args:
113
+ strategy_class: The strategy class to instantiate
114
+ mode: Edge mode for the strategy
115
+ traits: Edge traits for the strategy
116
+ **config: Configuration parameters for the strategy
117
+
118
+ Returns:
119
+ Shared strategy instance
120
+ """
121
+ # Create a hashable key from the class and configuration
122
+ cache_key = self._create_edge_cache_key(strategy_class, mode, traits, config)
123
+
124
+ with self._lock:
125
+ # Check if we already have this instance
126
+ if cache_key in self._edge_instances:
127
+ self._stats['cache_hits'] += 1
128
+ self._stats['edge_reused'] += 1
129
+ self._stats['memory_saved_instances'] += 1
130
+ logger.debug(f"♻️ Reusing edge strategy: {strategy_class.__name__}")
131
+ return self._edge_instances[cache_key]
132
+
133
+ # Create new instance
134
+ self._stats['cache_misses'] += 1
135
+ self._stats['edge_created'] += 1
136
+
137
+ try:
138
+ instance = strategy_class(traits=traits, mode=mode, **config)
139
+ self._edge_instances[cache_key] = instance
140
+ logger.debug(f"🆕 Created new edge strategy: {strategy_class.__name__}")
141
+ return instance
142
+
143
+ except Exception as e:
144
+ logger.error(f"❌ Failed to create {strategy_class.__name__} instance: {e}")
145
+ raise
146
+
147
+ def _create_node_cache_key(
148
+ self,
149
+ strategy_class: Type[T],
150
+ mode: NodeMode,
151
+ traits: NodeTrait,
152
+ config: Dict[str, Any]
153
+ ) -> str:
154
+ """
155
+ Create a hashable cache key from class, mode, traits, and configuration.
156
+
157
+ Args:
158
+ strategy_class: The strategy class
159
+ mode: Node mode
160
+ traits: Node traits
161
+ config: Configuration dictionary
162
+
163
+ Returns:
164
+ String cache key
165
+ """
166
+ # Start with class name and module
167
+ key_parts = [f"{strategy_class.__module__}.{strategy_class.__name__}"]
168
+
169
+ # Add mode and traits
170
+ key_parts.append(f"mode:{mode.name}")
171
+ key_parts.append(f"traits:{traits.name}")
172
+
173
+ # Add configuration (sorted for consistency)
174
+ if config:
175
+ config_str = json.dumps(config, sort_keys=True, default=str)
176
+ key_parts.append(f"config:{config_str}")
177
+
178
+ # Create hash for shorter key
179
+ key_string = "|".join(key_parts)
180
+ return hashlib.md5(key_string.encode()).hexdigest()
181
+
182
+ def _create_edge_cache_key(
183
+ self,
184
+ strategy_class: Type[T],
185
+ mode: EdgeMode,
186
+ traits: EdgeTrait,
187
+ config: Dict[str, Any]
188
+ ) -> str:
189
+ """
190
+ Create a hashable cache key from class, mode, traits, and configuration.
191
+
192
+ Args:
193
+ strategy_class: The strategy class
194
+ mode: Edge mode
195
+ traits: Edge traits
196
+ config: Configuration dictionary
197
+
198
+ Returns:
199
+ String cache key
200
+ """
201
+ # Start with class name and module
202
+ key_parts = [f"{strategy_class.__module__}.{strategy_class.__name__}"]
203
+
204
+ # Add mode and traits
205
+ key_parts.append(f"mode:{mode.name}")
206
+ key_parts.append(f"traits:{traits.name}")
207
+
208
+ # Add configuration (sorted for consistency)
209
+ if config:
210
+ config_str = json.dumps(config, sort_keys=True, default=str)
211
+ key_parts.append(f"config:{config_str}")
212
+
213
+ # Create hash for shorter key
214
+ key_string = "|".join(key_parts)
215
+ return hashlib.md5(key_string.encode()).hexdigest()
216
+
217
+ def get_stats(self) -> Dict[str, Any]:
218
+ """
219
+ Get flyweight statistics.
220
+
221
+ Returns:
222
+ Dictionary with cache statistics
223
+ """
224
+ with self._lock:
225
+ total_created = self._stats['node_created'] + self._stats['edge_created']
226
+ total_reused = self._stats['node_reused'] + self._stats['edge_reused']
227
+ total_requests = total_created + total_reused
228
+
229
+ cache_hit_rate = (self._stats['cache_hits'] / total_requests * 100) if total_requests > 0 else 0
230
+
231
+ return {
232
+ 'node_strategies': {
233
+ 'created': self._stats['node_created'],
234
+ 'reused': self._stats['node_reused'],
235
+ 'active': len(self._node_instances)
236
+ },
237
+ 'edge_strategies': {
238
+ 'created': self._stats['edge_created'],
239
+ 'reused': self._stats['edge_reused'],
240
+ 'active': len(self._edge_instances)
241
+ },
242
+ 'cache_performance': {
243
+ 'hits': self._stats['cache_hits'],
244
+ 'misses': self._stats['cache_misses'],
245
+ 'hit_rate_percent': round(cache_hit_rate, 2),
246
+ 'memory_saved_instances': self._stats['memory_saved_instances']
247
+ },
248
+ 'total_instances': {
249
+ 'created': total_created,
250
+ 'reused': total_reused,
251
+ 'active': len(self._node_instances) + len(self._edge_instances)
252
+ }
253
+ }
254
+
255
+ def clear_cache(self) -> None:
256
+ """Clear all cached strategy instances."""
257
+ with self._lock:
258
+ node_count = len(self._node_instances)
259
+ edge_count = len(self._edge_instances)
260
+
261
+ self._node_instances.clear()
262
+ self._edge_instances.clear()
263
+
264
+ logger.info(f"🧹 Cleared flyweight cache: {node_count} node + {edge_count} edge instances")
265
+
266
+ def get_cache_info(self) -> Dict[str, Any]:
267
+ """
268
+ Get detailed cache information.
269
+
270
+ Returns:
271
+ Dictionary with detailed cache information
272
+ """
273
+ with self._lock:
274
+ return {
275
+ 'node_cache_size': len(self._node_instances),
276
+ 'edge_cache_size': len(self._edge_instances),
277
+ 'total_cache_size': len(self._node_instances) + len(self._edge_instances),
278
+ 'node_cache_keys': list(self._node_instances.keys()),
279
+ 'edge_cache_keys': list(self._edge_instances.keys())
280
+ }
281
+
282
+
283
+ # Global flyweight instance
284
+ _flyweight_instance: Optional[StrategyFlyweight] = None
285
+ _flyweight_lock = threading.Lock()
286
+
287
+
288
+ def get_flyweight() -> StrategyFlyweight:
289
+ """
290
+ Get the global strategy flyweight instance.
291
+
292
+ Returns:
293
+ Global StrategyFlyweight instance
294
+ """
295
+ global _flyweight_instance
296
+
297
+ if _flyweight_instance is None:
298
+ with _flyweight_lock:
299
+ if _flyweight_instance is None:
300
+ _flyweight_instance = StrategyFlyweight()
301
+ logger.info("🏭 Initialized global strategy flyweight")
302
+
303
+ return _flyweight_instance
304
+
305
+
306
+ def get_flyweight_stats() -> Dict[str, Any]:
307
+ """
308
+ Get flyweight statistics.
309
+
310
+ Returns:
311
+ Flyweight statistics dictionary
312
+ """
313
+ return get_flyweight().get_stats()
314
+
315
+
316
+ def clear_flyweight_cache() -> None:
317
+ """Clear the global flyweight cache."""
318
+ get_flyweight().clear_cache()
319
+
320
+
321
+ def get_flyweight_cache_info() -> Dict[str, Any]:
322
+ """
323
+ Get flyweight cache information.
324
+
325
+ Returns:
326
+ Cache information dictionary
327
+ """
328
+ return get_flyweight().get_cache_info()
@@ -0,0 +1,13 @@
1
+ """
2
+ Strategy Implementations
3
+
4
+ This package contains all strategy implementations for the strategy system.
5
+ """
6
+
7
+ from ._base_node import aNodeStrategy
8
+ from ._base_edge import aEdgeStrategy
9
+
10
+ __all__ = [
11
+ 'aNodeStrategy',
12
+ 'aEdgeStrategy',
13
+ ]