From 27c609531ddd7936b3e4ebfab42e6273cf28bd72 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 27 Mar 2026 13:34:36 -1000 Subject: [PATCH] [text_sensor] Use std::array in MapFilter --- esphome/components/text_sensor/__init__.py | 2 +- esphome/components/text_sensor/filter.cpp | 14 ++++++-------- esphome/components/text_sensor/filter.h | 22 ++++++++++++++++++---- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/esphome/components/text_sensor/__init__.py b/esphome/components/text_sensor/__init__.py index 97f394ecf7..8598fa06b2 100644 --- a/esphome/components/text_sensor/__init__.py +++ b/esphome/components/text_sensor/__init__.py @@ -136,7 +136,7 @@ async def map_filter_to_code(config, filter_id): ) for conf in config ] - return cg.new_Pvariable(filter_id, mappings) + return cg.new_Pvariable(filter_id, cg.TemplateArguments(len(mappings)), mappings) validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_") diff --git a/esphome/components/text_sensor/filter.cpp b/esphome/components/text_sensor/filter.cpp index f7c6a695fb..bc044f3a73 100644 --- a/esphome/components/text_sensor/filter.cpp +++ b/esphome/components/text_sensor/filter.cpp @@ -93,17 +93,15 @@ bool SubstituteFilter::new_value(std::string &value) { return true; } -// Map -MapFilter::MapFilter(const std::initializer_list &mappings) : mappings_(mappings) {} - -bool MapFilter::new_value(std::string &value) { - for (const auto &mapping : this->mappings_) { - if (value == mapping.from) { - value.assign(mapping.to); +// Map — non-template helper +bool map_filter_apply(const Substitution *mappings, size_t count, std::string &value) { + for (size_t i = 0; i < count; i++) { + if (value == mappings[i].from) { + value.assign(mappings[i].to); return true; } } - return true; // Pass through if no match + return true; } } // namespace esphome::text_sensor diff --git a/esphome/components/text_sensor/filter.h b/esphome/components/text_sensor/filter.h index 8a8bc55c8e..ccc52e2770 100644 --- a/esphome/components/text_sensor/filter.h +++ b/esphome/components/text_sensor/filter.h @@ -3,6 +3,8 @@ #include "esphome/core/defines.h" #ifdef USE_TEXT_SENSOR_FILTER +#include + #include "esphome/core/component.h" #include "esphome/core/helpers.h" @@ -131,6 +133,9 @@ class SubstituteFilter : public Filter { FixedVector substitutions_; }; +/// Non-template helper (implementation in filter.cpp) +bool map_filter_apply(const Substitution *mappings, size_t count, std::string &value); + /** A filter that maps values from one set to another * * Uses linear search instead of std::map for typical small datasets (2-20 mappings). @@ -154,14 +159,23 @@ class SubstituteFilter : public Filter { * - Faster for typical ESPHome usage (2-10 mappings common, 20+ rare) * * Break-even point: ~35-40 mappings, but ESPHome configs rarely exceed 20 + * + * N is set by code generation to match the exact number of mappings configured in YAML. */ -class MapFilter : public Filter { +template class MapFilter : public Filter { public: - explicit MapFilter(const std::initializer_list &mappings); - bool new_value(std::string &value) override; + explicit MapFilter(const std::initializer_list &mappings) { + size_t i = 0; + for (const auto &m : mappings) { + if (i >= N) + break; + this->mappings_[i++] = m; + } + } + bool new_value(std::string &value) override { return map_filter_apply(this->mappings_.data(), N, value); } protected: - FixedVector mappings_; + std::array mappings_{}; }; } // namespace esphome::text_sensor