From c30e130a485ebd672d2c6c9499767a6f3272581d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 26 Oct 2025 01:07:08 -0700 Subject: [PATCH 1/2] dry --- esphome/components/binary_sensor/filter.h | 6 ++---- esphome/components/sensor/filter.h | 6 ++---- esphome/components/text_sensor/filter.h | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/esphome/components/binary_sensor/filter.h b/esphome/components/binary_sensor/filter.h index 7ee253ead5..c1c54709a9 100644 --- a/esphome/components/binary_sensor/filter.h +++ b/esphome/components/binary_sensor/filter.h @@ -118,14 +118,12 @@ class LambdaFilter : public Filter { */ class StatelessLambdaFilter : public Filter { public: - using stateless_lambda_filter_t = optional (*)(bool); - - explicit StatelessLambdaFilter(stateless_lambda_filter_t f) : f_(f) {} + explicit StatelessLambdaFilter(optional (*f)(bool)) : f_(f) {} optional new_value(bool value) override { return this->f_(value); } protected: - stateless_lambda_filter_t f_; + optional (*f_)(bool); }; class SettleFilter : public Filter, public Component { diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 4f0840a75e..ebcdbb8cab 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -303,14 +303,12 @@ class LambdaFilter : public Filter { */ class StatelessLambdaFilter : public Filter { public: - using stateless_lambda_filter_t = optional (*)(float); - - explicit StatelessLambdaFilter(stateless_lambda_filter_t lambda_filter) : lambda_filter_(lambda_filter) {} + explicit StatelessLambdaFilter(optional (*lambda_filter)(float)) : lambda_filter_(lambda_filter) {} optional new_value(float value) override { return this->lambda_filter_(value); } protected: - stateless_lambda_filter_t lambda_filter_; + optional (*lambda_filter_)(float); }; /// A simple filter that adds `offset` to each value it receives. diff --git a/esphome/components/text_sensor/filter.h b/esphome/components/text_sensor/filter.h index d8c71379ad..dddf1b2b34 100644 --- a/esphome/components/text_sensor/filter.h +++ b/esphome/components/text_sensor/filter.h @@ -69,14 +69,12 @@ class LambdaFilter : public Filter { */ class StatelessLambdaFilter : public Filter { public: - using stateless_lambda_filter_t = optional (*)(std::string); - - explicit StatelessLambdaFilter(stateless_lambda_filter_t lambda_filter) : lambda_filter_(lambda_filter) {} + explicit StatelessLambdaFilter(optional (*lambda_filter)(std::string)) : lambda_filter_(lambda_filter) {} optional new_value(std::string value) override { return this->lambda_filter_(value); } protected: - stateless_lambda_filter_t lambda_filter_; + optional (*lambda_filter_)(std::string); }; /// A simple filter that converts all text to uppercase From 97346e5644b7df53a3b4aa83f4316db2bd680799 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 26 Oct 2025 01:30:39 -0700 Subject: [PATCH 2/2] tweak --- esphome/components/binary_sensor/filter.h | 2 +- esphome/components/sensor/filter.h | 2 +- esphome/components/text_sensor/filter.h | 2 +- esphome/core/base_automation.h | 4 ++-- tests/unit_tests/test_cpp_generator.py | 17 +++++++++++++++++ 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/esphome/components/binary_sensor/filter.h b/esphome/components/binary_sensor/filter.h index c1c54709a9..2d473c3b64 100644 --- a/esphome/components/binary_sensor/filter.h +++ b/esphome/components/binary_sensor/filter.h @@ -114,7 +114,7 @@ class LambdaFilter : public Filter { /** Optimized lambda filter for stateless lambdas (no capture). * * Uses function pointer instead of std::function to reduce memory overhead. - * Memory: 8 bytes (function pointer) vs 32 bytes (std::function). + * Memory: 4 bytes (function pointer on 32-bit) vs 32 bytes (std::function). */ class StatelessLambdaFilter : public Filter { public: diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index ebcdbb8cab..75e28a1efe 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -299,7 +299,7 @@ class LambdaFilter : public Filter { /** Optimized lambda filter for stateless lambdas (no capture). * * Uses function pointer instead of std::function to reduce memory overhead. - * Memory: 8 bytes (function pointer) vs 32 bytes (std::function). + * Memory: 4 bytes (function pointer on 32-bit) vs 32 bytes (std::function). */ class StatelessLambdaFilter : public Filter { public: diff --git a/esphome/components/text_sensor/filter.h b/esphome/components/text_sensor/filter.h index dddf1b2b34..85acac5c8d 100644 --- a/esphome/components/text_sensor/filter.h +++ b/esphome/components/text_sensor/filter.h @@ -65,7 +65,7 @@ class LambdaFilter : public Filter { /** Optimized lambda filter for stateless lambdas (no capture). * * Uses function pointer instead of std::function to reduce memory overhead. - * Memory: 8 bytes (function pointer) vs 32 bytes (std::function). + * Memory: 4 bytes (function pointer on 32-bit) vs 32 bytes (std::function). */ class StatelessLambdaFilter : public Filter { public: diff --git a/esphome/core/base_automation.h b/esphome/core/base_automation.h index 683be2a9e9..1c60dd1c7a 100644 --- a/esphome/core/base_automation.h +++ b/esphome/core/base_automation.h @@ -81,7 +81,7 @@ template class LambdaCondition : public Condition { /// Optimized lambda condition for stateless lambdas (no capture). /// Uses function pointer instead of std::function to reduce memory overhead. -/// Memory: 8 bytes (function pointer) vs 32 bytes (std::function). +/// Memory: 4 bytes (function pointer on 32-bit) vs 32 bytes (std::function). template class StatelessLambdaCondition : public Condition { public: explicit StatelessLambdaCondition(bool (*f)(Ts...)) : f_(f) {} @@ -204,7 +204,7 @@ template class LambdaAction : public Action { /// Optimized lambda action for stateless lambdas (no capture). /// Uses function pointer instead of std::function to reduce memory overhead. -/// Memory: 8 bytes (function pointer) vs 32 bytes (std::function). +/// Memory: 4 bytes (function pointer on 32-bit) vs 32 bytes (std::function). template class StatelessLambdaAction : public Action { public: explicit StatelessLambdaAction(void (*f)(Ts...)) : f_(f) {} diff --git a/tests/unit_tests/test_cpp_generator.py b/tests/unit_tests/test_cpp_generator.py index b495b52064..f42ad180c7 100644 --- a/tests/unit_tests/test_cpp_generator.py +++ b/tests/unit_tests/test_cpp_generator.py @@ -213,6 +213,23 @@ class TestLambdaExpression: "+[](int32_t foo, float bar) -> float {\n return foo + bar;\n}" ) + def test_str__with_capture_no_prefix(self): + """Test lambda with capture (not stateless) does NOT get + prefix""" + target = cg.LambdaExpression( + ("return captured_var + x;",), + ((int, "x"),), + "captured_var", # Has capture (not stateless) + int, + ) + + actual = str(target) + + # Should NOT have + prefix + assert actual == ( + "[captured_var](int32_t x) -> int32_t {\n return captured_var + x;\n}" + ) + assert not actual.startswith("+") + class TestLiterals: @pytest.mark.parametrize(