Move grow path to helpers.cpp as non-template function

Since Callback is trivially copyable regardless of signature,
the grow logic is type-independent. Move it to a concrete
function in helpers.cpp using void*/memcpy, eliminating the
template definition from the header entirely.
This commit is contained in:
J. Nick Koston
2026-03-27 15:52:33 -10:00
parent 29b5b3eba1
commit 1bdf6402a2
2 changed files with 18 additions and 15 deletions
+12
View File
@@ -22,6 +22,18 @@ namespace esphome {
static const char *const TAG = "helpers";
__attribute__((noinline, cold)) void *callback_manager_grow(void *data, uint16_t size, uint16_t &capacity,
size_t elem_size) {
uint16_t new_cap = size + 1;
auto *new_data = ::operator new(new_cap *elem_size);
if (data) {
__builtin_memcpy(new_data, data, size * elem_size);
::operator delete(data);
}
capacity = new_cap;
return new_data;
}
static const uint16_t CRC16_A001_LE_LUT_L[] = {0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440};
static const uint16_t CRC16_A001_LE_LUT_H[] = {0x0000, 0xcc01, 0xd801, 0x1400, 0xf001, 0x3c00, 0x2800, 0xe401,
+6 -15
View File
@@ -1782,6 +1782,9 @@ template<typename... Ts> struct Callback<void(Ts...)> {
}
};
/// Grow a CallbackManager's backing array to exactly size+1. Defined in helpers.cpp.
void *callback_manager_grow(void *data, uint16_t size, uint16_t &capacity, size_t elem_size);
template<typename... X> class CallbackManager;
/** Helper class to allow having multiple subscribers to a callback.
@@ -1842,30 +1845,18 @@ template<typename... Ts> class CallbackManager<void(Ts...)> {
protected:
template<typename...> 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_().
/// Inline fast path; cold growth path is in helpers.cpp via callback_manager_grow().
void add_(CbType cb) {
if (this->size_ == this->capacity_)
this->grow_();
this->data_ =
static_cast<CbType *>(callback_manager_grow(this->data_, this->size_, this->capacity_, sizeof(CbType)));
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<typename... Ts> __attribute__((noinline, cold)) void CallbackManager<void(Ts...)>::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<typename... X> class LazyCallbackManager;
/** Lazy-allocating callback manager that only allocates memory when callbacks are registered.