mirror of
https://github.com/esphome/esphome.git
synced 2026-09-18 02:28:42 +00:00
[api] Add 2-byte inline fast path for sint32 varint encode/size
Add encode_varint_raw_short() and ProtoSize::varint_short() that inline both the 1-byte and 2-byte varint paths, falling back to the noinline slow path for 3+ bytes. Use these for sint32 fields (zigzag encoding), where values like RSSI (-100 to 0) produce zigzag values that are 1-2 bytes. This avoids a function call for the common case without bloating the generic encode_varint_raw fast path.
This commit is contained in:
@@ -2252,7 +2252,7 @@ void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer &buffer) const {
|
||||
buffer.write_raw_byte(8);
|
||||
buffer.encode_varint_raw_64(this->address);
|
||||
buffer.write_raw_byte(16);
|
||||
buffer.encode_varint_raw(encode_zigzag32(this->rssi));
|
||||
buffer.encode_varint_raw_short(encode_zigzag32(this->rssi));
|
||||
buffer.encode_uint32(3, this->address_type);
|
||||
buffer.write_raw_byte(34);
|
||||
buffer.encode_varint_raw(this->data_len);
|
||||
|
||||
@@ -207,6 +207,22 @@ class ProtoWriteBuffer {
|
||||
}
|
||||
this->encode_varint_raw_slow_(value);
|
||||
}
|
||||
/// Encode a varint that is expected to be 1-2 bytes (e.g. zigzag RSSI, small lengths).
|
||||
/// Inlines both the 1-byte and 2-byte paths; falls back to slow path for 3+ bytes.
|
||||
inline void ESPHOME_ALWAYS_INLINE encode_varint_raw_short(uint32_t value) {
|
||||
if (value < 128) [[likely]] {
|
||||
this->debug_check_bounds_(1);
|
||||
*this->pos_++ = static_cast<uint8_t>(value);
|
||||
return;
|
||||
}
|
||||
if (value < 16384) [[likely]] {
|
||||
this->debug_check_bounds_(2);
|
||||
*this->pos_++ = static_cast<uint8_t>(value | 0x80);
|
||||
*this->pos_++ = static_cast<uint8_t>(value >> 7);
|
||||
return;
|
||||
}
|
||||
this->encode_varint_raw_slow_(value);
|
||||
}
|
||||
void encode_varint_raw_64(uint64_t value) {
|
||||
while (value > 0x7F) {
|
||||
this->debug_check_bounds_(1);
|
||||
@@ -531,6 +547,17 @@ class ProtoSize {
|
||||
return varint_wide(value);
|
||||
return varint_slow(value);
|
||||
}
|
||||
/// Size of a varint expected to be 1-2 bytes (e.g. zigzag RSSI, small lengths).
|
||||
/// Inlines both checks; falls back to slow path for 3+ bytes.
|
||||
static constexpr inline uint32_t ESPHOME_ALWAYS_INLINE varint_short(uint32_t value) {
|
||||
if (value < VARINT_THRESHOLD_1_BYTE) [[likely]]
|
||||
return 1;
|
||||
if (value < VARINT_THRESHOLD_2_BYTE) [[likely]]
|
||||
return 2;
|
||||
if (__builtin_is_constant_evaluated())
|
||||
return varint_wide(value);
|
||||
return varint_slow(value);
|
||||
}
|
||||
|
||||
private:
|
||||
// Slow path for varint >= 128, outlined to keep fast path small
|
||||
@@ -645,10 +672,10 @@ class ProtoSize {
|
||||
return value ? field_id_size + 4 : 0;
|
||||
}
|
||||
static constexpr uint32_t calc_sint32(uint32_t field_id_size, int32_t value) {
|
||||
return value ? field_id_size + varint(encode_zigzag32(value)) : 0;
|
||||
return value ? field_id_size + varint_short(encode_zigzag32(value)) : 0;
|
||||
}
|
||||
static constexpr inline uint32_t ESPHOME_ALWAYS_INLINE calc_sint32_force(uint32_t field_id_size, int32_t value) {
|
||||
return field_id_size + varint(encode_zigzag32(value));
|
||||
return field_id_size + varint_short(encode_zigzag32(value));
|
||||
}
|
||||
static constexpr uint32_t calc_int64(uint32_t field_id_size, int64_t value) {
|
||||
return value ? field_id_size + varint(value) : 0;
|
||||
|
||||
@@ -229,7 +229,7 @@ class TypeInfo(ABC):
|
||||
RAW_ENCODE_MAP: dict[str, str] = {
|
||||
"encode_uint32": "buffer.encode_varint_raw({value});",
|
||||
"encode_uint64": "buffer.encode_varint_raw_64({value});",
|
||||
"encode_sint32": "buffer.encode_varint_raw(encode_zigzag32({value}));",
|
||||
"encode_sint32": "buffer.encode_varint_raw_short(encode_zigzag32({value}));",
|
||||
"encode_sint64": "buffer.encode_varint_raw_64(encode_zigzag64({value}));",
|
||||
"encode_int64": "buffer.encode_varint_raw_64(static_cast<uint64_t>({value}));",
|
||||
"encode_bool": "buffer.write_raw_byte({value} ? 0x01 : 0x00);",
|
||||
|
||||
Reference in New Issue
Block a user