[binary_sensor] Reduce flash: cache get_state(), guard full_state_callbacks call

- Cache get_state() result to avoid calling the virtual method twice
  (once for comparison, once for old_state construction)
- Move full_state_callbacks_.call() inside the !empty() guard so both
  the optional construction and the call are skipped when no callbacks
- Swap to had_state || get_trigger_on_initial_state() so the virtual
  call is skipped on the common path (every change except the first)

Saves ~21 bytes of flash in set_new_state.
This commit is contained in:
J. Nick Koston
2026-03-22 18:16:49 -10:00
parent 8a4b152488
commit 4a200f8a2b
+12 -7
View File
@@ -347,24 +347,29 @@ template<typename T> class StatefulEntityBase : public EntityBase {
virtual bool set_new_state(const optional<T> &new_state) {
// Access flags_ directly to avoid function call overhead in this hot path
bool had_state = this->flags_.has_state;
// Cache get_state() result to avoid calling the virtual method twice
T current{};
if (had_state)
current = this->get_state();
if (new_state.has_value()) {
if (had_state && this->get_state() == new_state.value())
if (had_state && current == new_state.value())
return false; // same value, no change
} else if (!had_state) {
return false; // already invalidated, no change
}
// State changed — update storage before firing callbacks so callback code
// can inspect the entity's current state via get_state()/has_state()
// Only construct old_state optional when full_state_callbacks need it
optional<T> old_state;
if (!this->full_state_callbacks_.empty())
old_state = had_state ? optional<T>(this->get_state()) : nullopt;
this->flags_.has_state = new_state.has_value();
if (new_state.has_value()) {
this->set_state_value(new_state.value());
}
this->full_state_callbacks_.call(old_state, new_state);
if (new_state.has_value() && (this->get_trigger_on_initial_state() || had_state))
// Only construct old_state and call full_state_callbacks when callbacks are registered
if (!this->full_state_callbacks_.empty()) {
optional<T> old_state = had_state ? optional<T>(current) : nullopt;
this->full_state_callbacks_.call(old_state, new_state);
}
// had_state first: on every change except the first, skips the virtual call
if (new_state.has_value() && (had_state || this->get_trigger_on_initial_state()))
this->state_callbacks_.call(new_state.value());
return true;
}