Skip to content

Commit ce684cd

Browse files
Optimised find/findall for byte aligned case.
Bug #326.
1 parent c8c7f74 commit ce684cd

3 files changed

Lines changed: 22 additions & 3 deletions

File tree

bitstring/bitstore.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,24 @@ def rfind(self, bs: BitStore, start: int, end: int, bytealigned: bool = False):
131131
return -1
132132

133133
def findall_msb0(self, bs: BitStore, start: int, end: int, bytealigned: bool = False) -> Iterator[int]:
134+
if bytealigned is True and len(bs) % 8 == 0:
135+
# Special case, looking for whole bytes on whole byte boundaries
136+
bytes_ = bs.tobytes()
137+
# Round up start byte to next byte, and round end byte down.
138+
# We're only looking for whole bytes, so can ignore bits at either end.
139+
start_byte = (start + 7) // 8
140+
end_byte = end // 8
141+
b = self._bitarray[start_byte * 8: end_byte * 8].tobytes()
142+
byte_pos = 0
143+
bytes_to_search = end_byte - start_byte
144+
while byte_pos < bytes_to_search:
145+
byte_pos = b.find(bytes_, byte_pos)
146+
if byte_pos == -1:
147+
break
148+
yield (byte_pos + start_byte) * 8
149+
byte_pos = byte_pos + 1
150+
return
151+
# General case
134152
i = self._bitarray.itersearch(bs._bitarray, start, end)
135153
if not bytealigned:
136154
for p in i:

release_notes.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ A couple more minor bug fixes.
1010
* Sometimes a ValueError was being raised instead of a ReadError. Bug #325.
1111
* Initialising a bitstring from None now raises a TypeError rather than generating
1212
an empty bitstring. Bug #323.
13+
* Fixed performance regression for find/findall in some situations. Bug #326.
1314

1415
-------------------------
1516
April 2024: version 4.2.1

tests/test_bitstream.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,10 @@ def test_find_corner_cases(self):
131131

132132
def test_find_bytes(self):
133133
s = BitStream.fromstring('0x010203040102ff')
134-
assert not s.find('0x05', bytealigned=True)
135-
assert s.find('0x02', bytealigned=True)
134+
assert s.find('0x05', bytealigned=True) ==()
135+
assert s.find('0x02', bytealigned=True) == (8,)
136136
assert s.read(16).hex == '0203'
137-
assert s.find('0x02', start=s.bitpos, bytealigned=True)
137+
assert s.find('0x02', start=s.bitpos, bytealigned=True) == (40,)
138138
s.read(1)
139139
assert not s.find('0x02', start=s.bitpos, bytealigned=True)
140140

0 commit comments

Comments
 (0)