flexfloat 0.1.2__py3-none-any.whl → 0.1.5__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.
- flexfloat/__init__.py +28 -5
- flexfloat/bitarray/__init__.py +31 -0
- flexfloat/bitarray/bitarray.py +298 -0
- flexfloat/bitarray/bitarray_bigint.py +305 -0
- flexfloat/bitarray/bitarray_bool.py +202 -0
- flexfloat/bitarray/bitarray_int64.py +333 -0
- flexfloat/bitarray/bitarray_mixins.py +156 -0
- flexfloat/core.py +482 -94
- flexfloat/types.py +7 -1
- flexfloat-0.1.5.dist-info/METADATA +340 -0
- flexfloat-0.1.5.dist-info/RECORD +15 -0
- flexfloat/bitarray.py +0 -257
- flexfloat-0.1.2.dist-info/METADATA +0 -147
- flexfloat-0.1.2.dist-info/RECORD +0 -10
- {flexfloat-0.1.2.dist-info → flexfloat-0.1.5.dist-info}/WHEEL +0 -0
- {flexfloat-0.1.2.dist-info → flexfloat-0.1.5.dist-info}/licenses/LICENSE +0 -0
- {flexfloat-0.1.2.dist-info → flexfloat-0.1.5.dist-info}/top_level.txt +0 -0
flexfloat/__init__.py
CHANGED
@@ -1,13 +1,36 @@
|
|
1
1
|
"""FlexFloat - A library for arbitrary precision floating point arithmetic.
|
2
2
|
|
3
|
-
This package provides the FlexFloat class for handling floating-point numbers
|
4
|
-
|
3
|
+
This package provides the FlexFloat class for handling floating-point numbers with
|
4
|
+
growable exponents and fixed-size fractions. It also provides several BitArray
|
5
|
+
implementations for efficient bit manipulation.
|
6
|
+
|
7
|
+
Example:
|
8
|
+
from flexfloat import FlexFloat
|
9
|
+
x = FlexFloat(1.5, exponent_length=8, fraction_length=23)
|
10
|
+
print(x)
|
11
|
+
# Output: FlexFloat(sign=False, exponent=..., fraction=...)
|
12
|
+
|
13
|
+
Modules:
|
14
|
+
core: Main FlexFloat class implementation
|
15
|
+
bitarray: BitArray implementations (bool, int64, bigint)
|
16
|
+
types: Type definitions
|
5
17
|
"""
|
6
18
|
|
7
|
-
from .bitarray import
|
19
|
+
from .bitarray import (
|
20
|
+
BigIntBitArray,
|
21
|
+
BitArray,
|
22
|
+
ListBoolBitArray,
|
23
|
+
ListInt64BitArray,
|
24
|
+
)
|
8
25
|
from .core import FlexFloat
|
9
26
|
|
10
|
-
__version__ = "0.1.
|
27
|
+
__version__ = "0.1.5"
|
11
28
|
__author__ = "Ferran Sanchez Llado"
|
12
29
|
|
13
|
-
__all__ = [
|
30
|
+
__all__ = [
|
31
|
+
"FlexFloat",
|
32
|
+
"BitArray",
|
33
|
+
"ListBoolBitArray",
|
34
|
+
"ListInt64BitArray",
|
35
|
+
"BigIntBitArray",
|
36
|
+
]
|
@@ -0,0 +1,31 @@
|
|
1
|
+
"""BitArray implementation for the flexfloat package.
|
2
|
+
|
3
|
+
This module provides a factory and utilities for working with different BitArray
|
4
|
+
implementations, including:
|
5
|
+
- ListBoolBitArray: List of booleans (default, flexible, easy to use)
|
6
|
+
- ListInt64BitArray: List of int64 chunks (memory efficient for large arrays)
|
7
|
+
- BigIntBitArray: Single Python int (arbitrary size, efficient for very large
|
8
|
+
arrays)
|
9
|
+
|
10
|
+
Example:
|
11
|
+
from flexfloat.bitarray import create_bitarray
|
12
|
+
ba = create_bitarray('int64', [True, False, True])
|
13
|
+
print(type(ba).__name__)
|
14
|
+
# Output: ListInt64BitArray
|
15
|
+
"""
|
16
|
+
|
17
|
+
from __future__ import annotations
|
18
|
+
|
19
|
+
from .bitarray import BitArray
|
20
|
+
from .bitarray_bigint import BigIntBitArray
|
21
|
+
from .bitarray_bool import ListBoolBitArray
|
22
|
+
from .bitarray_int64 import ListInt64BitArray
|
23
|
+
from .bitarray_mixins import BitArrayCommonMixin
|
24
|
+
|
25
|
+
__all__ = [
|
26
|
+
"BitArray",
|
27
|
+
"ListBoolBitArray",
|
28
|
+
"ListInt64BitArray",
|
29
|
+
"BigIntBitArray",
|
30
|
+
"BitArrayCommonMixin",
|
31
|
+
]
|
@@ -0,0 +1,298 @@
|
|
1
|
+
"""BitArray protocol definition for the flexfloat package.
|
2
|
+
|
3
|
+
This module defines the BitArray protocol, which all BitArray implementations must
|
4
|
+
follow. The protocol ensures a consistent interface for bit manipulation.
|
5
|
+
|
6
|
+
Example:
|
7
|
+
from flexfloat.bitarray import BitArray
|
8
|
+
class MyBitArray(BitArray):
|
9
|
+
...
|
10
|
+
my_bitarray = MyBitArray()
|
11
|
+
isinstance(my_bitarray, BitArray) # True
|
12
|
+
"""
|
13
|
+
|
14
|
+
from __future__ import annotations
|
15
|
+
|
16
|
+
from typing import Iterable, Iterator, Protocol, overload, runtime_checkable
|
17
|
+
|
18
|
+
|
19
|
+
@runtime_checkable
|
20
|
+
class BitArray(Protocol):
|
21
|
+
"""Protocol defining the interface for BitArray implementations.
|
22
|
+
|
23
|
+
This protocol defines all the methods and properties that a BitArray
|
24
|
+
implementation must provide.
|
25
|
+
|
26
|
+
For consistency, all BitArray implementations should order bits as LSB-first,
|
27
|
+
meaning the least significant bit is at index 0 and the most significant bit
|
28
|
+
is at the highest index.
|
29
|
+
"""
|
30
|
+
|
31
|
+
@classmethod
|
32
|
+
def from_bits(cls, bits: list[bool] | None = None) -> "BitArray":
|
33
|
+
"""Creates a BitArray from a list of boolean values.
|
34
|
+
|
35
|
+
Args:
|
36
|
+
bits (list[bool] | None, optional): List of boolean values. Defaults to
|
37
|
+
None, which creates an empty BitArray.
|
38
|
+
|
39
|
+
Returns:
|
40
|
+
BitArray: A BitArray created from the bits.
|
41
|
+
"""
|
42
|
+
...
|
43
|
+
|
44
|
+
@classmethod
|
45
|
+
def from_float(cls, value: float) -> "BitArray":
|
46
|
+
"""Converts a floating-point number to a bit array.
|
47
|
+
|
48
|
+
Args:
|
49
|
+
value (float): The floating-point number to convert.
|
50
|
+
|
51
|
+
Returns:
|
52
|
+
BitArray: A BitArray representing the bits of the floating-point number.
|
53
|
+
"""
|
54
|
+
...
|
55
|
+
|
56
|
+
@classmethod
|
57
|
+
def from_signed_int(cls, value: int, length: int) -> "BitArray":
|
58
|
+
"""Converts a signed integer to a bit array using off-set binary representation.
|
59
|
+
|
60
|
+
Args:
|
61
|
+
value (int): The signed integer to convert.
|
62
|
+
length (int): The length of the resulting bit array.
|
63
|
+
|
64
|
+
Returns:
|
65
|
+
BitArray: A BitArray representing the bits of the signed integer.
|
66
|
+
|
67
|
+
Raises:
|
68
|
+
AssertionError: If the value is out of range for the specified length.
|
69
|
+
"""
|
70
|
+
...
|
71
|
+
|
72
|
+
@classmethod
|
73
|
+
def zeros(cls, length: int) -> "BitArray":
|
74
|
+
"""Creates a BitArray filled with zeros.
|
75
|
+
|
76
|
+
Args:
|
77
|
+
length (int): The length of the bit array.
|
78
|
+
|
79
|
+
Returns:
|
80
|
+
BitArray: A BitArray filled with False values.
|
81
|
+
"""
|
82
|
+
...
|
83
|
+
|
84
|
+
@classmethod
|
85
|
+
def ones(cls, length: int) -> "BitArray":
|
86
|
+
"""Creates a BitArray filled with ones.
|
87
|
+
|
88
|
+
Args:
|
89
|
+
length (int): The length of the bit array.
|
90
|
+
|
91
|
+
Returns:
|
92
|
+
BitArray: A BitArray filled with True values.
|
93
|
+
"""
|
94
|
+
...
|
95
|
+
|
96
|
+
@classmethod
|
97
|
+
def parse_bitarray(cls, bitstring: Iterable[str]) -> "BitArray":
|
98
|
+
"""Parses a string of bits (with optional spaces) into a BitArray instance.
|
99
|
+
Non-valid characters are ignored.
|
100
|
+
|
101
|
+
Args:
|
102
|
+
bitstring (Iterable[str]): A string of bits, e.g., "1010 1100".
|
103
|
+
|
104
|
+
Returns:
|
105
|
+
BitArray: A BitArray instance created from the bit string.
|
106
|
+
"""
|
107
|
+
...
|
108
|
+
|
109
|
+
def to_float(self) -> float:
|
110
|
+
"""Converts a 64-bit array to a floating-point number.
|
111
|
+
|
112
|
+
Returns:
|
113
|
+
float: The floating-point number represented by the bit array.
|
114
|
+
|
115
|
+
Raises:
|
116
|
+
AssertionError: If the bit array is not 64 bits long.
|
117
|
+
"""
|
118
|
+
...
|
119
|
+
|
120
|
+
def to_int(self) -> int:
|
121
|
+
"""Converts the bit array to an unsigned integer.
|
122
|
+
|
123
|
+
Returns:
|
124
|
+
int: The integer represented by the bit array.
|
125
|
+
"""
|
126
|
+
...
|
127
|
+
|
128
|
+
def to_signed_int(self) -> int:
|
129
|
+
"""Converts a bit array into a signed integer using off-set binary
|
130
|
+
representation.
|
131
|
+
|
132
|
+
Returns:
|
133
|
+
int: The signed integer represented by the bit array.
|
134
|
+
|
135
|
+
Raises:
|
136
|
+
AssertionError: If the bit array is empty.
|
137
|
+
"""
|
138
|
+
...
|
139
|
+
|
140
|
+
def shift(self, shift_amount: int, fill: bool = False) -> "BitArray":
|
141
|
+
"""Shifts the bit array left or right by a specified number of bits.
|
142
|
+
|
143
|
+
This function shifts the bits in the array, filling in new bits with the
|
144
|
+
specified fill value.
|
145
|
+
If the value is positive, it shifts left; if negative, it shifts right.
|
146
|
+
Fills the new bits with the specified fill value (default is False).
|
147
|
+
|
148
|
+
Args:
|
149
|
+
shift_amount (int): The number of bits to shift. Positive for left shift,
|
150
|
+
negative for right shift.
|
151
|
+
fill (bool, optional): The value to fill in the new bits created by the
|
152
|
+
shift. Defaults to False.
|
153
|
+
|
154
|
+
Returns:
|
155
|
+
BitArray: A new BitArray with the bits shifted and filled.
|
156
|
+
"""
|
157
|
+
...
|
158
|
+
|
159
|
+
def copy(self) -> "BitArray":
|
160
|
+
"""Creates a copy of the bit array.
|
161
|
+
|
162
|
+
Returns:
|
163
|
+
BitArray: A new BitArray with the same bits.
|
164
|
+
"""
|
165
|
+
...
|
166
|
+
|
167
|
+
def __len__(self) -> int:
|
168
|
+
"""Returns the length of the bit array.
|
169
|
+
|
170
|
+
Returns:
|
171
|
+
int: The number of bits in the array.
|
172
|
+
"""
|
173
|
+
...
|
174
|
+
|
175
|
+
@overload
|
176
|
+
def __getitem__(self, index: int) -> bool: ...
|
177
|
+
@overload
|
178
|
+
def __getitem__(self, index: slice) -> "BitArray": ...
|
179
|
+
|
180
|
+
def __getitem__(self, index: int | slice) -> bool | BitArray:
|
181
|
+
"""Get a bit or a slice of bits as a new BitArray."""
|
182
|
+
...
|
183
|
+
|
184
|
+
@overload
|
185
|
+
def __setitem__(self, index: int, value: bool) -> None: ...
|
186
|
+
@overload
|
187
|
+
def __setitem__(self, index: slice, value: "BitArray" | list[bool]) -> None: ...
|
188
|
+
|
189
|
+
def __setitem__(
|
190
|
+
self, index: int | slice, value: bool | list[bool] | "BitArray"
|
191
|
+
) -> None:
|
192
|
+
"""Sets an item or slice in the bit array.
|
193
|
+
|
194
|
+
Args:
|
195
|
+
index (int or slice): The index or slice to set.
|
196
|
+
value (bool or list[bool] or BitArray): The value(s) to assign.
|
197
|
+
"""
|
198
|
+
...
|
199
|
+
|
200
|
+
def __iter__(self) -> Iterator[bool]:
|
201
|
+
"""Iterates over the bits in the array.
|
202
|
+
|
203
|
+
Yields:
|
204
|
+
bool: The next bit in the array.
|
205
|
+
"""
|
206
|
+
...
|
207
|
+
|
208
|
+
def __add__(self, other: "BitArray" | list[bool]) -> "BitArray":
|
209
|
+
"""Concatenates two bit arrays.
|
210
|
+
|
211
|
+
Args:
|
212
|
+
other (BitArray or list[bool]): The other bit array or list to concatenate.
|
213
|
+
|
214
|
+
Returns:
|
215
|
+
BitArray: The concatenated bit array.
|
216
|
+
"""
|
217
|
+
...
|
218
|
+
|
219
|
+
def __radd__(self, other: list[bool]) -> "BitArray":
|
220
|
+
"""Reverse concatenation with a list.
|
221
|
+
|
222
|
+
Args:
|
223
|
+
other (list[bool]): The list to concatenate before this bit array.
|
224
|
+
|
225
|
+
Returns:
|
226
|
+
BitArray: The concatenated bit array.
|
227
|
+
"""
|
228
|
+
...
|
229
|
+
|
230
|
+
def __eq__(self, other: object) -> bool:
|
231
|
+
"""Checks equality with another BitArray or list.
|
232
|
+
|
233
|
+
Args:
|
234
|
+
other (object): The object to compare with.
|
235
|
+
|
236
|
+
Returns:
|
237
|
+
bool: True if equal, False otherwise.
|
238
|
+
"""
|
239
|
+
...
|
240
|
+
|
241
|
+
def __bool__(self) -> bool:
|
242
|
+
"""Returns True if any bit is set.
|
243
|
+
|
244
|
+
Returns:
|
245
|
+
bool: True if any bit is set, False otherwise.
|
246
|
+
"""
|
247
|
+
...
|
248
|
+
|
249
|
+
def __repr__(self) -> str:
|
250
|
+
"""Returns a string representation of the BitArray.
|
251
|
+
|
252
|
+
Returns:
|
253
|
+
str: String representation of the BitArray.
|
254
|
+
"""
|
255
|
+
...
|
256
|
+
|
257
|
+
def __str__(self) -> str:
|
258
|
+
"""Returns a string representation of the bits.
|
259
|
+
|
260
|
+
Returns:
|
261
|
+
str: String representation of the bits.
|
262
|
+
"""
|
263
|
+
...
|
264
|
+
|
265
|
+
def any(self) -> bool:
|
266
|
+
"""Returns True if any bit is set to True.
|
267
|
+
|
268
|
+
Returns:
|
269
|
+
bool: True if any bit is set to True, False otherwise.
|
270
|
+
"""
|
271
|
+
...
|
272
|
+
|
273
|
+
def all(self) -> bool:
|
274
|
+
"""Returns True if all bits are set to True.
|
275
|
+
|
276
|
+
Returns:
|
277
|
+
bool: True if all bits are set to True, False otherwise.
|
278
|
+
"""
|
279
|
+
...
|
280
|
+
|
281
|
+
def count(self, value: bool = True) -> int:
|
282
|
+
"""Counts the number of bits set to the specified value.
|
283
|
+
|
284
|
+
Args:
|
285
|
+
value (bool, optional): The value to count. Defaults to True.
|
286
|
+
|
287
|
+
Returns:
|
288
|
+
int: The number of bits set to the specified value.
|
289
|
+
"""
|
290
|
+
...
|
291
|
+
|
292
|
+
def reverse(self) -> "BitArray":
|
293
|
+
"""Returns a new BitArray with the bits in reverse order.
|
294
|
+
|
295
|
+
Returns:
|
296
|
+
BitArray: A new BitArray with the bits in reverse order.
|
297
|
+
"""
|
298
|
+
...
|
@@ -0,0 +1,305 @@
|
|
1
|
+
"""Infinite-size int-based BitArray implementation for the flexfloat package.
|
2
|
+
|
3
|
+
This implementation is suitable for extremely large bit arrays, leveraging Python's
|
4
|
+
arbitrary-precision integers. Bit order: LSB-first (least significant bit at index 0).
|
5
|
+
|
6
|
+
Example:
|
7
|
+
from flexfloat.bitarray import BigIntBitArray
|
8
|
+
ba = BigIntBitArray(0b1011, length=4)
|
9
|
+
print(list(ba))
|
10
|
+
# Output: [True, True, False, True]
|
11
|
+
"""
|
12
|
+
|
13
|
+
from __future__ import annotations
|
14
|
+
|
15
|
+
import struct
|
16
|
+
from typing import Iterator, overload
|
17
|
+
|
18
|
+
from .bitarray import BitArray
|
19
|
+
from .bitarray_mixins import BitArrayCommonMixin
|
20
|
+
|
21
|
+
|
22
|
+
class BigIntBitArray(BitArrayCommonMixin):
|
23
|
+
"""A memory-efficient bit array class using Python's infinite-size int.
|
24
|
+
|
25
|
+
This implementation stores all bits as a single Python integer, leveraging
|
26
|
+
Python's arbitrary precision arithmetic for potentially unlimited size.
|
27
|
+
Since Python integers are arbitrary precision, this can handle bit arrays
|
28
|
+
of any size limited only by available memory.
|
29
|
+
"""
|
30
|
+
|
31
|
+
def __init__(self, value: int = 0, length: int = 0):
|
32
|
+
"""Initializes a BigIntBitArray.
|
33
|
+
|
34
|
+
Args:
|
35
|
+
value (int, optional): Initial integer value representing the bits. Defaults
|
36
|
+
to 0.
|
37
|
+
length (int, optional): The number of bits in the array. Defaults to 0.
|
38
|
+
|
39
|
+
Raises:
|
40
|
+
ValueError: If length is negative.
|
41
|
+
"""
|
42
|
+
super().__init__()
|
43
|
+
if length < 0:
|
44
|
+
raise ValueError("Length must be non-negative")
|
45
|
+
self._length: int = length
|
46
|
+
self._value: int = value
|
47
|
+
|
48
|
+
@classmethod
|
49
|
+
def from_bits(cls, bits: list[bool] | None = None) -> "BigIntBitArray":
|
50
|
+
"""Creates a BitArray from a list of boolean values.
|
51
|
+
|
52
|
+
Args:
|
53
|
+
bits (list[bool] | None, optional): List of boolean values. Defaults to
|
54
|
+
None, which creates an empty BitArray.
|
55
|
+
|
56
|
+
Returns:
|
57
|
+
BigIntBitArray: A BitArray created from the bits.
|
58
|
+
"""
|
59
|
+
if bits is None:
|
60
|
+
return cls()
|
61
|
+
value = 0
|
62
|
+
|
63
|
+
# Pack bits into a single integer (LSB-first)
|
64
|
+
# Least significant bit is at index 0
|
65
|
+
for i, bit in enumerate(bits):
|
66
|
+
if bit:
|
67
|
+
value |= 1 << i
|
68
|
+
|
69
|
+
return cls(value, len(bits))
|
70
|
+
|
71
|
+
@classmethod
|
72
|
+
def zeros(cls, length: int) -> "BigIntBitArray":
|
73
|
+
"""Creates a BitArray filled with zeros.
|
74
|
+
|
75
|
+
Args:
|
76
|
+
length (int): The length of the bit array.
|
77
|
+
|
78
|
+
Returns:
|
79
|
+
BigIntBitArray: A BitArray filled with False values.
|
80
|
+
"""
|
81
|
+
return cls(0, length)
|
82
|
+
|
83
|
+
@classmethod
|
84
|
+
def ones(cls, length: int) -> "BigIntBitArray":
|
85
|
+
"""Creates a BitArray filled with ones.
|
86
|
+
|
87
|
+
Args:
|
88
|
+
length (int): The length of the bit array.
|
89
|
+
|
90
|
+
Returns:
|
91
|
+
BigIntBitArray: A BitArray filled with True values.
|
92
|
+
"""
|
93
|
+
return cls((1 << length) - 1 if length > 0 else 0, length)
|
94
|
+
|
95
|
+
def _get_bit(self, index: int) -> bool:
|
96
|
+
"""Gets a single bit at the specified index (LSB-first).
|
97
|
+
|
98
|
+
Args:
|
99
|
+
index (int): The bit index (LSB-first).
|
100
|
+
|
101
|
+
Returns:
|
102
|
+
bool: The value of the bit at the specified index.
|
103
|
+
|
104
|
+
Raises:
|
105
|
+
IndexError: If index is out of range.
|
106
|
+
"""
|
107
|
+
if index < 0 or index >= self._length:
|
108
|
+
raise IndexError("Bit index out of range")
|
109
|
+
bit_position = index # LSB-first
|
110
|
+
return bool(self._value & (1 << bit_position))
|
111
|
+
|
112
|
+
def _set_bit(self, index: int, value: bool) -> None:
|
113
|
+
"""Sets a single bit at the specified index (LSB-first).
|
114
|
+
|
115
|
+
Args:
|
116
|
+
index (int): The bit index (LSB-first).
|
117
|
+
value (bool): The value to set.
|
118
|
+
|
119
|
+
Raises:
|
120
|
+
IndexError: If index is out of range.
|
121
|
+
"""
|
122
|
+
if index < 0 or index >= self._length:
|
123
|
+
raise IndexError("Bit index out of range")
|
124
|
+
bit_position = index # LSB-first
|
125
|
+
|
126
|
+
if value:
|
127
|
+
self._value |= 1 << bit_position
|
128
|
+
else:
|
129
|
+
self._value &= ~(1 << bit_position)
|
130
|
+
|
131
|
+
def to_float(self) -> float:
|
132
|
+
"""Converts a 64-bit array to a floating-point number (LSB-first).
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
float: The floating-point number represented by the bit array.
|
136
|
+
|
137
|
+
Raises:
|
138
|
+
AssertionError: If the bit array is not 64 bits long.
|
139
|
+
"""
|
140
|
+
assert self._length == 64, "Bit array must be 64 bits long."
|
141
|
+
|
142
|
+
# Convert integer to bytes (big-endian)
|
143
|
+
byte_values = bytearray()
|
144
|
+
value = self._value
|
145
|
+
for i in range(8):
|
146
|
+
byte = (value >> (i * 8)) & 0xFF # LSB-first
|
147
|
+
byte_values.append(byte)
|
148
|
+
|
149
|
+
# Unpack as double precision (64 bits)
|
150
|
+
float_value = struct.unpack("<d", bytes(byte_values))[0]
|
151
|
+
return float_value # type: ignore
|
152
|
+
|
153
|
+
def to_int(self) -> int:
|
154
|
+
"""Converts the bit array to an unsigned integer (LSB-first).
|
155
|
+
|
156
|
+
Returns:
|
157
|
+
int: The integer represented by the bit array.
|
158
|
+
"""
|
159
|
+
return self._value
|
160
|
+
|
161
|
+
def copy(self) -> "BigIntBitArray":
|
162
|
+
"""Creates a copy of the bit array.
|
163
|
+
|
164
|
+
Returns:
|
165
|
+
BigIntBitArray: A new BitArray with the same bits.
|
166
|
+
"""
|
167
|
+
return BigIntBitArray(self._value, self._length)
|
168
|
+
|
169
|
+
def __len__(self) -> int:
|
170
|
+
"""Returns the length of the bit array.
|
171
|
+
|
172
|
+
Returns:
|
173
|
+
int: The number of bits in the array.
|
174
|
+
"""
|
175
|
+
return self._length
|
176
|
+
|
177
|
+
@overload
|
178
|
+
def __getitem__(self, index: int) -> bool: ...
|
179
|
+
@overload
|
180
|
+
def __getitem__(self, index: slice) -> BigIntBitArray: ...
|
181
|
+
|
182
|
+
def __getitem__(self, index: int | slice) -> bool | BigIntBitArray:
|
183
|
+
"""Gets an item or slice from the bit array.
|
184
|
+
|
185
|
+
Args:
|
186
|
+
index (int or slice): The index or slice to retrieve.
|
187
|
+
|
188
|
+
Returns:
|
189
|
+
bool or BigIntBitArray: The bit value or a new BitArray for the slice.
|
190
|
+
"""
|
191
|
+
if isinstance(index, int):
|
192
|
+
return self._get_bit(index)
|
193
|
+
start, stop, step = index.indices(self._length)
|
194
|
+
if step != 1:
|
195
|
+
# Handle step != 1 by extracting individual bits
|
196
|
+
bits: list[bool] = [self._get_bit(i) for i in range(start, stop, step)]
|
197
|
+
else:
|
198
|
+
# Efficient slice extraction for step == 1
|
199
|
+
bits = []
|
200
|
+
for i in range(start, stop):
|
201
|
+
bits.append(self._get_bit(i))
|
202
|
+
return BigIntBitArray.from_bits(bits)
|
203
|
+
|
204
|
+
@overload
|
205
|
+
def __setitem__(self, index: int, value: bool) -> None: ...
|
206
|
+
@overload
|
207
|
+
def __setitem__(self, index: slice, value: BitArray | list[bool]) -> None: ...
|
208
|
+
|
209
|
+
def __setitem__(
|
210
|
+
self, index: int | slice, value: bool | list[bool] | BitArray
|
211
|
+
) -> None:
|
212
|
+
"""Sets an item or slice in the bit array.
|
213
|
+
|
214
|
+
Args:
|
215
|
+
index (int or slice): The index or slice to set.
|
216
|
+
value (bool or list[bool] or BitArray): The value(s) to assign.
|
217
|
+
|
218
|
+
Raises:
|
219
|
+
TypeError: If value type does not match index type.
|
220
|
+
ValueError: If value length does not match slice length.
|
221
|
+
"""
|
222
|
+
if isinstance(index, int):
|
223
|
+
if not isinstance(value, bool):
|
224
|
+
raise TypeError("Value must be bool for single index")
|
225
|
+
self._set_bit(index, value)
|
226
|
+
else: # slice
|
227
|
+
start, stop, step = index.indices(self._length)
|
228
|
+
|
229
|
+
# Convert value to list of bools
|
230
|
+
if isinstance(value, bool):
|
231
|
+
raise TypeError("Cannot assign bool to slice")
|
232
|
+
if not hasattr(value, "__iter__"):
|
233
|
+
raise TypeError("Value must be iterable for slice assignment")
|
234
|
+
value_list = list(value)
|
235
|
+
|
236
|
+
if step != 1:
|
237
|
+
# Handle step != 1
|
238
|
+
indices = list(range(start, stop, step))
|
239
|
+
if len(value_list) != len(indices):
|
240
|
+
raise ValueError("Value length doesn't match slice length")
|
241
|
+
for i, v in zip(indices, value_list):
|
242
|
+
self._set_bit(i, bool(v))
|
243
|
+
else:
|
244
|
+
# Handle step == 1
|
245
|
+
if len(value_list) != (stop - start):
|
246
|
+
raise ValueError("Value length doesn't match slice length")
|
247
|
+
for i, v in enumerate(value_list):
|
248
|
+
self._set_bit(start + i, bool(v))
|
249
|
+
|
250
|
+
def __iter__(self) -> Iterator[bool]:
|
251
|
+
"""Iterates over the bits in the array.
|
252
|
+
|
253
|
+
Yields:
|
254
|
+
bool: The next bit in the array.
|
255
|
+
"""
|
256
|
+
for i in range(self._length):
|
257
|
+
yield self._get_bit(i)
|
258
|
+
|
259
|
+
def __add__(self, other: BitArray | list[bool]) -> "BigIntBitArray":
|
260
|
+
"""Concatenates two bit arrays.
|
261
|
+
|
262
|
+
Args:
|
263
|
+
other (BitArray or list[bool]): The other bit array or list to concatenate.
|
264
|
+
|
265
|
+
Returns:
|
266
|
+
BigIntBitArray: The concatenated bit array.
|
267
|
+
|
268
|
+
Raises:
|
269
|
+
TypeError: If other is not iterable.
|
270
|
+
"""
|
271
|
+
if hasattr(other, "__iter__"):
|
272
|
+
other_bits = list(other)
|
273
|
+
else:
|
274
|
+
raise TypeError("Can only concatenate with iterable")
|
275
|
+
|
276
|
+
all_bits = list(self) + other_bits
|
277
|
+
return BigIntBitArray.from_bits(all_bits)
|
278
|
+
|
279
|
+
def __radd__(self, other: list[bool]) -> "BigIntBitArray":
|
280
|
+
"""Reverse concatenation with a list.
|
281
|
+
|
282
|
+
Args:
|
283
|
+
other (list[bool]): The list to concatenate before this bit array.
|
284
|
+
|
285
|
+
Returns:
|
286
|
+
BigIntBitArray: The concatenated bit array.
|
287
|
+
|
288
|
+
Raises:
|
289
|
+
TypeError: If other is not iterable.
|
290
|
+
"""
|
291
|
+
if hasattr(other, "__iter__"):
|
292
|
+
other_bits = list(other)
|
293
|
+
else:
|
294
|
+
raise TypeError("Can only concatenate with iterable")
|
295
|
+
|
296
|
+
all_bits = other_bits + list(self)
|
297
|
+
return BigIntBitArray.from_bits(all_bits)
|
298
|
+
|
299
|
+
def __repr__(self) -> str:
|
300
|
+
"""Returns a string representation of the BitArray.
|
301
|
+
|
302
|
+
Returns:
|
303
|
+
str: String representation of the BitArray.
|
304
|
+
"""
|
305
|
+
return f"BigIntBitArray({list(self)})"
|