Optimize protobuf varint decoder for ESPHome use case (#8791)

This commit is contained in:
J. Nick Koston 2025-05-15 00:16:25 -05:00 committed by Jesse Hills
parent 2341ff651a
commit c7e62d1279
No known key found for this signature in database
GPG Key ID: BEAAE804EFD8E83A

View File

@ -20,16 +20,26 @@ class ProtoVarInt {
explicit ProtoVarInt(uint64_t value) : value_(value) {} explicit ProtoVarInt(uint64_t value) : value_(value) {}
static optional<ProtoVarInt> parse(const uint8_t *buffer, uint32_t len, uint32_t *consumed) { static optional<ProtoVarInt> parse(const uint8_t *buffer, uint32_t len, uint32_t *consumed) {
if (consumed != nullptr) if (len == 0) {
*consumed = 0; if (consumed != nullptr)
*consumed = 0;
if (len == 0)
return {}; return {};
}
uint64_t result = 0; // Most common case: single-byte varint (values 0-127)
uint8_t bitpos = 0; if ((buffer[0] & 0x80) == 0) {
if (consumed != nullptr)
*consumed = 1;
return ProtoVarInt(buffer[0]);
}
for (uint32_t i = 0; i < len; i++) { // General case for multi-byte varints
// Since we know buffer[0]'s high bit is set, initialize with its value
uint64_t result = buffer[0] & 0x7F;
uint8_t bitpos = 7;
// Start from the second byte since we've already processed the first
for (uint32_t i = 1; i < len; i++) {
uint8_t val = buffer[i]; uint8_t val = buffer[i];
result |= uint64_t(val & 0x7F) << uint64_t(bitpos); result |= uint64_t(val & 0x7F) << uint64_t(bitpos);
bitpos += 7; bitpos += 7;
@ -40,7 +50,9 @@ class ProtoVarInt {
} }
} }
return {}; if (consumed != nullptr)
*consumed = 0;
return {}; // Incomplete or invalid varint
} }
uint32_t as_uint32() const { return this->value_; } uint32_t as_uint32() const { return this->value_; }