]> git.mxchange.org Git - simgear.git/blob - simgear/timing/timestamp.hxx
OS-X specific sleep helper, more stable.
[simgear.git] / simgear / timing / timestamp.hxx
1 /**
2  * \file timestamp.hxx
3  * Provides a class for managing a timestamp (seconds & milliseconds.)
4  */
5
6 // Written by Curtis Olson, started December 1998.
7 //
8 // Copyright (C) 1998  Curtis L. Olson  - http://www.flightgear.org/~curt
9 //
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License as
12 // published by the Free Software Foundation; either version 2 of the
13 // License, or (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 // General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23 //
24 // $Id$
25
26
27 #ifndef _TIMESTAMP_HXX
28 #define _TIMESTAMP_HXX
29
30
31 #ifndef __cplusplus
32 # error This library requires C++
33 #endif
34
35 #include <iosfwd>
36 #include <iomanip>
37 #include <sstream>
38 #include <simgear/compiler.h>
39 #include <simgear/math/SGCMath.hxx>
40
41 /**
42  * The SGTimeStamp class allows you to mark and compare time stamps
43  * with nanosecond accuracy (if your system has support for this
44  * level of accuracy).
45  *
46  * The SGTimeStamp is useful for tracking the elapsed time of various
47  * events in your program. You can also use it to keep consistent
48  * motion across varying frame rates.
49  *
50  * Note SGTimestamp does not deliver the time of day. The content of this
51  * stamps might be, dependent on the implementation, a time to an arbitrary
52  * base time.
53  */
54
55 class SGTimeStamp {
56 public:
57     typedef long sec_type;
58     typedef int nsec_type;
59
60     /** Default constructor, initialize time to zero. */
61     SGTimeStamp() :
62       _nsec(0),
63       _sec(0)
64     { }
65
66     /** Hmm, might reenable them at some time, but since it is not clear
67         what the input unit of the int is, omit them for now.
68         Use the static constructor functions where it is clear from the method
69         name how the arguments are meant.
70      */
71 //     SGTimeStamp(sec_type sec)
72 //     { setTime(sec, 0); }
73 //     SGTimeStamp(int sec)
74 //     { setTime(sec, 0); }
75 //     SGTimeStamp(const double& sec)
76 //     { setTime(sec); }
77
78     /** Update stored time to current time (seconds and nanoseconds) */
79     void stamp();
80
81     /** Set the time from a double value */
82     void setTime(const double& seconds)
83     {
84         sec_type wholeSecs = sec_type(floor(seconds));
85         nsec_type reminder;
86         reminder = nsec_type(floor((seconds - wholeSecs)*(1000*1000*1000)));
87         setTime(wholeSecs, reminder);
88     }
89     /** Set the time from a seconds/nanoseconds pair */
90     void setTime(sec_type sec, nsec_type nsec)
91     {
92         if (0 <= nsec) {
93             _sec = sec + nsec / (1000*1000*1000);
94             _nsec = nsec % (1000*1000*1000);
95         } else {
96             _sec = sec - 1 + nsec / (1000*1000*1000);
97             _nsec = (1000*1000*1000) + nsec % (1000*1000*1000);
98         }
99     }
100
101     
102     /** @return the saved seconds of this time stamp */
103     long get_seconds() const { return _sec; }
104
105     /** @return the saved microseconds of this time stamp */
106     int get_usec() const { return _nsec/1000; }
107
108     /** @return the saved seconds of this time stamp */
109     const sec_type& getSeconds() const
110     { return _sec; }
111     /** @return the saved nanoseconds of this time stamp */
112     const nsec_type& getNanoSeconds() const
113     { return _nsec; }
114
115     /** @return the value of the timestamp in nanoseconds,
116      *  use doubles to avoid overflow.
117      *  If you need real nanosecond accuracy for time differences, build up a
118      *  SGTimeStamp reference time and compare SGTimeStamps directly.
119      */
120     double toNSecs() const
121     { return _nsec + double(_sec)*1000*1000*1000; }
122
123     /** @return the value of the timestamp in microseconds,
124      *  use doubles to avoid overflow.
125      *  If you need real nanosecond accuracy for time differences, build up a
126      *  SGTimeStamp reference time and compare SGTimeStamps directly.
127      */
128     double toUSecs() const
129     { return 1e-3*_nsec + double(_sec)*1000*1000; }
130
131     /** @return the value of the timestamp in milliseconds,
132      *  use doubles to avoid overflow.
133      *  If you need real nanosecond accuracy for time differences, build up a
134      *  SGTimeStamp reference time and compare SGTimeStamps directly.
135      */
136     double toMSecs() const
137     { return 1e-6*_nsec + double(_sec)*1000; }
138
139     /** @return the value of the timestamp in seconds,
140      *  use doubles to avoid overflow.
141      *  If you need real nanosecond accuracy for time differences, build up a
142      *  SGTimeStamp reference time and compare SGTimeStamps directly.
143      */
144     double toSecs() const
145     { return 1e-9*_nsec + _sec; }
146
147     /** Inplace addition.
148      */
149     SGTimeStamp& operator+=(const SGTimeStamp& c)
150     {
151         _sec += c._sec;
152         _nsec += c._nsec;
153         if ((1000*1000*1000) <= _nsec) {
154             _nsec -= (1000*1000*1000);
155             _sec += 1;
156         }
157         return *this;
158     }
159
160     /** Inplace subtraction.
161      */
162     SGTimeStamp& operator-=(const SGTimeStamp& c)
163     {
164         _sec -= c._sec;
165         _nsec -= c._nsec;
166         if (_nsec < 0) {
167             _nsec += (1000*1000*1000);
168             _sec -= 1;
169         }
170         return *this;
171     }
172
173     /**
174      *  Create SGTimeStamps from input with given units 
175      */
176     static SGTimeStamp fromSecMSec(sec_type sec, nsec_type msec)
177     { return SGTimeStamp(sec, 1000*1000*msec); }
178     static SGTimeStamp fromSecUSec(sec_type sec, nsec_type usec)
179     { return SGTimeStamp(sec, 1000*usec); }
180     static SGTimeStamp fromSecNSec(sec_type sec, nsec_type nsec)
181     { return SGTimeStamp(sec, nsec); }
182
183     static SGTimeStamp fromSec(int sec)
184     { SGTimeStamp ts; ts.setTime(sec); return ts; }
185     static SGTimeStamp fromSec(const double& sec)
186     { SGTimeStamp ts; ts.setTime(sec); return ts; }
187     static SGTimeStamp fromMSec(nsec_type msec)
188     { return SGTimeStamp(0, 1000*1000*msec); }
189     static SGTimeStamp fromUSec(nsec_type usec)
190     { return SGTimeStamp(0, 1000*usec); }
191     static SGTimeStamp fromNSec(nsec_type nsec)
192     { return SGTimeStamp(0, nsec); }
193
194     /**
195      *  Return a timestamp with the current time.
196      */
197     static SGTimeStamp now()
198     { SGTimeStamp ts; ts.stamp(); return ts; }
199
200     /**
201      *  Sleep until the time of abstime is passed.
202      */
203     static bool sleepUntil(const SGTimeStamp& abstime);
204
205     /**
206      *  Sleep for reltime.
207      */
208     static bool sleepFor(const SGTimeStamp& reltime);
209
210     /**
211      *  Alias for the most common use case with milliseconds.
212      */
213     static bool sleepForMSec(unsigned msec)
214     { return sleepFor(fromMSec(msec)); }
215
216     /**
217      * elapsed time since the stamp was taken, in msec
218      */
219     int elapsedMSec() const;
220 private:
221     SGTimeStamp(sec_type sec, nsec_type nsec)
222     { setTime(sec, nsec); }
223
224     nsec_type _nsec;
225     sec_type _sec;
226 };
227
228 inline bool
229 operator==(const SGTimeStamp& c1, const SGTimeStamp& c2)
230 {
231   if (c1.getNanoSeconds() != c2.getNanoSeconds())
232     return false;
233   return c1.getSeconds() == c2.getSeconds();
234 }
235
236 inline bool
237 operator!=(const SGTimeStamp& c1, const SGTimeStamp& c2)
238 { return !operator==(c1, c2); }
239
240 inline bool
241 operator<(const SGTimeStamp& c1, const SGTimeStamp& c2)
242 {
243   if (c1.getSeconds() < c2.getSeconds())
244     return true;
245   if (c1.getSeconds() > c2.getSeconds())
246     return false;
247   return c1.getNanoSeconds() < c2.getNanoSeconds();
248 }
249
250 inline bool
251 operator>(const SGTimeStamp& c1, const SGTimeStamp& c2)
252 { return c2 < c1; }
253
254 inline bool
255 operator>=(const SGTimeStamp& c1, const SGTimeStamp& c2)
256 { return !(c1 < c2); }
257
258 inline bool
259 operator<=(const SGTimeStamp& c1, const SGTimeStamp& c2)
260 { return !(c1 > c2); }
261
262 inline SGTimeStamp
263 operator+(const SGTimeStamp& c1)
264 { return c1; }
265
266 inline SGTimeStamp
267 operator-(const SGTimeStamp& c1)
268 { return SGTimeStamp::fromSec(0) -= c1; }
269
270 inline SGTimeStamp
271 operator+(const SGTimeStamp& c1, const SGTimeStamp& c2)
272 { return SGTimeStamp(c1) += c2; }
273
274 inline SGTimeStamp
275 operator-(const SGTimeStamp& c1, const SGTimeStamp& c2)
276 { return SGTimeStamp(c1) -= c2; }
277
278 template<typename char_type, typename traits_type> 
279 inline
280 std::basic_ostream<char_type, traits_type>&
281 operator<<(std::basic_ostream<char_type, traits_type>& os, const SGTimeStamp& c)
282 {
283   std::basic_stringstream<char_type, traits_type> stream;
284
285   SGTimeStamp pos = c;
286   if (c.getSeconds() < 0) {
287     stream << stream.widen('-');
288     pos = - c;
289   }
290   stream << pos.getSeconds() << stream.widen('.');
291   stream << std::setw(9) << std::setfill('0') << pos.getNanoSeconds();
292
293   return os << stream.str();
294 }
295
296 #endif // _TIMESTAMP_HXX
297
298