From b236d097342fed4be0152e59a20c70294688bc59 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 1 Apr 2026 09:56:44 -1000 Subject: [PATCH] [api] Move add_item/add_item_front inline and remove push_item Both are only called from one site each. Moving them inline lets the compiler inline push_back directly into the caller without a function call barrier. Removes the now-unnecessary push_item wrapper. --- esphome/components/api/api_connection.cpp | 32 ----------------------- esphome/components/api/api_connection.h | 24 ++++++++++++++--- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index bbd6d4f049..c882d48112 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -2072,38 +2072,6 @@ void APIConnection::on_fatal_error() { this->flags_.remove = true; } -void __attribute__((flatten)) APIConnection::DeferredBatch::add_item(EntityBase *entity, uint8_t message_type, - uint8_t estimated_size, uint8_t aux_data_index) { - // Check if we already have a message of this type for this entity - // This provides deduplication per entity/message_type combination - // O(n) but optimized for RAM and not performance. - // Skip deduplication for events - they are edge-triggered, every occurrence matters -#ifdef USE_EVENT - if (message_type != EventResponse::MESSAGE_TYPE) -#endif - { - for (const auto &item : items) { - if (item.entity == entity && item.message_type == message_type) - return; // Already queued - } - } - // No existing item found (or event), add new one - this->push_item({entity, message_type, estimated_size, aux_data_index}); -} - -void __attribute__((flatten)) -APIConnection::DeferredBatch::add_item_front(EntityBase *entity, uint8_t message_type, uint8_t estimated_size) { - // Add high priority message and swap to front - // This avoids expensive vector::insert which shifts all elements - // Note: We only ever have one high-priority message at a time (ping OR disconnect) - // If we're disconnecting, pings are blocked, so this simple swap is sufficient - this->push_item({entity, message_type, estimated_size, AUX_DATA_UNUSED}); - if (items.size() > 1) { - // Swap the new high-priority item to the front - std::swap(items.front(), items.back()); - } -} - bool APIConnection::send_message_smart_(EntityBase *entity, uint8_t message_type, uint8_t estimated_size, uint8_t aux_data_index) { if (this->should_send_immediately_(message_type) && this->helper_->can_write_without_blocking()) { diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 3187a6df05..972871b076 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -644,10 +644,28 @@ class APIConnection final : public APIServerConnectionBase { // Add item to the batch (with deduplication) void add_item(EntityBase *entity, uint8_t message_type, uint8_t estimated_size, - uint8_t aux_data_index = AUX_DATA_UNUSED); + uint8_t aux_data_index = AUX_DATA_UNUSED) { + // Dedup: O(n) scan but optimized for RAM over performance + // Skip deduplication for events - they are edge-triggered, every occurrence matters +#ifdef USE_EVENT + if (message_type != EventResponse::MESSAGE_TYPE) +#endif + { + for (const auto &item : items) { + if (item.entity == entity && item.message_type == message_type) + return; // Already queued + } + } + items.push_back({entity, message_type, estimated_size, aux_data_index}); + } // Add item to the front of the batch (for high priority messages like ping) - void add_item_front(EntityBase *entity, uint8_t message_type, uint8_t estimated_size); - void push_item(const BatchItem &item) { items.push_back(item); } + void add_item_front(EntityBase *entity, uint8_t message_type, uint8_t estimated_size) { + // Swap to front avoids expensive vector::insert which shifts all elements + items.push_back({entity, message_type, estimated_size, AUX_DATA_UNUSED}); + if (items.size() > 1) { + std::swap(items.front(), items.back()); + } + } // Clear all items void clear() {