Skip to content

Commit a728dcf

Browse files
performance improvements
1 parent 94bd18b commit a728dcf

4 files changed

Lines changed: 44 additions & 10 deletions

File tree

‎.pylintrc‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
[MAIN]
2+
# make sure tests/ resolves science_mode_4 against the local src/ package
3+
# instead of whatever version happens to be installed in site-packages
4+
init-hook='import sys; sys.path.insert(0, "src")'
25
max-line-length=150
36
max-attributes=15
47
max-branches=15

‎src/science_mode_4/utils/bit_vector.py‎

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ def set_length(self, new_length: int):
5959
"""Set length to new_length, does preserve current data"""
6060
length_difference = new_length - len(self._data)
6161
if length_difference > 0:
62-
self.extend(BitVector.init_from_int(0, length_difference))
62+
self._data.extend([0] * length_difference)
6363
elif length_difference < 0:
64-
self._data = self._data[0:new_length]
64+
del self._data[new_length:]
6565

6666

6767
def extend(self, value: "BitVector"):
@@ -70,6 +70,23 @@ def extend(self, value: "BitVector"):
7070
self._data += value._data # pylint: disable=protected-access
7171

7272

73+
def extend_bits_from_int(self, value: int, bit_count: int):
74+
"""Appends bit_count bits (LSB first) taken from value at the end, without
75+
the intermediate zero-fill-then-overwrite of set_length() + __setitem__()"""
76+
self._data.extend((value >> x) & 0x1 for x in range(bit_count))
77+
78+
79+
def set_bits_from_int(self, value: int, position: int, bit_count: int):
80+
"""Sets bit_count bits (LSB first) taken from value starting at position, extending
81+
length if necessary. Skips the per-bit bounds/type validation of __setitem__(),
82+
which is redundant here because position/bit_count are controlled by the caller"""
83+
new_length = max(len(self._data), position + bit_count)
84+
self.set_length(new_length)
85+
data = self._data
86+
for x in range(bit_count):
87+
data[position + x] = (value >> x) & 0x1
88+
89+
7390
def get_bytes(self) -> bytes:
7491
"""Convert to bytes"""
7592
result = bytearray()

‎src/science_mode_4/utils/byte_builder.py‎

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,7 @@ def set_bit_to_position(self, value: int, bit_position: int, bit_count: int):
4949
Set bits starting with bit_position and a count of bit_count to value
5050
This method extends data to make room for value
5151
"""
52-
new_length = max(len(self._data), bit_position + bit_count)
53-
self._data.set_length(new_length)
54-
for x in range(bit_count):
55-
self._data[bit_position + x] = (value >> x) & 0x1
52+
self._data.set_bits_from_int(value, bit_position, bit_count)
5653

5754

5855
def set_bytes_to_position(self, value: bytes, byte_position: int, byte_count: int):
@@ -97,7 +94,4 @@ def __str__(self) -> str:
9794

9895
def _append_byte(self, value: int):
9996
"""Append value at the end of data, value is treated as byte"""
100-
start = len(self._data)
101-
self._data.set_length(start + 8)
102-
for x in range(8):
103-
self._data[start + x] = (value >> x) & 0x1
97+
self._data.extend_bits_from_int(value, 8)

‎tests/test_bit_vector.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,26 @@ def test_extend_appends_bits_from_other_bitvector():
7878
assert list(bv) == [1, 0, 1]
7979

8080

81+
def test_extend_bits_from_int_appends_lsb_first():
82+
bv = BitVector.init_from_int(0b1, 1)
83+
bv.extend_bits_from_int(0b101, 3)
84+
assert list(bv) == [1, 1, 0, 1]
85+
assert bv.get_bytes() == bytes([0b1011])
86+
87+
88+
def test_set_bits_from_int_extends_length():
89+
bv = BitVector()
90+
bv.set_bits_from_int(0b101, 2, 3)
91+
assert len(bv) == 5
92+
assert list(bv) == [0, 0, 1, 0, 1]
93+
94+
95+
def test_set_bits_from_int_overwrites_existing_range():
96+
bv = BitVector.init_from_int(0b1111, 4)
97+
bv.set_bits_from_int(0b00, 1, 2)
98+
assert list(bv) == [1, 0, 0, 1]
99+
100+
81101
def test_extend_ignores_non_bitvector_argument():
82102
# extend() silently does nothing if value is not a BitVector instance
83103
bv = BitVector.init_from_int(0b1, 1)

0 commit comments

Comments
 (0)