From 7f5409214b66f0b79e8016913397d54b50466137 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 27 Mar 2026 16:14:59 -1000 Subject: [PATCH] Use init_array_from helper for optimal codegen Uses memcpy for trivially copyable types, element-wise copy otherwise. ESPHOME_DEBUG_ASSERT catches size mismatches in integration tests. --- esphome/components/text_sensor/filter.h | 6 +----- esphome/core/helpers.h | 15 +++++++++++++++ tests/integration/fixtures/.gitignore | 5 +++++ 3 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 tests/integration/fixtures/.gitignore diff --git a/esphome/components/text_sensor/filter.h b/esphome/components/text_sensor/filter.h index 0366c7fb41b..07832af9e2b 100644 --- a/esphome/components/text_sensor/filter.h +++ b/esphome/components/text_sensor/filter.h @@ -165,11 +165,7 @@ bool map_filter_apply(const Substitution *mappings, size_t count, std::string &v template class MapFilter : public Filter { public: explicit MapFilter(const std::initializer_list &mappings) { - ESPHOME_DEBUG_ASSERT(mappings.size() == N); - size_t i = 0; - for (const auto &m : mappings) { - this->mappings_[i++] = m; - } + init_array_from(this->mappings_, mappings); } bool new_value(std::string &value) override { return map_filter_apply(this->mappings_.data(), N, value); } diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 82c6b3833ce..51feaa57c50 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -497,6 +497,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 diff --git a/tests/integration/fixtures/.gitignore b/tests/integration/fixtures/.gitignore new file mode 100644 index 00000000000..d8b4157aef9 --- /dev/null +++ b/tests/integration/fixtures/.gitignore @@ -0,0 +1,5 @@ +# Gitignore settings for ESPHome +# This is an example and may include too much for your use-case. +# You can modify this file to suit your needs. +/.esphome/ +/secrets.yaml