diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 8bb495edd2..896c5314c4 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -346,12 +346,7 @@ uint32_t get_loop_component_start_time(); template class ValueListFilter : public Filter { protected: explicit ValueListFilter(std::initializer_list> values) { - size_t i = 0; - for (const auto &v : values) { - if (i >= N) - break; - this->values_[i++] = v; - } + init_array_from(this->values_, values); } /// Check if sensor value matches any configured value (with accuracy rounding) diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 93b187d850..c7f35a2361 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -500,6 +500,21 @@ template::max()> index_type capacity_{0}; }; +/// Initialize a std::array from an initializer_list. Uses memcpy for trivially copyable types (optimal codegen), +/// falls back to element-wise copy for non-trivially copyable types (e.g. TemplatableValue). +/// N is set by code generation; ESPHOME_DEBUG_ASSERT catches mismatches in debug/integration tests. +template inline void init_array_from(std::array &dest, std::initializer_list src) { + ESPHOME_DEBUG_ASSERT(src.size() == N); + if constexpr (std::is_trivially_copyable_v) { + __builtin_memcpy(dest.data(), src.begin(), N * sizeof(T)); + } else { + size_t i = 0; + for (const auto &v : src) { + dest[i++] = v; + } + } +} + /// Fixed-capacity vector - allocates once at runtime, never reallocates /// This avoids std::vector template overhead (_M_realloc_insert, _M_default_append) /// when size is known at initialization but not at compile time