mirror of
https://github.com/esphome/esphome.git
synced 2026-09-12 15:57:33 +00:00
[core] Compile-time detection of loop() overrides
Replace the runtime GCC-specific pointer-to-member-function comparison in has_overridden_loop() with a compile-time std::is_same_v check in a templated register_component_(). The template resolves &T::loop vs &Component::loop at compile time and passes the result to register_component_impl_(), which stores it as bit 5 in the existing component_state_ byte (zero additional RAM). This eliminates: - The non-standard -Wpmf-conversions GCC extension - The USE_HOST/CLANG_TIDY special case that incorrectly returned true for all components (putting every component in the loop list) - Runtime vtable probing during calculate_looping_components_()
This commit is contained in:
@@ -79,7 +79,12 @@ static void insertion_sort_by_priority(Iterator first, Iterator last) {
|
||||
}
|
||||
}
|
||||
|
||||
void Application::register_component_(Component *comp) { this->components_.push_back(comp); }
|
||||
void Application::register_component_impl_(Component *comp, bool has_loop) {
|
||||
if (has_loop) {
|
||||
comp->component_state_ |= COMPONENT_HAS_LOOP;
|
||||
}
|
||||
this->components_.push_back(comp);
|
||||
}
|
||||
void Application::setup() {
|
||||
ESP_LOGI(TAG, "Running through setup()");
|
||||
ESP_LOGV(TAG, "Sorting components by setup priority");
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <limits>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
@@ -531,7 +532,14 @@ class Application {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void register_component_(Component *comp);
|
||||
/// Register a component, detecting loop() override at compile time.
|
||||
/// The template resolves &T::loop vs &Component::loop as a constexpr bool
|
||||
/// and forwards it to register_component_impl_ which stores it in component_state_.
|
||||
template<typename T> void register_component_(T *comp) {
|
||||
this->register_component_impl_(comp, !std::is_same_v<decltype(&T::loop), decltype(&Component::loop)>);
|
||||
}
|
||||
|
||||
void register_component_impl_(Component *comp, bool has_loop);
|
||||
|
||||
void calculate_looping_components_();
|
||||
void add_looping_components_by_state_(bool match_loop_done);
|
||||
|
||||
@@ -490,18 +490,6 @@ void Component::set_setup_priority(float priority) {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Component::has_overridden_loop() const {
|
||||
#if defined(USE_HOST) || defined(CLANG_TIDY)
|
||||
return true;
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpmf-conversions"
|
||||
bool loop_overridden = (void *) (this->*(&Component::loop)) != (void *) (&Component::loop);
|
||||
#pragma GCC diagnostic pop
|
||||
return loop_overridden;
|
||||
#endif
|
||||
}
|
||||
|
||||
PollingComponent::PollingComponent(uint32_t update_interval) : update_interval_(update_interval) {}
|
||||
|
||||
void PollingComponent::call_setup() {
|
||||
|
||||
@@ -76,6 +76,8 @@ inline constexpr uint8_t STATUS_LED_MASK = 0x18;
|
||||
inline constexpr uint8_t STATUS_LED_OK = 0x00;
|
||||
inline constexpr uint8_t STATUS_LED_WARNING = 0x08;
|
||||
inline constexpr uint8_t STATUS_LED_ERROR = 0x10;
|
||||
// Component loop override flag uses bit 5 (set at registration time)
|
||||
inline constexpr uint8_t COMPONENT_HAS_LOOP = 0x20;
|
||||
|
||||
// Remove before 2026.8.0
|
||||
enum class RetryResult { DONE, RETRY };
|
||||
@@ -271,7 +273,7 @@ class Component {
|
||||
*/
|
||||
void status_momentary_error(const char *name, uint32_t length = 5000);
|
||||
|
||||
bool has_overridden_loop() const;
|
||||
bool has_overridden_loop() const { return (this->component_state_ & COMPONENT_HAS_LOOP) != 0; }
|
||||
|
||||
/** Set where this component was loaded from for some debug messages.
|
||||
*
|
||||
@@ -510,7 +512,8 @@ class Component {
|
||||
/// Bits 0-2: Component state (0x00=CONSTRUCTION, 0x01=SETUP, 0x02=LOOP, 0x03=FAILED, 0x04=LOOP_DONE)
|
||||
/// Bit 3: STATUS_LED_WARNING
|
||||
/// Bit 4: STATUS_LED_ERROR
|
||||
/// Bits 5-7: Unused - reserved for future expansion
|
||||
/// Bit 5: Has overridden loop() (set at registration time)
|
||||
/// Bits 6-7: Unused - reserved for future expansion
|
||||
uint8_t component_state_{0x00};
|
||||
volatile bool pending_enable_loop_{false}; ///< ISR-safe flag for enable_loop_soon_any_context
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user