From f40eb9b78067f591cc3dd54108157979714ea3b3 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 26 Apr 2026 22:17:26 -0500 Subject: [PATCH] [core] Inline ContinuationAction in IfAction/WhileAction/RepeatAction Replace heap-allocated ContinuationAction/WhileLoopContinuation/ RepeatLoopContinuation instances with inline members, eliminating one heap allocation per IfAction/WhileAction/RepeatAction at setup. Each parent already needs exactly one continuation as the chain terminator that hands control back. Heap-allocating it costs the ~16-byte object plus an ~8-byte heap header per instance, plus heap fragmentation. Inlining moves the same 16 bytes from heap to BSS and drops the heap header overhead. Per-parent net change: - BSS: +16 B (the inline continuation; +32 B for IfAction) - Heap: -24 B per heap allocation eliminated (16 B object + ~8 B header) - Net RAM saved: ~8 B per simple parent, ~16 B for IfAction - Plus: one fewer heap allocation per parent at setup, less fragmentation For IfAction, the else continuation is elided via [[no_unique_address]] + an empty wrapper struct, so it costs 0 B. Note: CI memory analysis only measures static RAM (BSS), not heap. This change moves bytes from heap to BSS, so the report will show BSS increasing while the actual heap savings (and fragmentation reduction) are not directly visible. --- esphome/core/base_automation.h | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/esphome/core/base_automation.h b/esphome/core/base_automation.h index 17f937d10d..9418170b6d 100644 --- a/esphome/core/base_automation.h +++ b/esphome/core/base_automation.h @@ -273,18 +273,28 @@ template class WhileLoopContinuation : public Action { WhileAction *parent_; }; +// Wraps a ContinuationAction when Enabled, empty otherwise. +// Lets IfAction elide the else continuation when HasElse is false. +template struct OptionalContinuation { + ContinuationAction action; + explicit OptionalContinuation(Action *parent) : action(parent) {} +}; +template struct OptionalContinuation { + explicit OptionalContinuation(Action * /*parent*/) {} +}; + template class IfAction : public Action { public: explicit IfAction(Condition *condition) : condition_(condition) {} void add_then(const std::initializer_list *> &actions) { this->then_.add_actions(actions); - this->then_.add_action(new ContinuationAction(this)); + this->then_.add_action(&this->then_continuation_); } void add_else(const std::initializer_list *> &actions) requires(HasElse) { this->else_.add_actions(actions); - this->else_.add_action(new ContinuationAction(this)); + this->else_.add_action(&this->else_continuation_.action); } void play_complex(const Ts &...x) override { @@ -316,8 +326,10 @@ template class IfAction : public Action { protected: Condition *condition_; ActionList then_; + ContinuationAction then_continuation_{this}; struct NoElse {}; [[no_unique_address]] std::conditional_t, NoElse> else_; + [[no_unique_address]] OptionalContinuation else_continuation_{this}; }; template class WhileAction : public Action { @@ -326,7 +338,7 @@ template class WhileAction : public Action { void add_then(const std::initializer_list *> &actions) { this->then_.add_actions(actions); - this->then_.add_action(new WhileLoopContinuation(this)); + this->then_.add_action(&this->loop_continuation_); } friend class WhileLoopContinuation; @@ -354,6 +366,7 @@ template class WhileAction : public Action { protected: Condition *condition_; ActionList then_; + WhileLoopContinuation loop_continuation_{this}; }; // Implementation of WhileLoopContinuation::play @@ -388,7 +401,7 @@ template class RepeatAction : public Action { void add_then(const std::initializer_list *> &actions) { this->then_.add_actions(actions); - this->then_.add_action(new RepeatLoopContinuation(this)); + this->then_.add_action(&this->loop_continuation_); } friend class RepeatLoopContinuation; @@ -409,6 +422,7 @@ template class RepeatAction : public Action { protected: ActionList then_; + RepeatLoopContinuation loop_continuation_{this}; }; // Implementation of RepeatLoopContinuation::play