Skip to content

Latest commit

 

History

History
85 lines (80 loc) · 2.88 KB

README.md

File metadata and controls

85 lines (80 loc) · 2.88 KB

Bitfield

A Python bitfield class for easier bit manipulation of integers

This Python class is motivated by a previous need of mine to iterate over the bits of a bitfield. My original solution was to build a bitstream generator that consumed bytes and produced bits. However, in order to accumulate bits into a bitfield for manipulation, it was easiest to use itertools.islice and convert to a tuple. This was quite inefficient.

Bitfield is a partial solution. While it still does not provide any kind of interface to consume the bits of a bitstream, it allows bitwise manipulations extremely easily.

Examples:

  • A Bitfield is an int, along with all of the operations that can be performed on an int:

    >>> from bitfield import Bitfield
    >>> bits = Bitfield(0b1010)
    >>> bin(bits)
    '0b1010'
    >>> bin(bits + 1)
    '0b1110'
    >>> bin(bits << 2)
    '0b101000'
    >>> bin(bits >> 2)
    '0b10'

    Unfortunately, ints are immutable, so any subclass of an int must also be immutable. Subclassing an int would provide the above functionality for free, without all of the nasty duplicated code I have, but would destroy one of the bigger reasons this class exists in the first place: mutability using __setitem__.

  • It is also possible to construct a Bitfield from bytes or bytearray objects:

    >>> from bitfield import Bitfield
    >>> bits = Bitfield(b'abcd')
    >>> bin(bits)
    '0b1100100011000110110001001100001'
  • A Bitfield also has a __len__ and a __getitem__, and is thus an iterable. This is the main difference between a Bitfield and an int.

    >>> from bitfield import Bitfield
    >>> bits = Bitfield(0b1010)
    >>> len(bits)
    4
    >>> list(bits)  # Equivalent to: [bit for bit in bits]
    [0, 1, 0, 1]
    >>> bits[0]  # Indexed least significant bit first
    0
    >>> bits[1]
    1
    >>> bin(bits[::-1])  # Note: bin(0b0101) will give '0b101'
    '0b101'
    >>> bin(bits[::2])  # Note: 0b00 == 0b0
    '0b0'
    >>> bin(bits[1::2])
    '0b11'
  • Unlike ints, Bitfields are mutable, and define a __setitem__:

    >>> from bitfield import Bitfield
    >>> bits = Bitfield(0b1010)
    >>> bits[0] = 1
    >>> bin(bits)
    '0b1011'
    >>> bits[::2] = 0b10  # Toggles bits 0 and 2
    >>> bin(bits)
    '0b1110'
  • Has an optional width:

    >>> from bitfield import Bitfield
    >>> bits = Bitfield(0b0101, width=4)
    >>> 0b0101.bit_length()
    3
    >>> len(bits)
    4
    >>> list(bits)
    [1, 0, 1, 0]
    >>> list(Bitfield(0b0101))
    [1, 0, 1]
  • Implements __delitem__:

    >>> from bitfield import Bitfield
    >>> bits = Bitfield(0b1001)
    >>> del bits[1:3]
    >>> bin(bits)
    '0b11'

TODO:

  • Test more extensively with negative numbers -- especially negative fixed width numbers.
  • Sphinx documentation