From 29b5b3eba1837820251564057e0d2e727db1f5ef Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 27 Mar 2026 15:48:52 -1000 Subject: [PATCH] Move CallbackManager growth path out-of-line Split add_() into inline fast path (size check + store) and noinline cold grow_() for the allocation/memcpy/delete path. Prevents the cold growth code from bloating every call site. --- esphome/core/helpers.h | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 1557ca07900..99eabb704f4 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -1842,23 +1842,30 @@ template class CallbackManager { protected: template friend class LazyCallbackManager; /// Non-template core to avoid code duplication per lambda type. + /// Inline fast path; cold growth path is out-of-line in grow_(). void add_(CbType cb) { - if (this->size_ == this->capacity_) { - auto *new_data = new CbType[this->size_ + 1]; - if (this->data_) { - __builtin_memcpy(new_data, this->data_, this->size_ * sizeof(CbType)); - delete[] this->data_; - } - this->data_ = new_data; - this->capacity_ = this->size_ + 1; - } + if (this->size_ == this->capacity_) + this->grow_(); this->data_[this->size_++] = cb; } + /// Out-of-line cold path: allocate exact size needed. + void grow_(); CbType *data_{nullptr}; uint16_t size_{0}; uint16_t capacity_{0}; }; +/// Out-of-line cold growth path for CallbackManager::add_(). +template __attribute__((noinline, cold)) void CallbackManager::grow_() { + auto *new_data = new CbType[this->size_ + 1]; + if (this->data_) { + __builtin_memcpy(new_data, this->data_, this->size_ * sizeof(CbType)); + delete[] this->data_; + } + this->data_ = new_data; + this->capacity_ = this->size_ + 1; +} + template class LazyCallbackManager; /** Lazy-allocating callback manager that only allocates memory when callbacks are registered.