mirror of
https://github.com/esphome/esphome.git
synced 2026-09-02 02:56:01 +00:00
[binary_sensor] Use const T* instead of T current{} in set_new_state
Avoids requiring T to be default-constructible, which would break future instantiations with non-default-constructible state types. Capture old_state before set_state_value() since the pointer aliases subclass storage that gets overwritten.
This commit is contained in:
+10
-11
@@ -347,27 +347,26 @@ 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();
|
||||
// Use pointer to avoid requiring T to be default-constructible
|
||||
const T *current = had_state ? &this->get_state() : nullptr;
|
||||
if (new_state.has_value()) {
|
||||
if (had_state && current == new_state.value())
|
||||
if (current != nullptr && *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()
|
||||
// Capture old_state before set_state_value — current pointer aliases subclass storage
|
||||
bool has_full_cbs = !this->full_state_callbacks_.empty();
|
||||
optional<T> old_state;
|
||||
if (has_full_cbs)
|
||||
old_state = current != nullptr ? optional<T>(*current) : nullopt;
|
||||
// Update storage before firing callbacks so callback code can inspect current state
|
||||
this->flags_.has_state = new_state.has_value();
|
||||
if (new_state.has_value()) {
|
||||
this->set_state_value(new_state.value());
|
||||
}
|
||||
// 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;
|
||||
if (has_full_cbs)
|
||||
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());
|
||||
|
||||
Reference in New Issue
Block a user