From 44b50055afa8291398b09eea3fa0e7b61901a474 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 7 Mar 2026 15:31:33 -1000 Subject: [PATCH 1/3] Rename varint_slow_ to varint_slow for clang-tidy naming Static methods use lower_snake_case without trailing underscore. The trailing underscore convention is for member fields only. Co-Authored-By: Claude Opus 4.6 --- esphome/components/api/proto.cpp | 2 +- esphome/components/api/proto.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/api/proto.cpp b/esphome/components/api/proto.cpp index 6348c74c5f..4f16815d1b 100644 --- a/esphome/components/api/proto.cpp +++ b/esphome/components/api/proto.cpp @@ -8,7 +8,7 @@ namespace esphome::api { static const char *const TAG = "api.proto"; -uint32_t ProtoSize::varint_slow_(uint32_t value) { +uint32_t ProtoSize::varint_slow(uint32_t value) { // value is guaranteed >= 128 here (fast path handled inline) if (value < 16384) { return 2; // 14 bits diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 2ac8dbd844..ec49964035 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -524,10 +524,10 @@ class ProtoSize { return 4; return 5; } - return varint_slow_(value); + return varint_slow(value); } // Slow path for varint >= 128, outlined to keep fast path small - static uint32_t varint_slow_(uint32_t value) __attribute__((noinline)); + static uint32_t varint_slow(uint32_t value) __attribute__((noinline)); /** * @brief Calculates the size in bytes needed to encode a uint64_t value as a varint From a5780eec54ddcfa48d0f34439135bb7dfd08d278 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 7 Mar 2026 15:41:01 -1000 Subject: [PATCH 2/3] Extract varint_wide helper to deduplicate cascade The constexpr path and the noinline slow path shared the same if/else cascade for values >= 128. Extract into a private constexpr ESPHOME_ALWAYS_INLINE helper used by both. Co-Authored-By: Claude Opus 4.6 --- esphome/components/api/proto.cpp | 13 +------------ esphome/components/api/proto.h | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/esphome/components/api/proto.cpp b/esphome/components/api/proto.cpp index 4f16815d1b..2f51c5c2a6 100644 --- a/esphome/components/api/proto.cpp +++ b/esphome/components/api/proto.cpp @@ -8,18 +8,7 @@ namespace esphome::api { static const char *const TAG = "api.proto"; -uint32_t ProtoSize::varint_slow(uint32_t value) { - // value is guaranteed >= 128 here (fast path handled inline) - if (value < 16384) { - return 2; // 14 bits - } else if (value < 2097152) { - return 3; // 21 bits - } else if (value < 268435456) { - return 4; // 28 bits - } else { - return 5; // 32 bits (maximum for uint32_t) - } -} +uint32_t ProtoSize::varint_slow(uint32_t value) { return varint_wide(value); } #ifdef USE_API_VARINT64 optional ProtoVarInt::parse_wide(const uint8_t *buffer, uint32_t len, uint32_t *consumed, diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index ec49964035..10581a7f0a 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -514,21 +514,26 @@ class ProtoSize { static constexpr inline uint32_t ESPHOME_ALWAYS_INLINE varint(uint32_t value) { if (value < 128) return 1; // Fast path: 7 bits, most common case - if (__builtin_is_constant_evaluated()) { - // Compile-time: full cascade for constexpr callers - if (value < 16384) - return 2; - if (value < 2097152) - return 3; - if (value < 268435456) - return 4; - return 5; - } + if (__builtin_is_constant_evaluated()) + return varint_wide(value); return varint_slow(value); } // Slow path for varint >= 128, outlined to keep fast path small static uint32_t varint_slow(uint32_t value) __attribute__((noinline)); + private: + // Shared cascade for values >= 128 (used by both constexpr and noinline paths) + static constexpr inline uint32_t ESPHOME_ALWAYS_INLINE varint_wide(uint32_t value) { + if (value < 16384) + return 2; + if (value < 2097152) + return 3; + if (value < 268435456) + return 4; + return 5; + } + + public: /** * @brief Calculates the size in bytes needed to encode a uint64_t value as a varint * From 8ae54656fc3607b5780a6e8152b440ae0e415a78 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 7 Mar 2026 15:41:45 -1000 Subject: [PATCH 3/3] Move varint_slow to private It has a precondition (value >= 128) and should not be callable from outside the class. Co-Authored-By: Claude Opus 4.6 --- esphome/components/api/proto.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index 10581a7f0a..b6d68885b8 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -518,10 +518,10 @@ class ProtoSize { return varint_wide(value); return varint_slow(value); } - // Slow path for varint >= 128, outlined to keep fast path small - static uint32_t varint_slow(uint32_t value) __attribute__((noinline)); private: + // Slow path for varint >= 128, outlined to keep fast path small + static uint32_t varint_slow(uint32_t value) __attribute__((noinline)); // Shared cascade for values >= 128 (used by both constexpr and noinline paths) static constexpr inline uint32_t ESPHOME_ALWAYS_INLINE varint_wide(uint32_t value) { if (value < 16384)