-
Notifications
You must be signed in to change notification settings - Fork 0
Improve serialization/deserialization for raw bytes #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ | |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause | ||
| """ | ||
|
|
||
| import array as _array | ||
| import sys | ||
| import struct | ||
|
|
||
|
|
@@ -143,6 +144,40 @@ def read_multi(self, pack: str, size: int) -> Tuple[Any, ...]: | |
| self._pos += size | ||
| return v | ||
|
|
||
| def write_sequence(self, code: str, values) -> 'Buffer': | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The (de)serialization improvements look good. Could you add comments or docstrings to describe why these functions are necessary and perhaps how they address the |
||
| """Serialize a homogeneous sequence of primitives in one shot. | ||
|
|
||
| Using array.array instead of struct.pack with a length-prefixed format | ||
| string (e.g. "100f") avoids building that string on every call and lets | ||
| the C array machinery do the copy in bulk. byteswap() is applied when | ||
| the buffer's wire endianness differs from the host's native order. | ||
| 'B' (uint8) is special-cased because array.array('B').tobytes() and | ||
| bytes() are equivalent but bytes() is marginally faster for that type. | ||
| """ | ||
| if code == 'B': | ||
| return self.write_bytes(bytes(values)) | ||
| a = _array.array(code, values) | ||
| if (self.endianness == Endianness.Little) != (sys.byteorder == 'little'): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems this check is redundant, right? See the class definition:
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like even when the endianness is being initialized in the constructor, there are parts of the code that can set it again, based on the CDR encapsulation header in |
||
| a.byteswap() | ||
| return self.write_bytes(a.tobytes()) | ||
|
|
||
| def read_sequence(self, code: str, length: int) -> list: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Have you considered adding unit tests for these new functions? This PR is making performance improvement assertions but lacks a concrete metric showing how it improves the situation. Consider adding a metric to show the read/write performance with & without the
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done! I added some tests, as well as some metrics in the PR description There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for adding these comments and tests. |
||
| """Deserialize a homogeneous sequence of primitives in one shot. | ||
|
|
||
| Mirrors write_sequence: frombytes() fills the array directly from the | ||
| buffer slice without per-element struct.unpack calls, then byteswap() | ||
| fixes up the byte order when wire and host endianness differ. | ||
| """ | ||
| if code == 'B': | ||
| return list(self.read_bytes(length)) | ||
| a = _array.array(code) | ||
| nbytes = a.itemsize * length | ||
| a.frombytes(self._bytes[self._pos:self._pos + nbytes]) | ||
| self._pos += nbytes | ||
| if (self.endianness == Endianness.Little) != (sys.byteorder == 'little'): | ||
| a.byteswap() | ||
| return a.tolist() | ||
|
|
||
| def asbytes(self) -> bytes: | ||
| return bytes(self._bytes[0:self._pos]) | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meta: Some tests are supposed to be run. Can we verify that all tests still pass CI? And add tests if needed? Should we set up a github action to run these tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, let me take a look at it