forked from loveyacper/ananas
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTimer.h
171 lines (131 loc) · 5.39 KB
/
Timer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#ifndef BERT_TIMERMANAGER_H
#define BERT_TIMERMANAGER_H
#include <map>
#include <chrono>
#include <functional>
#include <memory>
#include <ostream>
///@file Timer.h
namespace ananas {
using DurationMs = std::chrono::milliseconds;
using TimePoint = std::chrono::steady_clock::time_point;
using TimerId = std::shared_ptr<std::pair<TimePoint, unsigned int> >;
constexpr int kForever = -1;
inline std::ostream& operator<< (std::ostream& os, const TimerId& d) {
os << "[TimerId:" << (void*)d.get() << "]";
return os;
}
namespace internal {
///@brief TimerManager class
///
/// You should not used it directly, but via Eventloop
class TimerManager final {
public:
TimerManager();
~TimerManager();
TimerManager(const TimerManager& ) = delete;
void operator= (const TimerManager& ) = delete;
// Tick
void Update();
///@brief Schedule timer at absolute timepoint then repeat with period
///@param triggerTime The absolute time when timer first triggered
///@param period After first trigger, will be trigger by this period repeated until RepeatCount
///@param f The function to execute
///@param args Args for f
///
/// RepeatCount: Timer will be canceled after trigger RepeatCount times, kForever implies forever.
template <int RepeatCount, typename Duration, typename F, typename... Args>
TimerId ScheduleAtWithRepeat(const TimePoint& triggerTime, const Duration& period, F&& f, Args&&... args);
///@brief Schedule timer with period
///@param period: Timer will be triggered every period
///
/// RepeatCount: Timer will be canceled after triggered RepeatCount times, kForever implies forever.
/// PAY ATTENTION: Timer's first trigger isn't at once, but after period time
template <int RepeatCount, typename Duration, typename F, typename... Args>
TimerId ScheduleAfterWithRepeat(const Duration& period, F&& f, Args&&... args);
///@brief Schedule timer at timepoint
///@param triggerTime: The absolute time when timer trigger
///
/// It'll trigger only once
template <typename F, typename... Args>
TimerId ScheduleAt(const TimePoint& triggerTime, F&& f, Args&&... args);
///@brief Schedule timer after duration
///@param duration: After duration, timer will be triggered
///
/// It'll trigger only once
template <typename Duration, typename F, typename... Args>
TimerId ScheduleAfter(const Duration& duration, F&& f, Args&&... args);
///@brief Cancel timer
bool Cancel(TimerId id);
///@brief how far the nearest timer will be trigger.
DurationMs NearestTimer() const;
private:
class Timer {
friend class TimerManager;
public:
explicit
Timer(const TimePoint& tp);
// only move
Timer(Timer&& timer);
Timer& operator= (Timer&& );
Timer(const Timer& ) = delete;
void operator= (const Timer& ) = delete;
template <typename F, typename... Args>
void SetCallback(F&& f, Args&&... args);
void OnTimer();
TimerId Id() const;
unsigned int UniqueId() const;
private:
void _Move(Timer&& timer);
TimerId id_;
std::function<void ()> func_;
DurationMs interval_;
int count_;
};
std::multimap<TimePoint, Timer> timers_;
friend class Timer;
// not thread-safe, but who cares?
static unsigned int s_timerIdGen_;
};
template <int RepeatCount, typename Duration, typename F, typename... Args>
TimerId TimerManager::ScheduleAtWithRepeat(const TimePoint& triggerTime, const Duration& period, F&& f, Args&&... args) {
static_assert(RepeatCount != 0, "Why you add a timer with zero count?");
using namespace std::chrono;
Timer t(triggerTime);
// precision: milliseconds
t.interval_ = std::max(DurationMs(1), duration_cast<DurationMs>(period));
t.count_ = RepeatCount;
TimerId id = t.Id();
t.SetCallback(std::forward<F>(f), std::forward<Args>(args)...);
timers_.insert(std::make_pair(triggerTime, std::move(t)));
return id;
}
template <int RepeatCount, typename Duration, typename F, typename... Args>
TimerId TimerManager::ScheduleAfterWithRepeat(const Duration& period, F&& f, Args&&... args) {
const auto now = std::chrono::steady_clock::now();
return ScheduleAtWithRepeat<RepeatCount>(now + period,
period,
std::forward<F>(f),
std::forward<Args>(args)...);
}
template <typename F, typename... Args>
TimerId TimerManager::ScheduleAt(const TimePoint& triggerTime, F&& f, Args&&... args) {
return ScheduleAtWithRepeat<1>(triggerTime,
DurationMs(0), // dummy
std::forward<F>(f),
std::forward<Args>(args)...);
}
template <typename Duration, typename F, typename... Args>
TimerId TimerManager::ScheduleAfter(const Duration& duration, F&& f, Args&&... args) {
const auto now = std::chrono::steady_clock::now();
return ScheduleAt(now + duration,
std::forward<F>(f),
std::forward<Args>(args)...);
}
template <typename F, typename... Args>
void TimerManager::Timer::SetCallback(F&& f, Args&&... args) {
func_ = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
}
} // end namespace internal
} // end namespace ananas
#endif