hmbdc
simplify-high-performance-messaging-programming
Timers.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 
4 #include "hmbdc/time/Time.hpp"
5 #include "hmbdc/Exception.hpp"
6 #include "hmbdc/Compile.hpp"
7 
8 #include <functional>
9 
10 #include <stdexcept>
11 #include <ctime>
12 
13 #include <boost/intrusive/set.hpp>
14 
15 
16 namespace hmbdc { namespace time {
17 struct TimerManager;
18 namespace timers_detail {
19  void noop(TimerManager&, SysTime const&);
20 }
21 
22 struct Timer
23 : boost::intrusive::set_base_hook<
24  boost::intrusive::link_mode<boost::intrusive::normal_link>
25  //the default safe_link appears too strict since many times the object is deleted
26  //before the container(TimerManager) is deleted and assert fires unnecesarily in that case
27 > {
28 protected:
29  SysTime getFireAt() const { return fireAt_; }
30 
31 public:
32  using Callback = std::function<void (TimerManager&, SysTime const&)>;
33  Timer(Callback cb = timers_detail::noop)
34  : armed(false)
35  , callback_(cb)
36  {}
37  void setCallback(Callback cb) {
38  callback_ = cb;
39  }
40  friend struct TimerManager;
41  bool operator < (Timer const& other) const
42  { return fireAt_ < other.fireAt_; }
43  bool operator <= (SysTime const& t) const
44  { return !(t < fireAt_); }
45 
46  virtual ~Timer(){}
47 
48 private:
49  void fired(TimerManager& tm, SysTime const& now) {
50  callback_(tm, now);
51  }
52  bool armed;
53  SysTime fireAt_;
54  Callback callback_;
55  virtual void reschedule(TimerManager& tm, SysTime const& now) = 0;
56 };
57 
58 namespace timers_detail {
59 inline
60 void noop(TimerManager&, SysTime const&)
61 {}
62 
63 } //timers_detail
64 
65 struct TimerManager {
66  void schedule(SysTime fireAt, Timer& timer) {
67  timer.fireAt_ = fireAt;
68  timers_.insert(timer);
69  timer.armed = true;
70  }
71  /**
72  * @brief cancel a timer previously scheduled with the TimerManager
73  * @details if not scheduled, no effect
74  *
75  * @param timer to be canceled
76  */
77  void cancel(Timer& timer) {
78  auto range = timers_.equal_range(timer);
79  for (auto it = range.first; it != range.second; ++it) {
80  if (&*it == &timer) {
81  timers_.erase(it);
82  timer.armed = false;
83  return;
84  }
85  }
86  }
87 
88  void checkTimers(time::SysTime);
89 
90  Duration untilNextFire() const {
91  auto res = std::numeric_limits<Duration>::max();
92  if (timers_.begin() != timers_.end()) {
93  res = timers_.begin()->fireAt_ - SysTime::now();
94  }
95  return res;
96  }
97 
98 private:
99  using Timers = boost::intrusive::multiset<Timer>;
100  Timers timers_;
101 };
102 
103 
105  ReoccuringTimer(Duration const& interval, Callback callback = timers_detail::noop)
106  : Timer(callback)
107  , interval(interval)
108  {}
109  const Duration interval;
110 private:
111  virtual void reschedule(TimerManager& tm, SysTime const& now)
112  { tm.schedule(now + interval, *this); };
113 };
114 
115 struct DailyTimer : Timer {
116  DailyTimer(Callback callback = timers_detail::noop)
117  : Timer(callback)
118  {}
119 private:
120  virtual void reschedule(TimerManager& tm, SysTime const& now) {
121  Duration day = Duration::seconds(86400);
122  SysTime newFireTime = getFireAt() + day;
123  while (newFireTime < now) newFireTime += day;
124  tm.schedule(newFireTime, *this);
125  };
126 };
127 
128 struct OneTimeTimer : Timer {
129  OneTimeTimer(Callback callback = timers_detail::noop)
130  : Timer(callback)
131  {}
132 
133 private:
134  virtual void reschedule(TimerManager&, SysTime const&){};
135 };
136 
137 }}
Definition: Timers.hpp:22
Definition: Timers.hpp:65
Definition: Timers.hpp:115
void cancel(Timer &timer)
cancel a timer previously scheduled with the TimerManager
Definition: Timers.hpp:77
Definition: Time.hpp:14
Definition: Timers.hpp:128
Definition: Time.hpp:125
Definition: Base.hpp:12
Definition: Timers.hpp:104