Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
IntervalTimer.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Execution_IntervalTimer_h_
5#define _Stroika_Foundation_Execution_IntervalTimer_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include "Stroika/Foundation/Common/Common.h"
10#include "Stroika/Foundation/Containers/KeyedCollection.h"
14
15/**
16 * \file
17 *
18 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
19 */
20
22
23 /**
24 * \brief Manage interval timers - like the javascript setIntervalTimer API.
25 *
26 * o Add and remove timers.
27 * o Support one-shot timers.
28 * o Timers run on arbitrary thread.
29 * o Can shut down manager at any time.
30 * o Can support multiple 'managers' - but then you have to add explicitly. Or use Adder object to add
31 * to default/global IdleTimer manager.
32 *
33 * \note Easiest way to use is IntervalTimer::Adder - see constructor example below
34 *
35 * \note https://stackoverflow.com/questions/33234403/using-setinterval-in-c
36 *
37 * note TODO:
38 * \todo sometimes want to use threadpool/ Sometime async; sometimes a single thread iff stuff
39 */
41 public:
42 /**
43 * Note: these timers CAN throw, and SHOULD throw if interrupted, but the Idle Manager will 'eat' those
44 * exceptions.
45 *
46 * \pre TimerCallback must be cancelable!
47 */
48 using TimerCallback = Function<void ()>;
49
50 public:
51 class Manager;
52
53 public:
54 class Adder;
55
56 public:
57 /**
58 * Used for reporting from the IntervalTimer::Manager (e.g. for debugging, to dump the status).
59 */
61 TimerCallback fCallback;
62 Time::TimePointSeconds fCallNextAt;
63 optional<Time::Duration> fFrequency; // if missing, this is a one-shot event
64 optional<Time::Duration> fHysteresis;
65
66 public:
67 /**
68 * @see Characters::ToString ()
69 */
70 nonvirtual Characters::String ToString () const;
71 };
72
73 private:
74 struct Key_Extractor_ {
75 TimerCallback operator() (const RegisteredTask& r) const
76 {
77 return r.fCallback;
78 };
79 };
80
81 public:
82 using RegisteredTaskCollection =
83 Containers::KeyedCollection<RegisteredTask, TimerCallback, Containers::KeyedCollection_DefaultTraits<RegisteredTask, Execution::Function<void (void)>, Key_Extractor_>>;
84 };
85
86 /**
87 * Very early draft implementation. Later allow plugin 'IManager' API to allow for different backend approaches,
88 * and allow adders to optionally target different managers.
89 *
90 * \note Timers can only be added after the start of main (), and must be removed before the end of main.
91 *
92 * \note each TimerCallback must compare UNIQUE. You cannot use the same one twice in a given Manager, even with
93 * different times. This is because we need SOME unique key for each entry, and the Function object
94 * provides us with a convenient one.
95 *
96 * \note \em Thread-Safety <a href="Thread-Safety.md#Internally-Synchronized-Thread-Safety">Internally-Synchronized-Thread-Safety</a>
97 *
98 */
100 public:
101 class IRep;
102
103 public:
104 class DefaultRep;
105
106 public:
107 /**
108 * Argument to Manager can be nullptr, but then not usable.
109 */
110 Manager (const Manager&) = delete;
111 Manager (Manager&&) = default;
112 Manager (const shared_ptr<IRep>& rep);
113
114 public:
115 ~Manager () = default;
116
117 public:
118 nonvirtual Manager& operator= (const Manager&) = delete;
119 nonvirtual Manager& operator= (Manager&&) = default;
120
121 public:
122 /**
123 * \brief Add a timer to be called once after duration when
124 *
125 * \pre intervalTimer valid function ptr (not null)
126 * \pre intervalTimer not already registered
127 * \pre when >= 0
128 */
129 nonvirtual void AddOneShot (const TimerCallback& intervalTimer, const Time::Duration& when);
130
131 public:
132 /**
133 * \brief Add a timer to be called repeatedly after duration repeatInterval
134 *
135 * \pre intervalTimer valid function ptr (not null)
136 * \pre intervalTimer not already registered
137 * \pre repeatInterval >= 0
138 * \pre hysteresis == nullopt or hysteresis >= 0
139 */
140 nonvirtual void AddRepeating (const TimerCallback& intervalTimer, const Time::Duration& repeatInterval,
141 const optional<Time::Duration>& hysteresis = nullopt);
142
143 public:
144 /**
145 * Can remove a repeating task, but cannot remove a oneShot, since it might not be there by the time you go to remove it.
146 *
147 * \pre argument intervalTimer is registered.
148 */
149 nonvirtual void RemoveRepeating (const TimerCallback& intervalTimer) noexcept;
150
151 public:
152 /**
153 */
154 nonvirtual RegisteredTaskCollection GetAllRegisteredTasks () const;
155
156 public:
157 /**
158 * \brief Having explicit activator object allows for users to control the starting/stopping of facility in a managed fashion.
159 *
160 * At most one such object may exist. When it does, the IntervalTimer::Manager::sThe is active and usable.
161 * Its illegal to call otherwise.
162 *
163 * \par Example Usage
164 * \code
165 * main () {
166 * ...
167 * // near the beginning, before IntervalManager used
168 * Execution::IntervalTimer::Manager::Activator intervalTimerMgrActivator;
169 * \endcode
170 *
171 * \pre (Debug::AppearsDuringMainLifetime ()); during activator lifetime
172 */
173 struct Activator {
174 Activator ();
175 ~Activator ();
176 };
177
178 public:
179 /**
180 * Default interval timer, but you can specify others.
181 */
182 static Manager sThe;
183
184 private:
185 shared_ptr<IRep> fRep_;
186 };
187
188 /**
189 */
190 class IntervalTimer::Manager::IRep {
191 public:
192 virtual ~IRep () = default;
193
194 public:
195 virtual void AddOneShot (const TimerCallback& intervalTimer, const Time::Duration& when) = 0;
196
197 public:
198 virtual void AddRepeating (const TimerCallback& intervalTimer, const Time::Duration& repeatInterval,
199 const optional<Time::Duration>& hysteresis) = 0;
200
201 public:
202 virtual void RemoveRepeating (const TimerCallback& intervalTimer) noexcept = 0;
203
204 public:
205 virtual RegisteredTaskCollection GetAllRegisteredTasks () const = 0;
206 };
207
208 /**
209 * Probably don't use directly. But this is the default implementation of interval timers.
210 */
212 public:
213 DefaultRep ();
214
215 public:
216 virtual void AddOneShot (const TimerCallback& intervalTimer, const Time::Duration& when) override;
217
218 public:
219 virtual void AddRepeating (const TimerCallback& intervalTimer, const Time::Duration& repeatInterval,
220 const optional<Time::Duration>& hysteresis) override;
221
222 public:
223 virtual void RemoveRepeating (const TimerCallback& intervalTimer) noexcept override;
224
225 public:
226 virtual RegisteredTaskCollection GetAllRegisteredTasks () const override;
227
228 private:
229 // hidden implementation so details not in header files
230 struct Rep_;
231 shared_ptr<Rep_> fHiddenRep_;
232 };
233
234 /**
235 * \brief Adder adds the given function object to the (for now default; later optionally explicit) IntervalTimer manager, and
236 * when its destroyed, the timer is removed.
237 *
238 * While the timer is registered, it will be called periodically from some arbitrary thread.
239 *
240 * Easiest way to add/remove idle manager. Construct one and its lifetime matches time when callback is potentially aftive.
241 * Destruction of Adder object removes from the Q. Be sure lifetime of these guys inside lifetime of main.
242 */
244 public:
245 /**
246 */
248 eDontRunImmediately,
249 /**
250 * If specified as argument to Adder, then the callback function 'f' will be invoked DIRECTLY from constructor once
251 * as well as being added as a repeated item.
252 *
253 * Pretty commonly, if we have a task you want done every x seconds, you will also want it done IMMEDIATELY
254 * as well.
255 */
257 };
258
259 public:
260 using RunImmediatelyFlag::eDontRunImmediately;
262
263 public:
264 /**
265 * \pre (but unenforced) - lifetime of manager must be > that of created Adder
266 * \note if no manager specified, IntervalTimer::Manager::sThe is used.
267 *
268 * \par Example Usage
269 * \code
270 * namespace {
271 * unique_ptr<IntervalTimer::Adder> sIntervalTimerAdder_;
272 * }
273 * Activator::Activator ()
274 * {
275 * sIntervalTimerAdder_ = make_unique<IntervalTimer::Adder> (
276 * [] () { sKeepCachedMonitorsUpToDate_.DoOnce (); }
277 * , 1min
278 * , IntervalTimer::Adder::eRunImmediately);
279 * }
280 * Activator::~Activator ()
281 * {
282 * sIntervalTimerAdder_.release ();
283 * }
284 * \endcode
285 */
286 Adder () = delete;
287 Adder (Adder&& src) noexcept;
288 Adder (const Function<void (void)>& f, const Time::Duration& repeatInterval, const optional<Time::Duration>& hysteresis = nullopt);
289 Adder (const Function<void (void)>& f, const Time::Duration& repeatInterval, RunImmediatelyFlag runImmediately,
290 const optional<Time::Duration>& hysteresis = nullopt);
291 Adder (IntervalTimer::Manager& manager, const Function<void (void)>& f, const Time::Duration& repeatInterval,
292 const optional<Time::Duration>& hysteresis = nullopt);
293 Adder (IntervalTimer::Manager& manager, const Function<void (void)>& f, const Time::Duration& repeatInterval,
294 RunImmediatelyFlag runImmediately, const optional<Time::Duration>& hysteresis = nullopt);
295
296 public:
297 ~Adder ();
298
299 public:
300 nonvirtual Adder& operator= (const Adder&) = delete;
301 nonvirtual Adder& operator= (Adder&& rhs) noexcept;
302
303 public:
304 /**
305 */
306 nonvirtual Function<void (void)> GetCallback () const;
307
308 private:
309 Time::Duration fRepeatInterval_;
310 optional<Time::Duration> fHysteresis_;
311 IntervalTimer::Manager* fManager_;
312 Function<void (void)> fFunction_;
313 };
314
315}
316
317/*
318 ********************************************************************************
319 ***************************** Implementation Details ***************************
320 ********************************************************************************
321 */
322#include "IntervalTimer.inl"
323
324#endif /*_Stroika_Foundation_Execution_IntervalTimer_h_*/
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Definition Realtime.h:82
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
a cross between Mapping<KEY, T> and Collection<T> and Set<T>
Adder adds the given function object to the (for now default; later optionally explicit) IntervalTime...
nonvirtual void AddRepeating(const TimerCallback &intervalTimer, const Time::Duration &repeatInterval, const optional< Time::Duration > &hysteresis=nullopt)
Add a timer to be called repeatedly after duration repeatInterval.
nonvirtual void RemoveRepeating(const TimerCallback &intervalTimer) noexcept
nonvirtual void AddOneShot(const TimerCallback &intervalTimer, const Time::Duration &when)
Add a timer to be called once after duration when.
Manage interval timers - like the javascript setIntervalTimer API.
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
Having explicit activator object allows for users to control the starting/stopping of facility in a m...