diff --git a/esphome/codegen.py b/esphome/codegen.py index 4ea41ad191..6d55c6023d 100644 --- a/esphome/codegen.py +++ b/esphome/codegen.py @@ -19,7 +19,6 @@ from esphome.cpp_generator import ( # noqa: F401 RawExpression, RawStatement, Statement, - StringRefLiteral, StructInitializer, TemplateArguments, add, diff --git a/esphome/components/text_sensor/__init__.py b/esphome/components/text_sensor/__init__.py index 2be14b36fd..0d22400a8e 100644 --- a/esphome/components/text_sensor/__init__.py +++ b/esphome/components/text_sensor/__init__.py @@ -86,12 +86,12 @@ async def to_lower_filter_to_code(config, filter_id): @FILTER_REGISTRY.register("append", AppendFilter, cv.string) async def append_filter_to_code(config, filter_id): - return cg.new_Pvariable(filter_id, cg.StringRefLiteral(config)) + return cg.new_Pvariable(filter_id, config) @FILTER_REGISTRY.register("prepend", PrependFilter, cv.string) async def prepend_filter_to_code(config, filter_id): - return cg.new_Pvariable(filter_id, cg.StringRefLiteral(config)) + return cg.new_Pvariable(filter_id, config) def validate_mapping(value): @@ -114,8 +114,8 @@ async def substitute_filter_to_code(config, filter_id): substitutions = [ cg.StructInitializer( cg.MockObj("Substitution", "esphome::text_sensor::"), - ("from", cg.StringRefLiteral(conf[CONF_FROM])), - ("to", cg.StringRefLiteral(conf[CONF_TO])), + ("from", conf[CONF_FROM]), + ("to", conf[CONF_TO]), ) for conf in config ] @@ -127,8 +127,8 @@ async def map_filter_to_code(config, filter_id): mappings = [ cg.StructInitializer( cg.MockObj("Substitution", "esphome::text_sensor::"), - ("from", cg.StringRefLiteral(conf[CONF_FROM])), - ("to", cg.StringRefLiteral(conf[CONF_TO])), + ("from", conf[CONF_FROM]), + ("to", conf[CONF_TO]), ) for conf in config ] diff --git a/esphome/components/text_sensor/filter.cpp b/esphome/components/text_sensor/filter.cpp index d9afaf80f1..4cace372ae 100644 --- a/esphome/components/text_sensor/filter.cpp +++ b/esphome/components/text_sensor/filter.cpp @@ -57,13 +57,13 @@ optional ToLowerFilter::new_value(std::string value) { // Append optional AppendFilter::new_value(std::string value) { - value += this->suffix_; + value.append(this->suffix_); return value; } // Prepend optional PrependFilter::new_value(std::string value) { - value.insert(0, this->prefix_.c_str(), this->prefix_.size()); + value.insert(0, this->prefix_); return value; } @@ -73,13 +73,15 @@ SubstituteFilter::SubstituteFilter(const std::initializer_list &su optional SubstituteFilter::new_value(std::string value) { for (const auto &sub : this->substitutions_) { + // Compute lengths once per substitution (strlen is fast, called infrequently) + const size_t from_len = strlen(sub.from); + const size_t to_len = strlen(sub.to); std::size_t pos = 0; - // Use c_str()/size() to avoid temporary std::string allocation from implicit conversion - while ((pos = value.find(sub.from.c_str(), pos, sub.from.size())) != std::string::npos) { - value.replace(pos, sub.from.size(), sub.to.c_str(), sub.to.size()); + while ((pos = value.find(sub.from, pos, from_len)) != std::string::npos) { + value.replace(pos, from_len, sub.to, to_len); // Advance past the replacement to avoid infinite loop when // the replacement contains the search pattern (e.g., f -> foo) - pos += sub.to.size(); + pos += to_len; } } return value; @@ -90,8 +92,8 @@ MapFilter::MapFilter(const std::initializer_list &mappings) : mapp optional MapFilter::new_value(std::string value) { for (const auto &mapping : this->mappings_) { - if (mapping.from == value) { - value.assign(mapping.to.c_str(), mapping.to.size()); + if (value == mapping.from) { + value.assign(mapping.to); return value; } } diff --git a/esphome/components/text_sensor/filter.h b/esphome/components/text_sensor/filter.h index 472dd87f15..0f66b753b4 100644 --- a/esphome/components/text_sensor/filter.h +++ b/esphome/components/text_sensor/filter.h @@ -2,7 +2,6 @@ #include "esphome/core/component.h" #include "esphome/core/helpers.h" -#include "esphome/core/string_ref.h" namespace esphome { namespace text_sensor { @@ -93,26 +92,26 @@ class ToLowerFilter : public Filter { /// A simple filter that adds a string to the end of another string class AppendFilter : public Filter { public: - explicit AppendFilter(StringRef suffix) : suffix_(suffix) {} + explicit AppendFilter(const char *suffix) : suffix_(suffix) {} optional new_value(std::string value) override; protected: - StringRef suffix_; + const char *suffix_; }; /// A simple filter that adds a string to the start of another string class PrependFilter : public Filter { public: - explicit PrependFilter(StringRef prefix) : prefix_(prefix) {} + explicit PrependFilter(const char *prefix) : prefix_(prefix) {} optional new_value(std::string value) override; protected: - StringRef prefix_; + const char *prefix_; }; struct Substitution { - StringRef from; - StringRef to; + const char *from; + const char *to; }; /// A simple filter that replaces a substring with another substring diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 89993d997c..1a47b346b7 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -243,23 +243,6 @@ class LogStringLiteral(Literal): return f"LOG_STR({cpp_string_escape(self.string)})" -class StringRefLiteral(Literal): - """A StringRef literal using from_lit() for compile-time string references. - - Uses StringRef::from_lit() which stores pointer + length (8 bytes) instead of - std::string (24-32 bytes + heap allocation). The string data stays in flash. - """ - - __slots__ = ("string",) - - def __init__(self, string: str) -> None: - super().__init__() - self.string = string - - def __str__(self) -> str: - return f"StringRef::from_lit({cpp_string_escape(self.string)})" - - class IntLiteral(Literal): __slots__ = ("i",) diff --git a/tests/unit_tests/test_cpp_generator.py b/tests/unit_tests/test_cpp_generator.py index 428e7626a1..2c9f760c8e 100644 --- a/tests/unit_tests/test_cpp_generator.py +++ b/tests/unit_tests/test_cpp_generator.py @@ -248,12 +248,6 @@ class TestLiterals: (cg.FloatLiteral(4.2), "4.2f"), (cg.FloatLiteral(1.23456789), "1.23456789f"), (cg.FloatLiteral(math.nan), "NAN"), - (cg.StringRefLiteral("foo"), 'StringRef::from_lit("foo")'), - (cg.StringRefLiteral(""), 'StringRef::from_lit("")'), - ( - cg.StringRefLiteral('with "quotes"'), - 'StringRef::from_lit("with \\042quotes\\042")', - ), ), ) def test_str__simple(self, target: cg.Literal, expected: str):