diff --git a/esphome/components/api/proto.cpp b/esphome/components/api/proto.cpp index 2f51c5c2a6b..fb229928e5a 100644 --- a/esphome/components/api/proto.cpp +++ b/esphome/components/api/proto.cpp @@ -10,6 +10,16 @@ static const char *const TAG = "api.proto"; uint32_t ProtoSize::varint_slow(uint32_t value) { return varint_wide(value); } +void ProtoWriteBuffer::encode_varint_raw_slow_(uint32_t value) { + do { + this->debug_check_bounds_(1); + *this->pos_++ = static_cast(value | 0x80); + value >>= 7; + } while (value > 0x7F); + this->debug_check_bounds_(1); + *this->pos_++ = static_cast(value); +} + #ifdef USE_API_VARINT64 optional ProtoVarInt::parse_wide(const uint8_t *buffer, uint32_t len, uint32_t *consumed, uint32_t result32) { diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index b6d68885b8f..adde0a8a85b 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -240,14 +240,13 @@ class ProtoWriteBuffer { ProtoWriteBuffer(std::vector *buffer) : buffer_(buffer), pos_(buffer->data() + buffer->size()) {} ProtoWriteBuffer(std::vector *buffer, size_t write_pos) : buffer_(buffer), pos_(buffer->data() + write_pos) {} - void encode_varint_raw(uint32_t value) { - while (value > 0x7F) { + inline void ESPHOME_ALWAYS_INLINE encode_varint_raw(uint32_t value) { + if (value < 128) [[likely]] { this->debug_check_bounds_(1); - *this->pos_++ = static_cast(value | 0x80); - value >>= 7; + *this->pos_++ = static_cast(value); + return; } - this->debug_check_bounds_(1); - *this->pos_++ = static_cast(value); + this->encode_varint_raw_slow_(value); } void encode_varint_raw_64(uint64_t value) { while (value > 0x7F) { @@ -378,6 +377,9 @@ class ProtoWriteBuffer { std::vector *get_buffer() const { return buffer_; } protected: + // Slow path for encode_varint_raw values >= 128, outlined to keep fast path small + void encode_varint_raw_slow_(uint32_t value) __attribute__((noinline)); + #ifdef ESPHOME_DEBUG_API void debug_check_bounds_(size_t bytes, const char *caller = __builtin_FUNCTION()); void debug_check_encode_size_(uint32_t field_id, uint32_t expected, ptrdiff_t actual); @@ -512,7 +514,7 @@ class ProtoSize { * @return The number of bytes needed to encode the value */ static constexpr inline uint32_t ESPHOME_ALWAYS_INLINE varint(uint32_t value) { - if (value < 128) + if (value < 128) [[likely]] return 1; // Fast path: 7 bits, most common case if (__builtin_is_constant_evaluated()) return varint_wide(value);