Corium 1.1.0
High-Performance Zero-Heap C++20 MPSC Application Runtime
Loading...
Searching...
No Matches
TimerScheduler.hpp
Go to the documentation of this file.
1
7#pragma once
8
9#include <chrono>
10#include <cstddef>
11#include <cstdint>
12#include <type_traits>
13#include <utility>
14
15#include "corium/Events.hpp"
19
20namespace corium {
21
22using TimerId = uint32_t;
24
32template <
33 typename EventVariant = DefaultEvents,
34 size_t MaxTimers = 64,
35 typename ClockPolicy = ChronoClockPolicy
36>
38public:
39 using Clock = ClockPolicy;
40 using time_point = typename ClockPolicy::time_point;
41 using duration = typename ClockPolicy::duration;
42
52
54 bool operator()(const TimerEntry& a, const TimerEntry& b) const noexcept {
55 return a.expiryTime > b.expiryTime; // Min-heap: earliest expiry at top
56 }
57 };
58
59 TimerScheduler() = default;
60
62 template <typename Rep, typename Period>
63 TimerId scheduleDelayed(EventVariant event, const std::chrono::duration<Rep, Period>& delay, EventPriority priority = EventPriority::Normal)
64 {
65 time_point now = ClockPolicy::now();
66 time_point expiry = ClockPolicy::add(now, delay);
67 duration zeroInterval{};
68 return allocateTimer(std::move(event), expiry, zeroInterval, priority, false);
69 }
70
73 requires (!std::is_same_v<duration, std::chrono::microseconds> && !std::is_same_v<duration, std::chrono::milliseconds>)
74 {
75 time_point now = ClockPolicy::now();
76 time_point expiry = ClockPolicy::add(now, delay);
77 duration zeroInterval{};
78 return allocateTimer(std::move(event), expiry, zeroInterval, priority, false);
79 }
80
82 template <typename Rep, typename Period>
83 TimerId schedulePeriodic(EventVariant event, const std::chrono::duration<Rep, Period>& interval, EventPriority priority = EventPriority::Normal)
84 {
85 time_point now = ClockPolicy::now();
86 time_point expiry = ClockPolicy::add(now, interval);
87 if constexpr (std::is_same_v<duration, std::chrono::microseconds>) {
88 return allocateTimer(std::move(event), expiry, std::chrono::duration_cast<std::chrono::microseconds>(interval), priority, true);
89 } else if constexpr (std::is_same_v<duration, std::chrono::milliseconds>) {
90 return allocateTimer(std::move(event), expiry, std::chrono::duration_cast<std::chrono::milliseconds>(interval), priority, true);
91 } else {
92 auto nativeInterval = static_cast<duration>(std::chrono::duration_cast<std::chrono::microseconds>(interval).count());
93 return allocateTimer(std::move(event), expiry, nativeInterval, priority, true);
94 }
95 }
96
98 TimerId schedulePeriodic(EventVariant event, duration interval, EventPriority priority = EventPriority::Normal)
99 requires (!std::is_same_v<duration, std::chrono::microseconds> && !std::is_same_v<duration, std::chrono::milliseconds>)
100 {
101 time_point now = ClockPolicy::now();
102 time_point expiry = ClockPolicy::add(now, interval);
103 return allocateTimer(std::move(event), expiry, interval, priority, true);
104 }
105
109 bool cancelTimer(TimerId id) noexcept
110 {
111 if (id == INVALID_TIMER_ID || _activeCount == 0) {
112 return false;
113 }
114
115 auto* data = _heap.data();
116 const std::size_t n = _heap.size();
117 for (std::size_t i = 0; i < n; ++i) {
118 if (data[i].active && data[i].id == id) {
119 data[i].active = false;
120 data[i].id = INVALID_TIMER_ID;
121 if (_activeCount > 0) {
122 _activeCount--;
123 }
124 return true;
125 }
126 }
127 return false;
128 }
129
136 template <typename EventSink>
137 std::size_t processDueTimers(EventSink& sink, time_point now = ClockPolicy::now())
138 {
139 if (_activeCount == 0 || _heap.empty()) {
140 return 0;
141 }
142
143 std::size_t posted = 0;
144
145 while (!_heap.empty()) {
146 auto& top = _heap.top();
147
148 // Discard cancelled timers at top of heap
149 if (!top.active) {
150 _heap.pop();
151 continue;
152 }
153
154 // O(1) early exit: if earliest scheduled timer is not due, nothing else is due
155 if (!ClockPolicy::isDue(now, top.expiryTime)) {
156 break;
157 }
158
159 TimerEntry entry = std::move(_heap.top());
160 _heap.pop();
161
162 sink.post(entry.event, entry.priority);
163 posted++;
164
165 if (entry.isPeriodic) {
166 entry.expiryTime = ClockPolicy::add(entry.expiryTime, entry.interval);
167 while (ClockPolicy::isDue(now, entry.expiryTime)) {
168 entry.expiryTime = ClockPolicy::add(entry.expiryTime, entry.interval);
169 }
170 _heap.push(std::move(entry));
171 } else {
172 if (_activeCount > 0) {
173 _activeCount--;
174 }
175 }
176 }
177
178 return posted;
179 }
180
182 [[nodiscard]] size_t activeCount() const noexcept
183 {
184 return _activeCount;
185 }
186
188 [[nodiscard]] constexpr size_t capacity() const noexcept
189 {
190 return MaxTimers;
191 }
192
193private:
194 TimerId allocateTimer(EventVariant event, time_point expiryTime, duration interval, EventPriority priority, bool isPeriodic)
195 {
196 if (_activeCount >= MaxTimers || _heap.full()) {
197 return INVALID_TIMER_ID;
198 }
199
200 TimerId id = _nextId++;
201 if (_nextId == INVALID_TIMER_ID) {
202 _nextId = 1;
203 }
204
205 TimerEntry entry{
206 .id = id,
207 .event = std::move(event),
208 .expiryTime = expiryTime,
209 .interval = interval,
210 .priority = priority,
211 .isPeriodic = isPeriodic,
212 .active = true
213 };
214
215 if (_heap.push(std::move(entry))) {
216 _activeCount++;
217 return id;
218 }
219
220 return INVALID_TIMER_ID;
221 }
222
223 internal::StaticMinHeap<TimerEntry, MaxTimers, TimerComparator> _heap{};
224 size_t _activeCount = 0;
225 TimerId _nextId = 1;
226};
227
228} // namespace corium
Hardware and simulated clock policies (Chrono, Manual, Tick, EspTimer, FreeRTOS).
Standard lifecycle events (QuitEvent, ErrorEvent, TimerEvent).
Bounded and multi-tier priority MPSC queueing policies.
Fixed-capacity zero-heap binary min-heap for deterministic priority queues and timers.
void post(EventVariant &&event, EventPriority priority=EventPriority::Normal) const
Post an event into the event sink with priority (rvalue overload).
Definition EventSink.hpp:44
Default host clock policy using std::chrono::steady_clock.
Definition ClockPolicies.hpp:44
Zero-heap Min-Heap Timer Scheduler for delayed and periodic events. Provides O(1) earliest-due timer ...
Definition TimerScheduler.hpp:37
TimerId scheduleDelayed(EventVariant event, const std::chrono::duration< Rep, Period > &delay, EventPriority priority=EventPriority::Normal)
Schedule a single-shot delayed event with std::chrono duration.
Definition TimerScheduler.hpp:63
ClockPolicy Clock
Definition TimerScheduler.hpp:39
bool cancelTimer(TimerId id) noexcept
Cancel an active timer by its TimerId handle.
Definition TimerScheduler.hpp:109
typename ClockPolicy::time_point time_point
Definition TimerScheduler.hpp:40
size_t activeCount() const noexcept
Get current number of active timers.
Definition TimerScheduler.hpp:182
constexpr size_t capacity() const noexcept
Get maximum timer capacity.
Definition TimerScheduler.hpp:188
TimerId schedulePeriodic(EventVariant event, const std::chrono::duration< Rep, Period > &interval, EventPriority priority=EventPriority::Normal)
Schedule a recurring periodic event with std::chrono duration.
Definition TimerScheduler.hpp:83
TimerId schedulePeriodic(EventVariant event, duration interval, EventPriority priority=EventPriority::Normal)
Schedule a recurring periodic event with native clock duration.
Definition TimerScheduler.hpp:98
std::size_t processDueTimers(EventSink &sink, time_point now=ClockPolicy::now())
Process all due timers and post their events into target event bus or sink. Uses O(1) early exit when...
Definition TimerScheduler.hpp:137
TimerId scheduleDelayed(EventVariant event, duration delay, EventPriority priority=EventPriority::Normal)
Schedule a single-shot delayed event with native clock duration.
Definition TimerScheduler.hpp:72
typename ClockPolicy::duration duration
Definition TimerScheduler.hpp:41
Definition Application.hpp:16
std::variant< QuitEvent, TickEvent, UpdateEvent, ErrorEvent, SignalEvent > DefaultEvents
Default variant list of core Corium events.
Definition Events.hpp:62
EventPriority
Event priority levels for multi-priority queue policies.
Definition QueuePolicies.hpp:32
uint32_t TimerId
Definition TimerScheduler.hpp:22
constexpr TimerId INVALID_TIMER_ID
Definition TimerScheduler.hpp:23
Definition TimerScheduler.hpp:53
bool operator()(const TimerEntry &a, const TimerEntry &b) const noexcept
Definition TimerScheduler.hpp:54
Definition TimerScheduler.hpp:43
duration interval
Definition TimerScheduler.hpp:47
bool active
Definition TimerScheduler.hpp:50
bool isPeriodic
Definition TimerScheduler.hpp:49
EventVariant event
Definition TimerScheduler.hpp:45
time_point expiryTime
Definition TimerScheduler.hpp:46
EventPriority priority
Definition TimerScheduler.hpp:48