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