]> git.localhorst.tv Git - l2e.git/blob - Timer.h
7e15952464057c61953653de28026afb8edb1f97
[l2e.git] / Timer.h
1 #ifndef APP_TIMER_H_
2 #define APP_TIMER_H_
3
4 #include <algorithm>
5 #include <list>
6 #include <cmath>
7
8 namespace app {
9
10 /// Stores timing information.
11 /// For use by app::Timer.
12 template<class Time>
13 struct TimerData {
14
15         TimerData() : time(0), target(0), refCount(0), justHit(false), repeat(false) { }
16         TimerData(Time target, bool repeat) : time(0), target(target), refCount(0), justHit(false), repeat(repeat) { }
17
18         Time time;
19         Time target;
20         int refCount;
21         bool justHit;
22         bool repeat;
23
24 };
25
26
27 /// Timer handle.
28 /// How the various information returned by the const member functions is to be
29 /// interpreted highly depends on how the timer was created (by app::Timers).
30 template<class Time>
31 class Timer {
32
33 public:
34         Timer() : data(0) { }
35         ~Timer() { if (data) --data->refCount; }
36         Timer(TimerData<Time> *data) : data(data) { ++data->refCount; }
37         Timer(const Timer<Time> &other)
38         : data(other.data) { if (data) ++(data->refCount); }
39         Timer<Time> &operator =(const Timer<Time> &other) {
40                 Timer<Time> temp(other);
41                 Swap(temp);
42                 return *this;
43         }
44         void Swap(Timer<Time> &other) {
45                 std::swap(data, other.data);
46         }
47
48 public:
49         /// Check if the timer was started (and not cleared) yet.
50         bool Started() const {
51                 return data;
52         }
53         /// Check if the timer has reached its target time (only sensible for
54         /// countdown timers).
55         bool Finished() const {
56                 return data && data->target != Time() && !data->repeat && data->time >= data->target;
57         }
58         /// Check if the timer was started and has not finished yet (in case it's a
59         /// countdown).
60         bool Running() const {
61                 return data && !Finished();
62         }
63         /// Get the elapsed time since the timer started.
64         Time Elapsed() const {
65                 return data ? data->time : Time();
66         }
67         /// Get the time remaining for countdowns.
68         Time Remaining() const {
69                 return data ? (data->target - data->time) : Time();
70         }
71         /// Get the iteration index for interval timers.
72         int Iteration() const {
73                 return (data && data->target > Time()) ? std::floor(data->time / data->target) : Time();
74         }
75         /// Check if the timer reached its interval or countdown goal this iteration.
76         bool JustHit() const {
77                 return data && data->justHit;
78         }
79
80         /// Unset the timer (does not stop other handles for a shared timer).
81         void Clear() {
82                 if (data) {
83                         --data->refCount;
84                         data = 0;
85                 }
86         }
87         /// Reset the timer, do not stop it if it's running.
88         void Reset() {
89                 if (data) data->time = Time();
90         }
91         /// Restart the timer.
92         /// Only works if the timer was started at least once.
93         void Restart() {
94                 if (data) {
95                         if (data->target > Time() && data->justHit) {
96                                 data->time -= data->target;
97                         } else {
98                                 data->time = Time();
99                         }
100                 }
101         }
102
103 private:
104         TimerData<Time> *data;
105
106 };
107
108
109 /// Tracker for timers, responsible for creating and updating them.
110 template<class Time>
111 class Timers {
112
113 public:
114         Timers() { }
115
116 public:
117         /// Move all timers forward by delta.
118         void Update(Time delta) {
119                 for (typename std::list<TimerData<Time> >::iterator i(data.begin()), end(data.end()); i != end;) {
120                         if (i->target > 0) {
121                                 Time intervalTime(i->time);
122                                 if (i->repeat) while (intervalTime > i->target) intervalTime -= i->target;
123                                 i->justHit = intervalTime < i->target && intervalTime + delta >= i->target;
124                         }
125                         i->time += delta;
126                         if (i->refCount <= 0) {
127                                 i = data.erase(i);
128                         } else {
129                                 ++i;
130                         }
131                 }
132         }
133         /// Start a timer that counts elapsed time until stopped manually.
134         Timer<Time> StartTimer() {
135                 data.push_back(TimerData<Time>());
136                 return Timer<Time>(&data.back());
137         }
138         /// Start a countdown that hits (JustHit() returing true) when duration
139         /// elapsed.
140         Timer<Time> StartCountdown(Time duration) {
141                 data.push_back(TimerData<Time>(duration, false));
142                 return Timer<Time>(&data.back());
143         }
144         /// Start an interval timer that hits (JustHit() returning true) each time
145         /// duration has passed.
146         Timer<Time> StartInterval(Time duration) {
147                 data.push_back(TimerData<Time>(duration, true));
148                 return Timer<Time>(&data.back());
149         }
150
151 private:
152         std::list<TimerData<Time> > data;
153
154 };
155
156 }
157
158 #endif /* APP_TIMER_H_ */