.. currentmodule:: bitstring

BitArray
========

.. class:: BitArray(__auto: BitsType | int | None, length: int | None = None, offset: int | None = None, **kwargs)

    The :class:`Bits` class is the base class for :class:`BitArray` and so (with the exception of :meth:`~Bits.__hash__`) all of its methods are also available for :class:`BitArray` objects. The initialiser is also the same as for :class:`Bits` and so won't be repeated here.

    A :class:`BitArray` is a mutable :class:`Bits`, and so the one thing all of the methods listed here have in common is that  they can modify the contents of the bitstring.

Methods
-------

.. method:: BitArray.append(bs: BitsType) -> None

   Join a :class:`BitArray` to the end of the current :class:`BitArray`. ::

       >>> s = BitArray('0xbad')
       >>> s.append('0xf00d')
       >>> s
       BitArray('0xbadf00d')

.. method:: BitArray.byteswap(fmt: str | int | Iterable[int] | None = None, start: int | None = None, end: int | None = None, repeat: bool = True) -> int

   Change the endianness of the :class:`BitArray` in-place according to *fmt*. Return the number of swaps done.

   The *fmt* can be an integer, an iterable of integers or a compact format string similar to those used in :func:`pack` (described in :ref:`compact_format`). It defaults to 0, which means reverse as many bytes as possible. The *fmt* gives a pattern of byte sizes to use to swap the endianness of the :class:`BitArray`. Note that if you use a compact format string then the endianness identifier (``<``, ``>`` or ``=``) is not needed, and if present it will be ignored.

   *start* and *end* optionally give a slice to apply the transformation to (it defaults to the whole :class:`BitArray`). If *repeat* is ``True`` then the byte swapping pattern given by the *fmt* is repeated in its entirety as many times as possible.

       >>> s = BitArray('0x00112233445566')
       >>> s.byteswap(2)
       3
       >>> s
       BitArray('0x11003322554466')
       >>> s.byteswap('h')
       3
       >>> s
       BitArray('0x00112233445566')
       >>> s.byteswap([2, 5])
       1
       >>> s
       BitArray('0x11006655443322')

   It can also be used to swap the endianness of the whole :class:`BitArray`. ::

       >>> s = BitArray('uintle32=1234')
       >>> s.byteswap()
       >>> print(s.uintbe)
       1234

.. method:: BitArray.clear() -> None

    Removes all bits from the bitstring.

    ``s.clear()`` is equivalent to ``del s[:]`` and simply makes the bitstring empty.

.. method:: BitArray.insert(bs: BitsType, pos: int) -> None

    Inserts *bs* at *pos*.

    When used with the :class:`BitStream` class the *pos* is optional, and if not present the current bit position will be used. After insertion the property :attr:`~ConstBitStream.pos` will be immediately after the inserted bitstring. ::

        >>> s = BitStream('0xccee')
        >>> s.insert('0xd', 8)
        >>> s
        BitStream('0xccdee')
        >>> s.insert('0x00')
        >>> s
        BitStream('0xccd00ee')

.. method:: BitArray.invert(pos: int | Iterable[int] | None = None) -> None

    Inverts one or many bits from ``1`` to ``0`` or vice versa.

    *pos* can be either a single bit position or an iterable of bit positions. Negative numbers are treated in the same way as slice indices and it will raise :exc:`IndexError` if ``pos < -len(s)`` or ``pos > len(s)``. The default is to invert the entire :class:`BitArray`. ::

        >>> s = BitArray('0b111001')
        >>> s.invert(0)
        >>> s.bin
        '011001'
        >>> s.invert([-2, -1])
        >>> s.bin
        '011010'
        >>> s.invert()
        >>> s.bin
        '100101'

.. method:: BitArray.overwrite(bs: BitsType, pos: int) -> None

    Replaces the contents of the current :class:`BitArray` with *bs* at *pos*.

    When used with the :class:`BitStream` class the *pos* is optional, and if not present the current bit position will be used. After insertion the property :attr:`~ConstBitStream.pos` will be immediately after the overwritten bitstring. ::

        >>> s = BitArray(length=10)
        >>> s.overwrite('0b111', 3)
        >>> s
        BitArray('0b0001110000')
        >>> s.pos
        6

.. method:: BitArray.prepend(bs: BitsType) -> None

    Inserts *bs* at the beginning of the current :class:`BitArray`. ::

        >>> s = BitArray('0b0')
        >>> s.prepend('0xf')
        >>> s
        BitArray('0b11110')

.. method:: BitArray.replace(old: BitsType, new: BitsType, start: int | None = None, end: int | None = None, count: int | None = None, bytealigned: bool | None = None) -> int

    Finds occurrences of *old* and replaces them with *new*. Returns the number of replacements made.

    If *bytealigned* is ``True`` then replacements will only be made on byte boundaries. *start* and *end* give the search range and default to ``0`` and :attr:`~Bits.len` respectively. If *count* is specified then no more than this many replacements will be made. ::

        >>> s = BitArray('0b0011001')
        >>> s.replace('0b1', '0xf')
        3
        >>> print(s.bin)
        0011111111001111
        >>> s.replace('0b1', '', count=6)
        6
        >>> print(s.bin)
        0011001111

.. method:: BitArray.reverse(start: int | None = None, end: int | None = None) -> None

    Reverses bits in the :class:`BitArray` in-place.

    *start* and *end* give the range of bits to reverse and default to ``0`` and :attr:`~Bits.len` respectively. ::

        >>> a = BitArray('0b000001101')
        >>> a.reverse()
        >>> a.bin
        '101100000'
        >>> a.reverse(0, 4)
        >>> a.bin
        '110100000'

.. method:: BitArray.rol(bits: int, start: int | None = None, end: int | None = None) -> None

    Rotates the contents of the :class:`BitArray` in-place by *bits* bits to the left.

    *start* and *end* define the slice to use and default to ``0`` and :attr:`~Bits.len` respectively.

    Raises :exc:`ValueError` if ``bits < 0``. ::

        >>> s = BitArray('0b01000001')
        >>> s.rol(2)
        >>> s.bin
        '00000101'

.. method:: BitArray.ror(bits: int, start: int | None = None, end: int | None = None) -> None

    Rotates the contents of the :class:`BitArray` in-place by *bits* bits to the right.

    *start* and *end* define the slice to use and default to ``0`` and :attr:`~Bits.len` respectively.

    Raises :exc:`ValueError` if ``bits < 0``.

.. method:: BitArray.set(value: bool, pos: int | Iterable[int] | None = None) -> None

    Sets one or many bits to either ``1`` (if *value* is ``True``) or ``0`` (if *value* isn't ``True``). *pos* can be either a single bit position or an iterable of bit positions. Negative numbers are treated in the same way as slice indices and it will raise :exc:`IndexError` if ``pos < -len(s)`` or ``pos > len(s)``. The default is to set every bit in the :class:`BitArray`.

    Using ``s.set(True, x)`` can be more efficient than other equivalent methods such as ``s[x] = 1``, ``s[x] = "0b1"`` or ``s.overwrite('0b1', x)``, especially if many bits are being set. In particular using a ``range`` object as an iterable is treated as a special case and is done efficiently. ::

        >>> s = BitArray('0x0000')
        >>> s.set(True, -1)
        >>> print(s)
        0x0001
        >>> s.set(1, (0, 4, 5, 7, 9))
        >>> s.bin
        '1000110101000001'
        >>> s.set(0)
        >>> s.bin
        '0000000000000000'
        >>> s.set(1, range(0, len(s), 2))
        >>> s.bin
        '1010101010101010'


Properties
----------

Note that the ``bin``, ``oct``, ``hex``, ``int``, ``uint`` and ``float`` properties can all be shortened to their initial letter.
Properties can also have a length in bits appended to them to make properties such as ``u8`` or ``floatle64`` (with the exception of the ``bytes`` property which uses a unit of bytes instead of bits, so ``bytes4`` is 32 bits long). These properties with lengths can be used to quickly create a new bitstring. ::

    >>> a = BitArray()
    >>> a.f32 = 17.6
    >>> a.h
    '418ccccd'
    >>> a.i7 = -1
    >>> a.b
    '1111111'


.. attribute:: BitArray.bin
    :type: str
    :noindex:
.. attribute:: BitArray.b
    :type: str
    :noindex:

    Writable version of :attr:`Bits.bin`.

.. attribute:: BitArray.bfloat
    :type: float
    :noindex:
.. attribute:: BitArray.bfloatbe
    :type: float
    :noindex:
.. attribute:: BitArray.bfloatle
    :type: float
    :noindex:
.. attribute:: BitArray.bfloatne
    :type: float
    :noindex:

    Writable versions of :attr:`Bits.bfloat` / :attr:`Bits.bfloatbe` / :attr:`Bits.bfloatle` / :attr:`Bits.bfloatne`.

.. attribute:: BitArray.bool
    :type: bool
    :noindex:

    Writable version of :attr:`Bits.bool`.

.. attribute:: BitArray.bytes
    :type: bytes
    :noindex:

    Writable version of :attr:`Bits.bytes`.

.. attribute:: BitArray.hex
    :type: str
    :noindex:
.. attribute:: BitArray.h
    :type: str
    :noindex:

    Writable version of :attr:`Bits.hex`.

.. attribute:: BitArray.int
    :type: int
    :noindex:
.. attribute:: BitArray.i
    :type: int
    :noindex:

    Writable version of :attr:`Bits.int`. The properties can have a bit length appended to it such as ``i32`` or ``int5`` to specify the new length of the bitstring. Using a length too small to contain the value given will raise a :exc:`CreationError`.

    When used  as a setter without a new length the value must fit into the current length of the :class:`BitArray`, else a :exc:`ValueError` will be raised. ::

        >>> s = BitArray('0xf3')
        >>> s.int
        -13
        >>> s.int = 1232
        ValueError: int 1232 is too large for a BitArray of length 8.


.. attribute:: BitArray.intbe
    :type: int
    :noindex:

    Writable version of :attr:`Bits.intbe`.

    When used as a setter the value must fit into the current length of the :class:`BitArray`, else a :exc:`ValueError` will be raised.

.. attribute:: BitArray.intle
    :type: int
    :noindex:

    Writable version of :attr:`Bits.intle`.

    When used as a setter the value must fit into the current length of the :class:`BitArray`, else a :exc:`ValueError` will be raised.

.. attribute:: BitArray.intne
    :type: int
    :noindex:

    Writable version of :attr:`Bits.intne`.

    When used as a setter the value must fit into the current length of the :class:`BitArray`, else a :exc:`ValueError` will be raised.

.. attribute:: BitArray.float
    :type: float
    :noindex:
.. attribute:: BitArray.floatbe
    :type: float
    :noindex:
.. attribute:: BitArray.f
    :type: float
    :noindex:

    Writable version of :attr:`Bits.float`. The standard ``float``, the big-endian ``floatbe`` and the shortened ``f`` are all equivalent.

    The properties can have a bit length appended to them such as ``f16`` or ``floatle64`` to specify the new length of the bitstring. Using a length that doesn't support any floating point types will raise a :exc:`CreationError`.

.. attribute:: BitArray.floatle
    :type: float
    :noindex:

    Writable version of :attr:`Bits.floatle`.

.. attribute:: BitArray.floatne
    :type: float
    :noindex:

    Writable version of :attr:`Bits.floatne`.

.. attribute:: BitArray.e4m3float
    :type: float
    :noindex:

    Writable version of :attr:`Bits.e4m3float`.

.. attribute:: BitArray.e5m2float
    :type: float
    :noindex:

    Writable version of :attr:`Bits.e5m2float`.

.. attribute:: BitArray.oct
    :type: str
    :noindex:
.. attribute:: BitArray.o
    :type: str
    :noindex:

    Writable version of :attr:`Bits.oct`.

.. attribute:: BitArray.se
    :type: int
    :noindex:

    Writable version of :attr:`Bits.se`.

.. attribute:: BitArray.ue
    :type: int
    :noindex:

    Writable version of :attr:`Bits.uie`.

.. attribute:: BitArray.sie
    :type: int
    :noindex:

    Writable version of :attr:`Bits.sie`.

.. attribute:: BitArray.uie
    :type: int
    :noindex:

    Writable version of :attr:`Bits.ue`.

.. attribute:: BitArray.uint
    :type: int
    :noindex:
.. attribute:: BitArray.u
    :type: int
    :noindex:

    Writable version of :attr:`Bits.uint`.

    When used as a setter the value must fit into the current length of the :class:`BitArray`, else a :exc:`ValueError` will be raised.

.. attribute:: BitArray.uintbe
    :type: int
    :noindex:

    Writable version of :attr:`Bits.uintbe`.

    When used as a setter the value must fit into the current length of the :class:`BitArray`, else a :exc:`ValueError` will be raised.

.. attribute:: BitArray.uintle
    :type: int
    :noindex:

    Writable version of :attr:`Bits.uintle`.

    When used as a setter the value must fit into the current length of the :class:`BitArray`, else a :exc:`ValueError` will be raised.

.. attribute:: BitArray.uintne
    :type: int
    :noindex:

    Writable version of :attr:`Bits.uintne`.

    When used as a setter the value must fit into the current length of the :class:`BitArray`, else a :exc:`ValueError` will be raised.

Special Methods
---------------

.. method:: BitArray.__delitem__(key)

    ``del s[start:end:step]``

    Deletes the slice specified.

.. method:: BitArray.__iadd__(bs)

    ``s1 += s2``

    Appends *bs* to the current bitstring.

    Note that for :class:`BitArray` objects this will be an in-place change, whereas for :class:`Bits` objects using ``+=`` will not call this method - instead a new object will be created (it is equivalent to a copy and an :meth:`~Bits.__add__`). ::

        >>> s = BitArray(ue=423)
        >>> s += BitArray(ue=12)
        >>> s.read('ue')
        423
        >>> s.read('ue')
        12

.. method:: BitArray.__iand__(bs)

    ``s &= bs``

    In-place bit-wise AND between two bitstrings. If the two bitstrings are not the same length then a :exc:`ValueError` is raised.

.. method:: BitArray.__ilshift__(n)

    ``s <<= n``

    Shifts the bits in-place *n* bits to the left. The *n* right-most bits will become zeros and bits shifted off the left will be lost.

.. method:: BitArray.__imul__(n)

    ``s *= n``

    In-place concatenation of *n* copies of the current bitstring.

        >>> s = BitArray('0xbad')
        >>> s *= 3
        >>> s.hex
        'badbadbad'

.. method:: BitArray.__ior__(bs)

    ``s |= bs``

    In-place bit-wise OR between two bitstrings. If the two bitstrings are not the same length then a :exc:`ValueError` is raised.

.. method:: BitArray.__irshift__(n)

    ``s >>= n``

    Shifts the bits in-place *n* bits to the right. The *n* left-most bits will become zeros and bits shifted off the right will be lost.

.. method:: BitArray.__ixor__(bs)

    ``s ^= bs``

    In-place bit-wise XOR between two bitstrings. If the two bitstrings are not the same length then a :exc:`ValueError` is raised.

.. method:: BitArray.__setitem__(key, value)

    ``s1[start:end:step] = s2``

    Replaces the slice specified with a new value. ::

        >>> s = BitArray('0x00000000')
        >>> s[::8] = '0xf'
        >>> print(s)
        0x80808080
        >>> s[-12:] = '0xf'
        >>> print(s)
        0x80808f

