bool-hybrid-array 9.10.10__py3-none-any.whl → 9.10.21__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.
bool_hybrid_array/core.py CHANGED
@@ -1,857 +1,875 @@
1
- from __future__ import annotations
2
- import builtins
3
- import array,bisect,numpy as np
4
- from collections.abc import MutableSequence,Iterable,Generator,Iterator,Sequence
5
- import itertools,copy,sys,math,weakref,random,mmap,os
6
- from functools import reduce
7
- import operator,ctypes,gc,abc,types
8
- from functools import lru_cache
9
- from typing import Union,_GenericAlias
10
- hybrid_array_cache = []
11
- if 'UnionType' in types.__dict__:
12
- class Union:
13
- def __getitem__(self,*args):
14
- return reduce(operator.or_, args)
15
- Union = Union()
16
- if 'GenericAlias' in types.__dict__:
17
- _GenericAlias = types.GenericAlias
18
- class ResurrectMeta(abc.ABCMeta,metaclass=abc.ABCMeta):
19
- __module__ = 'bool_hybrid_array'
20
- name = 'ResurrectMeta'
21
- def __new__(cls, name, bases, namespace):
22
- meta_bases = tuple(type(base) for base in bases)
23
- if cls not in meta_bases:
24
- meta_bases = (cls,) + meta_bases
25
- obj = super().__new__(cls, name, bases, namespace)
26
- super_cls = super(ResurrectMeta, obj)
27
- super_cls.__setattr__('x',None)
28
- super_cls.__setattr__('name', name)
29
- super_cls.__setattr__('bases', bases)
30
- super_cls.__setattr__('namespace', namespace)
31
- super_cls.__setattr__('original_dict', dict(obj.__dict__))
32
- del obj.original_dict["__abstractmethods__"]
33
- del obj.original_dict["_abc_impl"]
34
- return obj
35
- @lru_cache
36
- def __str__(cls):
37
- return super().__repr__()[8:][:-2]
38
- @lru_cache
39
- def __repr__(cls,detailed = False):
40
- if detailed:
41
- name, bases, namespace = cls.name,cls.bases,cls.namespace
42
- return f'ResurrectMeta(cls = {cls},{name = },{bases = },{namespace = })'
43
- return str(cls)
44
- def __del__(cls):
45
- exec(f"builtins.{cls.__name__} = cls")
46
- if not sys.is_finalizing():
47
- print(f'警告:禁止删除常变量:{cls}!')
48
- raise TypeError(f'禁止删除常变量:{cls}')
49
- def __hash__(cls):
50
- return hash(cls.name+cls.__module__)
51
- def __setattr__(cls,name,value):
52
- if not hasattr(cls, 'x'):
53
- super().__setattr__(name,value)
54
- return
55
- if hasattr(cls, 'name') and cls.name == 'BHA_Bool' and repr(value) in {'T','F'} and name in {'T','F'}:
56
- super().__setattr__(name,value)
57
- return
58
- if hasattr(cls, 'original_dict') and name in cls.original_dict:
59
- raise AttributeError(f'禁止修改属性:{name}')
60
- else:
61
- super().__setattr__(name,value)
62
- def __delattr__(cls,name):
63
- if name in cls.original_dict:
64
- raise AttributeError(f'禁止删除属性:{name}')
65
- else:
66
- super().__delattr__(name)
67
- if 'UnionType' not in types.__dict__:
68
- def __or__(self,other):
69
- return Union[self,other]
70
- __ror__ = __or__
71
- def __getitem__(self,*args):
72
- return _GenericAlias(self,args)
73
- x = None
74
- original_dict = {"__delattr__":__delattr__,"__getitem__":__getitem__,"__setattr__":__setattr__,"__hash__":__hash__,
75
- "__new__":__new__,"__del__":__del__,"__str__":__str__,"__repr__":__repr__,"__class__":abc.ABCMeta,"original_dict":None}
76
- try:
77
- original_dict["original_dict"] = original_dict
78
- original_dict["__ror__"] = __ror__
79
- original_dict["__or__"] = __or__
80
- except:
81
- pass
82
- ResurrectMeta.__class__ = ResurrectMeta
83
- class BHA_Function(metaclass=ResurrectMeta):
84
- def __init__(self,v):
85
- self.data,self.module = v,__name__
86
- def __call__(self,*a,**b):
87
- return self.data(*a,**b)
88
- def __getattr__(self,name):
89
- return getattr(self.data,name)
90
- @classmethod
91
- def string_define(cls, name, text, positional, default):
92
- param_strs = list(positional)
93
- param_strs.extend([f"{k}={v!r}" for k, v in default.items()])
94
- params = ", ".join(param_strs)
95
- func_code = f"""
96
- def {name}({params}):
97
- {text}
98
- """
99
- local_namespace = {}
100
- exec(func_code, globals(), local_namespace)
101
- dynamic_func = local_namespace[name]
102
- return cls(dynamic_func)
103
- class BoolHybridArray(MutableSequence,Exception,metaclass=ResurrectMeta):
104
- __module__ = 'bool_hybrid_array'
105
- class _CompactBoolArray(Sequence,Exception):
106
- def __init__(self, size: int):
107
- self.size = size
108
- self.n_uint8 = (size + 7) >> 3
109
- self.data = np.zeros(self.n_uint8, dtype=np.uint8)
110
- def __setitem__(self, index: int | slice, value):
111
- ctypes_arr = self.data.ctypes.data_as(ctypes.POINTER(ctypes.c_ubyte))
112
- if isinstance(index, slice):
113
- start, stop, step = index.indices(self.size)
114
- indices = list(range(start, stop, step))
115
- if isinstance(value, (list, tuple)):
116
- if len(value)!= len(indices):
117
- raise ValueError("值的数量与切片长度不匹配")
118
- for i, val in zip(indices, value):
119
- self._set_single(i, bool(val), ctypes_arr)
120
- else:
121
- val_bool = bool(value)
122
- for i in indices:
123
- self._set_single(i, val_bool, ctypes_arr)
124
- self.data = np.ctypeslib.as_array(ctypes_arr, shape=(self.n_uint8,))
125
- return
126
- if not (0 <= index < self.size):
127
- raise IndexError(f"密集区索引 {index} 超出范围 [0, {self.size})")
128
- self._set_single(index, bool(value), ctypes_arr)
129
- self.data = np.ctypeslib.as_array(ctypes_arr, shape=(self.n_uint8,))
130
- self.data = self.data.view()
131
- def _set_single(self, index: int, value: bool, ctypes_arr):
132
- uint8_pos = index >> 3
133
- bit_offset = index & 7
134
- ctypes_arr[uint8_pos] &= ~(1 << bit_offset) & 0xFF
135
- if value:
136
- ctypes_arr[uint8_pos] |= (1 << bit_offset)
137
- def __getitem__(self, index: int | slice) -> bool | list[bool]:
138
- if isinstance(index, slice):
139
- start, stop, step = index.indices(self.size)
140
- result = []
141
- for i in range(start, stop, step):
142
- uint8_pos = i >> 3
143
- bit_offset = i & 7
144
- result.append(bool((self.data[uint8_pos] >> bit_offset) & 1))
145
- return result
146
- if not (0 <= index < self.size):
147
- raise IndexError(f"密集区索引 {index} 超出范围 [0, {self.size})")
148
- uint8_pos = index >> 3
149
- bit_offset = index & 7
150
- return bool((self.data[uint8_pos] >> bit_offset) & 1)
151
- def __len__(self):
152
- return self.size
153
- def set_all(self, value: bool):
154
- ctypes_arr = self.data.ctypes.data_as(ctypes.POINTER(ctypes.c_ubyte))
155
- length = len(self.data)
156
- if value:ctypes.memset(ctypes_arr, 0xff, length)
157
- else:ctypes.memset(ctypes_arr, 0, length)
158
- def copy(self):
159
- new_instance = self.__class__(size=self.size)
160
- new_instance.data = self.data.copy()
161
- return new_instance
162
- def __init__(self, split_index: int, size=None, is_sparse=False ,Type:Callable = None,hash_ = True) -> None:
163
- self.Type = Type if Type is not None else builtins.BHA_Bool
164
- self.split_index = int(split_index)
165
- self.size = size or 0
166
- self.is_sparse = is_sparse
167
- self.small = self._CompactBoolArray(self.split_index + 1)
168
- self.small.set_all(not is_sparse)
169
- self.large = array.array('I') if size < 1<<32 else array.array('Q')
170
- self.generator = iter(self)
171
- self.hash_ = hash_
172
- if hash_:
173
- global hybrid_array_cache
174
- hybrid_array_cache = [
175
- (ref, h) for ref, h in hybrid_array_cache
176
- if ref() is not None
177
- ]
178
- for ref, existing_hash in hybrid_array_cache:
179
- existing_array = ref()
180
- try:
181
- if self.size != existing_array.size:
182
- continue
183
- elif self == existing_array:
184
- self._cached_hash = existing_hash
185
- return
186
- except Exception:
187
- continue
188
- new_hash = id(self)
189
- self._cached_hash = new_hash
190
- hybrid_array_cache.append((weakref.ref(self), new_hash))
191
- def __call__(self, func):
192
- func.self = self
193
- def wrapper(*args, **kwargs):
194
- return func(self, *args, **kwargs)
195
- setattr(self, func.__name__, wrapper)
196
- return func
197
- def __hash__(self):
198
- return self._cached_hash
199
- def accessor(self, i: int, value: bool|None = None) -> bool|None:
200
- def _get_sparse_info(index: int) -> tuple[int, bool]:
201
- pos = bisect.bisect_left(self.large, index)
202
- exists = pos < len(self.large) and self.large[pos] == index
203
- return pos, exists
204
- if value is None:
205
- if i <= self.split_index:
206
- return self.small[i]
207
- else:
208
- _, exists = _get_sparse_info(i)
209
- return exists if self.is_sparse else not exists
210
- else:
211
- if i <= self.split_index:
212
- self.small[i] = value
213
- return None
214
- else:
215
- pos, exists = _get_sparse_info(i)
216
- condition = not value or exists
217
- if self.is_sparse != condition:
218
- self.large.insert(pos, i)
219
- else:
220
- if pos < len(self.large):
221
- del self.large[pos]
222
- return None
223
- def __getitem__(self, key:int|slice) -> BoolHybridArray:
224
- if isinstance(key, slice):
225
- start, stop, step = key.indices(self.size)
226
- return BoolHybridArr((self[i] for i in range(start, stop, step)),hash_ = self.hash_)
227
- key = key if key >=0 else key + self.size
228
- if 0 <= key < self.size:
229
- return self.Type(self.accessor(key))
230
- raise IndexError("索引超出范围")
231
- def __setitem__(self, key: int | slice, value) -> None:
232
- if isinstance(key, int):
233
- adjusted_key = key if key >= 0 else key + self.size
234
- if not (0 <= adjusted_key < self.size):
235
- raise IndexError("索引超出范围")
236
- self.accessor(adjusted_key, bool(value))
237
- return
238
- if isinstance(key, slice):
239
- original_size = self.size
240
- start, stop, step = key.indices(original_size)
241
- value_list = list(value)
242
- new_len = len(value_list)
243
- if step != 1:
244
- slice_indices = list(range(start, stop, step))
245
- if new_len != len(slice_indices):
246
- raise ValueError(f"值长度与切片长度不匹配:{new_len} vs {len(slice_indices)}")
247
- for i, val in zip(slice_indices, value_list):
248
- self[i] = val
249
- return
250
- for i in range(stop - 1, start - 1, -1):
251
- if i <= self.split_index:
252
- if i >= len(self.small):
253
- self.small = np.pad(
254
- self.small,
255
- (0, i - len(self.small) + 1),
256
- constant_values=not self.is_sparse
257
- )
258
- del self[i]
259
- for idx, val in enumerate(value_list):
260
- self.insert(start + idx, bool(val))
261
- return
262
- raise TypeError("索引必须是整数或切片")
263
- def __repr__(self) -> str:
264
- return(f"BoolHybridArray(split_index={self.split_index}, size={self.size}, "
265
- +f"is_sparse={self.is_sparse}, small_len={len(self.small)}, large_len={len(self.large)})")
266
- def __delitem__(self, key: int) -> None:
267
- key = key if key >= 0 else key + self.size
268
- if not (0 <= key < self.size):
269
- raise IndexError(f"索引 {key} 超出范围 [0, {self.size})")
270
- if key <= self.split_index:
271
- if key >= len(self.small):
272
- raise IndexError(f"小索引 {key} 超出small数组范围(长度{len(self.small)})")
273
- self.small = np.delete(self.small, key)
274
- self.small = np.append(self.small, not self.is_sparse)
275
- self.split_index -= min(self.split_index, len(self.small) - 1)
276
- else:
277
- pos = bisect.bisect_left(self.large, key)
278
- if pos < len(self.large) and self.large[pos] == key:
279
- del self.large[pos]
280
- adjust_pos = bisect.bisect_right(self.large, key)
281
- for i in range(adjust_pos, len(self.large)):
282
- self.large[i] -= 1
283
- self.size -= 1
284
- def __str__(self) -> str:
285
- return f"BoolHybridArr([{','.join(map(str,self))}])"
286
- def insert(self, key: int, value: bool) -> None:
287
- value = bool(value)
288
- key = key if key >= 0 else key + self.size
289
- key = max(0, min(key, self.size))
290
- if key <= self.split_index:
291
- if key > len(self.small):
292
- self.small = np.pad(
293
- self.small,
294
- (0, key - len(self.small) + 1),
295
- constant_values=not self.is_sparse
296
- )
297
- self.small = np.insert(self.small, key, value)
298
- self.split_index = min(self.split_index + 1, len(self.small) - 1)
299
- else:
300
- pos = bisect.bisect_left(self.large, key)
301
- for i in range(pos, len(self.large)):
302
- self.large[i] += 1
303
- if (self.is_sparse and value) or (not self.is_sparse and not value):
304
- self.large.insert(pos, key)
305
- self.size += 1
306
- def __len__(self) -> int:
307
- return self.size
308
- def __iter__(self):
309
- return BHA_Iterator(map(self.__getitem__,range(self.size)))
310
- def __next__(self):
311
- return next(self.generator)
312
- def __contains__(self, value) -> bool:
313
- if not isinstance(value, (bool,np.bool_,self.Type,BHA_bool)):return False
314
- if not self.size:return False
315
- for i in range(10):
316
- if self[random.randint(0,self.size-1)] == value:
317
- return True
318
- b = any(1 for i in range(self.small.size+1>>1) if value==self.small[i] or value==self.small[self.small.size-i-1])
319
- if value == self.is_sparse:
320
- return self.large or b
321
- else:
322
- return len(self.large) == self.size-self.split_index-1 or b
323
- def __bool__(self) -> bool:
324
- return self.size
325
- def __any__(self):
326
- return T in self
327
- def __all__(self):
328
- return F not in self
329
- def __eq__(self, other) -> bool:
330
- if not isinstance(other, (BoolHybridArray, list, tuple, np.ndarray, array.array)):
331
- return False
332
- if len(self) != len(other):
333
- return False
334
- return all(a == b for a, b in zip(self, other))
335
- def __ne__(self, other) -> bool:
336
- return not self.__eq__(other)
337
- def __and__(self, other) -> BoolHybridArray:
338
- if type(other) == int:
339
- other = abs(other)
340
- other = bin(other)[2:]
341
- if len(self) != len(other):
342
- raise ValueError(f"与运算要求数组长度相同({len(self)} vs {len(other)})")
343
- return BoolHybridArr(map(operator.and_, self, other),hash_ = self.hash_)
344
- def __int__(self):
345
- if not self.size:
346
- return 0
347
- return reduce(lambda acc, val: operator.or_(operator.lshift(acc, 1), int(val)),self,0)
348
- def __or__(self, other) -> BoolHybridArray:
349
- if type(other) == int:
350
- other = bin(other)[2:]
351
- if self.size != len(other):
352
- raise ValueError(f"或运算要求数组长度相同({len(self)} vs {len(other)})")
353
- return BoolHybridArr(map(operator.or_, self, other),hash_ = self.hash_)
354
- def __ror__(self, other) -> BoolHybridArray:
355
- if type(other) == int:
356
- other = abs(other)
357
- other = bin(other)[2:]
358
- return self | other
359
- def __rshift__(self, other) -> BoolHybridArray:
360
- arr = BoolHybridArr(self)
361
- arr >>= other
362
- return arr
363
- def __irshift__(self, other) -> BoolHybridArray:
364
- if int(other) < 0:
365
- self <<= -other
366
- return self
367
- for i in range(int(other)):
368
- if self.size < 1:
369
- return self
370
- self.pop(-1)
371
- return self
372
- def __ilshift__(self ,other) -> BoolHybridArray:
373
- if int(other) < 0:
374
- self >>= -other
375
- return self
376
- if not self.is_sparse:
377
- self += FalsesArray(int(other))
378
- self.optimize()
379
- else:
380
- self.size += int(other)
381
- return self
382
- def __lshift__(self ,other) -> BoolHybridArray:
383
- if int(other) < 0:
384
- return self >> -other
385
- return self+FalsesArray(int(other))
386
- def __add__(self, other) -> BoolHybridArray:
387
- arr = self.copy()
388
- arr += other
389
- arr.optimize()
390
- return arr
391
- def __invert__(self) -> BoolHybridArray:
392
- return BoolHybridArr(not val for val in self)
393
- def __rand__(self, other) -> BoolHybridArray:
394
- if type(other) == int:
395
- other = bin(other)[2:]
396
- return self & other
397
- def __xor__(self, other) -> BoolHybridArray:
398
- if len(self) != len(other):
399
- raise ValueError(f"异或运算要求数组长度相同({len(self)} vs {len(other)})")
400
- return BoolHybridArr(map(operator.xor, self, other),hash_ = self.hash_)
401
- def __rxor__(self, other) -> BoolHybridArray:
402
- return self^other
403
- def __invert__(self) -> BoolHybridArray:
404
- return BoolHybridArr(not a for a in self)
405
- def copy(self) -> BoolHybridArray:
406
- arr = BoolHybridArray(split_index = self.split_index,size = self.size)
407
- arr.large,arr.small,arr.split_index,arr.is_sparse,arr.Type,arr.size = (array.array(self.large.typecode, self.large),self.small.copy(),
408
- self.split_index,BHA_Bool(self.is_sparse),self.Type,self.size)
409
- return arr
410
- def __copy__(self) -> BoolHybridArray:
411
- return self.copy()
412
- def find(self,value):
413
- return BHA_List([i for i in range(len(self)) if self[i]==value])
414
- def extend(self, iterable:Iterable) -> None:
415
- if isinstance(iterable, (Iterator, Generator, map)):
416
- iterable,copy = itertools.tee(iterable, 2)
417
- len_ = sum(1 for _ in copy)
418
- else:
419
- len_ = len(iterable)
420
- self.size += len_
421
- for i,j in zip(range(len_),iterable):
422
- self[-i-1] = j
423
- def append(self,v):
424
- self.size += 1
425
- self[-1] = v
426
- def index(self, value) -> int:
427
- if self.size == 0:
428
- raise ValueError('无法在空的 BoolHybridArray 中查找元素!')
429
- value = bool(value)
430
- x = 'not find'
431
- for i in range(self.size):
432
- if self[i] == value:
433
- return i
434
- if self[-i] == value:
435
- x = self.size-i
436
- if len(self)-i == i:
437
- break
438
- if x != 'not find':
439
- return x
440
- raise ValueError(f"{value} not in BoolHybridArray")
441
- def rindex(self, value) -> int:
442
- if self.size == 0:
443
- raise ValueError('无法在空的 BoolHybridArray 中查找元素!')
444
- value = bool(value)
445
- x = 'not find'
446
- for i in range(self.size):
447
- if self[-i] == value:
448
- return -i
449
- if self[i] == value:
450
- x = -(self.size-i)
451
- if len(self)-i == i:
452
- break
453
- if x != 'not find':
454
- return x
455
- raise ValueError(f"{value} not in BoolHybridArray")
456
- def count(self, value) -> int:
457
- value = bool(value)
458
- return sum(v == value for v in self)
459
- def optimize(self) -> None:
460
- arr = BoolHybridArr(self)
461
- self.large,self.small,self.split_index,self.is_sparse = (arr.large,arr.small,
462
- arr.split_index,arr.is_sparse)
463
- gc.collect()
464
- return self
465
- def memory_usage(self, detail=False) -> dict | int:
466
- small_mem = self.small.size // 8 + 32
467
- large_mem = len(self.large) * 4 + 32
468
- equivalent_list_mem = 40 + 8 * self.size
469
- equivalent_numpy_mem = 96 + self.size
470
- total = small_mem+large_mem
471
- if not detail:
472
- return total
473
- need_optimize = False
474
- optimize_reason = ""
475
- sparse_ratio = len(self.large) / max(len(self), 1)
476
- if sparse_ratio > 0.4 and len(self) > 500: # 阈值可根据测试调整
477
- need_optimize = True
478
- optimize_reason = "稀疏区索引密度过高,优化后可转为密集存储提升速度"
479
- elif len(self) < 32 and total > len(self):
480
- need_optimize = True
481
- optimize_reason = "小尺寸数组存储冗余,优化后将用int位存储进一步省内存"
482
- elif np.count_nonzero(np.array(self.small)) / max(len(self.small), 1) < 0.05 and len(self) > 1000:
483
- need_optimize = True
484
- optimize_reason = "密集区有效值占比过低,优化后可转为稀疏存储节省内存"
485
- return {
486
- "总占用(字节)": total,
487
- "密集区占用": small_mem,
488
- "稀疏区占用": large_mem,
489
- "对比原生list节省": f"{(1 - total/equivalent_list_mem)*100:.6f}%",
490
- "对比numpy节省": f"{(1 - total/equivalent_numpy_mem)*100:.6f}%" if equivalent_numpy_mem > 0 else "N/A",
491
- "是否需要优化": "" if need_optimize else "",
492
- "优化理由/说明": optimize_reason if need_optimize else "当前存储模式已适配数据特征,无需优化"
493
- }
494
- def get_shape(self):
495
- return (self.size,)
496
- def __array__(self,dtype = np.bool_,copy = None):
497
- arr = np.fromiter(map(np.bool_,self), dtype=np.bool_)
498
- return arr.copy() if copy else arr.view()
499
- def view(self):
500
- arr = TruesArray(0)
501
- arr.__dict__ = self.__dict__
502
- return arr
503
- class BoolHybridArr(BoolHybridArray,metaclass=ResurrectMeta):
504
- __module__ = 'bool_hybrid_array'
505
- def __new__(cls, lst: Iterable, is_sparse=None, Type = None, hash_ = True) -> BoolHybridArray:
506
- a = isinstance(lst, (Iterator, Generator, map))
507
- if a:
508
- lst, copy1, copy2 = itertools.tee(lst, 3)
509
- size = sum(1 for _ in copy1)
510
- true_count = sum(bool(val) for val in copy2)
511
- else:
512
- size = len(lst)
513
- true_count = sum(bool(val) for val in lst)
514
- if size == 0:
515
- return BoolHybridArray(0, 0, is_sparse=False if is_sparse is None else is_sparse)
516
- if is_sparse is None:
517
- is_sparse = true_count <= (size - true_count)
518
- split_index = int(min(size * 0.8, math.sqrt(size) * 100))
519
- split_index = math.isqrt(size) if true_count>size/3*2 or true_count<size/3 else max(split_index, 1)
520
- split_index = int(split_index) if split_index < 150e+7*2 else int(145e+7*2)
521
- arr = BoolHybridArray(split_index = split_index, size = size, is_sparse = is_sparse, Type = Type, hash_ = F)
522
- small_max_idx = min(split_index, size - 1)
523
- if a:
524
- small_data = []
525
- large_indices = []
526
- for i, val in enumerate(lst):
527
- val_bool = bool(val)
528
- if i <= small_max_idx:
529
- small_data.append(val_bool)
530
- else:
531
- if (is_sparse and val_bool) or (not is_sparse and not val_bool):
532
- large_indices.append(i)
533
- if small_data:
534
- arr.small[:len(small_data)] = small_data
535
- if large_indices:
536
- arr.large.extend(large_indices)
537
- else:
538
- if small_max_idx >= 0:
539
- arr.small[:small_max_idx + 1] = [bool(val) for val in lst[:small_max_idx + 1]]
540
- large_indices = [
541
- i for i in range(split_index + 1, size)
542
- if (is_sparse and bool(lst[i])) or (not is_sparse and not bool(lst[i]))
543
- ]
544
- arr.large.extend(large_indices)
545
- arr.large = sorted(arr.large)
546
- type_ = 'I' if size < 1 << 32 else 'Q'
547
- arr.large = array.array(type_, arr.large)
548
- if hash_:
549
- global hybrid_array_cache
550
- del hybrid_array_cache[-1]
551
- hybrid_array_cache = [
552
- (ref, h) for ref, h in hybrid_array_cache
553
- if ref() is not None
554
- ]
555
- for ref, existing_hash in hybrid_array_cache:
556
- existing_array = ref()
557
- try:
558
- if arr.size != existing_array.size:
559
- continue
560
- elif arr == existing_array:
561
- arr._cached_hash = existing_hash
562
- return arr
563
- except:
564
- continue
565
- return arr
566
- def TruesArray(size, Type = None, hash_ = True):
567
- split_index = min(size//10, math.isqrt(size))
568
- split_index = max(split_index, 1)
569
- split_index = int(split_index) if split_index < 150e+7*2 else int(145e+7*2)
570
- return BoolHybridArray(split_index,size,Type = Type,hash_ = hash_)
571
- def FalsesArray(size, Type = None,hash_ = True):
572
- split_index = min(size//10, math.isqrt(size))
573
- split_index = max(split_index, 1)
574
- split_index = int(split_index) if split_index < 150e+7*2 else int(145e+7*2)
575
- return BoolHybridArray(split_index,size,True,Type = Type,hash_ = hash_)
576
- Bool_Array = np.arange(2,dtype = np.uint8)
577
- class BHA_bool(int,metaclass=ResurrectMeta):
578
- __module__ = 'bool_hybrid_array'
579
- def __new__(cls, value):
580
- core_value = bool(value)
581
- instance = super().__new__(cls, core_value)
582
- instance.data = Bool_Array[1] if core_value else Bool_Array[0]
583
- instance.value = core_value
584
- return instance
585
- @lru_cache
586
- def __str__(self):
587
- return 'True' if self else 'False'
588
- @lru_cache
589
- def __repr__(self):
590
- return 'T' if self else 'F'
591
- @lru_cache
592
- def __bool__(self):
593
- return self.value
594
- @lru_cache
595
- def __int__(self):
596
- return int(self.data)
597
- @lru_cache
598
- def __or__(self,other):
599
- return BHA_Bool(self.value|other)
600
- @lru_cache
601
- def __and__(self,other):
602
- return BHA_Bool(self.value&other)
603
- @lru_cache
604
- def __xor__(self,other):
605
- return BHA_Bool(self.value^other)
606
- def __hash__(self):
607
- return hash(self.data)
608
- def __len__(self):
609
- raise TypeError("'BHA_bool' object has no attribute '__len__'")
610
- def __del__(self):
611
- if not sys.is_finalizing():
612
- print(f'你删除或修改了1个常变量:{repr(self)}!')
613
- if self:builtins.T = BHA_bool(1)
614
- else:builtins.F = BHA_bool(0)
615
- raise TypeError(f'禁止删除或修改常变量{repr(self)}!')
616
- __rand__,__ror__,__rxor__ = __and__,__or__,__xor__
617
- class BHA_Bool(BHA_bool,metaclass=ResurrectMeta):
618
- __module__ = 'bool_hybrid_array'
619
- @lru_cache
620
- def __new__(cls,v):
621
- if(builtins.T == True)and(builtins.F == False):
622
- return builtins.T if v else builtins.F
623
- else:
624
- builtins.T,builtins.F = BHA_Bool.T,BHA_Bool.F
625
- return BHA_Bool.T if v else BHA_Bool.F
626
- class BHA_List(list,metaclass=ResurrectMeta):
627
- __module__ = 'bool_hybrid_array'
628
- def __init__(self,arr):
629
- def Temp(v):
630
- if isinstance(v,(list,tuple)):
631
- v = (BoolHybridArr(v) if all(isinstance(i,
632
- (bool,BHA_bool,np.bool_)) for i in v)
633
- else BHA_List(v))
634
- if isinstance(v,BoolHybridArray):
635
- return v
636
- elif isinstance(v,(bool,np.bool_)):
637
- return BHA_Bool(v)
638
- else:
639
- return v
640
- super().__init__(map(Temp,arr))
641
- try:self.hash_value = sum(map(hash,self))
642
- except Exception as e:return hash(e)
643
- def __hash__(self):
644
- return self.hash_value
645
- def __call__(self, func):
646
- func.self = self
647
- def wrapper(self, *args, **kwargs):
648
- return func(self, *args, **kwargs)
649
- setattr(self, func.__name__, wrapper)
650
- return wrapper
651
- def __str__(self):
652
- def Temp(v):
653
- if isinstance(v,(BoolHybridArray,np.ndarray,BHA_List,array.array)):
654
- return str(v)+',\n'
655
- else:
656
- return repr(v)+','
657
- return f"BHA_List([\n{''.join(map(Temp,self))}])"
658
- def __repr__(self):
659
- return str(self)
660
- def __or__(self,other):
661
- return BHA_List(map(operator.or_, self, other))
662
- def __and__(self,other):
663
- return BHA_List(map(operator.and_, self, other))
664
- def __xor__(self,other):
665
- return BHA_List(map(operator.xor, self, other))
666
- def __rxor__(self,other):
667
- return self^other
668
- def __ror__(self,other):
669
- return self|other
670
- def __rand__(self,other):
671
- return self&other
672
- def optimize(self):
673
- for val in self:
674
- val.optimize()
675
- def memory_usage(self,detail=False):
676
- total = sum(val.memory_usage() for val in self) + 32
677
- if not detail:
678
- return total
679
- else:
680
- temp = sum(val.size for val in self)
681
- return {
682
- "占用(字节)": total,
683
- "对比原生list节省": f"{(1 - total / (temp * 8 + 40))*100:.6f}%",
684
- "对比numpy节省": f"{(1 - total / (temp + 96)) * 100:.6f}%"}
685
- def __iter__(self):
686
- return BHA_Iterator(super().__iter__())
687
- class BHA_Iterator(Iterator,metaclass=ResurrectMeta):
688
- __module__ = 'bool_hybrid_array'
689
- def __init__(self,data):
690
- self.data,self.copy_data = itertools.tee(iter(data),2)
691
- def __next__(self):
692
- try:return next(self.data)
693
- except Exception as e:
694
- self.__init__(self.copy_data)
695
- raise e
696
- def __iter__(self):
697
- return self
698
- def __or__(self,other):
699
- return BHA_Iterator(map(operator.or_, self, other))
700
- def __and__(self,other):
701
- return BHA_Iterator(map(operator.and_, self, other))
702
- def __xor__(self,other):
703
- return BHA_Iterator(map(operator.xor, self, other))
704
- def __array__(self,dtype = None,copy = None):
705
- arr = np.fromiter(self, dtype=dtype)
706
- return arr.copy() if copy else arr.view()
707
- __rand__,__ror__,__rxor__ = __and__,__or__,__xor__
708
- class ProtectedBuiltinsDict(dict,metaclass=ResurrectMeta):
709
- def __init__(self, *args, protected_names = ["T", "F", "BHA_Bool", "BHA_List", "BoolHybridArray", "BoolHybridArr",
710
- "TruesArray", "FalsesArray", "ProtectedBuiltinsDict", "builtins",
711
- "__builtins__", "__dict__","ResurrectMeta","math",
712
- "np","protected_names","BHA_Function",
713
- "__class__","Ask_BHA","Create_BHA","Ask_arr","numba_opt"],
714
- name = 'builtins', **kwargs):
715
- super().__init__(*args, **kwargs)
716
- if name == 'builtins':
717
- super().__setattr__('__dict__',self)
718
- super().__setattr__('builtins',self)
719
- super().__setattr__('__builtins__',self)
720
- self.name = name
721
- self.protected_names = protected_names
722
- def __setitem__(self, name, value):
723
- if name in ["T", "F"]:
724
- current_T = self.get("T")
725
- current_F = self.get("F")
726
- if isinstance(current_T, BHA_bool) and isinstance(current_F, BHA_bool):
727
- is_swap = (name == "T" and isinstance(value, BHA_bool) and value.value == current_F.value)or(name == "F" and isinstance(value, BHA_bool) and value.value == current_T.value)
728
- if is_swap:
729
- print(f"""警告:禁止交换内置常量 __{self.name}__["{name}"] 和 __builtins__["{'F' if name == 'T' else 'T'}"]!""")
730
- raise AttributeError(f"""禁止交换内置常量 __{self.name}__["{name}"] 和 __{self.name}__["{'F' if name == 'T' else 'T'}"]""")
731
- if name in self.protected_names and name not in ["T", "F"]:
732
- print(f"警告:禁止修改内置常量 __{self.name}__['{name}']!")
733
- raise AttributeError(f"禁止修改内置常量 __{self.name}__['{name}']")
734
- super().__setitem__(name, value)
735
- def __delitem__(self, name):
736
- if name in self.protected_names:
737
- print(f"警告:禁止删除内置常量 __builtins__['{name}']!")
738
- raise AttributeError(f"禁止删除内置常量 __builtins__['{name}']")
739
- if name in self:
740
- super().__delitem__(name)
741
- def __delattr__(self, name):
742
- if name in self.protected_names:
743
- raise AttributeError(f'禁止删除内置常量:{self.name}.{name}')
744
- else:
745
- del self[name]
746
- def __getattr__(self, name):
747
- if name in self:
748
- return self[name]
749
- else:
750
- raise AttributeError(f"module 'builtins' has no attribute '{name}'")
751
- def __setattr__(self,name,value):
752
- try:protected = self.protected_names
753
- except Exception:protected = self
754
- if(name in protected)and(not sys.is_finalizing())and(name != '_'):
755
- raise AttributeError(f'禁止修改内置常量:{self.name}.{name}')
756
- else:
757
- super().__setattr__(name,value)
758
- def Ask_arr(arr):
759
- if isinstance(arr,BHA_List):
760
- return '\n'.join(map(Ask_arr,arr))
761
- elif isinstance(arr,BoolHybridArray):
762
- h = hex(int(arr))[2:]
763
- h = '0'*(arr.size - len(bin(int(arr)))+2)+h
764
- return h
765
- else:
766
- return str(arr)
767
- def Ask_BHA(path):
768
- if '.bha' not in path.lower():
769
- path += '.bha'
770
- with open(path, 'a+b') as f:
771
- f.seek(0)
772
- file_size = os.fstat(f.fileno()).st_size
773
- if not file_size:
774
- return TruesArray(0)
775
- if os.name == 'nt':
776
- mm = mmap.mmap(f.fileno(), file_size, access=mmap.ACCESS_READ)
777
- else:
778
- mm = mmap.mmap(f.fileno(), file_size, flags=mmap.MAP_PRIVATE, prot=mmap.PROT_READ)
779
- with mm:
780
- temp = mm.read().decode('utf-8').strip()
781
- temp = temp.split()
782
- temp2 = lambda x:BoolHybridArr(map(int,'0'*(len(x) - len(x.lstrip('0')))+bin(int(x,base = 16))[2:]),hash_ = F)
783
- temp = BHA_List(map(temp2,temp))
784
- if len(temp) == 1:
785
- return temp[0]
786
- return temp
787
- def Create_BHA(path,arr):
788
- if '.bha' not in path.lower():
789
- path += '.bha'
790
- temp = Ask_arr(arr).strip().encode('utf-8')
791
- with open(path, "w+b") as f:
792
- f.truncate(len(temp))
793
- if not len(temp):
794
- return
795
- with mmap.mmap(
796
- f.fileno(),
797
- length=len(temp),
798
- access=mmap.ACCESS_WRITE
799
- ) as mm:
800
- mm[:] = temp
801
- mm.flush()
802
- def numba_opt():
803
- import numba
804
- sig = numba.types.Union([
805
- numba.types.intp(
806
- numba.types.Array(numba.types.uint32, 1, 'C'),
807
- numba.types.uint32,
808
- numba.types.uint32,
809
- numba.types.Optional(numba.types.uint32)
810
- ),
811
- numba.types.intp(
812
- numba.types.Array(numba.types.uint64, 1, 'C'),
813
- numba.types.uint64,
814
- numba.types.uint64,
815
- numba.types.Optional(numba.types.uint64)
816
- ),
817
- numba.types.intp(
818
- numba.types.Any,
819
- numba.types.Any,
820
- numba.types.Any,
821
- numba.types.Optional(numba.types.Any)
822
- )
823
- ])
824
- bisect.bisect_left = numba.njit(sig, cache=True)(bisect.bisect_left)
825
- bisect.bisect_right = numba.njit(sig, cache=True)(bisect.bisect_right)
826
- builtins.np = np
827
- builtins.T = BHA_bool(1)
828
- builtins.F = BHA_bool(0)
829
- builtins.BHA_Bool = BHA_Bool
830
- builtins.BHA_List = BHA_List
831
- builtins.FalsesArray = FalsesArray
832
- builtins.TruesArray = TruesArray
833
- builtins.BoolHybridArr = BoolHybridArr
834
- builtins.BHA_Iterator = BHA_Iterator
835
- builtins.BoolHybridArray = BoolHybridArray
836
- builtins.BHA_Bool.T,builtins.BHA_Bool.F = BHA_bool(1),BHA_bool(0)
837
- builtins.ResurrectMeta = ResurrectMeta
838
- builtins.ProtectedBuiltinsDict = ProtectedBuiltinsDict
839
- builtins.BHA_Function = BHA_Function
840
- builtins.Ask_BHA = Ask_BHA
841
- builtins.Create_BHA = Create_BHA
842
- builtins.numba_opt = numba_opt
843
- Tid,Fid = id(T),id(F)
844
- original_id = builtins.id
845
- def fake_id(obj):
846
- if isinstance(obj, BHA_bool):return Tid if obj else Fid
847
- else:return original_id(obj)
848
- builtins.id = fake_id
849
- original_builtins_dict = builtins.__dict__.copy()
850
- __builtins__ = ProtectedBuiltinsDict(original_builtins_dict)
851
- builtins = __builtins__
852
- sys.modules['builtins'] = builtins
853
- builtins.name = 'builtins'
854
- try:
855
- sys.flags.optimize = 2
856
- except:
1
+ from __future__ import annotations
2
+ import builtins
3
+ import array,bisect,numpy as np
4
+ from collections.abc import MutableSequence,Iterable,Generator,Iterator,Sequence
5
+ import itertools,copy,sys,math,weakref,random,mmap,os
6
+ from functools import reduce
7
+ import operator,ctypes,gc,abc,types
8
+ from functools import lru_cache
9
+ from typing import Union,_GenericAlias
10
+ hybrid_array_cache = []
11
+ if 'UnionType' in types.__dict__:
12
+ class Union:
13
+ def __getitem__(self,*args):
14
+ return reduce(operator.or_, args)
15
+ Union = Union()
16
+ if 'GenericAlias' in types.__dict__:
17
+ _GenericAlias = types.GenericAlias
18
+ class ResurrectMeta(abc.ABCMeta,metaclass=abc.ABCMeta):
19
+ __module__ = 'bool_hybrid_array'
20
+ name = 'ResurrectMeta'
21
+ def __new__(cls, name, bases, namespace):
22
+ meta_bases = tuple(type(base) for base in bases)
23
+ if cls not in meta_bases:
24
+ meta_bases = (cls,) + meta_bases
25
+ obj = super().__new__(cls, name, bases, namespace)
26
+ super_cls = super(ResurrectMeta, obj)
27
+ super_cls.__setattr__('x',None)
28
+ super_cls.__setattr__('name', name)
29
+ super_cls.__setattr__('bases', bases)
30
+ super_cls.__setattr__('namespace', namespace)
31
+ super_cls.__setattr__('original_dict', dict(obj.__dict__))
32
+ del obj.original_dict["__abstractmethods__"]
33
+ del obj.original_dict["_abc_impl"]
34
+ return obj
35
+ @lru_cache
36
+ def __str__(cls):
37
+ return super().__repr__()[8:][:-2]
38
+ @lru_cache
39
+ def __repr__(cls,detailed = False):
40
+ if detailed:
41
+ name, bases, namespace = cls.name,cls.bases,cls.namespace
42
+ return f'ResurrectMeta(cls = {cls},{name = },{bases = },{namespace = })'
43
+ return str(cls)
44
+ def __del__(cls):
45
+ exec(f"builtins.{cls.__name__} = cls")
46
+ if not sys.is_finalizing():
47
+ print(f'警告:禁止删除常变量:{cls}!')
48
+ raise TypeError(f'禁止删除常变量:{cls}')
49
+ def __hash__(cls):
50
+ return hash(cls.name+cls.__module__)
51
+ def __setattr__(cls,name,value):
52
+ if not hasattr(cls, 'x'):
53
+ super().__setattr__(name,value)
54
+ return
55
+ if hasattr(cls, 'name') and cls.name == 'BHA_Bool' and repr(value) in {'T','F'} and name in {'T','F'}:
56
+ super().__setattr__(name,value)
57
+ return
58
+ if hasattr(cls, 'original_dict') and name in cls.original_dict:
59
+ raise AttributeError(f'禁止修改属性:{name}')
60
+ else:
61
+ super().__setattr__(name,value)
62
+ def __delattr__(cls,name):
63
+ if name in cls.original_dict:
64
+ raise AttributeError(f'禁止删除属性:{name}')
65
+ else:
66
+ super().__delattr__(name)
67
+ if 'UnionType' not in types.__dict__:
68
+ def __or__(self,other):
69
+ return Union[self,other]
70
+ __ror__ = __or__
71
+ def __getitem__(self,*args):
72
+ return _GenericAlias(self,args)
73
+ x = None
74
+ original_dict = {"__delattr__":__delattr__,"__getitem__":__getitem__,"__setattr__":__setattr__,"__hash__":__hash__,
75
+ "__new__":__new__,"__del__":__del__,"__str__":__str__,"__repr__":__repr__,"__class__":abc.ABCMeta,"original_dict":None}
76
+ try:
77
+ original_dict["original_dict"] = original_dict
78
+ original_dict["__ror__"] = __ror__
79
+ original_dict["__or__"] = __or__
80
+ except:
81
+ pass
82
+ ResurrectMeta.__class__ = ResurrectMeta
83
+ class BHA_Function(metaclass=ResurrectMeta):
84
+ def __init__(self,v):
85
+ self.data,self.module = v,__name__
86
+ def __call__(self,*a,**b):
87
+ return self.data(*a,**b)
88
+ def __getattr__(self,name):
89
+ return getattr(self.data,name)
90
+ @classmethod
91
+ def string_define(cls, name, text, positional, default):
92
+ param_strs = list(positional)
93
+ param_strs.extend([f"{k}={v!r}" for k, v in default.items()])
94
+ params = ", ".join(param_strs)
95
+ func_code = f"""
96
+ def {name}({params}):
97
+ {text}
98
+ """
99
+ local_namespace = {}
100
+ exec(func_code, globals(), local_namespace)
101
+ dynamic_func = local_namespace[name]
102
+ return cls(dynamic_func)
103
+ class BoolHybridArray(MutableSequence,Exception,metaclass=ResurrectMeta):
104
+ __module__ = 'bool_hybrid_array'
105
+ class _CompactBoolArray(Sequence,Exception):
106
+ def __init__(self, size: int):
107
+ self.size = size
108
+ self.n_uint8 = (size + 7) >> 3
109
+ self.data = np.zeros(self.n_uint8, dtype=np.uint8)
110
+ def __setitem__(self, index: int | slice, value):
111
+ ctypes_arr = self.data.ctypes.data_as(ctypes.POINTER(ctypes.c_ubyte))
112
+ if isinstance(index, slice):
113
+ start, stop, step = index.indices(self.size)
114
+ indices = list(range(start, stop, step))
115
+ if isinstance(value, (list, tuple)):
116
+ if len(value)!= len(indices):
117
+ raise ValueError("值的数量与切片长度不匹配")
118
+ for i, val in zip(indices, value):
119
+ self._set_single(i, bool(val), ctypes_arr)
120
+ else:
121
+ val_bool = bool(value)
122
+ for i in indices:
123
+ self._set_single(i, val_bool, ctypes_arr)
124
+ self.data = np.ctypeslib.as_array(ctypes_arr, shape=(self.n_uint8,))
125
+ return
126
+ if not (0 <= index < self.size):
127
+ raise IndexError(f"密集区索引 {index} 超出范围 [0, {self.size})")
128
+ self._set_single(index, bool(value), ctypes_arr)
129
+ self.data = np.ctypeslib.as_array(ctypes_arr, shape=(self.n_uint8,))
130
+ self.data = self.data.view()
131
+ def _set_single(self, index: int, value: bool, ctypes_arr):
132
+ uint8_pos = index >> 3
133
+ bit_offset = index & 7
134
+ ctypes_arr[uint8_pos] &= ~(1 << bit_offset) & 0xFF
135
+ if value:
136
+ ctypes_arr[uint8_pos] |= (1 << bit_offset)
137
+ def __getitem__(self, index: int | slice) -> bool | list[bool]:
138
+ if isinstance(index, slice):
139
+ start, stop, step = index.indices(self.size)
140
+ result = []
141
+ for i in range(start, stop, step):
142
+ uint8_pos = i >> 3
143
+ bit_offset = i & 7
144
+ result.append(bool((self.data[uint8_pos] >> bit_offset) & 1))
145
+ return result
146
+ if not (0 <= index < self.size):
147
+ raise IndexError(f"密集区索引 {index} 超出范围 [0, {self.size})")
148
+ uint8_pos = index >> 3
149
+ bit_offset = index & 7
150
+ return bool((self.data[uint8_pos] >> bit_offset) & 1)
151
+ def __len__(self):
152
+ return self.size
153
+ def set_all(self, value: bool):
154
+ ctypes_arr = self.data.ctypes.data_as(ctypes.POINTER(ctypes.c_ubyte))
155
+ length = len(self.data)
156
+ if value:ctypes.memset(ctypes_arr, 0xff, length)
157
+ else:ctypes.memset(ctypes_arr, 0, length)
158
+ def copy(self):
159
+ new_instance = self.__class__(size=self.size)
160
+ new_instance.data = self.data.copy()
161
+ return new_instance
162
+ def __init__(self, split_index: int, size=None, is_sparse=False ,Type:Callable = None,hash_ = True) -> None:
163
+ self.Type = Type if Type is not None else builtins.BHA_Bool
164
+ self.split_index = int(split_index)
165
+ self.size = size or 0
166
+ self.is_sparse = is_sparse
167
+ self.small = self._CompactBoolArray(self.split_index + 1)
168
+ self.small.set_all(not is_sparse)
169
+ self.large = array.array('I') if size < 1<<32 else array.array('Q')
170
+ self.generator = iter(self)
171
+ self.hash_ = hash_
172
+ if hash_:
173
+ global hybrid_array_cache
174
+ hybrid_array_cache = [
175
+ (ref, h) for ref, h in hybrid_array_cache
176
+ if ref() is not None
177
+ ]
178
+ for ref, existing_hash in hybrid_array_cache:
179
+ existing_array = ref()
180
+ try:
181
+ if self.size != existing_array.size:
182
+ continue
183
+ elif self == existing_array:
184
+ self._cached_hash = existing_hash
185
+ return
186
+ except Exception:
187
+ continue
188
+ new_hash = id(self)
189
+ self._cached_hash = new_hash
190
+ hybrid_array_cache.append((weakref.ref(self), new_hash))
191
+ def __call__(self, func):
192
+ func.self = self
193
+ def wrapper(*args, **kwargs):
194
+ return func(self, *args, **kwargs)
195
+ setattr(self, func.__name__, wrapper)
196
+ return func
197
+ def __hash__(self):
198
+ return self._cached_hash
199
+ def accessor(self, i: int, value: bool|None = None) -> bool|None:
200
+ def _get_sparse_info(index: int) -> tuple[int, bool]:
201
+ pos = bisect.bisect_left(self.large, index)
202
+ exists = pos < len(self.large) and self.large[pos] == index
203
+ return pos, exists
204
+ if value is None:
205
+ if i <= self.split_index:
206
+ return self.small[i]
207
+ else:
208
+ _, exists = _get_sparse_info(i)
209
+ return exists if self.is_sparse else not exists
210
+ else:
211
+ if i <= self.split_index:
212
+ self.small[i] = value
213
+ return None
214
+ else:
215
+ pos, exists = _get_sparse_info(i)
216
+ condition = not value or exists
217
+ if self.is_sparse != condition:
218
+ self.large.insert(pos, i)
219
+ else:
220
+ if pos < len(self.large):
221
+ del self.large[pos]
222
+ return None
223
+ def __getitem__(self, key:int|slice) -> BoolHybridArray:
224
+ if isinstance(key, slice):
225
+ start, stop, step = key.indices(self.size)
226
+ return BoolHybridArr((self[i] for i in range(start, stop, step)),hash_ = self.hash_)
227
+ key = key if key >=0 else key + self.size
228
+ if 0 <= key < self.size:
229
+ return self.Type(self.accessor(key))
230
+ raise IndexError("索引超出范围")
231
+ def __setitem__(self, key: int | slice, value) -> None:
232
+ if isinstance(key, int):
233
+ adjusted_key = key if key >= 0 else key + self.size
234
+ if not (0 <= adjusted_key < self.size):
235
+ raise IndexError("索引超出范围")
236
+ self.accessor(adjusted_key, bool(value))
237
+ return
238
+ if isinstance(key, slice):
239
+ original_size = self.size
240
+ start, stop, step = key.indices(original_size)
241
+ value_list = list(value)
242
+ new_len = len(value_list)
243
+ if step != 1:
244
+ slice_indices = list(range(start, stop, step))
245
+ if new_len != len(slice_indices):
246
+ raise ValueError(f"值长度与切片长度不匹配:{new_len} vs {len(slice_indices)}")
247
+ for i, val in zip(slice_indices, value_list):
248
+ self[i] = val
249
+ return
250
+ for i in range(stop - 1, start - 1, -1):
251
+ if i <= self.split_index:
252
+ if i >= len(self.small):
253
+ self.small = np.pad(
254
+ self.small,
255
+ (0, i - len(self.small) + 1),
256
+ constant_values=not self.is_sparse
257
+ )
258
+ del self[i]
259
+ for idx, val in enumerate(value_list):
260
+ self.insert(start + idx, bool(val))
261
+ return
262
+ raise TypeError("索引必须是整数或切片")
263
+ def __repr__(self) -> str:
264
+ return(f"BoolHybridArray(split_index={self.split_index}, size={self.size}, "
265
+ +f"is_sparse={self.is_sparse}, small_len={len(self.small)}, large_len={len(self.large)})")
266
+ def __delitem__(self, key: int) -> None:
267
+ key = key if key >= 0 else key + self.size
268
+ if not (0 <= key < self.size):
269
+ raise IndexError(f"索引 {key} 超出范围 [0, {self.size})")
270
+ if key <= self.split_index:
271
+ if key >= len(self.small):
272
+ raise IndexError(f"小索引 {key} 超出small数组范围(长度{len(self.small)})")
273
+ self.small = np.delete(self.small, key)
274
+ self.small = np.append(self.small, not self.is_sparse)
275
+ self.split_index -= min(self.split_index, len(self.small) - 1)
276
+ else:
277
+ pos = bisect.bisect_left(self.large, key)
278
+ if pos < len(self.large) and self.large[pos] == key:
279
+ del self.large[pos]
280
+ adjust_pos = bisect.bisect_right(self.large, key)
281
+ for i in range(adjust_pos, len(self.large)):
282
+ self.large[i] -= 1
283
+ self.size -= 1
284
+ def __str__(self) -> str:
285
+ return f"BoolHybridArr([{','.join(map(str,self))}])"
286
+ def insert(self, key: int, value: bool) -> None:
287
+ value = bool(value)
288
+ key = key if key >= 0 else key + self.size
289
+ key = max(0, min(key, self.size))
290
+ if key <= self.split_index:
291
+ if key > len(self.small):
292
+ self.small = np.pad(
293
+ self.small,
294
+ (0, key - len(self.small) + 1),
295
+ constant_values=not self.is_sparse
296
+ )
297
+ self.small = np.insert(self.small, key, value)
298
+ self.split_index = min(self.split_index + 1, len(self.small) - 1)
299
+ else:
300
+ pos = bisect.bisect_left(self.large, key)
301
+ for i in range(pos, len(self.large)):
302
+ self.large[i] += 1
303
+ if (self.is_sparse and value) or (not self.is_sparse and not value):
304
+ self.large.insert(pos, key)
305
+ self.size += 1
306
+ def __len__(self) -> int:
307
+ return self.size
308
+ def __iter__(self):
309
+ return BHA_Iterator(map(self.__getitem__,range(self.size)))
310
+ def __next__(self):
311
+ return next(self.generator)
312
+ def __contains__(self, value) -> bool:
313
+ if not isinstance(value, (bool,np.bool_,self.Type,BHA_bool)):return False
314
+ if not self.size:return False
315
+ for i in range(10):
316
+ if self[random.randint(0,self.size-1)] == value:
317
+ return True
318
+ b = any(1 for i in range(self.small.size+1>>1) if value==self.small[i] or value==self.small[self.small.size-i-1])
319
+ if value == self.is_sparse:
320
+ return self.large or b
321
+ else:
322
+ return len(self.large) == self.size-self.split_index-1 or b
323
+ def __bool__(self) -> bool:
324
+ return self.size
325
+ def __any__(self):
326
+ return T in self
327
+ def __all__(self):
328
+ return F not in self
329
+ def __eq__(self, other) -> bool:
330
+ if not isinstance(other, (BoolHybridArray, list, tuple, np.ndarray, array.array)):
331
+ return False
332
+ if len(self) != len(other):
333
+ return False
334
+ return all(a == b for a, b in zip(self, other))
335
+ def __ne__(self, other) -> bool:
336
+ return not self == other
337
+ def __and__(self, other) -> BoolHybridArray:
338
+ if type(other) == int:
339
+ other = abs(other)
340
+ other = bin(other)[2:]
341
+ if len(self) != len(other):
342
+ raise ValueError(f"与运算要求数组长度相同({len(self)} vs {len(other)})")
343
+ return BoolHybridArr(map(operator.and_, self, other),hash_ = self.hash_)
344
+ def __int__(self):
345
+ if not self.size:
346
+ return 0
347
+ return reduce(lambda acc, val: operator.or_(operator.lshift(acc, 1), int(val)),self,0)
348
+ def __or__(self, other) -> BoolHybridArray:
349
+ if type(other) == int:
350
+ other = bin(other)[2:]
351
+ if self.size != len(other):
352
+ raise ValueError(f"或运算要求数组长度相同({len(self)} vs {len(other)})")
353
+ return BoolHybridArr(map(operator.or_, self, other),hash_ = self.hash_)
354
+ def __ror__(self, other) -> BoolHybridArray:
355
+ if type(other) == int:
356
+ other = abs(other)
357
+ other = bin(other)[2:]
358
+ return self | other
359
+ def __rshift__(self, other) -> BoolHybridArray:
360
+ arr = BoolHybridArr(self)
361
+ arr >>= other
362
+ return arr
363
+ def __irshift__(self, other) -> BoolHybridArray:
364
+ if int(other) < 0:
365
+ self <<= -other
366
+ return self
367
+ for i in range(int(other)):
368
+ if self.size < 1:
369
+ return self
370
+ self.pop(-1)
371
+ return self
372
+ def __ilshift__(self ,other) -> BoolHybridArray:
373
+ if int(other) < 0:
374
+ self >>= -other
375
+ return self
376
+ if not self.is_sparse:
377
+ self += FalsesArray(int(other))
378
+ self.optimize()
379
+ else:
380
+ self.size += int(other)
381
+ return self
382
+ def __lshift__(self ,other) -> BoolHybridArray:
383
+ if int(other) < 0:
384
+ return self >> -other
385
+ return self+FalsesArray(int(other))
386
+ def __add__(self, other) -> BoolHybridArray:
387
+ arr = self.copy()
388
+ arr += other
389
+ arr.optimize()
390
+ return arr
391
+ def __invert__(self) -> BoolHybridArray:
392
+ return BoolHybridArr(not val for val in self)
393
+ def __rand__(self, other) -> BoolHybridArray:
394
+ if type(other) == int:
395
+ other = bin(other)[2:]
396
+ return self & other
397
+ def __xor__(self, other) -> BoolHybridArray:
398
+ if len(self) != len(other):
399
+ raise ValueError(f"异或运算要求数组长度相同({len(self)} vs {len(other)})")
400
+ return BoolHybridArr(map(operator.xor, self, other),hash_ = self.hash_)
401
+ def __rxor__(self, other) -> BoolHybridArray:
402
+ return self^other
403
+ def __invert__(self) -> BoolHybridArray:
404
+ return BoolHybridArr(not a for a in self)
405
+ def copy(self) -> BoolHybridArray:
406
+ arr = BoolHybridArray(split_index = self.split_index,size = self.size)
407
+ arr.large,arr.small,arr.split_index,arr.is_sparse,arr.Type,arr.size = (array.array(self.large.typecode, self.large),self.small.copy(),
408
+ self.split_index,BHA_Bool(self.is_sparse),self.Type,self.size)
409
+ return arr
410
+ def __copy__(self) -> BoolHybridArray:
411
+ return self.copy()
412
+ def find(self,value):
413
+ from .int_array import IntHybridArray
414
+ return IntHybridArray([i for i in range(len(self)) if self[i]==value])
415
+ def extend(self, iterable:Iterable) -> None:
416
+ if isinstance(iterable, (Iterator, Generator, map)):
417
+ iterable,copy = itertools.tee(iterable, 2)
418
+ len_ = sum(1 for _ in copy)
419
+ else:
420
+ len_ = len(iterable)
421
+ self.size += len_
422
+ for i,j in zip(range(len_),iterable):
423
+ self[-i-1] = j
424
+ def append(self,v):
425
+ self.size += 1
426
+ self[-1] = v
427
+ def index(self, value) -> int:
428
+ if self.size == 0:
429
+ raise ValueError('无法在空的 BoolHybridArray 中查找元素!')
430
+ value = bool(value)
431
+ x = 'not find'
432
+ for i in range(self.size):
433
+ if self[i] == value:
434
+ return i
435
+ if self[-i] == value:
436
+ x = self.size-i
437
+ if len(self)-i == i:
438
+ break
439
+ if x != 'not find':
440
+ return x
441
+ raise ValueError(f"{value} not in BoolHybridArray")
442
+ def rindex(self, value) -> int:
443
+ if self.size == 0:
444
+ raise ValueError('无法在空的 BoolHybridArray 中查找元素!')
445
+ value = bool(value)
446
+ x = 'not find'
447
+ for i in range(self.size):
448
+ if self[-i] == value:
449
+ return -i
450
+ if self[i] == value:
451
+ x = -(self.size-i)
452
+ if len(self)-i == i:
453
+ break
454
+ if x != 'not find':
455
+ return x
456
+ raise ValueError(f"{value} not in BoolHybridArray")
457
+ def count(self, value) -> int:
458
+ value = bool(value)
459
+ return sum(v == value for v in self)
460
+ def optimize(self) -> None:
461
+ arr = BoolHybridArr(self)
462
+ self.large,self.small,self.split_index,self.is_sparse = (arr.large,arr.small,
463
+ arr.split_index,arr.is_sparse)
464
+ gc.collect()
465
+ return self
466
+ def memory_usage(self, detail=False) -> dict | int:
467
+ small_mem = self.small.size // 8 + 32
468
+ large_mem = len(self.large) * 4 + 32
469
+ equivalent_list_mem = 40 + 8 * self.size
470
+ equivalent_numpy_mem = 96 + self.size
471
+ total = small_mem+large_mem
472
+ if not detail:
473
+ return total
474
+ need_optimize = False
475
+ optimize_reason = ""
476
+ sparse_ratio = len(self.large) / max(len(self), 1)
477
+ if sparse_ratio > 0.4 and len(self) > 500: # 阈值可根据测试调整
478
+ need_optimize = True
479
+ optimize_reason = "稀疏区索引密度过高,优化后可转为密集存储提升速度"
480
+ elif len(self) < 32 and total > len(self):
481
+ need_optimize = True
482
+ optimize_reason = "小尺寸数组存储冗余,优化后将用int位存储进一步省内存"
483
+ elif np.count_nonzero(np.array(self.small)) / max(len(self.small), 1) < 0.05 and len(self) > 1000:
484
+ need_optimize = True
485
+ optimize_reason = "密集区有效值占比过低,优化后可转为稀疏存储节省内存"
486
+ return {
487
+ "总占用(字节)": total,
488
+ "密集区占用": small_mem,
489
+ "稀疏区占用": large_mem,
490
+ "对比原生list节省": f"{(1 - total/equivalent_list_mem)*100:.6f}%",
491
+ "对比numpy节省": f"{(1 - total/equivalent_numpy_mem)*100:.6f}%" if equivalent_numpy_mem > 0 else "N/A",
492
+ "是否需要优化": "是" if need_optimize else "",
493
+ "优化理由/说明": optimize_reason if need_optimize else "当前存储模式已适配数据特征,无需优化"
494
+ }
495
+ def get_shape(self):
496
+ return (self.size,)
497
+ def __array__(self,dtype = np.bool_,copy = None):
498
+ arr = np.fromiter(map(np.bool_,self), dtype=dtype)
499
+ return arr.copy() if copy else arr.view()
500
+ def view(self):
501
+ arr = TruesArray(0)
502
+ arr.__dict__ = self.__dict__
503
+ return arr
504
+ def __reduce__(self):
505
+ return BoolHybridArr,(np.asarray(self),self.is_sparse,self.Type,self.hash_,),
506
+ class BoolHybridArr(BoolHybridArray,metaclass=ResurrectMeta):
507
+ __module__ = 'bool_hybrid_array'
508
+ def __new__(cls, lst: Iterable, is_sparse=None, Type = None, hash_ = True) -> BoolHybridArray:
509
+ a = isinstance(lst, (Iterator, Generator, map))
510
+ if a:
511
+ lst, copy1, copy2 = itertools.tee(lst, 3)
512
+ size = sum(1 for _ in copy1)
513
+ true_count = sum(bool(val) for val in copy2)
514
+ else:
515
+ size = len(lst)
516
+ true_count = sum(bool(val) for val in lst)
517
+ if size == 0:
518
+ return BoolHybridArray(0, 0, is_sparse=False if is_sparse is None else is_sparse)
519
+ if is_sparse is None:
520
+ is_sparse = true_count <= (size - true_count)
521
+ split_index = int(min(size * 0.8, math.sqrt(size) * 100))
522
+ split_index = math.isqrt(size) if true_count>size/3*2 or true_count<size/3 else max(split_index, 1)
523
+ split_index = int(split_index) if split_index < 150e+7*2 else int(145e+7*2)
524
+ arr = BoolHybridArray(split_index = split_index, size = size, is_sparse = is_sparse, Type = Type, hash_ = F)
525
+ small_max_idx = min(split_index, size - 1)
526
+ if a:
527
+ small_data = []
528
+ large_indices = []
529
+ for i, val in enumerate(lst):
530
+ val_bool = bool(val)
531
+ if i <= small_max_idx:
532
+ small_data.append(val_bool)
533
+ else:
534
+ if (is_sparse and val_bool) or (not is_sparse and not val_bool):
535
+ large_indices.append(i)
536
+ if small_data:
537
+ arr.small[:len(small_data)] = small_data
538
+ if large_indices:
539
+ arr.large.extend(large_indices)
540
+ else:
541
+ if small_max_idx >= 0:
542
+ arr.small[:small_max_idx + 1] = [bool(val) for val in lst[:small_max_idx + 1]]
543
+ large_indices = [
544
+ i for i in range(split_index + 1, size)
545
+ if (is_sparse and bool(lst[i])) or (not is_sparse and not bool(lst[i]))
546
+ ]
547
+ arr.large.extend(large_indices)
548
+ arr.large = sorted(arr.large)
549
+ type_ = 'I' if size < 1 << 32 else 'Q'
550
+ arr.large = array.array(type_, arr.large)
551
+ if hash_:
552
+ global hybrid_array_cache
553
+ del hybrid_array_cache[-1]
554
+ hybrid_array_cache = [
555
+ (ref, h) for ref, h in hybrid_array_cache
556
+ if ref() is not None
557
+ ]
558
+ for ref, existing_hash in hybrid_array_cache:
559
+ existing_array = ref()
560
+ try:
561
+ if arr.size != existing_array.size:
562
+ continue
563
+ elif arr == existing_array:
564
+ arr._cached_hash = existing_hash
565
+ return arr
566
+ except:
567
+ continue
568
+ return arr
569
+ def TruesArray(size, Type = None, hash_ = True):
570
+ split_index = min(size//10, math.isqrt(size))
571
+ split_index = max(split_index, 1)
572
+ split_index = int(split_index) if split_index < 150e+7*2 else int(145e+7*2)
573
+ return BoolHybridArray(split_index,size,Type = Type,hash_ = hash_)
574
+ def FalsesArray(size, Type = None,hash_ = True):
575
+ split_index = min(size//10, math.isqrt(size))
576
+ split_index = max(split_index, 1)
577
+ split_index = int(split_index) if split_index < 150e+7*2 else int(145e+7*2)
578
+ return BoolHybridArray(split_index,size,True,Type = Type,hash_ = hash_)
579
+ Bool_Array = np.arange(2,dtype = np.uint8)
580
+ class BHA_bool(int,metaclass=ResurrectMeta):
581
+ __module__ = 'bool_hybrid_array'
582
+ def __new__(cls, value):
583
+ core_value = bool(value)
584
+ instance = super().__new__(cls, core_value)
585
+ instance.data = Bool_Array[1] if core_value else Bool_Array[0]
586
+ instance.value = core_value
587
+ return instance
588
+ @lru_cache
589
+ def __str__(self):
590
+ return 'True' if self else 'False'
591
+ @lru_cache
592
+ def __repr__(self):
593
+ return 'T' if self else 'F'
594
+ @lru_cache
595
+ def __bool__(self):
596
+ return self.value
597
+ @lru_cache
598
+ def __int__(self):
599
+ return int(self.data)
600
+ @lru_cache
601
+ def __or__(self,other):
602
+ return BHA_Bool(self.value|other)
603
+ @lru_cache
604
+ def __and__(self,other):
605
+ return BHA_Bool(self.value&other)
606
+ @lru_cache
607
+ def __xor__(self,other):
608
+ return BHA_Bool(self.value^other)
609
+ def __hash__(self):
610
+ return hash(self.data)
611
+ def __len__(self):
612
+ raise TypeError("'BHA_bool' object has no attribute '__len__'")
613
+ __rand__,__ror__,__rxor__ = __and__,__or__,__xor__
614
+ class BHA_Bool(BHA_bool,metaclass=ResurrectMeta):
615
+ __module__ = 'bool_hybrid_array'
616
+ @lru_cache
617
+ def __new__(cls,v):
618
+ if(builtins.T == True)and(builtins.F == False):
619
+ return builtins.T if v else builtins.F
620
+ else:
621
+ builtins.T,builtins.F = BHA_Bool.T,BHA_Bool.F
622
+ return BHA_Bool.T if v else BHA_Bool.F
623
+ class BHA_List(list,metaclass=ResurrectMeta):
624
+ __module__ = 'bool_hybrid_array'
625
+ def __init__(self,arr):
626
+ def Temp(v):
627
+ if isinstance(v,(list,tuple)):
628
+ v = (BoolHybridArr(v) if all(isinstance(i,
629
+ (bool,BHA_bool,np.bool_)) for i in v)
630
+ else BHA_List(v))
631
+ if isinstance(v,BoolHybridArray):
632
+ return v
633
+ elif isinstance(v,(bool,np.bool_)):
634
+ return BHA_Bool(v)
635
+ else:
636
+ return v
637
+ super().__init__(map(Temp,arr))
638
+ try:self.hash_value = sum(map(hash,self))
639
+ except Exception as e:return hash(e)
640
+ def __hash__(self):
641
+ return self.hash_value
642
+ def __call__(self, func):
643
+ func.self = self
644
+ def wrapper(*args, **kwargs):
645
+ return func(self, *args, **kwargs)
646
+ setattr(self, func.__name__, wrapper)
647
+ return func
648
+ def __str__(self):
649
+ def Temp(v):
650
+ if isinstance(v,(BoolHybridArray,np.ndarray,BHA_List,array.array)):
651
+ return str(v)+',\n'
652
+ else:
653
+ return repr(v)+','
654
+ return f"BHA_List([\n{''.join(map(Temp,self))}])"
655
+ def __repr__(self):
656
+ return str(self)
657
+ def __or__(self,other):
658
+ return BHA_List(map(operator.or_, self, other))
659
+ def __and__(self,other):
660
+ return BHA_List(map(operator.and_, self, other))
661
+ def __xor__(self,other):
662
+ return BHA_List(map(operator.xor, self, other))
663
+ def __rxor__(self,other):
664
+ return self^other
665
+ def __ror__(self,other):
666
+ return self|other
667
+ def __rand__(self,other):
668
+ return self&other
669
+ def optimize(self):
670
+ for val in self:
671
+ val.optimize()
672
+ def memory_usage(self,detail=False):
673
+ total = sum(val.memory_usage() for val in self) + 32
674
+ if not detail:
675
+ return total
676
+ else:
677
+ temp = sum(val.size for val in self)
678
+ return {
679
+ "占用(字节)": total,
680
+ "对比原生list节省": f"{(1 - total / (temp * 8 + 40))*100:.6f}%",
681
+ "对比numpy节省": f"{(1 - total / (temp + 96)) * 100:.6f}%"}
682
+ def __iter__(self):
683
+ return BHA_Iterator(super().__iter__())
684
+ class BHA_Iterator(Iterator,metaclass=ResurrectMeta):
685
+ __module__ = 'bool_hybrid_array'
686
+ def __init__(self,data):
687
+ self.data,self.copy_data = itertools.tee(iter(data),2)
688
+ def __next__(self):
689
+ try:return next(self.data)
690
+ except Exception as e:
691
+ self.__init__(self.copy_data)
692
+ raise e
693
+ def __iter__(self):
694
+ return self
695
+ def __or__(self,other):
696
+ return BHA_Iterator(map(operator.or_, self, other))
697
+ def __and__(self,other):
698
+ return BHA_Iterator(map(operator.and_, self, other))
699
+ def __xor__(self,other):
700
+ return BHA_Iterator(map(operator.xor, self, other))
701
+ def __array__(self,dtype = None,copy = None):
702
+ arr = np.fromiter(self, dtype=dtype)
703
+ return arr.copy() if copy else arr.view()
704
+ __rand__,__ror__,__rxor__ = __and__,__or__,__xor__
705
+ class ProtectedBuiltinsDict(dict,metaclass=ResurrectMeta):
706
+ def __init__(self, *args, protected_names = ["T", "F", "BHA_Bool", "BHA_List", "BoolHybridArray", "BoolHybridArr",
707
+ "TruesArray", "FalsesArray", "ProtectedBuiltinsDict", "builtins",
708
+ "__builtins__", "__dict__","ResurrectMeta","math",
709
+ "np","protected_names","BHA_Function",
710
+ "__class__","Ask_BHA","Create_BHA","Ask_arr","numba_opt"],
711
+ name = 'builtins', **kwargs):
712
+ super().__init__(*args, **kwargs)
713
+ if name == 'builtins':
714
+ super().__setattr__('__dict__',self)
715
+ super().__setattr__('builtins',self)
716
+ super().__setattr__('__builtins__',self)
717
+ self.name = name
718
+ self.protected_names = protected_names
719
+ def __setitem__(self, name, value):
720
+ if name in ["T", "F"]:
721
+ current_T = self.get("T")
722
+ current_F = self.get("F")
723
+ if isinstance(current_T, BHA_bool) and isinstance(current_F, BHA_bool):
724
+ is_swap = (name == "T" and isinstance(value, BHA_bool) and value.value == current_F.value)or(name == "F" and isinstance(value, BHA_bool) and value.value == current_T.value)
725
+ if is_swap:
726
+ print(f"""警告:禁止交换内置常量 __{self.name}__["{name}"] 和 __builtins__["{'F' if name == 'T' else 'T'}"]!""")
727
+ raise AttributeError(f"""禁止交换内置常量 __{self.name}__["{name}"] __{self.name}__["{'F' if name == 'T' else 'T'}"]""")
728
+ if name in self.protected_names and name not in ["T", "F"]:
729
+ print(f"警告:禁止修改内置常量 __{self.name}__['{name}']!")
730
+ raise AttributeError(f"禁止修改内置常量 __{self.name}__['{name}']")
731
+ super().__setitem__(name, value)
732
+ def __delitem__(self, name):
733
+ if name in self.protected_names:
734
+ print(f"警告:禁止删除内置常量 __builtins__['{name}']!")
735
+ raise AttributeError(f"禁止删除内置常量 __builtins__['{name}']")
736
+ if name in self:
737
+ super().__delitem__(name)
738
+ def __delattr__(self, name):
739
+ if name in self.protected_names:
740
+ raise AttributeError(f'禁止删除内置常量:{self.name}.{name}')
741
+ else:
742
+ del self[name]
743
+ def __getattr__(self, name):
744
+ if name in self:
745
+ return self[name]
746
+ else:
747
+ raise AttributeError(f"module 'builtins' has no attribute '{name}'")
748
+ def __setattr__(self,name,value):
749
+ try:protected = self.protected_names
750
+ except Exception:protected = self
751
+ if(name in protected)and(not sys.is_finalizing())and(name != '_'):
752
+ raise AttributeError(f'禁止修改内置常量:{self.name}.{name}')
753
+ else:
754
+ super().__setattr__(name,value)
755
+ def __import__(self, name, globals=None, locals=None, fromlist=(), level=0):
756
+ if fromlist:
757
+ result = []
758
+ for key in fromlist:
759
+ if key not in self:
760
+ raise AttributeError(f"'ImportableDict' object has no attribute '{key}'")
761
+ result.append(self[key])
762
+ return result[0] if len(result) == 1 else tuple(result)
763
+ return self
764
+ def Ask_arr(arr):
765
+ if isinstance(arr,BHA_List):
766
+ return '\n'.join(map(Ask_arr,arr))
767
+ elif isinstance(arr,BoolHybridArray):
768
+ h = hex(int(arr))[2:]
769
+ h = '0'*(arr.size - len(bin(int(arr)))+2)+h
770
+ return h
771
+ else:
772
+ return str(arr)
773
+ def Ask_BHA(path):
774
+ if '.bha' not in path.lower():
775
+ path += '.bha'
776
+ with open(path, 'a+b') as f:
777
+ f.seek(0)
778
+ file_size = os.fstat(f.fileno()).st_size
779
+ if not file_size:
780
+ return TruesArray(0)
781
+ if os.name == 'nt':
782
+ mm = mmap.mmap(f.fileno(), file_size, access=mmap.ACCESS_READ)
783
+ else:
784
+ mm = mmap.mmap(f.fileno(), file_size, flags=mmap.MAP_PRIVATE, prot=mmap.PROT_READ)
785
+ with mm:
786
+ temp = mm.read().decode('utf-8').strip()
787
+ temp = temp.split()
788
+ temp2 = lambda x: BoolHybridArr(
789
+ reduce(
790
+ lambda acc, k: acc.append(0 if k < lead_zero else
791
+ (n >> ((total_len - 1) - k)) & 1
792
+ ) or acc,
793
+ range(total_len),
794
+ array.array('B',[])),
795
+ hash_=F
796
+ )if(
797
+ n := int(x, base=16),
798
+ lead_zero := len(x) - len(x.lstrip('0')),
799
+ total_len := lead_zero + (n.bit_length() if n != 0 else 1)
800
+ )else None
801
+ temp = BHA_List(map(temp2,temp))
802
+ if len(temp) == 1:
803
+ return temp[0]
804
+ return temp
805
+ def Create_BHA(path,arr):
806
+ if '.bha' not in path.lower():
807
+ path += '.bha'
808
+ temp = Ask_arr(arr).strip().encode('utf-8')
809
+ with open(path, "w+b") as f:
810
+ f.truncate(len(temp))
811
+ if not len(temp):
812
+ return
813
+ with mmap.mmap(
814
+ f.fileno(),
815
+ length=len(temp),
816
+ access=mmap.ACCESS_WRITE
817
+ ) as mm:
818
+ mm[:] = temp
819
+ mm.flush()
820
+ def numba_opt():
821
+ import numba
822
+ sig = numba.types.Union([
823
+ numba.types.intp(
824
+ numba.types.Array(numba.types.uint32, 1, 'C'),
825
+ numba.types.uint32,
826
+ numba.types.uint32,
827
+ numba.types.Optional(numba.types.uint32)
828
+ ),
829
+ numba.types.intp(
830
+ numba.types.Array(numba.types.uint64, 1, 'C'),
831
+ numba.types.uint64,
832
+ numba.types.uint64,
833
+ numba.types.Optional(numba.types.uint64)
834
+ ),
835
+ numba.types.intp(
836
+ numba.types.Any,
837
+ numba.types.Any,
838
+ numba.types.Any,
839
+ numba.types.Optional(numba.types.Any)
840
+ )
841
+ ])
842
+ bisect.bisect_left = numba.njit(sig, cache=True)(bisect.bisect_left)
843
+ bisect.bisect_right = numba.njit(sig, cache=True)(bisect.bisect_right)
844
+ builtins.np = np
845
+ builtins.T = BHA_bool(1)
846
+ builtins.F = BHA_bool(0)
847
+ builtins.BHA_Bool = BHA_Bool
848
+ builtins.BHA_List = BHA_List
849
+ builtins.FalsesArray = FalsesArray
850
+ builtins.TruesArray = TruesArray
851
+ builtins.BoolHybridArr = BoolHybridArr
852
+ builtins.BHA_Iterator = BHA_Iterator
853
+ builtins.BoolHybridArray = BoolHybridArray
854
+ builtins.BHA_Bool.T,builtins.BHA_Bool.F = BHA_bool(1),BHA_bool(0)
855
+ builtins.ResurrectMeta = ResurrectMeta
856
+ builtins.ProtectedBuiltinsDict = ProtectedBuiltinsDict
857
+ builtins.BHA_Function = BHA_Function
858
+ builtins.Ask_BHA = Ask_BHA
859
+ builtins.Create_BHA = Create_BHA
860
+ builtins.numba_opt = numba_opt
861
+ Tid,Fid = id(T),id(F)
862
+ original_id = builtins.id
863
+ def fake_id(obj):
864
+ if isinstance(obj, BHA_bool):return Tid if obj else Fid
865
+ else:return original_id(obj)
866
+ builtins.id = fake_id
867
+ original_builtins_dict = builtins.__dict__.copy()
868
+ __builtins__ = ProtectedBuiltinsDict(original_builtins_dict)
869
+ builtins = __builtins__
870
+ sys.modules['builtins'] = builtins
871
+ builtins.name = 'builtins'
872
+ try:
873
+ sys.flags.optimize = 2
874
+ except:
857
875
  pass