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,420 @@
1
+ """
2
+ Bitmap Node Strategy Implementation
3
+
4
+ This module implements the BITMAP strategy for efficient bit manipulation
5
+ and boolean operations with compressed storage.
6
+ """
7
+
8
+ from typing import Any, Iterator, List, Dict, Optional, Union
9
+ import array
10
+ from .base import ANodeMatrixStrategy
11
+ from ...types import NodeMode, NodeTrait
12
+
13
+
14
+ class BitmapStrategy(ANodeMatrixStrategy):
15
+ """
16
+ Bitmap node strategy for efficient bit manipulation and boolean operations.
17
+
18
+ Provides space-efficient storage for boolean flags and supports
19
+ fast bitwise operations with compressed representation.
20
+ """
21
+
22
+ def __init__(self, traits: NodeTrait = NodeTrait.NONE, **options):
23
+ """Initialize the Bitmap strategy."""
24
+ super().__init__(NodeMode.BITMAP, traits, **options)
25
+
26
+ self.initial_size = options.get('initial_size', 1024)
27
+ self.auto_resize = options.get('auto_resize', True)
28
+ self.compression_threshold = options.get('compression_threshold', 0.1) # 10% fill rate
29
+
30
+ # Core storage using Python array for efficiency
31
+ self._bits = array.array('B') # Byte array for bit storage
32
+ self._capacity_bits = 0
33
+ self._size = 0 # Number of set bits
34
+ self._max_index = -1 # Highest index with a bit set
35
+
36
+ # Key-value mapping for compatibility
37
+ self._key_to_index: Dict[str, int] = {}
38
+ self._index_to_key: Dict[int, str] = {}
39
+ self._values: Dict[str, Any] = {} # Associated values
40
+ self._next_index = 0
41
+
42
+ # Initialize with initial capacity
43
+ self._resize_to(self.initial_size)
44
+
45
+ def get_supported_traits(self) -> NodeTrait:
46
+ """Get the traits supported by the bitmap strategy."""
47
+ return (NodeTrait.COMPRESSED | NodeTrait.INDEXED | NodeTrait.STREAMING)
48
+
49
+ def _resize_to(self, new_bit_capacity: int) -> None:
50
+ """Resize bitmap to new bit capacity."""
51
+ new_byte_capacity = (new_bit_capacity + 7) // 8 # Round up to nearest byte
52
+
53
+ if new_byte_capacity > len(self._bits):
54
+ # Expand
55
+ self._bits.extend([0] * (new_byte_capacity - len(self._bits)))
56
+ elif new_byte_capacity < len(self._bits):
57
+ # Shrink
58
+ self._bits = self._bits[:new_byte_capacity]
59
+
60
+ self._capacity_bits = new_bit_capacity
61
+
62
+ def _ensure_capacity(self, bit_index: int) -> None:
63
+ """Ensure bitmap has capacity for the given bit index."""
64
+ if bit_index >= self._capacity_bits:
65
+ if self.auto_resize:
66
+ new_capacity = max(bit_index + 1, self._capacity_bits * 2)
67
+ self._resize_to(new_capacity)
68
+ else:
69
+ raise IndexError(f"Bit index {bit_index} exceeds capacity {self._capacity_bits}")
70
+
71
+ def _get_bit(self, bit_index: int) -> bool:
72
+ """Get bit value at index."""
73
+ if bit_index >= self._capacity_bits or bit_index < 0:
74
+ return False
75
+
76
+ byte_index = bit_index // 8
77
+ bit_offset = bit_index % 8
78
+
79
+ if byte_index >= len(self._bits):
80
+ return False
81
+
82
+ return bool(self._bits[byte_index] & (1 << bit_offset))
83
+
84
+ def _set_bit(self, bit_index: int, value: bool) -> bool:
85
+ """Set bit value at index. Returns True if bit was changed."""
86
+ self._ensure_capacity(bit_index)
87
+
88
+ byte_index = bit_index // 8
89
+ bit_offset = bit_index % 8
90
+
91
+ old_value = bool(self._bits[byte_index] & (1 << bit_offset))
92
+
93
+ if value:
94
+ self._bits[byte_index] |= (1 << bit_offset)
95
+ if not old_value:
96
+ self._size += 1
97
+ self._max_index = max(self._max_index, bit_index)
98
+ else:
99
+ self._bits[byte_index] &= ~(1 << bit_offset)
100
+ if old_value:
101
+ self._size -= 1
102
+ if bit_index == self._max_index:
103
+ self._update_max_index()
104
+
105
+ return old_value != value
106
+
107
+ def _update_max_index(self) -> None:
108
+ """Update the maximum set bit index."""
109
+ self._max_index = -1
110
+ for i in range(self._capacity_bits - 1, -1, -1):
111
+ if self._get_bit(i):
112
+ self._max_index = i
113
+ break
114
+
115
+ # ============================================================================
116
+ # CORE OPERATIONS (Key-based interface for compatibility)
117
+ # ============================================================================
118
+
119
+ def put(self, key: Any, value: Any = None) -> None:
120
+ """Set a bit and associate a value."""
121
+ key_str = str(key)
122
+
123
+ # Get or assign bit index for this key
124
+ if key_str in self._key_to_index:
125
+ bit_index = self._key_to_index[key_str]
126
+ else:
127
+ # Try to parse key as integer index
128
+ try:
129
+ bit_index = int(key_str)
130
+ if bit_index < 0:
131
+ bit_index = self._next_index
132
+ self._next_index += 1
133
+ except ValueError:
134
+ bit_index = self._next_index
135
+ self._next_index += 1
136
+
137
+ self._key_to_index[key_str] = bit_index
138
+ self._index_to_key[bit_index] = key_str
139
+
140
+ # Set the bit (treat None as False, everything else as True)
141
+ bit_value = value is not None and value is not False
142
+ self._set_bit(bit_index, bit_value)
143
+
144
+ # Store associated value
145
+ if bit_value:
146
+ self._values[key_str] = value if value is not None else True
147
+ else:
148
+ self._values.pop(key_str, None)
149
+
150
+ def get(self, key: Any, default: Any = None) -> Any:
151
+ """Get value associated with key."""
152
+ key_str = str(key)
153
+
154
+ if key_str in self._key_to_index:
155
+ bit_index = self._key_to_index[key_str]
156
+ if self._get_bit(bit_index):
157
+ return self._values.get(key_str, True)
158
+
159
+ return default
160
+
161
+ def has(self, key: Any) -> bool:
162
+ """Check if bit is set for key."""
163
+ key_str = str(key)
164
+
165
+ if key_str in self._key_to_index:
166
+ bit_index = self._key_to_index[key_str]
167
+ return self._get_bit(bit_index)
168
+
169
+ return False
170
+
171
+ def remove(self, key: Any) -> bool:
172
+ """Clear bit for key."""
173
+ key_str = str(key)
174
+
175
+ if key_str in self._key_to_index:
176
+ bit_index = self._key_to_index[key_str]
177
+ was_set = self._get_bit(bit_index)
178
+
179
+ if was_set:
180
+ self._set_bit(bit_index, False)
181
+ self._values.pop(key_str, None)
182
+ return True
183
+
184
+ return False
185
+
186
+ def delete(self, key: Any) -> bool:
187
+ """Clear bit for key (alias for remove)."""
188
+ return self.remove(key)
189
+
190
+ def clear(self) -> None:
191
+ """Clear all bits."""
192
+ self._bits = array.array('B', [0] * len(self._bits))
193
+ self._size = 0
194
+ self._max_index = -1
195
+ self._values.clear()
196
+ # Keep key mappings for consistency
197
+
198
+ def keys(self) -> Iterator[str]:
199
+ """Get all keys with set bits."""
200
+ for key_str, bit_index in self._key_to_index.items():
201
+ if self._get_bit(bit_index):
202
+ yield key_str
203
+
204
+ def values(self) -> Iterator[Any]:
205
+ """Get all values for set bits."""
206
+ return iter(self._values.values())
207
+
208
+ def items(self) -> Iterator[tuple[str, Any]]:
209
+ """Get all key-value pairs for set bits."""
210
+ for key_str, bit_index in self._key_to_index.items():
211
+ if self._get_bit(bit_index):
212
+ yield (key_str, self._values.get(key_str, True))
213
+
214
+ def __len__(self) -> int:
215
+ """Get the number of set bits."""
216
+ return self._size
217
+
218
+ def to_native(self) -> Dict[str, bool]:
219
+ """Convert to native Python dict of boolean values."""
220
+ result = {}
221
+ for key_str, bit_index in self._key_to_index.items():
222
+ result[key_str] = self._get_bit(bit_index)
223
+ return result
224
+
225
+ @property
226
+ def is_list(self) -> bool:
227
+ """This can behave like a list for indexed access."""
228
+ return True
229
+
230
+ @property
231
+ def is_dict(self) -> bool:
232
+ """This can behave like a dict."""
233
+ return True
234
+
235
+ # ============================================================================
236
+ # BITMAP-SPECIFIC OPERATIONS
237
+ # ============================================================================
238
+
239
+ def set_bit(self, index: int, value: bool = True) -> bool:
240
+ """Set bit at index. Returns previous value."""
241
+ old_value = self._get_bit(index)
242
+ self._set_bit(index, value)
243
+ return old_value
244
+
245
+ def get_bit(self, index: int) -> bool:
246
+ """Get bit value at index."""
247
+ return self._get_bit(index)
248
+
249
+ def flip_bit(self, index: int) -> bool:
250
+ """Flip bit at index. Returns new value."""
251
+ current_value = self._get_bit(index)
252
+ new_value = not current_value
253
+ self._set_bit(index, new_value)
254
+ return new_value
255
+
256
+ def count_set_bits(self, start: int = 0, end: Optional[int] = None) -> int:
257
+ """Count set bits in range [start, end)."""
258
+ if end is None:
259
+ end = self._capacity_bits
260
+
261
+ count = 0
262
+ for i in range(start, min(end, self._capacity_bits)):
263
+ if self._get_bit(i):
264
+ count += 1
265
+
266
+ return count
267
+
268
+ def find_first_set(self, start: int = 0) -> Optional[int]:
269
+ """Find first set bit starting from index."""
270
+ for i in range(start, self._capacity_bits):
271
+ if self._get_bit(i):
272
+ return i
273
+ return None
274
+
275
+ def find_first_clear(self, start: int = 0) -> Optional[int]:
276
+ """Find first clear bit starting from index."""
277
+ for i in range(start, self._capacity_bits):
278
+ if not self._get_bit(i):
279
+ return i
280
+ return None
281
+
282
+ def bitwise_and(self, other: 'xBitmapStrategy') -> 'xBitmapStrategy':
283
+ """Bitwise AND with another bitmap."""
284
+ result = xBitmapStrategy(
285
+ traits=self._traits,
286
+ initial_size=max(self._capacity_bits, other._capacity_bits)
287
+ )
288
+
289
+ max_bits = min(self._capacity_bits, other._capacity_bits)
290
+ for i in range(max_bits):
291
+ if self._get_bit(i) and other._get_bit(i):
292
+ result._set_bit(i, True)
293
+
294
+ return result
295
+
296
+ def bitwise_or(self, other: 'xBitmapStrategy') -> 'xBitmapStrategy':
297
+ """Bitwise OR with another bitmap."""
298
+ result = xBitmapStrategy(
299
+ traits=self._traits,
300
+ initial_size=max(self._capacity_bits, other._capacity_bits)
301
+ )
302
+
303
+ max_bits = max(self._capacity_bits, other._capacity_bits)
304
+ for i in range(max_bits):
305
+ if self._get_bit(i) or other._get_bit(i):
306
+ result._set_bit(i, True)
307
+
308
+ return result
309
+
310
+ def bitwise_xor(self, other: 'xBitmapStrategy') -> 'xBitmapStrategy':
311
+ """Bitwise XOR with another bitmap."""
312
+ result = xBitmapStrategy(
313
+ traits=self._traits,
314
+ initial_size=max(self._capacity_bits, other._capacity_bits)
315
+ )
316
+
317
+ max_bits = max(self._capacity_bits, other._capacity_bits)
318
+ for i in range(max_bits):
319
+ if self._get_bit(i) != other._get_bit(i):
320
+ result._set_bit(i, True)
321
+
322
+ return result
323
+
324
+ def bitwise_not(self) -> 'xBitmapStrategy':
325
+ """Bitwise NOT (invert all bits)."""
326
+ result = xBitmapStrategy(
327
+ traits=self._traits,
328
+ initial_size=self._capacity_bits
329
+ )
330
+
331
+ for i in range(self._capacity_bits):
332
+ if not self._get_bit(i):
333
+ result._set_bit(i, True)
334
+
335
+ return result
336
+
337
+ def compress(self) -> None:
338
+ """Compress bitmap by removing trailing zero bytes."""
339
+ if self._max_index < 0:
340
+ # No bits set, minimize to 1 byte
341
+ self._resize_to(8)
342
+ return
343
+
344
+ # Resize to just fit the highest set bit
345
+ new_capacity = ((self._max_index + 8) // 8) * 8
346
+ self._resize_to(new_capacity)
347
+
348
+ def get_compression_ratio(self) -> float:
349
+ """Get compression ratio (set bits / total capacity)."""
350
+ if self._capacity_bits == 0:
351
+ return 0.0
352
+ return self._size / self._capacity_bits
353
+
354
+ def to_bytes(self) -> bytes:
355
+ """Export bitmap as bytes."""
356
+ return self._bits.tobytes()
357
+
358
+ def from_bytes(self, data: bytes) -> None:
359
+ """Import bitmap from bytes."""
360
+ self._bits = array.array('B', data)
361
+ self._capacity_bits = len(self._bits) * 8
362
+
363
+ # Recalculate size and max_index
364
+ self._size = 0
365
+ self._max_index = -1
366
+
367
+ for i in range(self._capacity_bits):
368
+ if self._get_bit(i):
369
+ self._size += 1
370
+ self._max_index = i
371
+
372
+ def get_bit_pattern(self, start: int = 0, length: int = 64) -> str:
373
+ """Get bit pattern as string for debugging."""
374
+ pattern = ""
375
+ end = min(start + length, self._capacity_bits)
376
+
377
+ for i in range(start, end):
378
+ pattern += "1" if self._get_bit(i) else "0"
379
+ if (i - start + 1) % 8 == 0 and i < end - 1:
380
+ pattern += " " # Byte separator
381
+
382
+ return pattern
383
+
384
+ # ============================================================================
385
+ # PERFORMANCE CHARACTERISTICS
386
+ # ============================================================================
387
+
388
+ @property
389
+ def backend_info(self) -> Dict[str, Any]:
390
+ """Get backend implementation info."""
391
+ return {
392
+ 'strategy': 'BITMAP',
393
+ 'backend': 'Python array (byte-based)',
394
+ 'capacity_bits': self._capacity_bits,
395
+ 'capacity_bytes': len(self._bits),
396
+ 'auto_resize': self.auto_resize,
397
+ 'complexity': {
398
+ 'set_bit': 'O(1)',
399
+ 'get_bit': 'O(1)',
400
+ 'count_bits': 'O(n)',
401
+ 'bitwise_ops': 'O(n)',
402
+ 'space': 'O(n/8) bytes'
403
+ }
404
+ }
405
+
406
+ @property
407
+ def metrics(self) -> Dict[str, Any]:
408
+ """Get performance metrics."""
409
+ compression_ratio = self.get_compression_ratio()
410
+ memory_efficiency = (self._size * 8) / max(1, len(self._bits)) * 100
411
+
412
+ return {
413
+ 'set_bits': self._size,
414
+ 'total_capacity_bits': self._capacity_bits,
415
+ 'capacity_bytes': len(self._bits),
416
+ 'max_set_index': self._max_index,
417
+ 'compression_ratio': f"{compression_ratio:.3f}",
418
+ 'memory_efficiency': f"{memory_efficiency:.1f}%",
419
+ 'memory_usage': f"{len(self._bits)} bytes (bits) + {len(self._values) * 24} bytes (values)"
420
+ }