Skip to content

Commit

Permalink
Improved as_binary() and slice operation performance.
Browse files Browse the repository at this point in the history
  • Loading branch information
eerimoq committed Nov 26, 2017
1 parent d6bc796 commit fcca0a3
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 36 deletions.
85 changes: 56 additions & 29 deletions bincopy.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,21 +446,25 @@ def __getitem__(self, key):
"""

if isinstance(key, slice):
if key.start is not None:
key = slice(key.start - self.minimum_address,
key.stop,
key.step)
if key.start is None:
minimum_address = self.minimum_address
else:
minimum_address = key.start

if key.stop is not None:
key = slice(key.start,
key.stop - self.minimum_address,
key.step)
if key.stop is None:
maximum_address = self.maximum_address
else:
maximum_address = key.stop

return self.as_binary()[key]
size = maximum_address - minimum_address
else:
relative_address = key - self.minimum_address
if key < self.minimum_address or key >= self.maximum_address:
return b''

minimum_address = key
size = 1

return self.as_binary()[relative_address:relative_address + 1]
return self.as_binary(minimum_address)[:size]

def __len__(self):
return len(self.segments)
Expand Down Expand Up @@ -645,9 +649,14 @@ def as_srec(self, number_of_data_bytes=32, address_length_bits=32):
"""Format the binary file as Motorola S-Records records and return
them as a string.
:param number_of_data_bytes: Number of data bytes in each record.
:param address_length_bits: Number of address bits in each record.
:returns: A string of Motorola S-Records records separated by a newline.
:param number_of_data_bytes: Number of data bytes in each
record.
:param address_length_bits: Number of address bits in each
record.
:returns: A string of Motorola S-Records records separated by
a newline.
"""

Expand Down Expand Up @@ -694,9 +703,14 @@ def as_ihex(self, number_of_data_bytes=32, address_length_bits=32):
"""Format the binary file as Intel HEX records and return them as a
string.
:param number_of_data_bytes: Number of data bytes in each record.
:param address_length_bits: Number of address bits in each record.
:returns: A string of Intel HEX records separated by a newline.
:param number_of_data_bytes: Number of data bytes in each
record.
:param address_length_bits: Number of address bits in each
record.
:returns: A string of Intel HEX records separated by a
newline.
"""

Expand Down Expand Up @@ -747,12 +761,14 @@ def as_ihex(self, number_of_data_bytes=32, address_length_bits=32):
def as_binary(self, minimum_address=None, padding=None):
"""Return a byte string of all data.
:param minimum_address: Start address of the resulting binary data. Must
be less than or equal to the start address of
the binary data.
:param padding: Word value of the padding between non-adjacent segments.
Give as a bytes object of length 1 when the word size is 8 bits, length 2 when
:param minimum_address: Absolute start address of the
resulting binary data.
:param padding: Word value of the padding between non-adjacent
segments. Give as a bytes object of length 1
when the word size is 8 bits, length 2 when
the word size is 16 bits, and so on.
:returns: A byte string of the binary data.
"""
Expand All @@ -767,14 +783,21 @@ def as_binary(self, minimum_address=None, padding=None):
padding = b'\xff' * self.word_size_bytes

if minimum_address is not None:
if minimum_address > self.minimum_address:
raise Error('the selected start address must be lower or '
'equal to the start address of the binary')
if minimum_address >= self.maximum_address:
return b''

current_maximum_address = minimum_address

for address, data in self.segments.iter():
address //= self.word_size_bytes

if address < current_maximum_address:
if address + len(data) <= current_maximum_address:
continue

data = data[current_maximum_address - address:]
current_maximum_address = address

res += padding * (address - current_maximum_address)
res += data
current_maximum_address = address + (len(data) // self.word_size_bytes)
Expand All @@ -786,11 +809,15 @@ def as_array(self, minimum_address=None, padding=None, separator=', '):
separator. This function can be used to generate array
initialization code for c and other languages.
:param minimum_address: Start address of the resulting binary data. Must
be less than or equal to the start address of
the binary data.
:param padding: Value of the padding between not adjacent segments.
:param minimum_address: Start address of the resulting binary
data. Must be less than or equal to
the start address of the binary data.
:param padding: Value of the padding between not adjacent
segments.
:param separator: Value separator.
:returns: A string of the separated values.
"""
Expand Down
30 changes: 23 additions & 7 deletions tests/test_bincopy.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,20 +123,32 @@ def test_binary(self):
self.assertEqual(binfile.as_binary(minimum_address=0,
padding=b'\x00'), fin.read())

# Exclude first byte ad readd it to test adjecent add before.
# Exclude first byte and read it to test adjecent add before.
binfile.exclude(0, 1)
binfile.add_binary(b'1')
with open('tests/files/binary3.bin', 'rb') as fin:
reference = b'1' + fin.read()[1:]
self.assertEqual(binfile.as_binary(minimum_address=0,
padding=b'\x00'), reference)

# Dump with too high start address
with self.assertRaises(bincopy.Error) as cm:
binfile.as_binary(minimum_address=512)
self.assertEqual(str(cm.exception),
'the selected start address must be lower or equal '
'to the start address of the binary')
# Basic checks.
self.assertEqual(binfile.minimum_address, 0)
self.assertEqual(binfile.maximum_address, 184)
self.assertEqual(len(binfile), 184)

# Dump with start address beyond end of binary.
self.assertEqual(binfile.as_binary(minimum_address=512), b'')

# Dump with start address one at maximum address.
self.assertEqual(binfile.as_binary(minimum_address=184), b'')

# Dump with start address one before maximum address.
self.assertEqual(binfile.as_binary(minimum_address=183), b'\n')

# Dump with start address one after minimum address.
self.assertEqual(binfile.as_binary(minimum_address=1,
padding=b'\x00'),
reference[1:])

def test_add(self):
binfile = bincopy.BinFile()
Expand Down Expand Up @@ -509,6 +521,10 @@ def test_set_get_item(self):
self.assertEqual(binfile[:], b'\x00\x01\x02\x03\x04\x05\xff\x07')
self.assertEqual(binfile[6], b'\xff')

# Add data at high address to test get performance.
binfile[0x10000000] = b'\x12'
self.assertEqual(binfile[0x10000000 - 1:], b'\xff\x12')

def test_header(self):
binfile = bincopy.BinFile()
binfile.add_file('tests/files/empty_main.s19')
Expand Down

0 comments on commit fcca0a3

Please sign in to comment.