mirror of
https://github.com/esphome/esphome.git
synced 2026-02-25 21:43:14 -07:00
Merge branch 'text_sensor_filters_no_alloc' into integration
This commit is contained in:
@@ -19,7 +19,6 @@ from esphome.cpp_generator import ( # noqa: F401
|
||||
RawExpression,
|
||||
RawStatement,
|
||||
Statement,
|
||||
StringRefLiteral,
|
||||
StructInitializer,
|
||||
TemplateArguments,
|
||||
add,
|
||||
|
||||
@@ -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
|
||||
]
|
||||
|
||||
@@ -57,13 +57,13 @@ optional<std::string> ToLowerFilter::new_value(std::string value) {
|
||||
|
||||
// Append
|
||||
optional<std::string> AppendFilter::new_value(std::string value) {
|
||||
value += this->suffix_;
|
||||
value.append(this->suffix_);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Prepend
|
||||
optional<std::string> 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<Substitution> &su
|
||||
|
||||
optional<std::string> 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<Substitution> &mappings) : mapp
|
||||
|
||||
optional<std::string> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<std::string> 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<std::string> 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
|
||||
|
||||
@@ -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",)
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user