-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Change to using a builder pattern for buffer reader. #3497
Change to using a builder pattern for buffer reader. #3497
Conversation
* @note The read can put the reader in a failed-status state if there are | ||
* not enough octets available. Callers must either continue to do | ||
* more reads on the return value or check its status to see whether | ||
* the sequence of reads that has been performed succeeded. | ||
*/ | ||
CHECK_RETURN_VALUE |
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.
do these still need CHECK_RETURN_VALUE?
Should that be needed for StatusCode instead?
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.
These do still need CHECK_RETURN_VALUE
, so people don't forget to call StatusCode
. Adding it to StatusCode
is a good idea; I will do that.
} | ||
|
||
// Explicit Read instantiations for the data types we want to support. | ||
template void Reader::Read(uint8_t *); |
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.
I noticed that our size actually increased. How about we place these in the header to allow for inlining instead? Does that make any difference in binary size?
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.
The size increased because we only have a few callsites of each function so far. With inlining, we pay N bytes per callsite. With them out of line, we pay 4N + M * (# of callsites) bytes, where M is the cost of the function call; M < N.
I did measurements after adding some more callsites (as part of the fix for #2168) and at that point the out-of-line version is smaller than the inline one.
SuccessOrExit(err); | ||
|
||
if (flags.Has(Header::FlagValues::kVendorIdPresent)) | ||
{ | ||
uint16_t vendor_id; | ||
err = reader.Read16(&vendor_id); | ||
err = reader.Read16(&vendor_id).StatusCode(); |
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.
why don't we read the vendor id directly? is it the wrong size/type? should we instead make the type match?
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.
mVendorId
is an Optional<uint16_t>
. So yes,it's the wrong type for reading directly, but it's the right type for what we are trying to express.
We could address this by adding a method on Optional
that sets it into the "have value" state and returns a reference to the value to be filled in. Then we could write something like:
err = reader.Read16(&mVendorId.SetValue()).StatusCode();
or something. I wasn't sure whether it was desirable to add such an API to Optional
; I've seen it on Optional
-like things in the past, but there are safety tradeoffs with having an API that temporarily leaves the object in an invalid state...
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.
Ah, forgot about optional. Existing code makes sense then.
For callers that read multiple things in a row with the reads not being conditional on what was already read, this leads to slightly smaller code. And in general it can lead to more readable code.
5cabe32
to
73c33ac
Compare
Size increase report for "nrfconnect-example-build" from 76e0d7b
Full report output
|
Size increase report for "esp32-example-build" from 76e0d7b
Full report output
|
|
Yes, I considered that approach (see #2914 approach number 1), but in practice we only end up reading little-endian things in CHIP as far as I can tell, at least once you move above the IP packet layer. And we haven't had any use cases for mixed-endian reading from a single buffer so far. So I opted for having a simpler API for each read at the expense of a bit of flexibility we don't actually plan to use. |
For callers that read multiple things in a row with the reads not
being conditional on what was already read, this leads to slightly
smaller code. And in general it can lead to more readable code.
Problem
Want to use a builder pattern for our buffer reader.
Summary of Changes
Change the API to support this pattern.
Fixes #3495