Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/bitstring/bits.py: 23%

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

997 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 bitstring 

15from bitstring import utils 

16from bitstring.dtypes import Dtype, dtype_register 

17from bitstring.fp8 import p4binary_fmt, p3binary_fmt 

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

19from bitstring.bitstring_options import Colour 

20 

21ConstBitStore = bitstring.bitstore.ConstBitStore 

22MutableBitStore = bitstring.bitstore.MutableBitStore 

23helpers = bitstring.bitstore_helpers 

24common_helpers = bitstring.bitstore_common_helpers 

25 

26 

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

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

29 

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

31 

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

33MAX_CHARS: int = 250 

34 

35 

36class Bits: 

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

38 

39 For a mutable container use the BitArray class instead. 

40 

41 Methods: 

42 

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

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

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

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

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

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

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

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

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

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

53 pp() -- Pretty print the bitstring. 

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

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

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

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

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

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

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

61 

62 Special methods: 

63 

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

65 

66 Properties: 

67 

68 [GENERATED_PROPERTY_DESCRIPTIONS] 

69 

70 len -- Length of the bitstring in bits. 

71 

72 """ 

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

74 

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

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

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

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

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

80 

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

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

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

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

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

86 int -- a signed integer. 

87 uint -- an unsigned integer. 

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

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

90 se -- a signed exponential-Golomb code. 

91 ue -- an unsigned exponential-Golomb code. 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

106 

107 Other keyword arguments: 

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

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

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

111 ignored and this is mainly intended for use when 

112 initialising using 'bytes' or 'filename'. 

113 

114 """ 

115 pass 

116 

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

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

119 x = super().__new__(cls) 

120 if auto is None and not kwargs: 

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

122 if length is not None: 

123 x._bitstore = ConstBitStore.from_zeros(length) 

124 else: 

125 x._bitstore = ConstBitStore() 

126 return x 

127 x._initialise(auto, length, offset, immutable=True, **kwargs) 

128 return x 

129 

130 @classmethod 

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

132 if isinstance(auto, cls): 

133 return auto 

134 b = super().__new__(cls) 

135 b._setauto_no_length_or_offset(auto) 

136 return b 

137 

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

139 if auto is not None: 

140 if isinstance(auto, numbers.Integral): 

141 # Initialise with s zero bits. 

142 if auto < 0: 

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

144 if immutable: 

145 self._bitstore = ConstBitStore.from_zeros(int(auto)) 

146 else: 

147 self._bitstore = MutableBitStore.from_zeros(int(auto)) 

148 return 

149 self._setauto(auto, length, offset) 

150 else: 

151 k, v = kwargs.popitem() 

152 if k == 'bytes': 

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

154 self._setbytes_with_truncation(v, length, offset) 

155 elif k == 'filename': 

156 self._setfile(v, length, offset) 

157 elif k == 'bitarray': 

158 self._setbitarray(v, length, offset) 

159 elif k == 'auto': 

160 raise bitstring.CreationError( 

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

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

163 else: 

164 if offset is not None: 

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

166 try: 

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

168 except ValueError as e: 

169 raise bitstring.CreationError(e) 

170 if not immutable: 

171 # TODO: This copy is not a good idea. 

172 self._bitstore = self._bitstore._mutable_copy() 

173 

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

175 # Support for arbitrary attributes like u16 or f64. 

176 try: 

177 d = Dtype(attribute) 

178 except ValueError: 

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

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

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

182 return d.get_fn(self) 

183 

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

185 return iter(self._bitstore) 

186 

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

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

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

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

191 return self 

192 

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

194 # bitstrings can't really be ordered. 

195 return NotImplemented 

196 

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

198 return NotImplemented 

199 

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

201 return NotImplemented 

202 

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

204 return NotImplemented 

205 

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

207 """Concatenate bitstrings and return new bitstring. 

208 

209 bs -- the bitstring to append. 

210 

211 """ 

212 bs = self.__class__._create_from_bitstype(bs) 

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

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

215 s._addright(bs) 

216 else: 

217 s._addleft(self) 

218 return s 

219 

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

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

222 

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

224 

225 """ 

226 bs = self.__class__._create_from_bitstype(bs) 

227 return bs.__add__(self) 

228 

229 @overload 

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

231 ... 

232 

233 @overload 

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

235 ... 

236 

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

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

239 

240 >>> print(Bits('0b00110')[1:4]) 

241 '0b011' 

242 

243 """ 

244 if isinstance(key, numbers.Integral): 

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

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

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

248 return bs 

249 

250 def __len__(self) -> int: 

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

252 return self._getlength() 

253 

254 def __bytes__(self) -> bytes: 

255 return self.tobytes() 

256 

257 def __str__(self) -> str: 

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

259 

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

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

262 be truncated with '...'. 

263 

264 """ 

265 length = len(self) 

266 if not length: 

267 return '' 

268 if length > MAX_CHARS * 4: 

269 # Too long for hex. Truncate... 

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

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

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

273 return '0b' + self.bin 

274 # If we can use hex then do so 

275 if not length % 4: 

276 return '0x' + self.hex 

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

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

279 bits_at_end = length % 4 

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

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

282 

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

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

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

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

287 else: 

288 s = self.__str__() 

289 lengthstring = '' 

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

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

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

293 

294 def __repr__(self) -> str: 

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

296 

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

298 

299 """ 

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

301 

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

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

304 

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

306 True 

307 

308 """ 

309 try: 

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

311 except TypeError: 

312 return False 

313 

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

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

316 

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

318 False 

319 

320 """ 

321 return not self.__eq__(bs) 

322 

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

324 """Return bitstring with every bit inverted. 

325 

326 Raises Error if the bitstring is empty. 

327 

328 """ 

329 if len(self) == 0: 

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

331 s = self.__class__.__new__(self.__class__) 

332 s._bitstore = ~self._bitstore 

333 return s 

334 

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

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

337 

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

339 

340 """ 

341 if n < 0: 

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

343 if len(self) == 0: 

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

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

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

347 s._addright(Bits(n)) 

348 return s 

349 

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

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

352 

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

354 

355 """ 

356 if n < 0: 

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

358 if len(self) == 0: 

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

360 if not n: 

361 return self._copy() 

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

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

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

365 return s 

366 

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

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

369 

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

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

372 

373 """ 

374 if n < 0: 

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

376 if n == 0: 

377 return self.__class__() 

378 s = self._copy() 

379 s._imul(n) 

380 return s 

381 

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

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

384 self._bitstore.__imul__(n) 

385 return self 

386 

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

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

389 

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

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

392 

393 """ 

394 return self.__mul__(n) 

395 

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

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

398 

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

400 

401 Raises ValueError if the two bitstrings have differing lengths. 

402 

403 """ 

404 if bs is self: 

405 return self.copy() 

406 bs = Bits._create_from_bitstype(bs) 

407 s = object.__new__(self.__class__) 

408 s._bitstore = self._bitstore & bs._bitstore 

409 return s 

410 

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

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

413 

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

415 

416 Raises ValueError if the two bitstrings have differing lengths. 

417 

418 """ 

419 return self.__and__(bs) 

420 

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

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

423 

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

425 

426 Raises ValueError if the two bitstrings have differing lengths. 

427 

428 """ 

429 if bs is self: 

430 return self.copy() 

431 bs = Bits._create_from_bitstype(bs) 

432 s = object.__new__(self.__class__) 

433 s._bitstore = self._bitstore | bs._bitstore 

434 return s 

435 

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

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

438 

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

440 

441 Raises ValueError if the two bitstrings have differing lengths. 

442 

443 """ 

444 return self.__or__(bs) 

445 

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

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

448 

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

450 

451 Raises ValueError if the two bitstrings have differing lengths. 

452 

453 """ 

454 bs = Bits._create_from_bitstype(bs) 

455 s = object.__new__(self.__class__) 

456 s._bitstore = self._bitstore ^ bs._bitstore 

457 return s 

458 

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

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

461 

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

463 

464 Raises ValueError if the two bitstrings have differing lengths. 

465 

466 """ 

467 return self.__xor__(bs) 

468 

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

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

471 

472 bs -- The bitstring to search for. 

473 

474 """ 

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

476 return bool(found) 

477 

478 def __hash__(self) -> int: 

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

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

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

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

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

484 if len(self) <= 2000: 

485 # Use the whole bitstring. 

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

487 else: 

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

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

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

491 

492 def __bool__(self) -> bool: 

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

494 return len(self) != 0 

495 

496 def _clear(self) -> None: 

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

498 self._bitstore.clear() 

499 

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

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

502 if isinstance(s, str): 

503 self._bitstore = common_helpers.str_to_bitstore(s) 

504 elif isinstance(s, Bits): 

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

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

507 self._bitstore = ConstBitStore.from_bytes(bytearray(s)) 

508 elif isinstance(s, io.BytesIO): 

509 self._bitstore = ConstBitStore.from_bytes(s.getvalue()) 

510 elif isinstance(s, io.BufferedReader): 

511 self._setfile(s.name) 

512 elif isinstance(s, bitarray.bitarray): 

513 self._bitstore = ConstBitStore(s) 

514 elif isinstance(s, array.array): 

515 self._bitstore = ConstBitStore.from_bytes(s.tobytes()) 

516 elif isinstance(s, abc.Iterable): 

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

518 self._setbin(''.join(str(int(bool(x))) for x in s)) 

519 elif isinstance(s, numbers.Integral): 

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

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

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

523 else: 

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

525 

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

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

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

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

530 if offset is None and length is None: 

531 self._setauto_no_length_or_offset(s) 

532 return 

533 if offset is None: 

534 offset = 0 

535 

536 if isinstance(s, io.BytesIO): 

537 if length is None: 

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

539 byteoffset, offset = divmod(offset, 8) 

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

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

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

543 self._bitstore = ConstBitStore.from_bytes(s.getvalue()[byteoffset: byteoffset + bytelength]).getslice( 

544 offset, offset + length) 

545 return 

546 

547 if isinstance(s, io.BufferedReader): 

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

549 return 

550 

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

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

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

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

555 

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

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

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

559 if offset is None: 

560 offset = 0 

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

562 if offset == 0: 

563 self._filename = source.name 

564 self._bitstore = ConstBitStore.frombuffer(m, length=length) 

565 else: 

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

567 temp = ConstBitStore.frombuffer(m) 

568 if length is None: 

569 if offset > len(temp): 

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

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

572 else: 

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

574 if len(self) != length: 

575 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.") 

576 

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

578 if offset is None: 

579 offset = 0 

580 if offset > len(ba): 

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

582 if length is None: 

583 self._bitstore = ConstBitStore(ba[offset:]) 

584 else: 

585 if offset + length > len(ba): 

586 raise bitstring.CreationError( 

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

588 self._bitstore = ConstBitStore(ba[offset: offset + length]) 

589 

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

591 bs = Bits._create_from_bitstype(bs) 

592 self._bitstore = bs._bitstore 

593 

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

595 self._bitstore = common_helpers.p3binary2bitstore(f) 

596 

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

598 self._bitstore = common_helpers.p4binary2bitstore(f) 

599 

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

601 self._bitstore = common_helpers.e4m3mxfp2bitstore(f) 

602 

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

604 self._bitstore = common_helpers.e5m2mxfp2bitstore(f) 

605 

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

607 self._bitstore = common_helpers.e3m2mxfp2bitstore(f) 

608 

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

610 self._bitstore = common_helpers.e2m3mxfp2bitstore(f) 

611 

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

613 self._bitstore = common_helpers.e2m1mxfp2bitstore(f) 

614 

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

616 self._bitstore = common_helpers.e8m0mxfp2bitstore(f) 

617 

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

619 self._bitstore = common_helpers.mxint2bitstore(f) 

620 

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

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

623 self._bitstore = ConstBitStore.from_bytes(bytes(data)) 

624 

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

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

627 if offset is None and length is None: 

628 return self._setbytes(data) 

629 data = bytearray(data) 

630 if offset is None: 

631 offset = 0 

632 if length is None: 

633 # Use to the end of the data 

634 length = len(data) * 8 - offset 

635 else: 

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

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

638 self._bitstore = ConstBitStore.from_bytes(data).getslice_msb0(offset, offset + length) 

639 

640 def _getbytes(self) -> bytes: 

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

642 if len(self) % 8: 

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

644 return self._bitstore.to_bytes() 

645 

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

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

648 

649 def _getbytes_printable(self) -> str: 

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

651 bytes_ = self._getbytes() 

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

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

654 return string 

655 

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

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

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

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

660 length = len(self) 

661 if length is None or length == 0: 

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

663 self._bitstore = helpers.int2bitstore(uint, length, False) 

664 

665 def _getuint(self) -> int: 

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

667 if len(self) == 0: 

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

669 return self._bitstore.to_u() 

670 

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

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

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

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

675 length = len(self) 

676 if length is None or length == 0: 

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

678 self._bitstore = helpers.int2bitstore(int_, length, True) 

679 

680 def _getint(self) -> int: 

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

682 if len(self) == 0: 

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

684 return self._bitstore.to_i() 

685 

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

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

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

689 length = len(self) 

690 if length is None or length == 0: 

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

692 self._bitstore = helpers.int2bitstore(uintbe, length, False) 

693 

694 def _getuintbe(self) -> int: 

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

696 if len(self) % 8: 

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

698 return self._getuint() 

699 

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

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

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

703 length = len(self) 

704 if length is None or length == 0: 

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

706 self._bitstore = helpers.int2bitstore(intbe, length, True) 

707 

708 def _getintbe(self) -> int: 

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

710 if len(self) % 8: 

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

712 return self._getint() 

713 

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

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

716 length = len(self) 

717 if length is None or length == 0: 

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

719 self._bitstore = helpers.intle2bitstore(uintle, length, False) 

720 

721 def _getuintle(self) -> int: 

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

723 if len(self) % 8: 

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

725 bs = ConstBitStore.from_bytes(self._bitstore.to_bytes()[::-1]) 

726 return bs.to_u() 

727 

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

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

730 length = len(self) 

731 if length is None or length == 0: 

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

733 self._bitstore = helpers.intle2bitstore(intle, length, True) 

734 

735 def _getintle(self) -> int: 

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

737 if len(self) % 8: 

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

739 bs = ConstBitStore.from_bytes(self._bitstore.to_bytes()[::-1]) 

740 return bs.to_i() 

741 

742 def _getp4binary(self) -> float: 

743 u = self._getuint() 

744 return p4binary_fmt.lut_binary8_to_float[u] 

745 

746 def _getp3binary(self) -> float: 

747 u = self._getuint() 

748 return p3binary_fmt.lut_binary8_to_float[u] 

749 

750 def _gete4m3mxfp(self) -> float: 

751 u = self._getuint() 

752 return e4m3mxfp_saturate_fmt.lut_int_to_float[u] 

753 

754 def _gete5m2mxfp(self) -> float: 

755 u = self._getuint() 

756 return e5m2mxfp_saturate_fmt.lut_int_to_float[u] 

757 

758 def _gete3m2mxfp(self) -> float: 

759 u = self._getuint() 

760 return e3m2mxfp_fmt.lut_int_to_float[u] 

761 

762 def _gete2m3mxfp(self) -> float: 

763 u = self._getuint() 

764 return e2m3mxfp_fmt.lut_int_to_float[u] 

765 

766 def _gete2m1mxfp(self) -> float: 

767 u = self._getuint() 

768 return e2m1mxfp_fmt.lut_int_to_float[u] 

769 

770 def _gete8m0mxfp(self) -> float: 

771 u = self._getuint() - 127 

772 if u == 128: 

773 return float('nan') 

774 return 2.0 ** u 

775 

776 def _getmxint(self) -> float: 

777 u = self._getint() 

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

779 

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

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

782 length = len(self) 

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

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

785 self._bitstore = helpers.float2bitstore(f, length, big_endian) 

786 

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

788 self._setfloat(f, length, True) 

789 

790 def _getfloatbe(self) -> float: 

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

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

793 return struct.unpack(fmt, self._bitstore.to_bytes())[0] 

794 

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

796 self._setfloat(f, length, False) 

797 

798 def _getfloatle(self) -> float: 

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

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

801 return struct.unpack(fmt, self._bitstore.to_bytes())[0] 

802 

803 def _getbfloatbe(self) -> float: 

804 zero_padded = self + Bits(16) 

805 return zero_padded._getfloatbe() 

806 

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

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

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

810 self._bitstore = common_helpers.bfloat2bitstore(f, True) 

811 

812 def _getbfloatle(self) -> float: 

813 zero_padded = Bits(16) + self 

814 return zero_padded._getfloatle() 

815 

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

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

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

819 self._bitstore = common_helpers.bfloat2bitstore(f, False) 

820 

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

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

823 

824 Raises CreationError if i < 0. 

825 

826 """ 

827 if bitstring.options.lsb0: 

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

829 self._bitstore = common_helpers.ue2bitstore(i) 

830 

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

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

833 

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

835 reading the code. 

836 

837 """ 

838 if bitstring.options.lsb0: 

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

840 oldpos = pos 

841 try: 

842 while not self[pos]: 

843 pos += 1 

844 except IndexError: 

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

846 leadingzeros = pos - oldpos 

847 codenum = (1 << leadingzeros) - 1 

848 if leadingzeros > 0: 

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

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

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

852 pos += leadingzeros + 1 

853 else: 

854 assert codenum == 0 

855 pos += 1 

856 return codenum, pos 

857 

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

859 try: 

860 return self._readue(0) 

861 except bitstring.ReadError: 

862 raise bitstring.InterpretError 

863 

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

865 try: 

866 return self._readse(0) 

867 except bitstring.ReadError: 

868 raise bitstring.InterpretError 

869 

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

871 try: 

872 return self._readuie(0) 

873 except bitstring.ReadError: 

874 raise bitstring.InterpretError 

875 

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

877 try: 

878 return self._readsie(0) 

879 except bitstring.ReadError: 

880 raise bitstring.InterpretError 

881 

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

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

884 if bitstring.options.lsb0: 

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

886 self._bitstore = common_helpers.se2bitstore(i) 

887 

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

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

890 

891 Advances position to after the read code. 

892 

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

894 reading the code. 

895 

896 """ 

897 codenum, pos = self._readue(pos) 

898 m = (codenum + 1) // 2 

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

900 

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

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

903 

904 Raises CreationError if i < 0. 

905 

906 """ 

907 if bitstring.options.lsb0: 

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

909 self._bitstore = common_helpers.uie2bitstore(i) 

910 

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

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

913 

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

915 reading the code. 

916 

917 """ 

918 if bitstring.options.lsb0: 

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

920 try: 

921 codenum: int = 1 

922 while not self[pos]: 

923 pos += 1 

924 codenum <<= 1 

925 codenum += self[pos] 

926 pos += 1 

927 pos += 1 

928 except IndexError: 

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

930 return codenum - 1, pos 

931 

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

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

934 if bitstring.options.lsb0: 

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

936 self._bitstore = common_helpers.sie2bitstore(i) 

937 

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

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

940 

941 Advances position to after the read code. 

942 

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

944 reading the code. 

945 

946 """ 

947 codenum, pos = self._readuie(pos) 

948 if not codenum: 

949 return 0, pos 

950 try: 

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

952 except IndexError: 

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

954 

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

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

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

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

959 self._bitstore = ConstBitStore.from_bin('1') 

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

961 self._bitstore = ConstBitStore.from_bin('0') 

962 else: 

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

964 

965 def _getbool(self) -> bool: 

966 return self[0] 

967 

968 def _getpad(self) -> None: 

969 return None 

970 

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

972 self._bitstore = ConstBitStore.from_zeros(length) 

973 

974 def _setbin(self, binstring: str, length: None = None) -> None: 

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

976 self._bitstore = helpers.bin2bitstore(binstring) 

977 

978 def _getbin(self) -> str: 

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

980 return self._bitstore.to_bin() 

981 

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

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

984 self._bitstore = helpers.oct2bitstore(octstring) 

985 

986 def _getoct(self) -> str: 

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

988 return self._bitstore.to_oct() 

989 

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

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

992 self._bitstore = helpers.hex2bitstore(hexstring) 

993 

994 def _gethex(self) -> str: 

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

996 

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

998 

999 """ 

1000 return self._bitstore.to_hex() 

1001 

1002 def _getlength(self) -> int: 

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

1004 return len(self._bitstore) 

1005 

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

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

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

1009 s_copy = self.__class__() 

1010 s_copy._bitstore = self._bitstore._mutable_copy() 

1011 return s_copy 

1012 

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

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

1015 bs = self.__class__() 

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

1017 return bs 

1018 

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

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

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

1022 if end == start: 

1023 return self.__class__() 

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

1025 bs = self.__class__() 

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

1027 return bs 

1028 

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

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

1031 dtype = dtype_register.get_dtype(name, length) 

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

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

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

1035 try: 

1036 val = dtype.read_fn(self, pos) 

1037 if isinstance(val, tuple): 

1038 return val 

1039 else: 

1040 assert length is not None 

1041 return val, pos + dtype.bitlength 

1042 except KeyError: 

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

1044 

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

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

1047 self._bitstore += bs._bitstore 

1048 

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

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

1051 self._bitstore.extend_left(bs._bitstore) 

1052 

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

1054 """Insert bs at pos.""" 

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

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

1057 return 

1058 

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

1060 """Overwrite with bs at pos.""" 

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

1062 if bs is self: 

1063 # Just overwriting with self, so do nothing. 

1064 assert pos == 0 

1065 return 

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

1067 

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

1069 """Delete bits at pos.""" 

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

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

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

1073 

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

1075 """Reverse bytes in-place.""" 

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

1077 self._bitstore[start:end] = ConstBitStore.from_bytes(self._bitstore.getslice(start, end).to_bytes()[::-1]) 

1078 

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

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

1081 assert 0 <= pos < len(self) 

1082 self._bitstore.invert(pos) 

1083 

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

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

1086 self._bitstore.__ilshift__(n) 

1087 return self 

1088 

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

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

1091 self._bitstore.__irshift__(n) 

1092 return self 

1093 

1094 def _getbits(self: TBits): 

1095 return self._copy() 

1096 

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

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

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

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

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

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

1103 return start, end 

1104 

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

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

1107 

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

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

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

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

1112 format string will be replaced with their given value. 

1113 

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

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

1116 

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

1118 

1119 """ 

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

1121 

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

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

1124 if isinstance(fmt, str): 

1125 fmt = [fmt] 

1126 # Convert to a flat list of Dtypes 

1127 dtype_list = [] 

1128 for f_item in fmt: 

1129 if isinstance(f_item, numbers.Integral): 

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

1131 elif isinstance(f_item, Dtype): 

1132 dtype_list.append(f_item) 

1133 else: 

1134 token_list = utils.preprocess_tokens(f_item) 

1135 for t in token_list: 

1136 try: 

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

1138 except ValueError: 

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

1140 else: 

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

1142 return self._read_dtype_list(dtype_list, pos) 

1143 

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

1145 has_stretchy_token = False 

1146 bits_after_stretchy_token = 0 

1147 for dtype in dtypes: 

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

1149 if stretchy: 

1150 if has_stretchy_token: 

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

1152 has_stretchy_token = True 

1153 elif has_stretchy_token: 

1154 if dtype.variable_length: 

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

1156 bits_after_stretchy_token += dtype.bitlength 

1157 

1158 # We should have precisely zero or one stretchy token 

1159 vals = [] 

1160 for dtype in dtypes: 

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

1162 if stretchy: 

1163 bits_remaining = len(self) - pos 

1164 # Set length to the remaining bits 

1165 bitlength = max(bits_remaining - bits_after_stretchy_token, 0) 

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

1167 if remainder != 0: 

1168 raise ValueError( 

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

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

1171 dtype = Dtype(dtype.name, items) 

1172 if dtype.bitlength is not None: 

1173 val = dtype.read_fn(self, pos) 

1174 pos += dtype.bitlength 

1175 else: 

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

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

1178 vals.append(val) 

1179 return vals, pos 

1180 

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

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

1183 """Find first occurrence of substring bs. 

1184 

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

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

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

1188 

1189 bs -- The bitstring to find. 

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

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

1192 Defaults to len(self). 

1193 bytealigned -- If True the bitstring will only be 

1194 found on byte boundaries. 

1195 

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

1197 if end < start. 

1198 

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

1200 (6,) 

1201 

1202 """ 

1203 bs = Bits._create_from_bitstype(bs) 

1204 if len(bs) == 0: 

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

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

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

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

1209 return p 

1210 

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

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

1213 assert start <= end 

1214 assert bitstring.options.lsb0 

1215 

1216 new_slice = bitstring.helpers.offset_slice_indices_lsb0(slice(start, end, None), len(self)) 

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

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

1219 

1220 if p: 

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

1222 else: 

1223 return () 

1224 

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

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

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

1228 return () if p is None else (p,) 

1229 

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

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

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

1233 

1234 bs -- The bitstring to find. 

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

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

1237 Defaults to len(self). 

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

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

1240 byte boundaries. 

1241 

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

1243 if end < start. 

1244 

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

1246 

1247 """ 

1248 if count is not None and count < 0: 

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

1250 bs = Bits._create_from_bitstype(bs) 

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

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

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

1254 

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

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

1257 c = 0 

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

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

1260 return 

1261 c += 1 

1262 yield i 

1263 return 

1264 

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

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

1267 assert start <= end 

1268 assert bitstring.options.lsb0 

1269 

1270 new_slice = bitstring.helpers.offset_slice_indices_lsb0(slice(start, end, None), len(self)) 

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

1272 

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

1274 c = 0 

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

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

1277 pos = max(msb0_start, msb0_end - buffersize) 

1278 while True: 

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

1280 if not found: 

1281 if pos == msb0_start: 

1282 return 

1283 pos = max(msb0_start, pos - increment) 

1284 continue 

1285 while found: 

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

1287 return 

1288 c += 1 

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

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

1291 yield lsb0_pos 

1292 

1293 pos = max(msb0_start, pos - increment) 

1294 if pos == msb0_start: 

1295 return 

1296 

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

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

1299 """Find final occurrence of substring bs. 

1300 

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

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

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

1304 

1305 bs -- The bitstring to find. 

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

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

1308 Defaults to len(self). 

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

1310 boundaries. 

1311 

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

1313 if end < start. 

1314 

1315 """ 

1316 bs = Bits._create_from_bitstype(bs) 

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

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

1319 if len(bs) == 0: 

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

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

1322 return p 

1323 

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

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

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

1327 return () if p is None else (p,) 

1328 

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

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

1331 assert start <= end 

1332 assert bitstring.options.lsb0 

1333 new_slice = bitstring.helpers.offset_slice_indices_lsb0(slice(start, end, None), len(self)) 

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

1335 

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

1337 if p: 

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

1339 else: 

1340 return () 

1341 

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

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

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

1345 

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

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

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

1349 Defaults to len(self). 

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

1351 Default is to cut as many times as possible. 

1352 

1353 """ 

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

1355 if count is not None and count < 0: 

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

1357 if bits <= 0: 

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

1359 c = 0 

1360 while count is None or c < count: 

1361 c += 1 

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

1363 if len(nextchunk) == 0: 

1364 return 

1365 yield nextchunk 

1366 if len(nextchunk) != bits: 

1367 return 

1368 start_ += bits 

1369 return 

1370 

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

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

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

1374 

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

1376 which may be an empty bitstring. 

1377 

1378 delimiter -- The bitstring used as the divider. 

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

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

1381 Defaults to len(self). 

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

1383 Default is to split as many times as possible. 

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

1385 

1386 Raises ValueError if the delimiter is empty. 

1387 

1388 """ 

1389 delimiter = Bits._create_from_bitstype(delimiter) 

1390 if len(delimiter) == 0: 

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

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

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

1394 if count is not None and count < 0: 

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

1396 if count == 0: 

1397 return 

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

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

1400 if not found: 

1401 # Initial bits are the whole bitstring being searched 

1402 yield self._slice(start, end) 

1403 return 

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

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

1406 startpos = pos = found[0] 

1407 c = 1 

1408 while count is None or c < count: 

1409 pos += len(delimiter) 

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

1411 if not found: 

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

1413 yield self._slice(startpos, end) 

1414 return 

1415 c += 1 

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

1417 startpos = pos = found[0] 

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

1419 return 

1420 

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

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

1423 

1424 sequence -- A sequence of bitstrings. 

1425 

1426 """ 

1427 bs = MutableBitStore() 

1428 if len(self) == 0: 

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

1430 for item in sequence: 

1431 bs += Bits._create_from_bitstype(item)._bitstore 

1432 else: 

1433 sequence_iter = iter(sequence) 

1434 try: 

1435 bs += Bits._create_from_bitstype(next(sequence_iter))._bitstore 

1436 except StopIteration: 

1437 pass 

1438 else: 

1439 for item in sequence_iter: 

1440 bs += self._bitstore 

1441 bs += Bits._create_from_bitstype(item)._bitstore 

1442 s = self.__class__() 

1443 s._bitstore = bs 

1444 return s 

1445 

1446 def tobytes(self) -> bytes: 

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

1448 

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

1450 

1451 """ 

1452 return self._bitstore.to_bytes() 

1453 

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

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

1456 return self._bitstore.tobitarray() 

1457 

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

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

1460 

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

1462 

1463 """ 

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

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

1466 for chunk in self.cut(chunk_size): 

1467 f.write(chunk.tobytes()) 

1468 

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

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

1471 

1472 prefix -- The bitstring to search for. 

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

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

1475 

1476 """ 

1477 prefix = self._create_from_bitstype(prefix) 

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

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

1480 

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

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

1483 

1484 suffix -- The bitstring to search for. 

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

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

1487 

1488 """ 

1489 suffix = self._create_from_bitstype(suffix) 

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

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

1492 

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

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

1495 

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

1497 checks for bits set to 0. 

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

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

1500 

1501 """ 

1502 value = 1 if bool(value) else 0 

1503 if pos is None: 

1504 return self._bitstore.all() if value else not self._bitstore.any() 

1505 for p in pos: 

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

1507 return False 

1508 return True 

1509 

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

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

1512 

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

1514 checks for bits set to 0. 

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

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

1517 

1518 """ 

1519 value = 1 if bool(value) else 0 

1520 if pos is None: 

1521 return self._bitstore.any() if value else not self._bitstore.all() 

1522 for p in pos: 

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

1524 return True 

1525 return False 

1526 

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

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

1529 

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

1531 to 0 are counted. 

1532 

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

1534 7 

1535 

1536 """ 

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

1538 count = self._bitstore.count(1) 

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

1540 

1541 @staticmethod 

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

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

1544 get_fn = dtype.get_fn 

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

1546 get_fn = Bits._getbytes_printable 

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

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

1549 if bits_per_group == 0: 

1550 x = str(get_fn(bits)) 

1551 else: 

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

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

1554 chars_per_group = 0 

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

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

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

1558 

1559 chars_used = len(x) 

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

1561 x = colour_start + x + colour_end 

1562 # Pad final line with spaces to align it 

1563 if bitstring.options.lsb0: 

1564 x = ' ' * padding_spaces + x 

1565 else: 

1566 x += ' ' * padding_spaces 

1567 return x, chars_used 

1568 

1569 @staticmethod 

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

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

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

1573 return 0 

1574 return dtype_register[fmt].bitlength2chars_fn(bits_per_group) 

1575 

1576 @staticmethod 

1577 def _bits_per_char(fmt: str): 

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

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

1580 raise ValueError 

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

1582 

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

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

1585 """Internal pretty print method.""" 

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

1587 name1 = dtype1.name 

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

1589 if dtype1.variable_length: 

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

1591 if dtype2 is not None and dtype2.variable_length: 

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

1593 offset_width = 0 

1594 offset_sep = ' :' if lsb0 else ': ' 

1595 if show_offset: 

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

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

1598 if bits_per_group > 0: 

1599 group_chars1 = Bits._chars_per_group(bits_per_group, name1) 

1600 group_chars2 = Bits._chars_per_group(bits_per_group, name2) 

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

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

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

1604 format_sep) * bool(group_chars2) 

1605 width_excluding_offset_and_final_group = max(width_excluding_offset_and_final_group, 0) 

1606 groups_per_line = 1 + width_excluding_offset_and_final_group // total_group_chars 

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

1608 else: 

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

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

1611 width_available = max(width_available, 1) 

1612 if name2 is None: 

1613 max_bits_per_line = width_available * Bits._bits_per_char(name1) 

1614 else: 

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

1616 max_bits_per_line = 24 * (width_available // chars_per_24_bits) 

1617 if max_bits_per_line == 0: 

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

1619 assert max_bits_per_line > 0 

1620 

1621 bitpos = 0 

1622 first_fb_width = second_fb_width = None 

1623 for bits in self.cut(max_bits_per_line): 

1624 offset_str = '' 

1625 if show_offset: 

1626 offset = bitpos // offset_factor 

1627 bitpos += len(bits) 

1628 if bitstring.options.lsb0: 

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

1630 else: 

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

1632 

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

1634 if first_fb_width is None: 

1635 first_fb_width = chars_used 

1636 

1637 fb2 = '' 

1638 if dtype2 is not None: 

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

1640 if second_fb_width is None: 

1641 second_fb_width = chars_used 

1642 fb2 = format_sep + fb2 

1643 

1644 if bitstring.options.lsb0 is True: 

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

1646 else: 

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

1648 stream.write(line_fmt) 

1649 return 

1650 

1651 @staticmethod 

1652 def _process_pp_tokens(token_list, fmt): 

1653 if len(token_list) not in [1, 2]: 

1654 raise ValueError( 

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

1656 has_length_in_fmt = True 

1657 name1, length1 = utils.parse_name_length_token(token_list[0]) 

1658 dtype1 = Dtype(name1, length1) 

1659 bits_per_group = dtype1.bitlength 

1660 dtype2 = None 

1661 

1662 if len(token_list) == 2: 

1663 name2, length2 = utils.parse_name_length_token(token_list[1]) 

1664 dtype2 = Dtype(name2, length2) 

1665 if None not in {dtype1.bitlength, dtype2.bitlength} and dtype1.bitlength != dtype2.bitlength: 

1666 raise ValueError( 

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

1668 if bits_per_group is None: 

1669 bits_per_group = dtype2.bitlength 

1670 

1671 if bits_per_group is None: 

1672 has_length_in_fmt = False 

1673 if len(token_list) == 1: 

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

1675 if bits_per_group is None: 

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

1677 else: 

1678 try: 

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

1680 except ValueError: 

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

1682 if bits_per_group >= 24: 

1683 bits_per_group //= 2 

1684 return dtype1, dtype2, bits_per_group, has_length_in_fmt 

1685 

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

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

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

1689 

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

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

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

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

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

1695 per line even if it exceeds the max width. 

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

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

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

1699 

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

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

1702 

1703 """ 

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

1705 if fmt is None: 

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

1707 token_list = utils.preprocess_tokens(fmt) 

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

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

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

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

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

1713 if dtype2 is not None: 

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

1715 output_stream = io.StringIO() 

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

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

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

1719 output_stream, bitstring.options.lsb0, 1) 

1720 output_stream.write("]") 

1721 if trailing_bit_length != 0: 

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

1723 output_stream.write("\n") 

1724 stream.write(output_stream.getvalue()) 

1725 return 

1726 

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

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

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

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

1731 return self 

1732 

1733 @classmethod 

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

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

1736 x = super().__new__(cls) 

1737 x._bitstore = common_helpers.str_to_bitstore(s) 

1738 return x 

1739 

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

1741 

1742