Packing small integers#

If every value is known to fit in a small fixed width, a Tibs can store the values densely without allocating a Python object per value. This is useful for compact lookup tables, quantized levels, or small counters.

from tibs import Tibs


def pack_values(values, width):
    max_value = 1 << width
    for value in values:
        if not 0 <= value < max_value:
            raise ValueError("value does not fit in the requested width")
    return Tibs.from_joined(Tibs.from_u(value, width) for value in values)


def unpack_values(bits, width):
    return [chunk.u for chunk in bits.chunks(width)]


levels = [3, 17, 31, 0, 12, 4]
packed = pack_values(levels, width=5)

assert len(packed) == 30
assert packed.bin == "000111000111111000000110000100"
assert unpack_values(packed, width=5) == levels

try:
    pack_values([32], width=5)
except ValueError:
    pass
else:
    raise AssertionError("expected a value-width error")

The packed value in this example is only 30 bits long. It does not need to be a whole number of bytes until you choose to serialize it.