From 825b1113b6e690cf93c3bd16046f751dfa9dbef2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 25 Jun 2025 23:17:41 +0200 Subject: [PATCH] tweak --- esphome/core/scheduler.cpp | 122 +++++++++++++++++++++++++++---------- esphome/core/scheduler.h | 12 ++-- 2 files changed, 98 insertions(+), 36 deletions(-) diff --git a/esphome/core/scheduler.cpp b/esphome/core/scheduler.cpp index fbf68522aa..a701147d32 100644 --- a/esphome/core/scheduler.cpp +++ b/esphome/core/scheduler.cpp @@ -22,20 +22,21 @@ static const uint32_t MAX_LOGICALLY_DELETED_ITEMS = 10; // iterating over them from the loop task is fine; but iterating from any other context requires the lock to be held to // avoid the main thread modifying the list while it is being accessed. -void HOT Scheduler::set_timeout(Component *component, const char *name, uint32_t timeout, std::function func) { - return this->set_timeout_(component, name, timeout, func, false); -} - -void HOT Scheduler::set_timeout(Component *component, const std::string &name, uint32_t timeout, - std::function func) { - return this->set_timeout_(component, name, timeout, func, true); -} - -void HOT Scheduler::set_timeout_(Component *component, const std::string &name, uint32_t timeout, - std::function func, bool make_copy) { +// Template implementation for set_timeout +template +void HOT Scheduler::set_timeout_impl_(Component *component, const NameType &name, uint32_t timeout, + std::function func, bool make_copy) { const auto now = this->millis_(); - if (!name.empty()) + // Handle empty name check based on type + bool is_empty = false; + if constexpr (std::is_same_v) { + is_empty = name.empty(); + } else { + is_empty = (name == nullptr || name[0] == '\0'); + } + + if (!is_empty) this->cancel_timeout(component, name); if (timeout == SCHEDULER_DONT_RUN) @@ -43,32 +44,62 @@ void HOT Scheduler::set_timeout_(Component *component, const std::string &name, auto item = make_unique(); item->component = component; - item->set_name(name.c_str(), make_copy); + + // Set name based on type + if constexpr (std::is_same_v) { + item->set_name(name.c_str(), make_copy); + } else { + item->set_name(name, make_copy); + } + item->type = SchedulerItem::TIMEOUT; item->next_execution_ = now + timeout; item->callback = std::move(func); item->remove = false; #ifdef ESPHOME_DEBUG_SCHEDULER - ESP_LOGD(TAG, "set_timeout(name='%s/%s', timeout=%" PRIu32 ")", item->get_source(), name.c_str(), timeout); + const char *name_str = nullptr; + if constexpr (std::is_same_v) { + name_str = name.c_str(); + } else { + name_str = name; + } + ESP_LOGD(TAG, "set_timeout(name='%s/%s', timeout=%" PRIu32 ")", item->get_source(), name_str, timeout); #endif this->push_(std::move(item)); } + +// Explicit instantiations +template void Scheduler::set_timeout_impl_(Component *, const std::string &, uint32_t, + std::function, bool); +template void Scheduler::set_timeout_impl_(Component *, const char *const &, uint32_t, + std::function, bool); + +void HOT Scheduler::set_timeout(Component *component, const char *name, uint32_t timeout, std::function func) { + return this->set_timeout_impl_(component, name, timeout, std::move(func), false); +} + +void HOT Scheduler::set_timeout(Component *component, const std::string &name, uint32_t timeout, + std::function func) { + return this->set_timeout_impl_(component, name, timeout, std::move(func), true); +} bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name) { return this->cancel_item_(component, name, SchedulerItem::TIMEOUT); } -void HOT Scheduler::set_interval(Component *component, const std::string &name, uint32_t interval, - std::function func) { - this->set_interval_(component, name, interval, func, true); -} -void HOT Scheduler::set_interval(Component *component, const char *name, uint32_t interval, - std::function func) { - this->set_interval_(component, name, interval, func, false); -} -void HOT Scheduler::set_interval_(Component *component, const std::string &name, uint32_t interval, - std::function func, bool make_copy) { +// Template implementation for set_interval +template +void HOT Scheduler::set_interval_impl_(Component *component, const NameType &name, uint32_t interval, + std::function func, bool make_copy) { const auto now = this->millis_(); - if (!name.empty()) + // Handle empty name check based on type + bool is_empty = false; + if constexpr (std::is_same_v) { + is_empty = name.empty(); + } else { + is_empty = (name == nullptr || name[0] == '\0'); + } + + if (!is_empty) this->cancel_interval(component, name); if (interval == SCHEDULER_DONT_RUN) @@ -81,18 +112,46 @@ void HOT Scheduler::set_interval_(Component *component, const std::string &name, auto item = make_unique(); item->component = component; - item->set_name(name.c_str(), make_copy); + + // Set name based on type + if constexpr (std::is_same_v) { + item->set_name(name.c_str(), make_copy); + } else { + item->set_name(name, make_copy); + } + item->type = SchedulerItem::INTERVAL; item->interval = interval; item->next_execution_ = now + offset; item->callback = std::move(func); item->remove = false; #ifdef ESPHOME_DEBUG_SCHEDULER - ESP_LOGD(TAG, "set_interval(name='%s/%s', interval=%" PRIu32 ", offset=%" PRIu32 ")", item->get_source(), - name.c_str(), interval, offset); + const char *name_str = nullptr; + if constexpr (std::is_same_v) { + name_str = name.c_str(); + } else { + name_str = name; + } + ESP_LOGD(TAG, "set_interval(name='%s/%s', interval=%" PRIu32 ", offset=%" PRIu32 ")", item->get_source(), name_str, + interval, offset); #endif this->push_(std::move(item)); } + +// Explicit instantiations +template void Scheduler::set_interval_impl_(Component *, const std::string &, uint32_t, + std::function, bool); +template void Scheduler::set_interval_impl_(Component *, const char *const &, uint32_t, + std::function, bool); + +void HOT Scheduler::set_interval(Component *component, const std::string &name, uint32_t interval, + std::function func) { + return this->set_interval_impl_(component, name, interval, std::move(func), true); +} +void HOT Scheduler::set_interval(Component *component, const char *name, uint32_t interval, + std::function func) { + return this->set_interval_impl_(component, name, interval, std::move(func), false); +} bool HOT Scheduler::cancel_interval(Component *component, const std::string &name) { return this->cancel_item_(component, name, SchedulerItem::INTERVAL); } @@ -180,8 +239,8 @@ void HOT Scheduler::call() { this->lock_.unlock(); ESP_LOGD(TAG, " %s '%s/%s' interval=%" PRIu32 " next_execution in %" PRIu64 "ms at %" PRIu64, - item->get_type_str(), item->get_source(), item->name.c_str(), item->interval, - item->next_execution_ - now, item->next_execution_); + item->get_type_str(), item->get_source(), item->get_name(), item->interval, item->next_execution_ - now, + item->next_execution_); old_items.push_back(std::move(item)); } @@ -238,8 +297,7 @@ void HOT Scheduler::call() { #ifdef ESPHOME_DEBUG_SCHEDULER ESP_LOGV(TAG, "Running %s '%s/%s' with interval=%" PRIu32 " next_execution=%" PRIu64 " (now=%" PRIu64 ")", - item->get_type_str(), item->get_source(), item->name.c_str(), item->interval, item->next_execution_, - now); + item->get_type_str(), item->get_source(), item->get_name(), item->interval, item->next_execution_, now); #endif // Warning: During callback(), a lot of stuff can happen, including: diff --git a/esphome/core/scheduler.h b/esphome/core/scheduler.h index 80452d6628..ca437e690c 100644 --- a/esphome/core/scheduler.h +++ b/esphome/core/scheduler.h @@ -15,14 +15,10 @@ class Scheduler { // Public API - accepts std::string for backward compatibility void set_timeout(Component *component, const std::string &name, uint32_t timeout, std::function func); void set_timeout(Component *component, const char *name, uint32_t timeout, std::function func); - void set_timeout_(Component *component, const std::string &name, uint32_t timeout, std::function func, - bool make_copy); bool cancel_timeout(Component *component, const std::string &name); void set_interval(Component *component, const std::string &name, uint32_t interval, std::function func); void set_interval(Component *component, const char *name, uint32_t interval, std::function func); - void set_interval_(Component *component, const std::string &name, uint32_t interval, std::function func, - bool make_copy); bool cancel_interval(Component *component, const std::string &name); void set_retry(Component *component, const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts, @@ -36,6 +32,14 @@ class Scheduler { void process_to_add(); protected: + // Template helper to handle both const char* and std::string efficiently + template + void set_timeout_impl_(Component *component, const NameType &name, uint32_t timeout, std::function func, + bool make_copy); + template + void set_interval_impl_(Component *component, const NameType &name, uint32_t interval, std::function func, + bool make_copy); + struct SchedulerItem { // Ordered by size to minimize padding Component *component;