Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/bitstring/bits.py: 22%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1034 statements  

1from __future__ import annotations 

2 

3import numbers 

4import pathlib 

5import sys 

6import mmap 

7import struct 

8import array 

9import io 

10from collections import abc 

11import functools 

12from typing import Tuple, Union, List, Iterable, Any, Optional, BinaryIO, TextIO, overload, Iterator, Type, TypeVar 

13import bitarray 

14import bitarray.util 

15import bitstring 

16from bitstring.bitstore import BitStore 

17from bitstring import bitstore_helpers, utils 

18from bitstring.dtypes import Dtype, dtype_register 

19from bitstring.fp8 import p4binary_fmt, p3binary_fmt 

20from bitstring.mxfp import e3m2mxfp_fmt, e2m3mxfp_fmt, e2m1mxfp_fmt, e4m3mxfp_saturate_fmt, e5m2mxfp_saturate_fmt 

21from bitstring.bitstring_options import Colour 

22 

23# Things that can be converted to Bits when a Bits type is needed 

24BitsType = Union['Bits', str, Iterable[Any], bool, BinaryIO, bytearray, bytes, memoryview, bitarray.bitarray] 

25 

26TBits = TypeVar("TBits", bound='Bits') 

27 

28# Maximum number of digits to use in __str__ and __repr__. 

29MAX_CHARS: int = 250 

30 

31 

32class Bits: 

33 """A container holding an immutable sequence of bits. 

34 

35 For a mutable container use the BitArray class instead. 

36 

37 Methods: 

38 

39 all() -- Check if all specified bits are set to 1 or 0. 

40 any() -- Check if any of specified bits are set to 1 or 0. 

41 copy() - Return a copy of the bitstring. 

42 count() -- Count the number of bits set to 1 or 0. 

43 cut() -- Create generator of constant sized chunks. 

44 endswith() -- Return whether the bitstring ends with a sub-string. 

45 find() -- Find a sub-bitstring in the current bitstring. 

46 findall() -- Find all occurrences of a sub-bitstring in the current bitstring. 

47 fromstring() -- Create a bitstring from a formatted string. 

48 join() -- Join bitstrings together using current bitstring. 

49 pp() -- Pretty print the bitstring. 

50 rfind() -- Seek backwards to find a sub-bitstring. 

51 split() -- Create generator of chunks split by a delimiter. 

52 startswith() -- Return whether the bitstring starts with a sub-bitstring. 

53 tobitarray() -- Return bitstring as a bitarray from the bitarray package. 

54 tobytes() -- Return bitstring as bytes, padding if needed. 

55 tofile() -- Write bitstring to file, padding if needed. 

56 unpack() -- Interpret bits using format string. 

57 

58 Special methods: 

59 

60 Also available are the operators [], ==, !=, +, *, ~, <<, >>, &, |, ^. 

61 

62 Properties: 

63 

64 [GENERATED_PROPERTY_DESCRIPTIONS] 

65 

66 len -- Length of the bitstring in bits. 

67 

68 """ 

69 __slots__ = ('_bitstore', '_filename') 

70 

71 def __init__(self, auto: Optional[Union[BitsType, int]] = None, /, length: Optional[int] = None, 

72 offset: Optional[int] = None, **kwargs) -> None: 

73 """Either specify an 'auto' initialiser: 

74 A string of comma separated tokens, an integer, a file object, 

75 a bytearray, a boolean iterable, an array or another bitstring. 

76 

77 Or initialise via **kwargs with one (and only one) of: 

78 bin -- binary string representation, e.g. '0b001010'. 

79 hex -- hexadecimal string representation, e.g. '0x2ef' 

80 oct -- octal string representation, e.g. '0o777'. 

81 bytes -- raw data as a bytes object, for example read from a binary file. 

82 int -- a signed integer. 

83 uint -- an unsigned integer. 

84 float / floatbe -- a big-endian floating point number. 

85 bool -- a boolean (True or False). 

86 se -- a signed exponential-Golomb code. 

87 ue -- an unsigned exponential-Golomb code. 

88 sie -- a signed interleaved exponential-Golomb code. 

89 uie -- an unsigned interleaved exponential-Golomb code. 

90 floatle -- a little-endian floating point number. 

91 floatne -- a native-endian floating point number. 

92 bfloat / bfloatbe - a big-endian bfloat format 16-bit floating point number. 

93 bfloatle -- a little-endian bfloat format 16-bit floating point number. 

94 bfloatne -- a native-endian bfloat format 16-bit floating point number. 

95 intbe -- a signed big-endian whole byte integer. 

96 intle -- a signed little-endian whole byte integer. 

97 intne -- a signed native-endian whole byte integer. 

98 uintbe -- an unsigned big-endian whole byte integer. 

99 uintle -- an unsigned little-endian whole byte integer. 

100 uintne -- an unsigned native-endian whole byte integer. 

101 filename -- the path of a file which will be opened in binary read-only mode. 

102 

103 Other keyword arguments: 

104 length -- length of the bitstring in bits, if needed and appropriate. 

105 It must be supplied for all integer and float initialisers. 

106 offset -- bit offset to the data. These offset bits are 

107 ignored and this is mainly intended for use when 

108 initialising using 'bytes' or 'filename'. 

109 

110 """ 

111 self._bitstore.immutable = True 

112 

113 def __new__(cls: Type[TBits], auto: Optional[Union[BitsType, int]] = None, /, length: Optional[int] = None, 

114 offset: Optional[int] = None, pos: Optional[int] = None, **kwargs) -> TBits: 

115 x = super().__new__(cls) 

116 if auto is None and not kwargs: 

117 # No initialiser so fill with zero bits up to length 

118 if length is not None: 

119 x._bitstore = BitStore(length) 

120 x._bitstore.setall(0) 

121 else: 

122 x._bitstore = BitStore() 

123 return x 

124 x._initialise(auto, length, offset, **kwargs) 

125 return x 

126 

127 @classmethod 

128 def _create_from_bitstype(cls: Type[TBits], auto: BitsType, /) -> TBits: 

129 if isinstance(auto, Bits): 

130 return auto 

131 b = super().__new__(cls) 

132 b._setauto_no_length_or_offset(auto) 

133 return b 

134 

135 def _initialise(self, auto: Any, /, length: Optional[int], offset: Optional[int], **kwargs) -> None: 

136 if auto is not None: 

137 if isinstance(auto, numbers.Integral): 

138 # Initialise with s zero bits. 

139 if auto < 0: 

140 raise bitstring.CreationError(f"Can't create bitstring of negative length {auto}.") 

141 self._bitstore = BitStore(int(auto)) 

142 self._bitstore.setall(0) 

143 return 

144 self._setauto(auto, length, offset) 

145 return 

146 k, v = kwargs.popitem() 

147 if k == 'bytes': 

148 # Special case for bytes as we want to allow offsets and lengths to work only on creation. 

149 self._setbytes_with_truncation(v, length, offset) 

150 return 

151 if k == 'filename': 

152 self._setfile(v, length, offset) 

153 return 

154 if k == 'bitarray': 

155 self._setbitarray(v, length, offset) 

156 return 

157 if k == 'auto': 

158 raise bitstring.CreationError( 

159 f"The 'auto' parameter should not be given explicitly - just use the first positional argument. " 

160 f"Instead of '{self.__class__.__name__}(auto=x)' use '{self.__class__.__name__}(x)'.") 

161 if offset is not None: 

162 raise bitstring.CreationError("offset cannot be used when initialising with '{k}'.") 

163 try: 

164 Dtype(k, length).set_fn(self, v) 

165 except ValueError as e: 

166 raise bitstring.CreationError(e) 

167 

168 def __getattr__(self, attribute: str) -> Any: 

169 # Support for arbitrary attributes like u16 or f64. 

170 try: 

171 d = Dtype(attribute) 

172 except ValueError: 

173 raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{attribute}'.") 

174 if d.bitlength is not None and len(self) != d.bitlength: 

175 raise ValueError(f"bitstring length {len(self)} doesn't match length {d.bitlength} of property '{attribute}'.") 

176 return d.read_fn(self, 0) 

177 

178 def __iter__(self) -> Iterable[bool]: 

179 return iter(self._bitstore) 

180 

181 def __copy__(self: TBits) -> TBits: 

182 """Return a new copy of the Bits for the copy module.""" 

183 # Note that if you want a new copy (different ID), use _copy instead. 

184 # The copy can return self as it's immutable. 

185 return self 

186 

187 def __lt__(self, other: Any) -> bool: 

188 # bitstrings can't really be ordered. 

189 return NotImplemented 

190 

191 def __gt__(self, other: Any) -> bool: 

192 return NotImplemented 

193 

194 def __le__(self, other: Any) -> bool: 

195 return NotImplemented 

196 

197 def __ge__(self, other: Any) -> bool: 

198 return NotImplemented 

199 

200 def __add__(self: TBits, bs: BitsType) -> TBits: 

201 """Concatenate bitstrings and return new bitstring. 

202 

203 bs -- the bitstring to append. 

204 

205 """ 

206 bs = self.__class__._create_from_bitstype(bs) 

207 s = self._copy() if len(bs) <= len(self) else bs._copy() 

208 if len(bs) <= len(self): 

209 s._addright(bs) 

210 else: 

211 s._addleft(self) 

212 return s 

213 

214 def __radd__(self: TBits, bs: BitsType) -> TBits: 

215 """Append current bitstring to bs and return new bitstring. 

216 

217 bs -- An object that can be 'auto' initialised as a bitstring that will be appended to. 

218 

219 """ 

220 bs = self.__class__._create_from_bitstype(bs) 

221 return bs.__add__(self) 

222 

223 @overload 

224 def __getitem__(self: TBits, key: slice, /) -> TBits: 

225 ... 

226 

227 @overload 

228 def __getitem__(self, key: int, /) -> bool: 

229 ... 

230 

231 def __getitem__(self: TBits, key: Union[slice, int], /) -> Union[TBits, bool]: 

232 """Return a new bitstring representing a slice of the current bitstring. 

233 

234 Indices are in units of the step parameter (default 1 bit). 

235 Stepping is used to specify the number of bits in each item. 

236 

237 >>> print(BitArray('0b00110')[1:4]) 

238 '0b011' 

239 >>> print(BitArray('0x00112233')[1:3:8]) 

240 '0x1122' 

241 

242 """ 

243 if isinstance(key, numbers.Integral): 

244 return bool(self._bitstore.getindex(key)) 

245 bs = super().__new__(self.__class__) 

246 bs._bitstore = self._bitstore.getslice_withstep(key) 

247 return bs 

248 

249 def __len__(self) -> int: 

250 """Return the length of the bitstring in bits.""" 

251 return self._getlength() 

252 

253 def __bytes__(self) -> bytes: 

254 return self.tobytes() 

255 

256 def __str__(self) -> str: 

257 """Return approximate string representation of bitstring for printing. 

258 

259 Short strings will be given wholly in hexadecimal or binary. Longer 

260 strings may be part hexadecimal and part binary. Very long strings will 

261 be truncated with '...'. 

262 

263 """ 

264 length = len(self) 

265 if not length: 

266 return '' 

267 if length > MAX_CHARS * 4: 

268 # Too long for hex. Truncate... 

269 return ''.join(('0x', self[0:MAX_CHARS*4]._gethex(), '...')) 

270 # If it's quite short and we can't do hex then use bin 

271 if length < 32 and length % 4 != 0: 

272 return '0b' + self.bin 

273 # If we can use hex then do so 

274 if not length % 4: 

275 return '0x' + self.hex 

276 # Otherwise first we do as much as we can in hex 

277 # then add on 1, 2 or 3 bits on at the end 

278 bits_at_end = length % 4 

279 return ''.join(('0x', self[0:length - bits_at_end]._gethex(), 

280 ', ', '0b', self[length - bits_at_end:]._getbin())) 

281 

282 def _repr(self, classname: str, length: int, pos: int): 

283 pos_string = f', pos={pos}' if pos else '' 

284 if hasattr(self, '_filename') and self._filename: 

285 return f"{classname}(filename={self._filename!r}, length={length}{pos_string})" 

286 else: 

287 s = self.__str__() 

288 lengthstring = '' 

289 if s.endswith('...'): 

290 lengthstring = f' # length={length}' 

291 return f"{classname}('{s}'{pos_string}){lengthstring}" 

292 

293 def __repr__(self) -> str: 

294 """Return representation that could be used to recreate the bitstring. 

295 

296 If the returned string is too long it will be truncated. See __str__(). 

297 

298 """ 

299 return self._repr(self.__class__.__name__, len(self), 0) 

300 

301 def __eq__(self, bs: Any, /) -> bool: 

302 """Return True if two bitstrings have the same binary representation. 

303 

304 >>> BitArray('0b1110') == '0xe' 

305 True 

306 

307 """ 

308 try: 

309 return self._bitstore == Bits._create_from_bitstype(bs)._bitstore 

310 except TypeError: 

311 return False 

312 

313 def __ne__(self, bs: Any, /) -> bool: 

314 """Return False if two bitstrings have the same binary representation. 

315 

316 >>> BitArray('0b111') == '0x7' 

317 False 

318 

319 """ 

320 return not self.__eq__(bs) 

321 

322 def __invert__(self: TBits) -> TBits: 

323 """Return bitstring with every bit inverted. 

324 

325 Raises Error if the bitstring is empty. 

326 

327 """ 

328 if len(self) == 0: 

329 raise bitstring.Error("Cannot invert empty bitstring.") 

330 s = self._copy() 

331 s._invert_all() 

332 return s 

333 

334 def __lshift__(self: TBits, n: int, /) -> TBits: 

335 """Return bitstring with bits shifted by n to the left. 

336 

337 n -- the number of bits to shift. Must be >= 0. 

338 

339 """ 

340 if n < 0: 

341 raise ValueError("Cannot shift by a negative amount.") 

342 if len(self) == 0: 

343 raise ValueError("Cannot shift an empty bitstring.") 

344 n = min(n, len(self)) 

345 s = self._absolute_slice(n, len(self)) 

346 s._addright(Bits(n)) 

347 return s 

348 

349 def __rshift__(self: TBits, n: int, /) -> TBits: 

350 """Return bitstring with bits shifted by n to the right. 

351 

352 n -- the number of bits to shift. Must be >= 0. 

353 

354 """ 

355 if n < 0: 

356 raise ValueError("Cannot shift by a negative amount.") 

357 if len(self) == 0: 

358 raise ValueError("Cannot shift an empty bitstring.") 

359 if not n: 

360 return self._copy() 

361 s = self.__class__(length=min(n, len(self))) 

362 n = min(n, len(self)) 

363 s._addright(self._absolute_slice(0, len(self) - n)) 

364 return s 

365 

366 def __mul__(self: TBits, n: int, /) -> TBits: 

367 """Return bitstring consisting of n concatenations of self. 

368 

369 Called for expression of the form 'a = b*3'. 

370 n -- The number of concatenations. Must be >= 0. 

371 

372 """ 

373 if n < 0: 

374 raise ValueError("Cannot multiply by a negative integer.") 

375 if not n: 

376 return self.__class__() 

377 s = self._copy() 

378 s._imul(n) 

379 return s 

380 

381 def __rmul__(self: TBits, n: int, /) -> TBits: 

382 """Return bitstring consisting of n concatenations of self. 

383 

384 Called for expressions of the form 'a = 3*b'. 

385 n -- The number of concatenations. Must be >= 0. 

386 

387 """ 

388 return self.__mul__(n) 

389 

390 def __and__(self: TBits, bs: BitsType, /) -> TBits: 

391 """Bit-wise 'and' between two bitstrings. Returns new bitstring. 

392 

393 bs -- The bitstring to '&' with. 

394 

395 Raises ValueError if the two bitstrings have differing lengths. 

396 

397 """ 

398 if bs is self: 

399 return self.copy() 

400 bs = Bits._create_from_bitstype(bs) 

401 s = object.__new__(self.__class__) 

402 s._bitstore = self._bitstore & bs._bitstore 

403 return s 

404 

405 def __rand__(self: TBits, bs: BitsType, /) -> TBits: 

406 """Bit-wise 'and' between two bitstrings. Returns new bitstring. 

407 

408 bs -- the bitstring to '&' with. 

409 

410 Raises ValueError if the two bitstrings have differing lengths. 

411 

412 """ 

413 return self.__and__(bs) 

414 

415 def __or__(self: TBits, bs: BitsType, /) -> TBits: 

416 """Bit-wise 'or' between two bitstrings. Returns new bitstring. 

417 

418 bs -- The bitstring to '|' with. 

419 

420 Raises ValueError if the two bitstrings have differing lengths. 

421 

422 """ 

423 if bs is self: 

424 return self.copy() 

425 bs = Bits._create_from_bitstype(bs) 

426 s = object.__new__(self.__class__) 

427 s._bitstore = self._bitstore | bs._bitstore 

428 return s 

429 

430 def __ror__(self: TBits, bs: BitsType, /) -> TBits: 

431 """Bit-wise 'or' between two bitstrings. Returns new bitstring. 

432 

433 bs -- The bitstring to '|' with. 

434 

435 Raises ValueError if the two bitstrings have differing lengths. 

436 

437 """ 

438 return self.__or__(bs) 

439 

440 def __xor__(self: TBits, bs: BitsType, /) -> TBits: 

441 """Bit-wise 'xor' between two bitstrings. Returns new bitstring. 

442 

443 bs -- The bitstring to '^' with. 

444 

445 Raises ValueError if the two bitstrings have differing lengths. 

446 

447 """ 

448 bs = Bits._create_from_bitstype(bs) 

449 s = object.__new__(self.__class__) 

450 s._bitstore = self._bitstore ^ bs._bitstore 

451 return s 

452 

453 def __rxor__(self: TBits, bs: BitsType, /) -> TBits: 

454 """Bit-wise 'xor' between two bitstrings. Returns new bitstring. 

455 

456 bs -- The bitstring to '^' with. 

457 

458 Raises ValueError if the two bitstrings have differing lengths. 

459 

460 """ 

461 return self.__xor__(bs) 

462 

463 def __contains__(self, bs: BitsType, /) -> bool: 

464 """Return whether bs is contained in the current bitstring. 

465 

466 bs -- The bitstring to search for. 

467 

468 """ 

469 found = Bits.find(self, bs, bytealigned=False) 

470 return bool(found) 

471 

472 def __hash__(self) -> int: 

473 """Return an integer hash of the object.""" 

474 # Only requirement is that equal bitstring should return the same hash. 

475 # For equal bitstrings the bytes at the start/end will be the same and they will have the same length 

476 # (need to check the length as there could be zero padding when getting the bytes). We do not check any 

477 # bit position inside the bitstring as that does not feature in the __eq__ operation. 

478 if len(self) <= 2000: 

479 # Use the whole bitstring. 

480 return hash((self.tobytes(), len(self))) 

481 else: 

482 # We can't in general hash the whole bitstring (it could take hours!) 

483 # So instead take some bits from the start and end. 

484 return hash(((self[:800] + self[-800:]).tobytes(), len(self))) 

485 

486 def __bool__(self) -> bool: 

487 """Return False if bitstring is empty, otherwise return True.""" 

488 return len(self) != 0 

489 

490 def _clear(self) -> None: 

491 """Reset the bitstring to an empty state.""" 

492 self._bitstore = BitStore() 

493 

494 def _setauto_no_length_or_offset(self, s: BitsType, /) -> None: 

495 """Set bitstring from a bitstring, file, bool, array, iterable or string.""" 

496 if isinstance(s, str): 

497 self._bitstore = bitstore_helpers.str_to_bitstore(s) 

498 elif isinstance(s, Bits): 

499 self._bitstore = s._bitstore.copy() 

500 elif isinstance(s, (bytes, bytearray, memoryview)): 

501 self._bitstore = BitStore.frombytes(bytearray(s)) 

502 elif isinstance(s, io.BytesIO): 

503 self._bitstore = BitStore.frombytes(s.getvalue()) 

504 elif isinstance(s, io.BufferedReader): 

505 self._setfile(s.name) 

506 elif isinstance(s, bitarray.bitarray): 

507 self._bitstore = BitStore(s) 

508 elif isinstance(s, array.array): 

509 self._bitstore = BitStore.frombytes(s.tobytes()) 

510 elif isinstance(s, abc.Iterable): 

511 # Evaluate each item as True or False and set bits to 1 or 0. 

512 self._setbin_unsafe(''.join(str(int(bool(x))) for x in s)) 

513 elif isinstance(s, numbers.Integral): 

514 raise TypeError(f"It's no longer possible to auto initialise a bitstring from an integer." 

515 f" Use '{self.__class__.__name__}({s})' instead of just '{s}' as this makes it " 

516 f"clearer that a bitstring of {int(s)} zero bits will be created.") 

517 else: 

518 raise TypeError(f"Cannot initialise bitstring from type '{type(s)}'.") 

519 

520 def _setauto(self, s: BitsType, length: Optional[int], offset: Optional[int], /) -> None: 

521 """Set bitstring from a bitstring, file, bool, array, iterable or string.""" 

522 # As s can be so many different things it's important to do the checks 

523 # in the correct order, as some types are also other allowed types. 

524 if offset is None and length is None: 

525 return self._setauto_no_length_or_offset(s) 

526 if offset is None: 

527 offset = 0 

528 

529 if isinstance(s, io.BytesIO): 

530 if length is None: 

531 length = s.seek(0, 2) * 8 - offset 

532 byteoffset, offset = divmod(offset, 8) 

533 bytelength = (length + byteoffset * 8 + offset + 7) // 8 - byteoffset 

534 if length + byteoffset * 8 + offset > s.seek(0, 2) * 8: 

535 raise bitstring.CreationError("BytesIO object is not long enough for specified length and offset.") 

536 self._bitstore = BitStore.frombytes(s.getvalue()[byteoffset: byteoffset + bytelength]).getslice( 

537 offset, offset + length) 

538 return 

539 

540 if isinstance(s, io.BufferedReader): 

541 self._setfile(s.name, length, offset) 

542 return 

543 

544 if isinstance(s, (str, Bits, bytes, bytearray, memoryview, io.BytesIO, io.BufferedReader, 

545 bitarray.bitarray, array.array, abc.Iterable)): 

546 raise bitstring.CreationError(f"Cannot initialise bitstring from type '{type(s)}' when using explicit lengths or offsets.") 

547 raise TypeError(f"Cannot initialise bitstring from type '{type(s)}'.") 

548 

549 def _setfile(self, filename: str, length: Optional[int] = None, offset: Optional[int] = None) -> None: 

550 """Use file as source of bits.""" 

551 with open(pathlib.Path(filename), 'rb') as source: 

552 if offset is None: 

553 offset = 0 

554 m = mmap.mmap(source.fileno(), 0, access=mmap.ACCESS_READ) 

555 if offset == 0: 

556 self._filename = source.name 

557 self._bitstore = BitStore.frombuffer(m, length=length) 

558 else: 

559 # If offset is given then always read into memory. 

560 temp = BitStore.frombuffer(m) 

561 if length is None: 

562 if offset > len(temp): 

563 raise bitstring.CreationError(f"The offset of {offset} bits is greater than the file length ({len(temp)} bits).") 

564 self._bitstore = temp.getslice(offset, None) 

565 else: 

566 self._bitstore = temp.getslice(offset, offset + length) 

567 if len(self) != length: 

568 raise bitstring.CreationError(f"Can't use a length of {length} bits and an offset of {offset} bits as file length is only {len(temp)} bits.") 

569 

570 def _setbitarray(self, ba: bitarray.bitarray, length: Optional[int], offset: Optional[int]) -> None: 

571 if offset is None: 

572 offset = 0 

573 if offset > len(ba): 

574 raise bitstring.CreationError(f"Offset of {offset} too large for bitarray of length {len(ba)}.") 

575 if length is None: 

576 self._bitstore = BitStore(ba[offset:]) 

577 else: 

578 if offset + length > len(ba): 

579 raise bitstring.CreationError( 

580 f"Offset of {offset} and length of {length} too large for bitarray of length {len(ba)}.") 

581 self._bitstore = BitStore(ba[offset: offset + length]) 

582 

583 def _setbits(self, bs: BitsType, length: None = None) -> None: 

584 bs = Bits._create_from_bitstype(bs) 

585 self._bitstore = bs._bitstore 

586 

587 def _setp3binary(self, f: float) -> None: 

588 self._bitstore = bitstore_helpers.p3binary2bitstore(f) 

589 

590 def _setp4binary(self, f: float) -> None: 

591 self._bitstore = bitstore_helpers.p4binary2bitstore(f) 

592 

593 def _sete4m3mxfp(self, f: float) -> None: 

594 self._bitstore = bitstore_helpers.e4m3mxfp2bitstore(f) 

595 

596 def _sete5m2mxfp(self, f: float) -> None: 

597 self._bitstore = bitstore_helpers.e5m2mxfp2bitstore(f) 

598 

599 def _sete3m2mxfp(self, f: float) -> None: 

600 self._bitstore = bitstore_helpers.e3m2mxfp2bitstore(f) 

601 

602 def _sete2m3mxfp(self, f: float) -> None: 

603 self._bitstore = bitstore_helpers.e2m3mxfp2bitstore(f) 

604 

605 def _sete2m1mxfp(self, f: float) -> None: 

606 self._bitstore = bitstore_helpers.e2m1mxfp2bitstore(f) 

607 

608 def _sete8m0mxfp(self, f: float) -> None: 

609 self._bitstore = bitstore_helpers.e8m0mxfp2bitstore(f) 

610 

611 def _setmxint(self, f: float) -> None: 

612 self._bitstore = bitstore_helpers.mxint2bitstore(f) 

613 

614 def _setbytes(self, data: Union[bytearray, bytes, List], length:None = None) -> None: 

615 """Set the data from a bytes or bytearray object.""" 

616 self._bitstore = BitStore.frombytes(bytes(data)) 

617 

618 def _setbytes_with_truncation(self, data: Union[bytearray, bytes], length: Optional[int] = None, offset: Optional[int] = None) -> None: 

619 """Set the data from a bytes or bytearray object, with optional offset and length truncations.""" 

620 if offset is None and length is None: 

621 return self._setbytes(data) 

622 data = bytearray(data) 

623 if offset is None: 

624 offset = 0 

625 if length is None: 

626 # Use to the end of the data 

627 length = len(data) * 8 - offset 

628 else: 

629 if length + offset > len(data) * 8: 

630 raise bitstring.CreationError(f"Not enough data present. Need {length + offset} bits, have {len(data) * 8}.") 

631 self._bitstore = BitStore.frombytes(data).getslice_msb0(offset, offset + length) 

632 

633 def _getbytes(self) -> bytes: 

634 """Return the data as an ordinary bytes object.""" 

635 if len(self) % 8: 

636 raise bitstring.InterpretError("Cannot interpret as bytes unambiguously - not multiple of 8 bits.") 

637 return self._bitstore.tobytes() 

638 

639 _unprintable = list(range(0x00, 0x20)) # ASCII control characters 

640 _unprintable.extend(range(0x7f, 0xff)) # DEL char + non-ASCII 

641 

642 def _getbytes_printable(self) -> str: 

643 """Return an approximation of the data as a string of printable characters.""" 

644 bytes_ = self._getbytes() 

645 # For everything that isn't printable ASCII, use value from 'Latin Extended-A' unicode block. 

646 string = ''.join(chr(0x100 + x) if x in Bits._unprintable else chr(x) for x in bytes_) 

647 return string 

648 

649 def _setuint(self, uint: int, length: Optional[int] = None) -> None: 

650 """Reset the bitstring to have given unsigned int interpretation.""" 

651 # If no length given, and we've previously been given a length, use it. 

652 if length is None and hasattr(self, 'len') and len(self) != 0: 

653 length = len(self) 

654 if length is None or length == 0: 

655 raise bitstring.CreationError("A non-zero length must be specified with a uint initialiser.") 

656 self._bitstore = bitstore_helpers.int2bitstore(uint, length, False) 

657 

658 def _getuint(self) -> int: 

659 """Return data as an unsigned int.""" 

660 if len(self) == 0: 

661 raise bitstring.InterpretError("Cannot interpret a zero length bitstring as an integer.") 

662 return self._bitstore.slice_to_uint() 

663 

664 def _setint(self, int_: int, length: Optional[int] = None) -> None: 

665 """Reset the bitstring to have given signed int interpretation.""" 

666 # If no length given, and we've previously been given a length, use it. 

667 if length is None and hasattr(self, 'len') and len(self) != 0: 

668 length = len(self) 

669 if length is None or length == 0: 

670 raise bitstring.CreationError("A non-zero length must be specified with an int initialiser.") 

671 self._bitstore = bitstore_helpers.int2bitstore(int_, length, True) 

672 

673 def _getint(self) -> int: 

674 """Return data as a two's complement signed int.""" 

675 if len(self) == 0: 

676 raise bitstring.InterpretError("Cannot interpret bitstring without a length as an integer.") 

677 return self._bitstore.slice_to_int() 

678 

679 def _setuintbe(self, uintbe: int, length: Optional[int] = None) -> None: 

680 """Set the bitstring to a big-endian unsigned int interpretation.""" 

681 if length is None and hasattr(self, 'len') and len(self) != 0: 

682 length = len(self) 

683 if length is None or length == 0: 

684 raise bitstring.CreationError("A non-zero length must be specified with a uintbe initialiser.") 

685 self._bitstore = bitstore_helpers.int2bitstore(uintbe, length, False) 

686 

687 def _getuintbe(self) -> int: 

688 """Return data as a big-endian two's complement unsigned int.""" 

689 if len(self) % 8: 

690 raise bitstring.InterpretError(f"Big-endian integers must be whole-byte. Length = {len(self)} bits.") 

691 return self._getuint() 

692 

693 def _setintbe(self, intbe: int, length: Optional[int] = None) -> None: 

694 """Set bitstring to a big-endian signed int interpretation.""" 

695 if length is None and hasattr(self, 'len') and len(self) != 0: 

696 length = len(self) 

697 if length is None or length == 0: 

698 raise bitstring.CreationError("A non-zero length must be specified with a intbe initialiser.") 

699 self._bitstore = bitstore_helpers.int2bitstore(intbe, length, True) 

700 

701 def _getintbe(self) -> int: 

702 """Return data as a big-endian two's complement signed int.""" 

703 if len(self) % 8: 

704 raise bitstring.InterpretError(f"Big-endian integers must be whole-byte. Length = {len(self)} bits.") 

705 return self._getint() 

706 

707 def _setuintle(self, uintle: int, length: Optional[int] = None) -> None: 

708 if length is None and hasattr(self, 'len') and len(self) != 0: 

709 length = len(self) 

710 if length is None or length == 0: 

711 raise bitstring.CreationError("A non-zero length must be specified with a uintle initialiser.") 

712 self._bitstore = bitstore_helpers.intle2bitstore(uintle, length, False) 

713 

714 def _getuintle(self) -> int: 

715 """Interpret as a little-endian unsigned int.""" 

716 if len(self) % 8: 

717 raise bitstring.InterpretError(f"Little-endian integers must be whole-byte. Length = {len(self)} bits.") 

718 bs = BitStore.frombytes(self._bitstore.tobytes()[::-1]) 

719 return bs.slice_to_uint() 

720 

721 def _setintle(self, intle: int, length: Optional[int] = None) -> None: 

722 if length is None and hasattr(self, 'len') and len(self) != 0: 

723 length = len(self) 

724 if length is None or length == 0: 

725 raise bitstring.CreationError("A non-zero length must be specified with an intle initialiser.") 

726 self._bitstore = bitstore_helpers.intle2bitstore(intle, length, True) 

727 

728 def _getintle(self) -> int: 

729 """Interpret as a little-endian signed int.""" 

730 if len(self) % 8: 

731 raise bitstring.InterpretError(f"Little-endian integers must be whole-byte. Length = {len(self)} bits.") 

732 bs = BitStore.frombytes(self._bitstore.tobytes()[::-1]) 

733 return bs.slice_to_int() 

734 

735 def _getp4binary(self) -> float: 

736 u = self._getuint() 

737 return p4binary_fmt.lut_binary8_to_float[u] 

738 

739 def _getp3binary(self) -> float: 

740 u = self._getuint() 

741 return p3binary_fmt.lut_binary8_to_float[u] 

742 

743 def _gete4m3mxfp(self) -> float: 

744 u = self._getuint() 

745 return e4m3mxfp_saturate_fmt.lut_int_to_float[u] 

746 

747 def _gete5m2mxfp(self) -> float: 

748 u = self._getuint() 

749 return e5m2mxfp_saturate_fmt.lut_int_to_float[u] 

750 

751 def _gete3m2mxfp(self) -> float: 

752 u = self._getuint() 

753 return e3m2mxfp_fmt.lut_int_to_float[u] 

754 

755 def _gete2m3mxfp(self) -> float: 

756 u = self._getuint() 

757 return e2m3mxfp_fmt.lut_int_to_float[u] 

758 

759 def _gete2m1mxfp(self) -> float: 

760 u = self._getuint() 

761 return e2m1mxfp_fmt.lut_int_to_float[u] 

762 

763 def _gete8m0mxfp(self) -> float: 

764 u = self._getuint() - 127 

765 if u == 128: 

766 return float('nan') 

767 return 2.0 ** u 

768 

769 def _getmxint(self) -> float: 

770 u = self._getint() 

771 return float(u) * 2 ** -6 

772 

773 

774 def _setfloat(self, f: float, length: Optional[int], big_endian: bool) -> None: 

775 if length is None and hasattr(self, 'len') and len(self) != 0: 

776 length = len(self) 

777 if length is None or length not in [16, 32, 64]: 

778 raise bitstring.CreationError("A length of 16, 32, or 64 must be specified with a float initialiser.") 

779 self._bitstore = bitstore_helpers.float2bitstore(f, length, big_endian) 

780 

781 def _setfloatbe(self, f: float, length: Optional[int] = None) -> None: 

782 self._setfloat(f, length, True) 

783 

784 def _getfloatbe(self) -> float: 

785 """Interpret the whole bitstring as a big-endian float.""" 

786 fmt = {16: '>e', 32: '>f', 64: '>d'}[len(self)] 

787 return struct.unpack(fmt, self._bitstore.tobytes())[0] 

788 

789 def _setfloatle(self, f: float, length: Optional[int] = None) -> None: 

790 self._setfloat(f, length, False) 

791 

792 def _getfloatle(self) -> float: 

793 """Interpret the whole bitstring as a little-endian float.""" 

794 fmt = {16: '<e', 32: '<f', 64: '<d'}[len(self)] 

795 return struct.unpack(fmt, self._bitstore.tobytes())[0] 

796 

797 def _getbfloatbe(self) -> float: 

798 zero_padded = self + Bits(16) 

799 return zero_padded._getfloatbe() 

800 

801 def _setbfloatbe(self, f: Union[float, str], length: Optional[int] = None) -> None: 

802 if length is not None and length != 16: 

803 raise bitstring.CreationError(f"bfloats must be length 16, received a length of {length} bits.") 

804 self._bitstore = bitstore_helpers.bfloat2bitstore(f, True) 

805 

806 def _getbfloatle(self) -> float: 

807 zero_padded = Bits(16) + self 

808 return zero_padded._getfloatle() 

809 

810 def _setbfloatle(self, f: Union[float, str], length: Optional[int] = None) -> None: 

811 if length is not None and length != 16: 

812 raise bitstring.CreationError(f"bfloats must be length 16, received a length of {length} bits.") 

813 self._bitstore = bitstore_helpers.bfloat2bitstore(f, False) 

814 

815 def _setue(self, i: int) -> None: 

816 """Initialise bitstring with unsigned exponential-Golomb code for integer i. 

817 

818 Raises CreationError if i < 0. 

819 

820 """ 

821 if bitstring.options.lsb0: 

822 raise bitstring.CreationError("Exp-Golomb codes cannot be used in lsb0 mode.") 

823 self._bitstore = bitstore_helpers.ue2bitstore(i) 

824 

825 def _readue(self, pos: int) -> Tuple[int, int]: 

826 """Return interpretation of next bits as unsigned exponential-Golomb code. 

827 

828 Raises ReadError if the end of the bitstring is encountered while 

829 reading the code. 

830 

831 """ 

832 if bitstring.options.lsb0: 

833 raise bitstring.ReadError("Exp-Golomb codes cannot be read in lsb0 mode.") 

834 oldpos = pos 

835 try: 

836 while not self[pos]: 

837 pos += 1 

838 except IndexError: 

839 raise bitstring.ReadError("Read off end of bitstring trying to read code.") 

840 leadingzeros = pos - oldpos 

841 codenum = (1 << leadingzeros) - 1 

842 if leadingzeros > 0: 

843 if pos + leadingzeros + 1 > len(self): 

844 raise bitstring.ReadError("Read off end of bitstring trying to read code.") 

845 codenum += self[pos + 1:pos + 1 + leadingzeros]._getuint() 

846 pos += leadingzeros + 1 

847 else: 

848 assert codenum == 0 

849 pos += 1 

850 return codenum, pos 

851 

852 def _getue(self) -> Tuple[int, int]: 

853 try: 

854 return self._readue(0) 

855 except bitstring.ReadError: 

856 raise bitstring.InterpretError 

857 

858 def _getse(self) -> Tuple[int, int]: 

859 try: 

860 return self._readse(0) 

861 except bitstring.ReadError: 

862 raise bitstring.InterpretError 

863 

864 def _getuie(self) -> Tuple[int, int]: 

865 try: 

866 return self._readuie(0) 

867 except bitstring.ReadError: 

868 raise bitstring.InterpretError 

869 

870 def _getsie(self) -> Tuple[int, int]: 

871 try: 

872 return self._readsie(0) 

873 except bitstring.ReadError: 

874 raise bitstring.InterpretError 

875 

876 def _setse(self, i: int) -> None: 

877 """Initialise bitstring with signed exponential-Golomb code for integer i.""" 

878 if bitstring.options.lsb0: 

879 raise bitstring.CreationError("Exp-Golomb codes cannot be used in lsb0 mode.") 

880 self._bitstore = bitstore_helpers.se2bitstore(i) 

881 

882 def _readse(self, pos: int) -> Tuple[int, int]: 

883 """Return interpretation of next bits as a signed exponential-Golomb code. 

884 

885 Advances position to after the read code. 

886 

887 Raises ReadError if the end of the bitstring is encountered while 

888 reading the code. 

889 

890 """ 

891 codenum, pos = self._readue(pos) 

892 m = (codenum + 1) // 2 

893 return (m, pos) if codenum % 2 else (-m, pos) 

894 

895 def _setuie(self, i: int) -> None: 

896 """Initialise bitstring with unsigned interleaved exponential-Golomb code for integer i. 

897 

898 Raises CreationError if i < 0. 

899 

900 """ 

901 if bitstring.options.lsb0: 

902 raise bitstring.CreationError("Exp-Golomb codes cannot be used in lsb0 mode.") 

903 self._bitstore = bitstore_helpers.uie2bitstore(i) 

904 

905 def _readuie(self, pos: int) -> Tuple[int, int]: 

906 """Return interpretation of next bits as unsigned interleaved exponential-Golomb code. 

907 

908 Raises ReadError if the end of the bitstring is encountered while 

909 reading the code. 

910 

911 """ 

912 if bitstring.options.lsb0: 

913 raise bitstring.ReadError("Exp-Golomb codes cannot be read in lsb0 mode.") 

914 try: 

915 codenum: int = 1 

916 while not self[pos]: 

917 pos += 1 

918 codenum <<= 1 

919 codenum += self[pos] 

920 pos += 1 

921 pos += 1 

922 except IndexError: 

923 raise bitstring.ReadError("Read off end of bitstring trying to read code.") 

924 return codenum - 1, pos 

925 

926 def _setsie(self, i: int, ) -> None: 

927 """Initialise bitstring with signed interleaved exponential-Golomb code for integer i.""" 

928 if bitstring.options.lsb0: 

929 raise bitstring.CreationError("Exp-Golomb codes cannot be used in lsb0 mode.") 

930 self._bitstore = bitstore_helpers.sie2bitstore(i) 

931 

932 def _readsie(self, pos: int) -> Tuple[int, int]: 

933 """Return interpretation of next bits as a signed interleaved exponential-Golomb code. 

934 

935 Advances position to after the read code. 

936 

937 Raises ReadError if the end of the bitstring is encountered while 

938 reading the code. 

939 

940 """ 

941 codenum, pos = self._readuie(pos) 

942 if not codenum: 

943 return 0, pos 

944 try: 

945 return (-codenum, pos + 1) if self[pos] else (codenum, pos + 1) 

946 except IndexError: 

947 raise bitstring.ReadError("Read off end of bitstring trying to read code.") 

948 

949 def _setbool(self, value: Union[bool, str]) -> None: 

950 # We deliberately don't want to have implicit conversions to bool here. 

951 # If we did then it would be difficult to deal with the 'False' string. 

952 if value in (1, 'True', '1'): 

953 self._bitstore = BitStore('1') 

954 elif value in (0, 'False', '0'): 

955 self._bitstore = BitStore('0') 

956 else: 

957 raise bitstring.CreationError(f"Cannot initialise boolean with {value}.") 

958 

959 def _getbool(self) -> bool: 

960 return self[0] 

961 

962 def _getpad(self) -> None: 

963 return None 

964 

965 def _setpad(self, value: None, length: int) -> None: 

966 self._bitstore = BitStore(length) 

967 

968 def _setbin_safe(self, binstring: str, length: None = None) -> None: 

969 """Reset the bitstring to the value given in binstring.""" 

970 self._bitstore = bitstore_helpers.bin2bitstore(binstring) 

971 

972 def _setbin_unsafe(self, binstring: str, length: None = None) -> None: 

973 """Same as _setbin_safe, but input isn't sanity checked. binstring mustn't start with '0b'.""" 

974 self._bitstore = bitstore_helpers.bin2bitstore_unsafe(binstring) 

975 

976 def _getbin(self) -> str: 

977 """Return interpretation as a binary string.""" 

978 return self._bitstore.slice_to_bin() 

979 

980 def _setoct(self, octstring: str, length: None = None) -> None: 

981 """Reset the bitstring to have the value given in octstring.""" 

982 self._bitstore = bitstore_helpers.oct2bitstore(octstring) 

983 

984 def _getoct(self) -> str: 

985 """Return interpretation as an octal string.""" 

986 return self._bitstore.slice_to_oct() 

987 

988 def _sethex(self, hexstring: str, length: None = None) -> None: 

989 """Reset the bitstring to have the value given in hexstring.""" 

990 self._bitstore = bitstore_helpers.hex2bitstore(hexstring) 

991 

992 def _gethex(self) -> str: 

993 """Return the hexadecimal representation as a string. 

994 

995 Raises an InterpretError if the bitstring's length is not a multiple of 4. 

996 

997 """ 

998 return self._bitstore.slice_to_hex() 

999 

1000 def _getlength(self) -> int: 

1001 """Return the length of the bitstring in bits.""" 

1002 return len(self._bitstore) 

1003 

1004 def _copy(self: TBits) -> TBits: 

1005 """Create and return a new copy of the Bits (always in memory).""" 

1006 # Note that __copy__ may choose to return self if it's immutable. This method always makes a copy. 

1007 s_copy = self.__class__() 

1008 s_copy._bitstore = self._bitstore._copy() 

1009 return s_copy 

1010 

1011 def _slice(self: TBits, start: int, end: int) -> TBits: 

1012 """Used internally to get a slice, without error checking.""" 

1013 bs = self.__class__() 

1014 bs._bitstore = self._bitstore.getslice(start, end) 

1015 return bs 

1016 

1017 def _absolute_slice(self: TBits, start: int, end: int) -> TBits: 

1018 """Used internally to get a slice, without error checking. 

1019 Uses MSB0 bit numbering even if LSB0 is set.""" 

1020 if end == start: 

1021 return self.__class__() 

1022 assert start < end, f"start={start}, end={end}" 

1023 bs = self.__class__() 

1024 bs._bitstore = self._bitstore.getslice_msb0(start, end) 

1025 return bs 

1026 

1027 def _readtoken(self, name: str, pos: int, length: Optional[int]) -> Tuple[Union[float, int, str, None, Bits], int]: 

1028 """Reads a token from the bitstring and returns the result.""" 

1029 dtype = dtype_register.get_dtype(name, length) 

1030 if dtype.bitlength is not None and dtype.bitlength > len(self) - pos: 

1031 raise bitstring.ReadError("Reading off the end of the data. " 

1032 f"Tried to read {dtype.bitlength} bits when only {len(self) - pos} available.") 

1033 try: 

1034 val = dtype.read_fn(self, pos) 

1035 if isinstance(val, tuple): 

1036 return val 

1037 else: 

1038 assert length is not None 

1039 return val, pos + dtype.bitlength 

1040 except KeyError: 

1041 raise ValueError(f"Can't parse token {name}:{length}") 

1042 

1043 def _addright(self, bs: Bits, /) -> None: 

1044 """Add a bitstring to the RHS of the current bitstring.""" 

1045 self._bitstore += bs._bitstore 

1046 

1047 def _addleft(self, bs: Bits, /) -> None: 

1048 """Prepend a bitstring to the current bitstring.""" 

1049 if bs._bitstore.immutable: 

1050 self._bitstore = bs._bitstore._copy() + self._bitstore 

1051 else: 

1052 self._bitstore = bs._bitstore + self._bitstore 

1053 

1054 def _truncateleft(self: TBits, bits: int, /) -> TBits: 

1055 """Truncate bits from the start of the bitstring. Return the truncated bits.""" 

1056 assert 0 <= bits <= len(self) 

1057 if bits == 0: 

1058 return self.__class__() 

1059 truncated_bits = self._absolute_slice(0, bits) 

1060 if bits == len(self): 

1061 self._clear() 

1062 return truncated_bits 

1063 self._bitstore = self._bitstore.getslice_msb0(bits, None) 

1064 return truncated_bits 

1065 

1066 def _truncateright(self: TBits, bits: int, /) -> TBits: 

1067 """Truncate bits from the end of the bitstring. Return the truncated bits.""" 

1068 assert 0 <= bits <= len(self) 

1069 if bits == 0: 

1070 return self.__class__() 

1071 truncated_bits = self._absolute_slice(len(self) - bits, len(self)) 

1072 if bits == len(self): 

1073 self._clear() 

1074 return truncated_bits 

1075 self._bitstore = self._bitstore.getslice_msb0(None, -bits) 

1076 return truncated_bits 

1077 

1078 def _insert(self, bs: Bits, pos: int, /) -> None: 

1079 """Insert bs at pos.""" 

1080 assert 0 <= pos <= len(self) 

1081 self._bitstore[pos: pos] = bs._bitstore 

1082 return 

1083 

1084 def _overwrite(self, bs: Bits, pos: int, /) -> None: 

1085 """Overwrite with bs at pos.""" 

1086 assert 0 <= pos <= len(self) 

1087 if bs is self: 

1088 # Just overwriting with self, so do nothing. 

1089 assert pos == 0 

1090 return 

1091 self._bitstore[pos: pos + len(bs)] = bs._bitstore 

1092 

1093 def _delete(self, bits: int, pos: int, /) -> None: 

1094 """Delete bits at pos.""" 

1095 assert 0 <= pos <= len(self) 

1096 assert pos + bits <= len(self), f"pos={pos}, bits={bits}, len={len(self)}" 

1097 del self._bitstore[pos: pos + bits] 

1098 return 

1099 

1100 def _reversebytes(self, start: int, end: int) -> None: 

1101 """Reverse bytes in-place.""" 

1102 assert (end - start) % 8 == 0 

1103 self._bitstore[start:end] = BitStore.frombytes(self._bitstore.getslice(start, end).tobytes()[::-1]) 

1104 

1105 def _invert(self, pos: int, /) -> None: 

1106 """Flip bit at pos 1<->0.""" 

1107 assert 0 <= pos < len(self) 

1108 self._bitstore.invert(pos) 

1109 

1110 def _invert_all(self) -> None: 

1111 """Invert every bit.""" 

1112 self._bitstore.invert() 

1113 

1114 def _ilshift(self: TBits, n: int, /) -> TBits: 

1115 """Shift bits by n to the left in place. Return self.""" 

1116 assert 0 < n <= len(self) 

1117 self._addright(Bits(n)) 

1118 self._truncateleft(n) 

1119 return self 

1120 

1121 def _irshift(self: TBits, n: int, /) -> TBits: 

1122 """Shift bits by n to the right in place. Return self.""" 

1123 assert 0 < n <= len(self) 

1124 self._addleft(Bits(n)) 

1125 self._truncateright(n) 

1126 return self 

1127 

1128 def _imul(self: TBits, n: int, /) -> TBits: 

1129 """Concatenate n copies of self in place. Return self.""" 

1130 assert n >= 0 

1131 if n == 0: 

1132 self._clear() 

1133 else: 

1134 m = 1 

1135 old_len = len(self) 

1136 while m * 2 < n: 

1137 self._addright(self) 

1138 m *= 2 

1139 self._addright(self[0:(n - m) * old_len]) 

1140 return self 

1141 

1142 def _getbits(self: TBits): 

1143 return self._copy() 

1144 

1145 def _validate_slice(self, start: Optional[int], end: Optional[int]) -> Tuple[int, int]: 

1146 """Validate start and end and return them as positive bit positions.""" 

1147 start = 0 if start is None else (start + len(self) if start < 0 else start) 

1148 end = len(self) if end is None else (end + len(self) if end < 0 else end) 

1149 if not 0 <= start <= end <= len(self): 

1150 raise ValueError(f"Invalid slice positions for bitstring length {len(self)}: start={start}, end={end}.") 

1151 return start, end 

1152 

1153 def unpack(self, fmt: Union[str, List[Union[str, int]]], **kwargs) -> List[Union[int, float, str, Bits, bool, bytes, None]]: 

1154 """Interpret the whole bitstring using fmt and return list. 

1155 

1156 fmt -- A single string or a list of strings with comma separated tokens 

1157 describing how to interpret the bits in the bitstring. Items 

1158 can also be integers, for reading new bitstring of the given length. 

1159 kwargs -- A dictionary or keyword-value pairs - the keywords used in the 

1160 format string will be replaced with their given value. 

1161 

1162 Raises ValueError if the format is not understood. If not enough bits 

1163 are available then all bits to the end of the bitstring will be used. 

1164 

1165 See the docstring for 'read' for token examples. 

1166 

1167 """ 

1168 return self._readlist(fmt, 0, **kwargs)[0] 

1169 

1170 def _readlist(self, fmt: Union[str, List[Union[str, int, Dtype]]], pos: int, **kwargs) \ 

1171 -> Tuple[List[Union[int, float, str, Bits, bool, bytes, None]], int]: 

1172 if isinstance(fmt, str): 

1173 fmt = [fmt] 

1174 # Convert to a flat list of Dtypes 

1175 dtype_list = [] 

1176 for f_item in fmt: 

1177 if isinstance(f_item, numbers.Integral): 

1178 dtype_list.append(Dtype('bits', f_item)) 

1179 elif isinstance(f_item, Dtype): 

1180 dtype_list.append(f_item) 

1181 else: 

1182 token_list = utils.preprocess_tokens(f_item) 

1183 for t in token_list: 

1184 try: 

1185 name, length = utils.parse_name_length_token(t, **kwargs) 

1186 except ValueError: 

1187 dtype_list.append(Dtype('bits', int(t))) 

1188 else: 

1189 dtype_list.append(Dtype(name, length)) 

1190 return self._read_dtype_list(dtype_list, pos) 

1191 

1192 def _read_dtype_list(self, dtypes: List[Dtype], pos: int) -> Tuple[List[Union[int, float, str, Bits, bool, bytes, None]], int]: 

1193 has_stretchy_token = False 

1194 bits_after_stretchy_token = 0 

1195 for dtype in dtypes: 

1196 stretchy = dtype.bitlength is None and not dtype.variable_length 

1197 if stretchy: 

1198 if has_stretchy_token: 

1199 raise bitstring.Error("It's not possible to have more than one 'filler' token.") 

1200 has_stretchy_token = True 

1201 elif has_stretchy_token: 

1202 if dtype.variable_length: 

1203 raise bitstring.Error(f"It's not possible to parse a variable length token '{dtype}' after a 'filler' token.") 

1204 bits_after_stretchy_token += dtype.bitlength 

1205 

1206 # We should have precisely zero or one stretchy token 

1207 vals = [] 

1208 for dtype in dtypes: 

1209 stretchy = dtype.bitlength is None and not dtype.variable_length 

1210 if stretchy: 

1211 bits_remaining = len(self) - pos 

1212 # Set length to the remaining bits 

1213 bitlength = max(bits_remaining - bits_after_stretchy_token, 0) 

1214 items, remainder = divmod(bitlength, dtype.bits_per_item) 

1215 if remainder != 0: 

1216 raise ValueError( 

1217 f"The '{dtype.name}' type must have a bit length that is a multiple of {dtype.bits_per_item}" 

1218 f" so cannot be created from the {bitlength} bits that are available for this stretchy token.") 

1219 dtype = Dtype(dtype.name, items) 

1220 if dtype.bitlength is not None: 

1221 val = dtype.read_fn(self, pos) 

1222 pos += dtype.bitlength 

1223 else: 

1224 val, pos = dtype.read_fn(self, pos) 

1225 if val is not None: # Don't append pad tokens 

1226 vals.append(val) 

1227 return vals, pos 

1228 

1229 def find(self, bs: BitsType, /, start: Optional[int] = None, end: Optional[int] = None, 

1230 bytealigned: Optional[bool] = None) -> Union[Tuple[int], Tuple[()]]: 

1231 """Find first occurrence of substring bs. 

1232 

1233 Returns a single item tuple with the bit position if found, or an 

1234 empty tuple if not found. The bit position (pos property) will 

1235 also be set to the start of the substring if it is found. 

1236 

1237 bs -- The bitstring to find. 

1238 start -- The bit position to start the search. Defaults to 0. 

1239 end -- The bit position one past the last bit to search. 

1240 Defaults to len(self). 

1241 bytealigned -- If True the bitstring will only be 

1242 found on byte boundaries. 

1243 

1244 Raises ValueError if bs is empty, if start < 0, if end > len(self) or 

1245 if end < start. 

1246 

1247 >>> BitArray('0xc3e').find('0b1111') 

1248 (6,) 

1249 

1250 """ 

1251 bs = Bits._create_from_bitstype(bs) 

1252 if len(bs) == 0: 

1253 raise ValueError("Cannot find an empty bitstring.") 

1254 start, end = self._validate_slice(start, end) 

1255 ba = bitstring.options.bytealigned if bytealigned is None else bytealigned 

1256 p = self._find(bs, start, end, ba) 

1257 return p 

1258 

1259 def _find_lsb0(self, bs: Bits, start: int, end: int, bytealigned: bool) -> Union[Tuple[int], Tuple[()]]: 

1260 # A forward find in lsb0 is very like a reverse find in msb0. 

1261 assert start <= end 

1262 assert bitstring.options.lsb0 

1263 

1264 new_slice = bitstring.bitstore.offset_slice_indices_lsb0(slice(start, end, None), len(self)) 

1265 msb0_start, msb0_end = self._validate_slice(new_slice.start, new_slice.stop) 

1266 p = self._rfind_msb0(bs, msb0_start, msb0_end, bytealigned) 

1267 

1268 if p: 

1269 return (len(self) - p[0] - len(bs),) 

1270 else: 

1271 return () 

1272 

1273 def _find_msb0(self, bs: Bits, start: int, end: int, bytealigned: bool) -> Union[Tuple[int], Tuple[()]]: 

1274 """Find first occurrence of a binary string.""" 

1275 p = self._bitstore.find(bs._bitstore, start, end, bytealigned) 

1276 return () if p == -1 else (p,) 

1277 

1278 def findall(self, bs: BitsType, start: Optional[int] = None, end: Optional[int] = None, count: Optional[int] = None, 

1279 bytealigned: Optional[bool] = None) -> Iterable[int]: 

1280 """Find all occurrences of bs. Return generator of bit positions. 

1281 

1282 bs -- The bitstring to find. 

1283 start -- The bit position to start the search. Defaults to 0. 

1284 end -- The bit position one past the last bit to search. 

1285 Defaults to len(self). 

1286 count -- The maximum number of occurrences to find. 

1287 bytealigned -- If True the bitstring will only be found on 

1288 byte boundaries. 

1289 

1290 Raises ValueError if bs is empty, if start < 0, if end > len(self) or 

1291 if end < start. 

1292 

1293 Note that all occurrences of bs are found, even if they overlap. 

1294 

1295 """ 

1296 if count is not None and count < 0: 

1297 raise ValueError("In findall, count must be >= 0.") 

1298 bs = Bits._create_from_bitstype(bs) 

1299 start, end = self._validate_slice(start, end) 

1300 ba = bitstring.options.bytealigned if bytealigned is None else bytealigned 

1301 return self._findall(bs, start, end, count, ba) 

1302 

1303 def _findall_msb0(self, bs: Bits, start: int, end: int, count: Optional[int], 

1304 bytealigned: bool) -> Iterable[int]: 

1305 c = 0 

1306 for i in self._bitstore.findall_msb0(bs._bitstore, start, end, bytealigned): 

1307 if count is not None and c >= count: 

1308 return 

1309 c += 1 

1310 yield i 

1311 return 

1312 

1313 def _findall_lsb0(self, bs: Bits, start: int, end: int, count: Optional[int], 

1314 bytealigned: bool) -> Iterable[int]: 

1315 assert start <= end 

1316 assert bitstring.options.lsb0 

1317 

1318 new_slice = bitstring.bitstore.offset_slice_indices_lsb0(slice(start, end, None), len(self)) 

1319 msb0_start, msb0_end = self._validate_slice(new_slice.start, new_slice.stop) 

1320 

1321 # Search chunks starting near the end and then moving back. 

1322 c = 0 

1323 increment = max(8192, len(bs) * 80) 

1324 buffersize = min(increment + len(bs), msb0_end - msb0_start) 

1325 pos = max(msb0_start, msb0_end - buffersize) 

1326 while True: 

1327 found = list(self._findall_msb0(bs, start=pos, end=pos + buffersize, count=None, bytealigned=False)) 

1328 if not found: 

1329 if pos == msb0_start: 

1330 return 

1331 pos = max(msb0_start, pos - increment) 

1332 continue 

1333 while found: 

1334 if count is not None and c >= count: 

1335 return 

1336 c += 1 

1337 lsb0_pos = len(self) - found.pop() - len(bs) 

1338 if not bytealigned or lsb0_pos % 8 == 0: 

1339 yield lsb0_pos 

1340 

1341 pos = max(msb0_start, pos - increment) 

1342 if pos == msb0_start: 

1343 return 

1344 

1345 def rfind(self, bs: BitsType, /, start: Optional[int] = None, end: Optional[int] = None, 

1346 bytealigned: Optional[bool] = None) -> Union[Tuple[int], Tuple[()]]: 

1347 """Find final occurrence of substring bs. 

1348 

1349 Returns a single item tuple with the bit position if found, or an 

1350 empty tuple if not found. The bit position (pos property) will 

1351 also be set to the start of the substring if it is found. 

1352 

1353 bs -- The bitstring to find. 

1354 start -- The bit position to end the reverse search. Defaults to 0. 

1355 end -- The bit position one past the first bit to reverse search. 

1356 Defaults to len(self). 

1357 bytealigned -- If True the bitstring will only be found on byte 

1358 boundaries. 

1359 

1360 Raises ValueError if bs is empty, if start < 0, if end > len(self) or 

1361 if end < start. 

1362 

1363 """ 

1364 bs = Bits._create_from_bitstype(bs) 

1365 start, end = self._validate_slice(start, end) 

1366 ba = bitstring.options.bytealigned if bytealigned is None else bytealigned 

1367 if len(bs) == 0: 

1368 raise ValueError("Cannot find an empty bitstring.") 

1369 p = self._rfind(bs, start, end, ba) 

1370 return p 

1371 

1372 def _rfind_msb0(self, bs: Bits, start: int, end: int, bytealigned: bool) -> Union[Tuple[int], Tuple[()]]: 

1373 """Find final occurrence of a binary string.""" 

1374 p = self._bitstore.rfind(bs._bitstore, start, end, bytealigned) 

1375 return () if p == -1 else (p,) 

1376 

1377 def _rfind_lsb0(self, bs: Bits, start: int, end: int, bytealigned: bool) -> Union[Tuple[int], Tuple[()]]: 

1378 # A reverse find in lsb0 is very like a forward find in msb0. 

1379 assert start <= end 

1380 assert bitstring.options.lsb0 

1381 new_slice = bitstring.bitstore.offset_slice_indices_lsb0(slice(start, end, None), len(self)) 

1382 msb0_start, msb0_end = self._validate_slice(new_slice.start, new_slice.stop) 

1383 

1384 p = self._find_msb0(bs, msb0_start, msb0_end, bytealigned) 

1385 if p: 

1386 return (len(self) - p[0] - len(bs),) 

1387 else: 

1388 return () 

1389 

1390 def cut(self, bits: int, start: Optional[int] = None, end: Optional[int] = None, 

1391 count: Optional[int] = None) -> Iterator[Bits]: 

1392 """Return bitstring generator by cutting into bits sized chunks. 

1393 

1394 bits -- The size in bits of the bitstring chunks to generate. 

1395 start -- The bit position to start the first cut. Defaults to 0. 

1396 end -- The bit position one past the last bit to use in the cut. 

1397 Defaults to len(self). 

1398 count -- If specified then at most count items are generated. 

1399 Default is to cut as many times as possible. 

1400 

1401 """ 

1402 start_, end_ = self._validate_slice(start, end) 

1403 if count is not None and count < 0: 

1404 raise ValueError("Cannot cut - count must be >= 0.") 

1405 if bits <= 0: 

1406 raise ValueError("Cannot cut - bits must be >= 0.") 

1407 c = 0 

1408 while count is None or c < count: 

1409 c += 1 

1410 nextchunk = self._slice(start_, min(start_ + bits, end_)) 

1411 if len(nextchunk) == 0: 

1412 return 

1413 yield nextchunk 

1414 if len(nextchunk) != bits: 

1415 return 

1416 start_ += bits 

1417 return 

1418 

1419 def split(self, delimiter: BitsType, start: Optional[int] = None, end: Optional[int] = None, 

1420 count: Optional[int] = None, bytealigned: Optional[bool] = None) -> Iterable[Bits]: 

1421 """Return bitstring generator by splitting using a delimiter. 

1422 

1423 The first item returned is the initial bitstring before the delimiter, 

1424 which may be an empty bitstring. 

1425 

1426 delimiter -- The bitstring used as the divider. 

1427 start -- The bit position to start the split. Defaults to 0. 

1428 end -- The bit position one past the last bit to use in the split. 

1429 Defaults to len(self). 

1430 count -- If specified then at most count items are generated. 

1431 Default is to split as many times as possible. 

1432 bytealigned -- If True splits will only occur on byte boundaries. 

1433 

1434 Raises ValueError if the delimiter is empty. 

1435 

1436 """ 

1437 delimiter = Bits._create_from_bitstype(delimiter) 

1438 if len(delimiter) == 0: 

1439 raise ValueError("split delimiter cannot be empty.") 

1440 start, end = self._validate_slice(start, end) 

1441 bytealigned_: bool = bitstring.options.bytealigned if bytealigned is None else bytealigned 

1442 if count is not None and count < 0: 

1443 raise ValueError("Cannot split - count must be >= 0.") 

1444 if count == 0: 

1445 return 

1446 f = functools.partial(self._find_msb0, bs=delimiter, bytealigned=bytealigned_) 

1447 found = f(start=start, end=end) 

1448 if not found: 

1449 # Initial bits are the whole bitstring being searched 

1450 yield self._slice(start, end) 

1451 return 

1452 # yield the bytes before the first occurrence of the delimiter, even if empty 

1453 yield self._slice(start, found[0]) 

1454 startpos = pos = found[0] 

1455 c = 1 

1456 while count is None or c < count: 

1457 pos += len(delimiter) 

1458 found = f(start=pos, end=end) 

1459 if not found: 

1460 # No more occurrences, so return the rest of the bitstring 

1461 yield self._slice(startpos, end) 

1462 return 

1463 c += 1 

1464 yield self._slice(startpos, found[0]) 

1465 startpos = pos = found[0] 

1466 # Have generated count bitstrings, so time to quit. 

1467 return 

1468 

1469 def join(self: TBits, sequence: Iterable[Any]) -> TBits: 

1470 """Return concatenation of bitstrings joined by self. 

1471 

1472 sequence -- A sequence of bitstrings. 

1473 

1474 """ 

1475 s = self.__class__() 

1476 if len(self) == 0: 

1477 # Optimised version that doesn't need to add self between every item 

1478 for item in sequence: 

1479 s._addright(Bits._create_from_bitstype(item)) 

1480 return s 

1481 else: 

1482 sequence_iter = iter(sequence) 

1483 try: 

1484 s._addright(Bits._create_from_bitstype(next(sequence_iter))) 

1485 except StopIteration: 

1486 return s 

1487 for item in sequence_iter: 

1488 s._addright(self) 

1489 s._addright(Bits._create_from_bitstype(item)) 

1490 return s 

1491 

1492 def tobytes(self) -> bytes: 

1493 """Return the bitstring as bytes, padding with zero bits if needed. 

1494 

1495 Up to seven zero bits will be added at the end to byte align. 

1496 

1497 """ 

1498 return self._bitstore.tobytes() 

1499 

1500 def tobitarray(self) -> bitarray.bitarray: 

1501 """Convert the bitstring to a bitarray object.""" 

1502 if self._bitstore.modified_length is not None: 

1503 # Removes the offset and truncates to length 

1504 return self._bitstore.getslice(0, len(self))._bitarray 

1505 else: 

1506 return self._bitstore._bitarray 

1507 

1508 def tofile(self, f: BinaryIO) -> None: 

1509 """Write the bitstring to a file object, padding with zero bits if needed. 

1510 

1511 Up to seven zero bits will be added at the end to byte align. 

1512 

1513 """ 

1514 # If the bitstring is file based then we don't want to read it all in to memory first. 

1515 chunk_size = 8 * 100 * 1024 * 1024 # 100 MiB 

1516 for chunk in self.cut(chunk_size): 

1517 f.write(chunk.tobytes()) 

1518 

1519 def startswith(self, prefix: BitsType, start: Optional[int] = None, end: Optional[int] = None) -> bool: 

1520 """Return whether the current bitstring starts with prefix. 

1521 

1522 prefix -- The bitstring to search for. 

1523 start -- The bit position to start from. Defaults to 0. 

1524 end -- The bit position to end at. Defaults to len(self). 

1525 

1526 """ 

1527 prefix = self._create_from_bitstype(prefix) 

1528 start, end = self._validate_slice(start, end) 

1529 return self._slice(start, start + len(prefix)) == prefix if end >= start + len(prefix) else False 

1530 

1531 def endswith(self, suffix: BitsType, start: Optional[int] = None, end: Optional[int] = None) -> bool: 

1532 """Return whether the current bitstring ends with suffix. 

1533 

1534 suffix -- The bitstring to search for. 

1535 start -- The bit position to start from. Defaults to 0. 

1536 end -- The bit position to end at. Defaults to len(self). 

1537 

1538 """ 

1539 suffix = self._create_from_bitstype(suffix) 

1540 start, end = self._validate_slice(start, end) 

1541 return self._slice(end - len(suffix), end) == suffix if start + len(suffix) <= end else False 

1542 

1543 def all(self, value: Any, pos: Optional[Iterable[int]] = None) -> bool: 

1544 """Return True if one or many bits are all set to bool(value). 

1545 

1546 value -- If value is True then checks for bits set to 1, otherwise 

1547 checks for bits set to 0. 

1548 pos -- An iterable of bit positions. Negative numbers are treated in 

1549 the same way as slice indices. Defaults to the whole bitstring. 

1550 

1551 """ 

1552 value = 1 if bool(value) else 0 

1553 if pos is None: 

1554 return self._bitstore.all_set() if value else not self._bitstore.any_set() 

1555 for p in pos: 

1556 if self._bitstore.getindex(p) != value: 

1557 return False 

1558 return True 

1559 

1560 def any(self, value: Any, pos: Optional[Iterable[int]] = None) -> bool: 

1561 """Return True if any of one or many bits are set to bool(value). 

1562 

1563 value -- If value is True then checks for bits set to 1, otherwise 

1564 checks for bits set to 0. 

1565 pos -- An iterable of bit positions. Negative numbers are treated in 

1566 the same way as slice indices. Defaults to the whole bitstring. 

1567 

1568 """ 

1569 value = 1 if bool(value) else 0 

1570 if pos is None: 

1571 return self._bitstore.any_set() if value else not self._bitstore.all_set() 

1572 for p in pos: 

1573 if self._bitstore.getindex(p) == value: 

1574 return True 

1575 return False 

1576 

1577 def count(self, value: Any) -> int: 

1578 """Return count of total number of either zero or one bits. 

1579 

1580 value -- If bool(value) is True then bits set to 1 are counted, otherwise bits set 

1581 to 0 are counted. 

1582 

1583 >>> Bits('0xef').count(1) 

1584 7 

1585 

1586 """ 

1587 # count the number of 1s (from which it's easy to work out the 0s). 

1588 count = self._bitstore.count(1) 

1589 return count if value else len(self) - count 

1590 

1591 @staticmethod 

1592 def _format_bits(bits: Bits, bits_per_group: int, sep: str, dtype: Dtype, 

1593 colour_start: str, colour_end: str, width: Optional[int]=None) -> Tuple[str, int]: 

1594 get_fn = dtype.get_fn 

1595 if dtype.name == 'bytes': # Special case for bytes to print one character each. 

1596 get_fn = Bits._getbytes_printable 

1597 if dtype.name == 'bool': # Special case for bool to print '1' or '0' instead of `True` or `False`. 

1598 get_fn = dtype_register.get_dtype('uint', bits_per_group).get_fn 

1599 if bits_per_group == 0: 

1600 x = str(get_fn(bits)) 

1601 else: 

1602 # Left-align for fixed width types when msb0, otherwise right-align. 

1603 align = '<' if dtype.name in ['bin', 'oct', 'hex', 'bits', 'bytes'] and not bitstring.options.lsb0 else '>' 

1604 chars_per_group = 0 

1605 if dtype_register[dtype.name].bitlength2chars_fn is not None: 

1606 chars_per_group = dtype_register[dtype.name].bitlength2chars_fn(bits_per_group) 

1607 x = sep.join(f"{str(get_fn(b)): {align}{chars_per_group}}" for b in bits.cut(bits_per_group)) 

1608 

1609 chars_used = len(x) 

1610 padding_spaces = 0 if width is None else max(width - len(x), 0) 

1611 x = colour_start + x + colour_end 

1612 # Pad final line with spaces to align it 

1613 if bitstring.options.lsb0: 

1614 x = ' ' * padding_spaces + x 

1615 else: 

1616 x += ' ' * padding_spaces 

1617 return x, chars_used 

1618 

1619 @staticmethod 

1620 def _chars_per_group(bits_per_group: int, fmt: Optional[str]): 

1621 """How many characters are needed to represent a number of bits with a given format.""" 

1622 if fmt is None or dtype_register[fmt].bitlength2chars_fn is None: 

1623 return 0 

1624 return dtype_register[fmt].bitlength2chars_fn(bits_per_group) 

1625 

1626 @staticmethod 

1627 def _bits_per_char(fmt: str): 

1628 """How many bits are represented by each character of a given format.""" 

1629 if fmt not in ['bin', 'oct', 'hex', 'bytes']: 

1630 raise ValueError 

1631 return 24 // dtype_register[fmt].bitlength2chars_fn(24) 

1632 

1633 def _pp(self, dtype1: Dtype, dtype2: Optional[Dtype], bits_per_group: int, width: int, sep: str, format_sep: str, 

1634 show_offset: bool, stream: TextIO, lsb0: bool, offset_factor: int) -> None: 

1635 """Internal pretty print method.""" 

1636 colour = Colour(not bitstring.options.no_color) 

1637 name1 = dtype1.name 

1638 name2 = dtype2.name if dtype2 is not None else None 

1639 if dtype1.variable_length: 

1640 raise ValueError(f"Can't use Dtype '{dtype1}' in pp() as it has a variable length.") 

1641 if dtype2 is not None and dtype2.variable_length: 

1642 raise ValueError(f"Can't use Dtype '{dtype2}' in pp() as it has a variable length.") 

1643 offset_width = 0 

1644 offset_sep = ' :' if lsb0 else ': ' 

1645 if show_offset: 

1646 # This could be 1 too large in some circumstances. Slightly recurrent logic needed to fix it... 

1647 offset_width = len(str(len(self))) + len(offset_sep) 

1648 if bits_per_group > 0: 

1649 group_chars1 = Bits._chars_per_group(bits_per_group, name1) 

1650 group_chars2 = Bits._chars_per_group(bits_per_group, name2) 

1651 # The number of characters that get added when we add an extra group (after the first one) 

1652 total_group_chars = group_chars1 + group_chars2 + len(sep) + len(sep) * bool(group_chars2) 

1653 width_excluding_offset_and_final_group = width - offset_width - group_chars1 - group_chars2 - len( 

1654 format_sep) * bool(group_chars2) 

1655 width_excluding_offset_and_final_group = max(width_excluding_offset_and_final_group, 0) 

1656 groups_per_line = 1 + width_excluding_offset_and_final_group // total_group_chars 

1657 max_bits_per_line = groups_per_line * bits_per_group # Number of bits represented on each line 

1658 else: 

1659 assert bits_per_group == 0 # Don't divide into groups 

1660 width_available = width - offset_width - len(format_sep) * (name2 is not None) 

1661 width_available = max(width_available, 1) 

1662 if name2 is None: 

1663 max_bits_per_line = width_available * Bits._bits_per_char(name1) 

1664 else: 

1665 chars_per_24_bits = dtype_register[name1].bitlength2chars_fn(24) + dtype_register[name2].bitlength2chars_fn(24) 

1666 max_bits_per_line = 24 * (width_available // chars_per_24_bits) 

1667 if max_bits_per_line == 0: 

1668 max_bits_per_line = 24 # We can't fit into the width asked for. Show something small. 

1669 assert max_bits_per_line > 0 

1670 

1671 bitpos = 0 

1672 first_fb_width = second_fb_width = None 

1673 for bits in self.cut(max_bits_per_line): 

1674 offset_str = '' 

1675 if show_offset: 

1676 offset = bitpos // offset_factor 

1677 bitpos += len(bits) 

1678 if bitstring.options.lsb0: 

1679 offset_str = colour.green + offset_sep + f'{offset: <{offset_width - len(offset_sep)}}' + colour.off 

1680 else: 

1681 offset_str = colour.green + f'{offset: >{offset_width - len(offset_sep)}}' + offset_sep + colour.off 

1682 

1683 fb1, chars_used = Bits._format_bits(bits, bits_per_group, sep, dtype1, colour.purple, colour.off, first_fb_width) 

1684 if first_fb_width is None: 

1685 first_fb_width = chars_used 

1686 

1687 fb2 = '' 

1688 if dtype2 is not None: 

1689 fb2, chars_used = Bits._format_bits(bits, bits_per_group, sep, dtype2, colour.blue, colour.off, second_fb_width) 

1690 if second_fb_width is None: 

1691 second_fb_width = chars_used 

1692 fb2 = format_sep + fb2 

1693 

1694 if bitstring.options.lsb0 is True: 

1695 line_fmt = fb1 + fb2 + offset_str + '\n' 

1696 else: 

1697 line_fmt = offset_str + fb1 + fb2 + '\n' 

1698 stream.write(line_fmt) 

1699 return 

1700 

1701 @staticmethod 

1702 def _process_pp_tokens(token_list, fmt): 

1703 has_length_in_fmt = True 

1704 if len(token_list) == 1: 

1705 dtype1 = Dtype(*utils.parse_name_length_token(token_list[0])) 

1706 dtype2 = None 

1707 bits_per_group = dtype1.bitlength 

1708 if bits_per_group is None: 

1709 has_length_in_fmt = False 

1710 bits_per_group = {'bin': 8, 'hex': 8, 'oct': 12, 'bytes': 32}.get(dtype1.name) 

1711 if bits_per_group is None: 

1712 raise ValueError(f"No length or default length available for pp() format '{fmt}'.") 

1713 elif len(token_list) == 2: 

1714 dtype1 = Dtype(*utils.parse_name_length_token(token_list[0])) 

1715 dtype2 = Dtype(*utils.parse_name_length_token(token_list[1])) 

1716 if dtype1.bitlength is not None and dtype2.bitlength is not None and dtype1.bitlength != dtype2.bitlength: 

1717 raise ValueError( 

1718 f"Differing bit lengths of {dtype1.bitlength} and {dtype2.bitlength} in format string '{fmt}'.") 

1719 bits_per_group = dtype1.bitlength if dtype1.bitlength is not None else dtype2.bitlength 

1720 if bits_per_group is None: 

1721 has_length_in_fmt = False 

1722 try: 

1723 bits_per_group = 2 * Bits._bits_per_char(dtype1.name) * Bits._bits_per_char(dtype2.name) 

1724 except ValueError: 

1725 raise ValueError(f"Can't find a default bitlength to use for pp() format '{fmt}'.") 

1726 if bits_per_group >= 24: 

1727 bits_per_group //= 2 

1728 else: 

1729 raise ValueError( 

1730 f"Only one or two tokens can be used in an pp() format - '{fmt}' has {len(token_list)} tokens.") 

1731 return dtype1, dtype2, bits_per_group, has_length_in_fmt 

1732 

1733 def pp(self, fmt: Optional[str] = None, width: int = 120, sep: str = ' ', 

1734 show_offset: bool = True, stream: TextIO = sys.stdout) -> None: 

1735 """Pretty print the bitstring's value. 

1736 

1737 fmt -- Printed data format. One or two of 'bin', 'oct', 'hex' or 'bytes'. 

1738 The number of bits represented in each printed group defaults to 8 for hex and bin, 

1739 12 for oct and 32 for bytes. This can be overridden with an explicit length, e.g. 'hex:64'. 

1740 Use a length of 0 to not split into groups, e.g. `bin:0`. 

1741 width -- Max width of printed lines. Defaults to 120. A single group will always be printed 

1742 per line even if it exceeds the max width. 

1743 sep -- A separator string to insert between groups. Defaults to a single space. 

1744 show_offset -- If True (the default) shows the bit offset in the first column of each line. 

1745 stream -- A TextIO object with a write() method. Defaults to sys.stdout. 

1746 

1747 >>> s.pp('hex16') 

1748 >>> s.pp('b, h', sep='_', show_offset=False) 

1749 

1750 """ 

1751 colour = Colour(not bitstring.options.no_color) 

1752 if fmt is None: 

1753 fmt = 'bin, hex' if len(self) % 8 == 0 and len(self) >= 8 else 'bin' 

1754 token_list = utils.preprocess_tokens(fmt) 

1755 dtype1, dtype2, bits_per_group, has_length_in_fmt = Bits._process_pp_tokens(token_list, fmt) 

1756 trailing_bit_length = len(self) % bits_per_group if has_length_in_fmt and bits_per_group else 0 

1757 data = self if trailing_bit_length == 0 else self[0: -trailing_bit_length] 

1758 format_sep = " : " # String to insert on each line between multiple formats 

1759 tidy_fmt = colour.purple + str(dtype1) + colour.off 

1760 if dtype2 is not None: 

1761 tidy_fmt += ', ' + colour.blue + str(dtype2) + colour.off 

1762 output_stream = io.StringIO() 

1763 len_str = colour.green + str(len(self)) + colour.off 

1764 output_stream.write(f"<{self.__class__.__name__}, fmt='{tidy_fmt}', length={len_str} bits> [\n") 

1765 data._pp(dtype1, dtype2, bits_per_group, width, sep, format_sep, show_offset, 

1766 output_stream, bitstring.options.lsb0, 1) 

1767 output_stream.write("]") 

1768 if trailing_bit_length != 0: 

1769 output_stream.write(" + trailing_bits = " + str(self[-trailing_bit_length:])) 

1770 output_stream.write("\n") 

1771 stream.write(output_stream.getvalue()) 

1772 return 

1773 

1774 def copy(self: TBits) -> TBits: 

1775 """Return a copy of the bitstring.""" 

1776 # Note that if you want a new copy (different ID), use _copy instead. 

1777 # The copy can return self as it's immutable. 

1778 return self 

1779 

1780 @classmethod 

1781 def fromstring(cls: TBits, s: str, /) -> TBits: 

1782 """Create a new bitstring from a formatted string.""" 

1783 x = super().__new__(cls) 

1784 x._bitstore = bitstore_helpers.str_to_bitstore(s) 

1785 return x 

1786 

1787 len = length = property(_getlength, doc="The length of the bitstring in bits. Read only.") 

1788 

1789