Inspections#
Once you’ve created a Tibs you can treat it very like an array of bits.
Indexing and slicing#
The default behaviour for indexing and slicing should hold no surprises.
Indexing returns a bool, slicing returns a new Tibs:
>>> t = Tibs('0x0f')
>>> t[0]
False
>>> t[-1]
True
>>> t[:4]
Tibs('0x0')
>>> t[-4:]
Tibs('0xf')
You can also use extended slices:
>>> t[::-1].bin
'11110000'
>>> t[::2].bin
'0011'
A Mutibs can also have bits and slices set:
>>> m = Mutibs('0xff01')
>>> m[0] = 0
>>> m[-4:] = '0xbeef'
>>> m
Mutibs('0x7f0beef')
Information methods#
count#
To count the number of times a bit value or sequence of bits occurs use the Tibs.count() method:
>>> t = Tibs.from_random(100_000_000)
>>> t.count(1)
49996739
>>> t.count([1, 0, 1])
12503821
Counting should be fast, especially when just counting the number 1 or 0.
find / rfind#
Use Tibs.find() to find the first occurrence of a bit pattern, and
Tibs.rfind() to search from the right. Both methods return the bit index of
the match, or None if no match is found:
>>> t = Tibs('0b0011010101100')
>>> t.find('0b101')
3
>>> t.rfind('0b101')
7
>>> t.find('0b111')
None
The pattern can be anything that can be promoted to a Tibs: a binary string,
bytes, a list of bool-like values, or another Tibs.
The optional start and end arguments restrict the search to a slice of
the data, using the same half-open convention as Python slicing. If you know the
pattern can only start on a byte boundary, set byte_aligned=True. This is
often faster for scanning binary files or network frames:
>>> capture = Tibs('0x00ffaa551122aa553344')
>>> capture.find('0xaa55', byte_aligned=True)
16
The in operator is a convenient shorthand when you only care whether the
pattern exists:
>>> '0xaa55' in capture
True
find_all / find_all_iter#
Use Tibs.find_all() to get every matching start position:
>>> t = Tibs('0b10100101')
>>> t.find_all('0b101')
[0, 5]
Matches may overlap. This is useful when searching for bit patterns rather than tokens:
>>> Tibs('0b1111').find_all('0b11')
[0, 1, 2]
For large inputs, Tibs.find_all_iter() avoids building the whole list up
front:
>>> t = Tibs('0b10100101')
>>> for pos in t.find_all_iter('0b101'):
... print(pos)
0
5
There is also Tibs.rfind_all_iter(), which yields matches from right to
left. Iterator forms are only available on Tibs; convert a Mutibs with
Mutibs.to_tibs() first if you need them.
starts_with / ends_with#
The Tibs.starts_with() and Tibs.ends_with() methods test prefixes and
suffixes without spelling out slice boundaries:
>>> packet = Tibs('0xaa551234')
>>> packet.starts_with('0xaa55')
True
>>> packet.ends_with('0x1234')
True
any / all#
The Tibs.any() and Tibs.all() methods mirror Python’s built-in
any() and all(), but operate directly on the stored bits:
>>> Tibs('0b0001').any()
True
>>> Tibs('0b0001').all()
False
>>> Tibs.from_ones(8).all()
True
They are most useful when the bit sequence itself is the data, for example when checking whether a mask has any flags set, or whether every flag in a required set is present.