1from __future__ import annotations
2
3import bitstring
4from bitstring.bits import Bits, BitsType
5from bitstring.dtypes import Dtype
6from typing import Union, List, Any, Optional, overload, TypeVar, Tuple
7import copy
8import numbers
9
10TConstBitStream = TypeVar("TConstBitStream", bound='ConstBitStream')
11
12
13class ConstBitStream(Bits):
14 """A container or stream holding an immutable sequence of bits.
15
16 For a mutable container use the BitStream class instead.
17
18 Methods inherited from Bits:
19
20 all() -- Check if all specified bits are set to 1 or 0.
21 any() -- Check if any of specified bits are set to 1 or 0.
22 copy() -- Return a copy of the bitstring.
23 count() -- Count the number of bits set to 1 or 0.
24 cut() -- Create generator of constant sized chunks.
25 endswith() -- Return whether the bitstring ends with a sub-string.
26 find() -- Find a sub-bitstring in the current bitstring.
27 findall() -- Find all occurrences of a sub-bitstring in the current bitstring.
28 fromstring() -- Create a bitstring from a formatted string.
29 join() -- Join bitstrings together using current bitstring.
30 pp() -- Pretty print the bitstring.
31 rfind() -- Seek backwards to find a sub-bitstring.
32 split() -- Create generator of chunks split by a delimiter.
33 startswith() -- Return whether the bitstring starts with a sub-bitstring.
34 tobitarray() -- Return bitstring as a bitarray from the bitarray package.
35 tobytes() -- Return bitstring as bytes, padding if needed.
36 tofile() -- Write bitstring to file, padding if needed.
37 unpack() -- Interpret bits using format string.
38
39 Other methods:
40
41 bytealign() -- Align to next byte boundary.
42 peek() -- Peek at and interpret next bits as a single item.
43 peeklist() -- Peek at and interpret next bits as a list of items.
44 read() -- Read and interpret next bits as a single item.
45 readlist() -- Read and interpret next bits as a list of items.
46 readto() -- Read up to and including next occurrence of a bitstring.
47
48 Special methods:
49
50 Also available are the operators [], ==, !=, +, *, ~, <<, >>, &, |, ^.
51
52 Properties:
53
54 [GENERATED_PROPERTY_DESCRIPTIONS]
55
56 len -- Length of the bitstring in bits.
57 pos -- The current bit position in the bitstring.
58 """
59
60 __slots__ = ('_pos')
61
62 def __init__(self, auto: Optional[Union[BitsType, int]] = None, /, length: Optional[int] = None,
63 offset: Optional[int] = None, pos: int = 0, **kwargs) -> None:
64 """Either specify an 'auto' initialiser:
65 A string of comma separated tokens, an integer, a file object,
66 a bytearray, a boolean iterable or another bitstring.
67
68 Or initialise via **kwargs with one (and only one) of:
69 bin -- binary string representation, e.g. '0b001010'.
70 hex -- hexadecimal string representation, e.g. '0x2ef'
71 oct -- octal string representation, e.g. '0o777'.
72 bytes -- raw data as a bytes object, for example read from a binary file.
73 int -- a signed integer.
74 uint -- an unsigned integer.
75 float / floatbe -- a big-endian floating point number.
76 bool -- a boolean (True or False).
77 se -- a signed exponential-Golomb code.
78 ue -- an unsigned exponential-Golomb code.
79 sie -- a signed interleaved exponential-Golomb code.
80 uie -- an unsigned interleaved exponential-Golomb code.
81 floatle -- a little-endian floating point number.
82 floatne -- a native-endian floating point number.
83 bfloat / bfloatbe - a big-endian bfloat format 16-bit floating point number.
84 bfloatle -- a little-endian bfloat format 16-bit floating point number.
85 bfloatne -- a native-endian bfloat format 16-bit floating point number.
86 intbe -- a signed big-endian whole byte integer.
87 intle -- a signed little-endian whole byte integer.
88 intne -- a signed native-endian whole byte integer.
89 uintbe -- an unsigned big-endian whole byte integer.
90 uintle -- an unsigned little-endian whole byte integer.
91 uintne -- an unsigned native-endian whole byte integer.
92 filename -- the path of a file which will be opened in binary read-only mode.
93
94 Other keyword arguments:
95 length -- length of the bitstring in bits, if needed and appropriate.
96 It must be supplied for all integer and float initialisers.
97 offset -- bit offset to the data. These offset bits are
98 ignored and this is mainly intended for use when
99 initialising using 'bytes' or 'filename'.
100 pos -- Initial bit position, defaults to 0.
101
102 """
103 if pos < 0:
104 pos += len(self._bitstore)
105 if pos < 0 or pos > len(self._bitstore):
106 raise bitstring.CreationError(f"Cannot set pos to {pos} when length is {len(self._bitstore)}.")
107 self._pos = pos
108 self._bitstore.immutable = True
109
110 def _setbytepos(self, bytepos: int) -> None:
111 """Move to absolute byte-aligned position in stream."""
112 self._setbitpos(bytepos * 8)
113
114 def _getbytepos(self) -> int:
115 """Return the current position in the stream in bytes. Must be byte aligned."""
116 if self._pos % 8:
117 raise bitstring.ByteAlignError("Not byte aligned when using bytepos property.")
118 return self._pos // 8
119
120 def _setbitpos(self, pos: int) -> None:
121 """Move to absolute position bit in bitstream."""
122 if pos < 0:
123 raise ValueError("Bit position cannot be negative.")
124 if pos > len(self):
125 raise ValueError("Cannot seek past the end of the data.")
126 self._pos = pos
127
128 def _getbitpos(self) -> int:
129 """Return the current position in the stream in bits."""
130 return self._pos
131
132 def _clear(self) -> None:
133 Bits._clear(self)
134 self._pos = 0
135
136 def __copy__(self: TConstBitStream) -> TConstBitStream:
137 """Return a new copy of the ConstBitStream for the copy module."""
138 # Note that if you want a new copy (different ID), use _copy instead.
139 # The copy can use the same datastore as it's immutable.
140 s = self.__class__()
141 s._bitstore = self._bitstore
142 # Reset the bit position, don't copy it.
143 s._pos = 0
144 return s
145
146 def __and__(self: TConstBitStream, bs: BitsType, /) -> TConstBitStream:
147 """Bit-wise 'and' between two bitstrings. Returns new bitstring.
148
149 bs -- The bitstring to '&' with.
150
151 Raises ValueError if the two bitstrings have differing lengths.
152
153 """
154 s = Bits.__and__(self, bs)
155 s._pos = 0
156 return s
157
158 def __or__(self: TConstBitStream, bs: BitsType, /) -> TConstBitStream:
159 """Bit-wise 'or' between two bitstrings. Returns new bitstring.
160
161 bs -- The bitstring to '|' with.
162
163 Raises ValueError if the two bitstrings have differing lengths.
164
165 """
166 s = Bits.__or__(self, bs)
167 s._pos = 0
168 return s
169
170 def __xor__(self: TConstBitStream, bs: BitsType, /) -> TConstBitStream:
171 """Bit-wise 'xor' between two bitstrings. Returns new bitstring.
172
173 bs -- The bitstring to '^' with.
174
175 Raises ValueError if the two bitstrings have differing lengths.
176
177 """
178 s = Bits.__xor__(self, bs)
179 s._pos = 0
180 return s
181
182 def __add__(self: TConstBitStream, bs: BitsType, /) -> TConstBitStream:
183 """Concatenate bitstrings and return new bitstring.
184
185 bs -- the bitstring to append.
186
187 """
188 s = Bits.__add__(self, bs)
189 s._pos = 0
190 return s
191
192 def append(self, bs: BitsType, /) -> None:
193 """Append a bitstring to the current bitstring.
194
195 bs -- The bitstring to append.
196
197 The current bit position will be moved to the end of the BitStream.
198
199 """
200 self._append(bs)
201 self._pos = len(self)
202
203 def __repr__(self) -> str:
204 """Return representation that could be used to recreate the bitstring.
205
206 If the returned string is too long it will be truncated. See __str__().
207
208 """
209 return self._repr(self.__class__.__name__, len(self), self._pos)
210
211 def overwrite(self, bs: BitsType, /, pos: Optional[int] = None) -> None:
212 """Overwrite with bitstring at bit position pos.
213
214 bs -- The bitstring to overwrite with.
215 pos -- The bit position to begin overwriting from.
216
217 The current bit position will be moved to the end of the overwritten section.
218 Raises ValueError if pos < 0 or pos > len(self).
219
220 """
221 bs = Bits._create_from_bitstype(bs)
222 if len(bs) == 0:
223 return
224 if pos is None:
225 pos = self._pos
226 if pos < 0:
227 pos += len(self)
228 if pos < 0 or pos > len(self):
229 raise ValueError("Overwrite starts outside boundary of bitstring.")
230 self._overwrite(bs, pos)
231 self._pos = pos + len(bs)
232
233 def find(self, bs: BitsType, /, start: Optional[int] = None, end: Optional[int] = None,
234 bytealigned: Optional[bool] = None) -> Union[Tuple[int], Tuple[()]]:
235 """Find first occurrence of substring bs.
236
237 Returns a single item tuple with the bit position if found, or an
238 empty tuple if not found. The bit position (pos property) will
239 also be set to the start of the substring if it is found.
240
241 bs -- The bitstring to find.
242 start -- The bit position to start the search. Defaults to 0.
243 end -- The bit position one past the last bit to search.
244 Defaults to len(self).
245 bytealigned -- If True the bitstring will only be
246 found on byte boundaries.
247
248 Raises ValueError if bs is empty, if start < 0, if end > len(self) or
249 if end < start.
250
251 >>> BitStream('0xc3e').find('0b1111')
252 (6,)
253
254 """
255
256 p = super().find(bs, start, end, bytealigned)
257 if p:
258 self._pos = p[0]
259 return p
260
261 def rfind(self, bs: BitsType, /, start: Optional[int] = None, end: Optional[int] = None,
262 bytealigned: Optional[bool] = None) -> Union[Tuple[int], Tuple[()]]:
263 """Find final occurrence of substring bs.
264
265 Returns a single item tuple with the bit position if found, or an
266 empty tuple if not found. The bit position (pos property) will
267 also be set to the start of the substring if it is found.
268
269 bs -- The bitstring to find.
270 start -- The bit position to end the reverse search. Defaults to 0.
271 end -- The bit position one past the first bit to reverse search.
272 Defaults to len(self).
273 bytealigned -- If True the bitstring will only be found on byte
274 boundaries.
275
276 Raises ValueError if bs is empty, if start < 0, if end > len(self) or
277 if end < start.
278
279 """
280 p = super().rfind(bs, start, end, bytealigned)
281 if p:
282 self._pos = p[0]
283 return p
284
285 @overload
286 def read(self, fmt: int) -> Bits:
287 ...
288
289 @overload
290 def read(self, fmt: str) -> Any:
291 ...
292
293 def read(self, fmt: Union[int, str, Dtype]) -> Union[int, float, str, Bits, bool, bytes, None]:
294 """Interpret next bits according to the format string and return result.
295
296 fmt -- Token string describing how to interpret the next bits.
297
298 Token examples: 'int:12' : 12 bits as a signed integer
299 'uint:8' : 8 bits as an unsigned integer
300 'float:64' : 8 bytes as a big-endian float
301 'intbe:16' : 2 bytes as a big-endian signed integer
302 'uintbe:16' : 2 bytes as a big-endian unsigned integer
303 'intle:32' : 4 bytes as a little-endian signed integer
304 'uintle:32' : 4 bytes as a little-endian unsigned integer
305 'floatle:64': 8 bytes as a little-endian float
306 'intne:24' : 3 bytes as a native-endian signed integer
307 'uintne:24' : 3 bytes as a native-endian unsigned integer
308 'floatne:32': 4 bytes as a native-endian float
309 'hex:80' : 80 bits as a hex string
310 'oct:9' : 9 bits as an octal string
311 'bin:1' : single bit binary string
312 'ue' : next bits as unsigned exp-Golomb code
313 'se' : next bits as signed exp-Golomb code
314 'uie' : next bits as unsigned interleaved exp-Golomb code
315 'sie' : next bits as signed interleaved exp-Golomb code
316 'bits:5' : 5 bits as a bitstring
317 'bytes:10' : 10 bytes as a bytes object
318 'bool' : 1 bit as a bool
319 'pad:3' : 3 bits of padding to ignore - returns None
320
321 fmt may also be an integer, which will be treated like the 'bits' token.
322
323 The position in the bitstring is advanced to after the read items.
324
325 Raises ReadError if not enough bits are available.
326 Raises ValueError if the format is not understood.
327
328 """
329 p = self._pos
330 if isinstance(fmt, numbers.Integral):
331 if fmt < 0:
332 raise ValueError("Cannot read negative amount.")
333 if fmt > len(self) - self._pos:
334 raise bitstring.ReadError(f"Cannot read {fmt} bits, only {len(self) - self._pos} available.")
335 bs = self._slice(self._pos, self._pos + fmt)
336 self._pos += fmt
337 return bs
338 dtype = bitstring.dtypes.Dtype(fmt)
339 if dtype.bitlength is None and not dtype.variable_length:
340 # No length specified? Try again, but read to end.
341 bitlength = len(self) - self._pos
342 items, remainder = divmod(bitlength, dtype.bits_per_item)
343 if remainder != 0:
344 raise ValueError(
345 f"The '{dtype.name}' type must have a bit length that is a multiple of {dtype.bits_per_item}"
346 f" so cannot be read from the {bitlength} bits that are available.")
347 dtype = bitstring.dtypes.Dtype(fmt, items)
348 if dtype.bitlength is not None:
349 val = dtype.read_fn(self, self._pos)
350 self._pos += dtype.bitlength
351 else:
352 val, self._pos = dtype.read_fn(self, self._pos)
353
354 if self._pos > len(self):
355 self._pos = p
356 raise bitstring.ReadError(f"Reading off end of bitstring with fmt '{fmt}'. Only {len(self) - p} bits available.")
357 return val
358
359 def readlist(self, fmt: Union[str, List[Union[int, str, Dtype]]], **kwargs) \
360 -> List[Union[int, float, str, Bits, bool, bytes, None]]:
361 """Interpret next bits according to format string(s) and return list.
362
363 fmt -- A single string or list of strings with comma separated tokens
364 describing how to interpret the next bits in the bitstring. Items
365 can also be integers, for reading new bitstring of the given length.
366 kwargs -- A dictionary or keyword-value pairs - the keywords used in the
367 format string will be replaced with their given value.
368
369 The position in the bitstring is advanced to after the read items.
370
371 Raises ReadError is not enough bits are available.
372 Raises ValueError if the format is not understood.
373
374 See the docstring for 'read' for token examples. 'pad' tokens are skipped
375 and not added to the returned list.
376
377 >>> h, b1, b2 = s.readlist('hex:20, bin:5, bin:3')
378 >>> i, bs1, bs2 = s.readlist(['uint:12', 10, 10])
379
380 """
381 value, self._pos = self._readlist(fmt, self._pos, **kwargs)
382 return value
383
384 def readto(self: TConstBitStream, bs: BitsType, /, bytealigned: Optional[bool] = None) -> TConstBitStream:
385 """Read up to and including next occurrence of bs and return result.
386
387 bs -- The bitstring to find.
388 bytealigned -- If True the bitstring will only be
389 found on byte boundaries.
390
391 Raises ValueError if bs is empty.
392 Raises ReadError if bs is not found.
393
394 """
395 if isinstance(bs, numbers.Integral):
396 raise ValueError("Integers cannot be searched for")
397 bs = Bits._create_from_bitstype(bs)
398 oldpos = self._pos
399 p = self.find(bs, self._pos, bytealigned=bytealigned)
400 if not p:
401 raise bitstring.ReadError("Substring not found")
402 self._pos += len(bs)
403 return self._slice(oldpos, self._pos)
404
405 @overload
406 def peek(self: TConstBitStream, fmt: int) -> TConstBitStream:
407 ...
408
409 @overload
410 def peek(self, fmt: str) -> Union[int, float, str, TConstBitStream, bool, bytes, None]:
411 ...
412
413 def peek(self: TConstBitStream, fmt: Union[int, str]) -> Union[int, float, str, TConstBitStream, bool, bytes, None]:
414 """Interpret next bits according to format string and return result.
415
416 fmt -- Token string describing how to interpret the next bits.
417
418 The position in the bitstring is not changed. If not enough bits are
419 available then all bits to the end of the bitstring will be used.
420
421 Raises ReadError if not enough bits are available.
422 Raises ValueError if the format is not understood.
423
424 See the docstring for 'read' for token examples.
425
426 """
427 pos_before = self._pos
428 value = self.read(fmt)
429 self._pos = pos_before
430 return value
431
432 def peeklist(self, fmt: Union[str, List[Union[int, str]]], **kwargs) \
433 -> List[Union[int, float, str, Bits, None]]:
434 """Interpret next bits according to format string(s) and return list.
435
436 fmt -- One or more integers or strings with comma separated tokens describing
437 how to interpret the next bits in the bitstring.
438 kwargs -- A dictionary or keyword-value pairs - the keywords used in the
439 format string will be replaced with their given value.
440
441 The position in the bitstring is not changed. If not enough bits are
442 available then all bits to the end of the bitstring will be used.
443
444 Raises ReadError if not enough bits are available.
445 Raises ValueError if the format is not understood.
446
447 See the docstring for 'read' for token examples.
448
449 """
450 pos = self._pos
451 return_values = self.readlist(fmt, **kwargs)
452 self._pos = pos
453 return return_values
454
455 def bytealign(self) -> int:
456 """Align to next byte and return number of skipped bits.
457
458 Raises ValueError if the end of the bitstring is reached before
459 aligning to the next byte.
460
461 """
462 skipped = (8 - (self._pos % 8)) % 8
463 self.pos += skipped
464 return skipped
465
466 @classmethod
467 def fromstring(cls: TBits, s: str, /) -> TBits:
468 x = super().fromstring(s)
469 x._pos = 0
470 x._bitstore.immutable = True
471 return x
472
473 @overload
474 def __getitem__(self: TBits, key: slice, /) -> TBits:
475 ...
476
477 @overload
478 def __getitem__(self: TBits, key: int, /) -> bool:
479 ...
480
481 def __getitem__(self: TBits, key: Union[slice, int], /) -> Union[TBits, bool]:
482 """Return a new bitstring representing a slice of the current bitstring."""
483 if isinstance(key, numbers.Integral):
484 return bool(self._bitstore.getindex(key))
485 bs = super().__new__(self.__class__)
486 bs._bitstore = self._bitstore.getslice_withstep(key)
487 bs._pos = 0
488 return bs
489
490 pos = property(_getbitpos, _setbitpos,
491 doc="""The position in the bitstring in bits. Read and write.
492 """)
493 bitpos = property(_getbitpos, _setbitpos,
494 doc="""The position in the bitstring in bits. Read and write.
495 """)
496 bytepos = property(_getbytepos, _setbytepos,
497 doc="""The position in the bitstring in bytes. Read and write.
498 """)
499
500
501class BitStream(ConstBitStream, bitstring.BitArray):
502 """A container or stream holding a mutable sequence of bits
503
504 Subclass of the ConstBitStream and BitArray classes. Inherits all of
505 their methods.
506
507 Methods:
508
509 all() -- Check if all specified bits are set to 1 or 0.
510 any() -- Check if any of specified bits are set to 1 or 0.
511 append() -- Append a bitstring.
512 bytealign() -- Align to next byte boundary.
513 byteswap() -- Change byte endianness in-place.
514 clear() -- Remove all bits from the bitstring.
515 copy() -- Return a copy of the bitstring.
516 count() -- Count the number of bits set to 1 or 0.
517 cut() -- Create generator of constant sized chunks.
518 endswith() -- Return whether the bitstring ends with a sub-string.
519 find() -- Find a sub-bitstring in the current bitstring.
520 findall() -- Find all occurrences of a sub-bitstring in the current bitstring.
521 fromstring() -- Create a bitstring from a formatted string.
522 insert() -- Insert a bitstring.
523 invert() -- Flip bit(s) between one and zero.
524 join() -- Join bitstrings together using current bitstring.
525 overwrite() -- Overwrite a section with a new bitstring.
526 peek() -- Peek at and interpret next bits as a single item.
527 peeklist() -- Peek at and interpret next bits as a list of items.
528 pp() -- Pretty print the bitstring.
529 prepend() -- Prepend a bitstring.
530 read() -- Read and interpret next bits as a single item.
531 readlist() -- Read and interpret next bits as a list of items.
532 readto() -- Read up to and including next occurrence of a bitstring.
533 replace() -- Replace occurrences of one bitstring with another.
534 reverse() -- Reverse bits in-place.
535 rfind() -- Seek backwards to find a sub-bitstring.
536 rol() -- Rotate bits to the left.
537 ror() -- Rotate bits to the right.
538 set() -- Set bit(s) to 1 or 0.
539 split() -- Create generator of chunks split by a delimiter.
540 startswith() -- Return whether the bitstring starts with a sub-bitstring.
541 tobitarray() -- Return bitstring as a bitarray from the bitarray package.
542 tobytes() -- Return bitstring as bytes, padding if needed.
543 tofile() -- Write bitstring to file, padding if needed.
544 unpack() -- Interpret bits using format string.
545
546 Special methods:
547
548 Mutating operators are available: [], <<=, >>=, +=, *=, &=, |= and ^=
549 in addition to [], ==, !=, +, *, ~, <<, >>, &, | and ^.
550
551 Properties:
552
553 [GENERATED_PROPERTY_DESCRIPTIONS]
554
555 len -- Length of the bitstring in bits.
556 pos -- The current bit position in the bitstring.
557 """
558
559 __slots__ = ()
560
561 def __init__(self, auto: Optional[Union[BitsType, int]] = None, /, length: Optional[int] = None,
562 offset: Optional[int] = None, pos: int = 0, **kwargs) -> None:
563 """Either specify an 'auto' initialiser:
564 A string of comma separated tokens, an integer, a file object,
565 a bytearray, a boolean iterable or another bitstring.
566
567 Or initialise via **kwargs with one (and only one) of:
568 bin -- binary string representation, e.g. '0b001010'.
569 hex -- hexadecimal string representation, e.g. '0x2ef'
570 oct -- octal string representation, e.g. '0o777'.
571 bytes -- raw data as a bytes object, for example read from a binary file.
572 int -- a signed integer.
573 uint -- an unsigned integer.
574 float / floatbe -- a big-endian floating point number.
575 bool -- a boolean (True or False).
576 se -- a signed exponential-Golomb code.
577 ue -- an unsigned exponential-Golomb code.
578 sie -- a signed interleaved exponential-Golomb code.
579 uie -- an unsigned interleaved exponential-Golomb code.
580 floatle -- a little-endian floating point number.
581 floatne -- a native-endian floating point number.
582 bfloat / bfloatbe - a big-endian bfloat format 16-bit floating point number.
583 bfloatle -- a little-endian bfloat format 16-bit floating point number.
584 bfloatne -- a native-endian bfloat format 16-bit floating point number.
585 intbe -- a signed big-endian whole byte integer.
586 intle -- a signed little-endian whole byte integer.
587 intne -- a signed native-endian whole byte integer.
588 uintbe -- an unsigned big-endian whole byte integer.
589 uintle -- an unsigned little-endian whole byte integer.
590 uintne -- an unsigned native-endian whole byte integer.
591 filename -- the path of a file which will be opened in binary read-only mode.
592
593 Other keyword arguments:
594 length -- length of the bitstring in bits, if needed and appropriate.
595 It must be supplied for all integer and float initialisers.
596 offset -- bit offset to the data. These offset bits are
597 ignored and this is intended for use when
598 initialising using 'bytes' or 'filename'.
599 pos -- Initial bit position, defaults to 0.
600
601 """
602 ConstBitStream.__init__(self, auto, length, offset, pos, **kwargs)
603 if self._bitstore.immutable:
604 self._bitstore = self._bitstore._copy()
605 self._bitstore.immutable = False
606
607 def __copy__(self) -> BitStream:
608 """Return a new copy of the BitStream."""
609 s_copy = object.__new__(BitStream)
610 s_copy._pos = 0
611 s_copy._bitstore = self._bitstore.copy()
612 return s_copy
613
614 def __iadd__(self, bs: BitsType, /) -> BitStream:
615 """Append to current bitstring. Return self.
616
617 bs -- the bitstring to append.
618
619 The current bit position will be moved to the end of the BitStream.
620 """
621 self._append(bs)
622 self._pos = len(self)
623 return self
624
625 def prepend(self, bs: BitsType, /) -> None:
626 """Prepend a bitstring to the current bitstring.
627
628 bs -- The bitstring to prepend.
629
630 """
631 bs = Bits._create_from_bitstype(bs)
632 super().prepend(bs)
633 self._pos = 0
634
635 def __setitem__(self, /, key: Union[slice, int], value: BitsType) -> None:
636 length_before = len(self)
637 super().__setitem__(key, value)
638 if len(self) != length_before:
639 self._pos = 0
640 return
641
642 def __delitem__(self, /, key: Union[slice, int]) -> None:
643 """Delete item or range.
644
645 >>> a = BitStream('0x001122')
646 >>> del a[8:16]
647 >>> print a
648 0x0022
649
650 """
651 length_before = len(self)
652 self._bitstore.__delitem__(key)
653 if len(self) != length_before:
654 self._pos = 0
655
656 def insert(self, bs: BitsType, /, pos: Optional[int] = None) -> None:
657 """Insert bitstring at bit position pos.
658
659 bs -- The bitstring to insert.
660 pos -- The bit position to insert at.
661
662 The current bit position will be moved to the end of the inserted section.
663 Raises ValueError if pos < 0 or pos > len(self).
664
665 """
666 bs = Bits._create_from_bitstype(bs)
667 if len(bs) == 0:
668 return
669 if bs is self:
670 bs = self._copy()
671 if pos is None:
672 pos = self._pos
673 if pos < 0:
674 pos += len(self)
675 if not 0 <= pos <= len(self):
676 raise ValueError("Invalid insert position.")
677 self._insert(bs, pos)
678 self._pos = pos + len(bs)
679
680 def replace(self, old: BitsType, new: BitsType, start: Optional[int] = None, end: Optional[int] = None,
681 count: Optional[int] = None, bytealigned: Optional[bool] = None) -> int:
682 """Replace all occurrences of old with new in place.
683
684 Returns number of replacements made.
685
686 old -- The bitstring to replace.
687 new -- The replacement bitstring.
688 start -- Any occurrences that start before this will not be replaced.
689 Defaults to 0.
690 end -- Any occurrences that finish after this will not be replaced.
691 Defaults to len(self).
692 count -- The maximum number of replacements to make. Defaults to
693 replace all occurrences.
694 bytealigned -- If True replacements will only be made on byte
695 boundaries.
696
697 Raises ValueError if old is empty or if start or end are
698 out of range.
699
700 """
701 if count == 0:
702 return 0
703 if len(old := Bits._create_from_bitstype(old)) == 0:
704 raise ValueError("Empty bitstring cannot be replaced.")
705 start, end = self._validate_slice(start, end)
706 new = Bits._create_from_bitstype(new)
707 if new is self:
708 # Prevent self assignment woes
709 new = copy.copy(self)
710 length_before = len(self)
711 replacement_count = self._replace(old, new, start, end, 0 if count is None else count, bytealigned)
712 if len(self) != length_before:
713 self._pos = 0
714 return replacement_count