1 | // time2_demo.cpp ----------------------------------------------------------// |
2 | |
3 | // Copyright 2008 Howard Hinnant |
4 | // Copyright 2008 Beman Dawes |
5 | |
6 | // Distributed under the Boost Software License, Version 1.0. |
7 | // See http://www.boost.org/LICENSE_1_0.txt |
8 | |
9 | /* |
10 | |
11 | This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype. |
12 | Many thanks to Howard for making his code available under the Boost license. |
13 | The original code was modified to conform to Boost conventions and to section |
14 | 20.9 Time utilities [time] of the C++ committee's working paper N2798. |
15 | See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf. |
16 | |
17 | time2_demo contained this comment: |
18 | |
19 | Much thanks to Andrei Alexandrescu, |
20 | Walter Brown, |
21 | Peter Dimov, |
22 | Jeff Garland, |
23 | Terry Golubiewski, |
24 | Daniel Krugler, |
25 | Anthony Williams. |
26 | */ |
27 | |
28 | #define _CRT_SECURE_NO_WARNINGS // disable VC++ foolishness |
29 | |
30 | #include <boost/chrono/chrono.hpp> |
31 | #include <boost/type_traits.hpp> |
32 | |
33 | #include <cassert> |
34 | #include <climits> |
35 | #include <iostream> |
36 | #include <ostream> |
37 | #include <stdexcept> |
38 | |
39 | #include <windows.h> |
40 | |
41 | namespace |
42 | { |
43 | //struct timeval { |
44 | // long tv_sec; /* seconds */ |
45 | // long tv_usec; /* and microseconds */ |
46 | //}; |
47 | |
48 | int gettimeofday(struct timeval * tp, void *) |
49 | { |
50 | FILETIME ft; |
51 | ::GetSystemTimeAsFileTime( &ft ); // never fails |
52 | long long t = (static_cast<long long>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; |
53 | # if !defined( BOOST_MSVC ) || BOOST_MSVC > 1300 // > VC++ 7.0 |
54 | t -= 116444736000000000LL; |
55 | # else |
56 | t -= 116444736000000000; |
57 | # endif |
58 | t /= 10; // microseconds |
59 | tp->tv_sec = static_cast<long>( t / 1000000UL); |
60 | tp->tv_usec = static_cast<long>( t % 1000000UL); |
61 | return 0; |
62 | } |
63 | } // unnamed namespace |
64 | |
65 | ////////////////////////////////////////////////////////// |
66 | ///////////// simulated thread interface ///////////////// |
67 | ////////////////////////////////////////////////////////// |
68 | |
69 | |
70 | namespace std { |
71 | |
72 | void __print_time(boost::chrono::system_clock::time_point t) |
73 | { |
74 | using namespace boost::chrono; |
75 | time_t c_time = system_clock::to_time_t(t); |
76 | std::tm* tmptr = std::localtime(timer: &c_time); |
77 | system_clock::duration d = t.time_since_epoch(); |
78 | std::cout << tmptr->tm_hour << ':' << tmptr->tm_min << ':' << tmptr->tm_sec |
79 | << '.' << (d - duration_cast<seconds>(fd: d)).count(); |
80 | } |
81 | |
82 | namespace this_thread { |
83 | |
84 | template <class Rep, class Period> |
85 | void sleep_for(const boost::chrono::duration<Rep, Period>& d) |
86 | { |
87 | boost::chrono::microseconds t = boost::chrono::duration_cast<boost::chrono::microseconds>(d); |
88 | if (t < d) |
89 | ++t; |
90 | if (t > boost::chrono::microseconds(0)) |
91 | std::cout << "sleep_for " << t.count() << " microseconds\n" ; |
92 | } |
93 | |
94 | template <class Clock, class Duration> |
95 | void sleep_until(const boost::chrono::time_point<Clock, Duration>& t) |
96 | { |
97 | using namespace boost::chrono; |
98 | typedef time_point<Clock, Duration> Time; |
99 | typedef system_clock::time_point SysTime; |
100 | if (t > Clock::now()) |
101 | { |
102 | typedef typename boost::common_type<typename Time::duration, |
103 | typename SysTime::duration>::type D; |
104 | /* auto */ D d = t - Clock::now(); |
105 | microseconds us = duration_cast<microseconds>(d); |
106 | if (us < d) |
107 | ++us; |
108 | SysTime st = system_clock::now() + us; |
109 | std::cout << "sleep_until " ; |
110 | __print_time(t: st); |
111 | std::cout << " which is " << (st - system_clock::now()).count() << " microseconds away\n" ; |
112 | } |
113 | } |
114 | |
115 | } // this_thread |
116 | |
117 | struct mutex {}; |
118 | |
119 | struct timed_mutex |
120 | { |
121 | bool try_lock() {std::cout << "timed_mutex::try_lock()\n" ; return true;} |
122 | |
123 | template <class Rep, class Period> |
124 | bool try_lock_for(const boost::chrono::duration<Rep, Period>& d) |
125 | { |
126 | boost::chrono::microseconds t = boost::chrono::duration_cast<boost::chrono::microseconds>(d); |
127 | if (t <= boost::chrono::microseconds(0)) |
128 | return try_lock(); |
129 | std::cout << "try_lock_for " << t.count() << " microseconds\n" ; |
130 | return true; |
131 | } |
132 | |
133 | template <class Clock, class Duration> |
134 | bool try_lock_until(const boost::chrono::time_point<Clock, Duration>& t) |
135 | { |
136 | using namespace boost::chrono; |
137 | typedef time_point<Clock, Duration> Time; |
138 | typedef system_clock::time_point SysTime; |
139 | if (t <= Clock::now()) |
140 | return try_lock(); |
141 | typedef typename boost::common_type<typename Time::duration, |
142 | typename Clock::duration>::type D; |
143 | /* auto */ D d = t - Clock::now(); |
144 | microseconds us = duration_cast<microseconds>(d); |
145 | SysTime st = system_clock::now() + us; |
146 | std::cout << "try_lock_until " ; |
147 | __print_time(st); |
148 | std::cout << " which is " << (st - system_clock::now()).count() |
149 | << " microseconds away\n" ; |
150 | return true; |
151 | } |
152 | }; |
153 | |
154 | struct condition_variable |
155 | { |
156 | template <class Rep, class Period> |
157 | bool wait_for(mutex&, const boost::chrono::duration<Rep, Period>& d) |
158 | { |
159 | boost::chrono::microseconds t = boost::chrono::duration_cast<boost::chrono::microseconds>(d); |
160 | std::cout << "wait_for " << t.count() << " microseconds\n" ; |
161 | return true; |
162 | } |
163 | |
164 | template <class Clock, class Duration> |
165 | bool wait_until(mutex&, const boost::chrono::time_point<Clock, Duration>& t) |
166 | { |
167 | using namespace boost::chrono; |
168 | typedef time_point<Clock, Duration> Time; |
169 | typedef system_clock::time_point SysTime; |
170 | if (t <= Clock::now()) |
171 | return false; |
172 | typedef typename boost::common_type<typename Time::duration, |
173 | typename Clock::duration>::type D; |
174 | /* auto */ D d = t - Clock::now(); |
175 | microseconds us = duration_cast<microseconds>(d); |
176 | SysTime st = system_clock::now() + us; |
177 | std::cout << "wait_until " ; |
178 | __print_time(t: st); |
179 | std::cout << " which is " << (st - system_clock::now()).count() |
180 | << " microseconds away\n" ; |
181 | return true; |
182 | } |
183 | }; |
184 | |
185 | } // namespace std |
186 | |
187 | ////////////////////////////////////////////////////////// |
188 | //////////// Simple sleep and wait examples ////////////// |
189 | ////////////////////////////////////////////////////////// |
190 | |
191 | std::mutex m; |
192 | std::timed_mutex mut; |
193 | std::condition_variable cv; |
194 | |
195 | void basic_examples() |
196 | { |
197 | std::cout << "Running basic examples\n" ; |
198 | using namespace std; |
199 | using namespace boost::chrono; |
200 | system_clock::time_point time_limit = system_clock::now() + seconds(4) + milliseconds(500); |
201 | this_thread::sleep_for(d: seconds(3)); |
202 | this_thread::sleep_for(d: nanoseconds(300)); |
203 | this_thread::sleep_until(t: time_limit); |
204 | // this_thread::sleep_for(time_limit); // desired compile-time error |
205 | // this_thread::sleep_until(seconds(3)); // desired compile-time error |
206 | mut.try_lock_for(milliseconds(30)); |
207 | mut.try_lock_until(time_limit); |
208 | // mut.try_lock_for(time_limit); // desired compile-time error |
209 | // mut.try_lock_until(milliseconds(30)); // desired compile-time error |
210 | cv.wait_for(m, d: minutes(1)); // real code would put this in a loop |
211 | cv.wait_until(m, t: time_limit); // real code would put this in a loop |
212 | // For those who prefer floating point |
213 | this_thread::sleep_for(d: duration<double>(0.25)); |
214 | this_thread::sleep_until(t: system_clock::now() + duration<double>(1.5)); |
215 | } |
216 | |
217 | ////////////////////////////////////////////////////////// |
218 | //////////////////// User1 Example /////////////////////// |
219 | ////////////////////////////////////////////////////////// |
220 | |
221 | namespace User1 |
222 | { |
223 | // Example type-safe "physics" code interoperating with boost::chrono::duration types |
224 | // and taking advantage of the boost::ratio infrastructure and design philosophy. |
225 | |
226 | // length - mimics boost::chrono::duration except restricts representation to double. |
227 | // Uses boost::ratio facilities for length units conversions. |
228 | |
229 | template <class Ratio> |
230 | class length |
231 | { |
232 | public: |
233 | typedef Ratio ratio; |
234 | private: |
235 | double len_; |
236 | public: |
237 | |
238 | length() : len_(1) {} |
239 | length(const double& len) : len_(len) {} |
240 | |
241 | // conversions |
242 | template <class R> |
243 | length(const length<R>& d) |
244 | : len_(d.count() * boost::ratio_divide<Ratio, R>::type::den / |
245 | boost::ratio_divide<Ratio, R>::type::num) {} |
246 | |
247 | // observer |
248 | |
249 | double count() const {return len_;} |
250 | |
251 | // arithmetic |
252 | |
253 | length& operator+=(const length& d) {len_ += d.count(); return *this;} |
254 | length& operator-=(const length& d) {len_ -= d.count(); return *this;} |
255 | |
256 | length operator+() const {return *this;} |
257 | length operator-() const {return length(-len_);} |
258 | |
259 | length& operator*=(double rhs) {len_ *= rhs; return *this;} |
260 | length& operator/=(double rhs) {len_ /= rhs; return *this;} |
261 | }; |
262 | |
263 | // Sparse sampling of length units |
264 | typedef length<boost::ratio<1> > meter; // set meter as "unity" |
265 | typedef length<boost::centi> centimeter; // 1/100 meter |
266 | typedef length<boost::kilo> kilometer; // 1000 meters |
267 | typedef length<boost::ratio<254, 10000> > inch; // 254/10000 meters |
268 | // length takes ratio instead of two integral types so that definitions can be made like so: |
269 | typedef length<boost::ratio_multiply<boost::ratio<12>, inch::ratio>::type> ; // 12 inchs |
270 | typedef length<boost::ratio_multiply<boost::ratio<5280>, foot::ratio>::type> mile; // 5280 feet |
271 | |
272 | // Need a floating point definition of seconds |
273 | typedef boost::chrono::duration<double> seconds; // unity |
274 | // Demo of (scientific) support for sub-nanosecond resolutions |
275 | typedef boost::chrono::duration<double, boost::pico> picosecond; // 10^-12 seconds |
276 | typedef boost::chrono::duration<double, boost::femto> femtosecond; // 10^-15 seconds |
277 | typedef boost::chrono::duration<double, boost::atto> attosecond; // 10^-18 seconds |
278 | |
279 | // A very brief proof-of-concept for SIUnits-like library |
280 | // Hard-wired to floating point seconds and meters, but accepts other units (shown in testUser1()) |
281 | template <class R1, class R2> |
282 | class quantity |
283 | { |
284 | double q_; |
285 | public: |
286 | quantity() : q_(1) {} |
287 | |
288 | double get() const {return q_;} |
289 | void set(double q) {q_ = q;} |
290 | }; |
291 | |
292 | template <> |
293 | class quantity<boost::ratio<1>, boost::ratio<0> > |
294 | { |
295 | double q_; |
296 | public: |
297 | quantity() : q_(1) {} |
298 | quantity(seconds d) : q_(d.count()) {} // note: only User1::seconds needed here |
299 | |
300 | double get() const {return q_;} |
301 | void set(double q) {q_ = q;} |
302 | }; |
303 | |
304 | template <> |
305 | class quantity<boost::ratio<0>, boost::ratio<1> > |
306 | { |
307 | double q_; |
308 | public: |
309 | quantity() : q_(1) {} |
310 | quantity(meter d) : q_(d.count()) {} // note: only User1::meter needed here |
311 | |
312 | double get() const {return q_;} |
313 | void set(double q) {q_ = q;} |
314 | }; |
315 | |
316 | template <> |
317 | class quantity<boost::ratio<0>, boost::ratio<0> > |
318 | { |
319 | double q_; |
320 | public: |
321 | quantity() : q_(1) {} |
322 | quantity(double d) : q_(d) {} |
323 | |
324 | double get() const {return q_;} |
325 | void set(double q) {q_ = q;} |
326 | }; |
327 | |
328 | // Example SI-Units |
329 | typedef quantity<boost::ratio<0>, boost::ratio<0> > Scalar; |
330 | typedef quantity<boost::ratio<1>, boost::ratio<0> > Time; // second |
331 | typedef quantity<boost::ratio<0>, boost::ratio<1> > Distance; // meter |
332 | typedef quantity<boost::ratio<-1>, boost::ratio<1> > Speed; // meter/second |
333 | typedef quantity<boost::ratio<-2>, boost::ratio<1> > Acceleration; // meter/second^2 |
334 | |
335 | template <class R1, class R2, class R3, class R4> |
336 | quantity<typename boost::ratio_subtract<R1, R3>::type, typename boost::ratio_subtract<R2, R4>::type> |
337 | operator/(const quantity<R1, R2>& x, const quantity<R3, R4>& y) |
338 | { |
339 | typedef quantity<typename boost::ratio_subtract<R1, R3>::type, typename boost::ratio_subtract<R2, R4>::type> R; |
340 | R r; |
341 | r.set(x.get() / y.get()); |
342 | return r; |
343 | } |
344 | |
345 | template <class R1, class R2, class R3, class R4> |
346 | quantity<typename boost::ratio_add<R1, R3>::type, typename boost::ratio_add<R2, R4>::type> |
347 | operator*(const quantity<R1, R2>& x, const quantity<R3, R4>& y) |
348 | { |
349 | typedef quantity<typename boost::ratio_add<R1, R3>::type, typename boost::ratio_add<R2, R4>::type> R; |
350 | R r; |
351 | r.set(x.get() * y.get()); |
352 | return r; |
353 | } |
354 | |
355 | template <class R1, class R2> |
356 | quantity<R1, R2> |
357 | operator+(const quantity<R1, R2>& x, const quantity<R1, R2>& y) |
358 | { |
359 | typedef quantity<R1, R2> R; |
360 | R r; |
361 | r.set(x.get() + y.get()); |
362 | return r; |
363 | } |
364 | |
365 | template <class R1, class R2> |
366 | quantity<R1, R2> |
367 | operator-(const quantity<R1, R2>& x, const quantity<R1, R2>& y) |
368 | { |
369 | typedef quantity<R1, R2> R; |
370 | R r; |
371 | r.set(x.get() - y.get()); |
372 | return r; |
373 | } |
374 | |
375 | // Example type-safe physics function |
376 | Distance |
377 | compute_distance(Speed v0, Time t, Acceleration a) |
378 | { |
379 | return v0 * t + Scalar(.5) * a * t * t; // if a units mistake is made here it won't compile |
380 | } |
381 | |
382 | } // User1 |
383 | |
384 | |
385 | // Exercise example type-safe physics function and show interoperation |
386 | // of custom time durations (User1::seconds) and standard time durations (std::hours). |
387 | // Though input can be arbitrary (but type-safe) units, output is always in SI-units |
388 | // (a limitation of the simplified Units lib demoed here). |
389 | void testUser1() |
390 | { |
391 | std::cout << "*************\n" ; |
392 | std::cout << "* testUser1 *\n" ; |
393 | std::cout << "*************\n" ; |
394 | User1::Distance d( User1::mile(110) ); |
395 | User1::Time t( boost::chrono::hours(2) ); |
396 | User1::Speed s = d / t; |
397 | std::cout << "Speed = " << s.get() << " meters/sec\n" ; |
398 | User1::Acceleration a = User1::Distance( User1::foot(32.2) ) / User1::Time() / User1::Time(); |
399 | std::cout << "Acceleration = " << a.get() << " meters/sec^2\n" ; |
400 | User1::Distance df = compute_distance(v0: s, t: User1::Time( User1::seconds(0.5) ), a); |
401 | std::cout << "Distance = " << df.get() << " meters\n" ; |
402 | std::cout << "There are " << User1::mile::ratio::den << '/' << User1::mile::ratio::num << " miles/meter" ; |
403 | User1::meter mt = 1; |
404 | User1::mile mi = mt; |
405 | std::cout << " which is approximately " << mi.count() << '\n'; |
406 | std::cout << "There are " << User1::mile::ratio::num << '/' << User1::mile::ratio::den << " meters/mile" ; |
407 | mi = 1; |
408 | mt = mi; |
409 | std::cout << " which is approximately " << mt.count() << '\n'; |
410 | User1::attosecond as(1); |
411 | User1::seconds sec = as; |
412 | std::cout << "1 attosecond is " << sec.count() << " seconds\n" ; |
413 | std::cout << "sec = as; // compiles\n" ; |
414 | sec = User1::seconds(1); |
415 | as = sec; |
416 | std::cout << "1 second is " << as.count() << " attoseconds\n" ; |
417 | std::cout << "as = sec; // compiles\n" ; |
418 | std::cout << "\n" ; |
419 | } |
420 | |
421 | ////////////////////////////////////////////////////////// |
422 | //////////////////// User2 Example /////////////////////// |
423 | ////////////////////////////////////////////////////////// |
424 | |
425 | // Demonstrate User2: |
426 | // A "saturating" signed integral type is developed. This type has +/- infinity and a nan |
427 | // (like IEEE floating point) but otherwise obeys signed integral arithmetic. |
428 | // This class is subsequently used as the rep in boost::chrono::duration to demonstrate a |
429 | // duration class that does not silently ignore overflow. |
430 | |
431 | namespace User2 |
432 | { |
433 | |
434 | template <class I> |
435 | class saturate |
436 | { |
437 | public: |
438 | typedef I int_type; |
439 | |
440 | static const int_type nan = int_type(int_type(1) << (sizeof(int_type) * CHAR_BIT - 1)); |
441 | static const int_type neg_inf = nan + 1; |
442 | static const int_type pos_inf = -neg_inf; |
443 | private: |
444 | int_type i_; |
445 | |
446 | // static_assert(std::is_integral<int_type>::value && std::is_signed<int_type>::value, |
447 | // "saturate only accepts signed integral types"); |
448 | // static_assert(nan == -nan && neg_inf < pos_inf, |
449 | // "saturate assumes two's complement hardware for signed integrals"); |
450 | |
451 | public: |
452 | saturate() : i_(nan) {} |
453 | explicit saturate(int_type i) : i_(i) {} |
454 | // explicit |
455 | operator int_type() const; |
456 | |
457 | saturate& operator+=(saturate x); |
458 | saturate& operator-=(saturate x) {return *this += -x;} |
459 | saturate& operator*=(saturate x); |
460 | saturate& operator/=(saturate x); |
461 | saturate& operator%=(saturate x); |
462 | |
463 | saturate operator- () const {return saturate(-i_);} |
464 | saturate& operator++() {*this += saturate(int_type(1)); return *this;} |
465 | saturate operator++(int) {saturate tmp(*this); ++(*this); return tmp;} |
466 | saturate& operator--() {*this -= saturate(int_type(1)); return *this;} |
467 | saturate operator--(int) {saturate tmp(*this); --(*this); return tmp;} |
468 | |
469 | friend saturate operator+(saturate x, saturate y) {return x += y;} |
470 | friend saturate operator-(saturate x, saturate y) {return x -= y;} |
471 | friend saturate operator*(saturate x, saturate y) {return x *= y;} |
472 | friend saturate operator/(saturate x, saturate y) {return x /= y;} |
473 | friend saturate operator%(saturate x, saturate y) {return x %= y;} |
474 | |
475 | friend bool operator==(saturate x, saturate y) |
476 | { |
477 | if (x.i_ == nan || y.i_ == nan) |
478 | return false; |
479 | return x.i_ == y.i_; |
480 | } |
481 | |
482 | friend bool operator!=(saturate x, saturate y) {return !(x == y);} |
483 | |
484 | friend bool operator<(saturate x, saturate y) |
485 | { |
486 | if (x.i_ == nan || y.i_ == nan) |
487 | return false; |
488 | return x.i_ < y.i_; |
489 | } |
490 | |
491 | friend bool operator<=(saturate x, saturate y) |
492 | { |
493 | if (x.i_ == nan || y.i_ == nan) |
494 | return false; |
495 | return x.i_ <= y.i_; |
496 | } |
497 | |
498 | friend bool operator>(saturate x, saturate y) |
499 | { |
500 | if (x.i_ == nan || y.i_ == nan) |
501 | return false; |
502 | return x.i_ > y.i_; |
503 | } |
504 | |
505 | friend bool operator>=(saturate x, saturate y) |
506 | { |
507 | if (x.i_ == nan || y.i_ == nan) |
508 | return false; |
509 | return x.i_ >= y.i_; |
510 | } |
511 | |
512 | friend std::ostream& operator<<(std::ostream& os, saturate s) |
513 | { |
514 | switch (s.i_) |
515 | { |
516 | case pos_inf: |
517 | return os << "inf" ; |
518 | case nan: |
519 | return os << "nan" ; |
520 | case neg_inf: |
521 | return os << "-inf" ; |
522 | }; |
523 | return os << s.i_; |
524 | } |
525 | }; |
526 | |
527 | template <class I> |
528 | saturate<I>::operator int_type() const |
529 | { |
530 | switch (i_) |
531 | { |
532 | case nan: |
533 | case neg_inf: |
534 | case pos_inf: |
535 | throw std::out_of_range("saturate special value can not convert to int_type" ); |
536 | } |
537 | return i_; |
538 | } |
539 | |
540 | template <class I> |
541 | saturate<I>& |
542 | saturate<I>::operator+=(saturate x) |
543 | { |
544 | switch (i_) |
545 | { |
546 | case pos_inf: |
547 | switch (x.i_) |
548 | { |
549 | case neg_inf: |
550 | case nan: |
551 | i_ = nan; |
552 | } |
553 | return *this; |
554 | case nan: |
555 | return *this; |
556 | case neg_inf: |
557 | switch (x.i_) |
558 | { |
559 | case pos_inf: |
560 | case nan: |
561 | i_ = nan; |
562 | } |
563 | return *this; |
564 | } |
565 | switch (x.i_) |
566 | { |
567 | case pos_inf: |
568 | case neg_inf: |
569 | case nan: |
570 | i_ = x.i_; |
571 | return *this; |
572 | } |
573 | if (x.i_ >= 0) |
574 | { |
575 | if (i_ < pos_inf - x.i_) |
576 | i_ += x.i_; |
577 | else |
578 | i_ = pos_inf; |
579 | return *this; |
580 | } |
581 | if (i_ > neg_inf - x.i_) |
582 | i_ += x.i_; |
583 | else |
584 | i_ = neg_inf; |
585 | return *this; |
586 | } |
587 | |
588 | template <class I> |
589 | saturate<I>& |
590 | saturate<I>::operator*=(saturate x) |
591 | { |
592 | switch (i_) |
593 | { |
594 | case 0: |
595 | switch (x.i_) |
596 | { |
597 | case pos_inf: |
598 | case neg_inf: |
599 | case nan: |
600 | i_ = nan; |
601 | } |
602 | return *this; |
603 | case pos_inf: |
604 | switch (x.i_) |
605 | { |
606 | case nan: |
607 | case 0: |
608 | i_ = nan; |
609 | return *this; |
610 | } |
611 | if (x.i_ < 0) |
612 | i_ = neg_inf; |
613 | return *this; |
614 | case nan: |
615 | return *this; |
616 | case neg_inf: |
617 | switch (x.i_) |
618 | { |
619 | case nan: |
620 | case 0: |
621 | i_ = nan; |
622 | return *this; |
623 | } |
624 | if (x.i_ < 0) |
625 | i_ = pos_inf; |
626 | return *this; |
627 | } |
628 | switch (x.i_) |
629 | { |
630 | case 0: |
631 | i_ = 0; |
632 | return *this; |
633 | case nan: |
634 | i_ = nan; |
635 | return *this; |
636 | case pos_inf: |
637 | if (i_ < 0) |
638 | i_ = neg_inf; |
639 | else |
640 | i_ = pos_inf; |
641 | return *this; |
642 | case neg_inf: |
643 | if (i_ < 0) |
644 | i_ = pos_inf; |
645 | else |
646 | i_ = neg_inf; |
647 | return *this; |
648 | } |
649 | int s = (i_ < 0 ? -1 : 1) * (x.i_ < 0 ? -1 : 1); |
650 | i_ = i_ < 0 ? -i_ : i_; |
651 | int_type x_i_ = x.i_ < 0 ? -x.i_ : x.i_; |
652 | if (i_ <= pos_inf / x_i_) |
653 | i_ *= x_i_; |
654 | else |
655 | i_ = pos_inf; |
656 | i_ *= s; |
657 | return *this; |
658 | } |
659 | |
660 | template <class I> |
661 | saturate<I>& |
662 | saturate<I>::operator/=(saturate x) |
663 | { |
664 | switch (x.i_) |
665 | { |
666 | case pos_inf: |
667 | case neg_inf: |
668 | switch (i_) |
669 | { |
670 | case pos_inf: |
671 | case neg_inf: |
672 | case nan: |
673 | i_ = nan; |
674 | break; |
675 | default: |
676 | i_ = 0; |
677 | break; |
678 | } |
679 | return *this; |
680 | case nan: |
681 | i_ = nan; |
682 | return *this; |
683 | case 0: |
684 | switch (i_) |
685 | { |
686 | case pos_inf: |
687 | case neg_inf: |
688 | case nan: |
689 | return *this; |
690 | case 0: |
691 | i_ = nan; |
692 | return *this; |
693 | } |
694 | if (i_ > 0) |
695 | i_ = pos_inf; |
696 | else |
697 | i_ = neg_inf; |
698 | return *this; |
699 | } |
700 | switch (i_) |
701 | { |
702 | case 0: |
703 | case nan: |
704 | return *this; |
705 | case pos_inf: |
706 | case neg_inf: |
707 | if (x.i_ < 0) |
708 | i_ = -i_; |
709 | return *this; |
710 | } |
711 | i_ /= x.i_; |
712 | return *this; |
713 | } |
714 | |
715 | template <class I> |
716 | saturate<I>& |
717 | saturate<I>::operator%=(saturate x) |
718 | { |
719 | // *this -= *this / x * x; // definition |
720 | switch (x.i_) |
721 | { |
722 | case nan: |
723 | case neg_inf: |
724 | case 0: |
725 | case pos_inf: |
726 | i_ = nan; |
727 | return *this; |
728 | } |
729 | switch (i_) |
730 | { |
731 | case neg_inf: |
732 | case pos_inf: |
733 | i_ = nan; |
734 | case nan: |
735 | return *this; |
736 | } |
737 | i_ %= x.i_; |
738 | return *this; |
739 | } |
740 | |
741 | // Demo overflow-safe integral durations ranging from picoseconds resolution to millennium resolution |
742 | typedef boost::chrono::duration<saturate<long long>, boost::pico > picoseconds; |
743 | typedef boost::chrono::duration<saturate<long long>, boost::nano > nanoseconds; |
744 | typedef boost::chrono::duration<saturate<long long>, boost::micro > microseconds; |
745 | typedef boost::chrono::duration<saturate<long long>, boost::milli > milliseconds; |
746 | typedef boost::chrono::duration<saturate<long long> > seconds; |
747 | typedef boost::chrono::duration<saturate<long long>, boost::ratio< 60LL> > minutes; |
748 | typedef boost::chrono::duration<saturate<long long>, boost::ratio< 3600LL> > hours; |
749 | typedef boost::chrono::duration<saturate<long long>, boost::ratio< 86400LL> > days; |
750 | typedef boost::chrono::duration<saturate<long long>, boost::ratio< 31556952LL> > years; |
751 | typedef boost::chrono::duration<saturate<long long>, boost::ratio<31556952000LL> > millennium; |
752 | |
753 | } // User2 |
754 | |
755 | // Demonstrate custom promotion rules (needed only if there are no implicit conversions) |
756 | namespace User2 { namespace detail { |
757 | |
758 | template <class T1, class T2, bool = boost::is_integral<T1>::value> |
759 | struct promote_helper; |
760 | |
761 | template <class T1, class T2> |
762 | struct promote_helper<T1, saturate<T2>, true> // integral |
763 | { |
764 | typedef typename boost::common_type<T1, T2>::type rep; |
765 | typedef User2::saturate<rep> type; |
766 | }; |
767 | |
768 | template <class T1, class T2> |
769 | struct promote_helper<T1, saturate<T2>, false> // floating |
770 | { |
771 | typedef T1 type; |
772 | }; |
773 | |
774 | } } |
775 | |
776 | namespace boost |
777 | { |
778 | |
779 | template <class T1, class T2> |
780 | struct common_type<User2::saturate<T1>, User2::saturate<T2> > |
781 | { |
782 | typedef typename common_type<T1, T2>::type rep; |
783 | typedef User2::saturate<rep> type; |
784 | }; |
785 | |
786 | template <class T1, class T2> |
787 | struct common_type<T1, User2::saturate<T2> > |
788 | : User2::detail::promote_helper<T1, User2::saturate<T2> > {}; |
789 | |
790 | template <class T1, class T2> |
791 | struct common_type<User2::saturate<T1>, T2> |
792 | : User2::detail::promote_helper<T2, User2::saturate<T1> > {}; |
793 | |
794 | |
795 | // Demonstrate specialization of duration_values: |
796 | |
797 | namespace chrono { |
798 | |
799 | template <class I> |
800 | struct duration_values<User2::saturate<I> > |
801 | { |
802 | typedef User2::saturate<I> Rep; |
803 | public: |
804 | static Rep zero() {return Rep(0);} |
805 | static Rep max BOOST_PREVENT_MACRO_SUBSTITUTION () {return Rep(Rep::pos_inf-1);} |
806 | static Rep min BOOST_PREVENT_MACRO_SUBSTITUTION () {return -(max) ();} |
807 | }; |
808 | |
809 | } // namespace chrono |
810 | |
811 | } // namespace boost |
812 | |
813 | |
814 | void testUser2() |
815 | { |
816 | std::cout << "*************\n" ; |
817 | std::cout << "* testUser2 *\n" ; |
818 | std::cout << "*************\n" ; |
819 | using namespace User2; |
820 | typedef seconds::rep sat; |
821 | years yr(sat(100)); |
822 | std::cout << "100 years expressed as years = " << yr.count() << '\n'; |
823 | nanoseconds ns = yr; |
824 | std::cout << "100 years expressed as nanoseconds = " << ns.count() << '\n'; |
825 | ns += yr; |
826 | std::cout << "200 years expressed as nanoseconds = " << ns.count() << '\n'; |
827 | ns += yr; |
828 | std::cout << "300 years expressed as nanoseconds = " << ns.count() << '\n'; |
829 | // yr = ns; // does not compile |
830 | std::cout << "yr = ns; // does not compile\n" ; |
831 | // picoseconds ps1 = yr; // does not compile, compile-time overflow in ratio arithmetic |
832 | std::cout << "ps = yr; // does not compile\n" ; |
833 | ns = yr; |
834 | picoseconds ps = ns; |
835 | std::cout << "100 years expressed as picoseconds = " << ps.count() << '\n'; |
836 | ps = ns / sat(1000); |
837 | std::cout << "0.1 years expressed as picoseconds = " << ps.count() << '\n'; |
838 | yr = years(sat(-200000000)); |
839 | std::cout << "200 million years ago encoded in years: " << yr.count() << '\n'; |
840 | days d = boost::chrono::duration_cast<days>(fd: yr); |
841 | std::cout << "200 million years ago encoded in days: " << d.count() << '\n'; |
842 | millennium c = boost::chrono::duration_cast<millennium>(fd: yr); |
843 | std::cout << "200 million years ago encoded in millennium: " << c.count() << '\n'; |
844 | std::cout << "Demonstrate \"uninitialized protection\" behavior:\n" ; |
845 | seconds sec; |
846 | for (++sec; sec < seconds(sat(10)); ++sec) |
847 | ; |
848 | std::cout << sec.count() << '\n'; |
849 | std::cout << "\n" ; |
850 | } |
851 | |
852 | void testStdUser() |
853 | { |
854 | std::cout << "***************\n" ; |
855 | std::cout << "* testStdUser *\n" ; |
856 | std::cout << "***************\n" ; |
857 | using namespace boost::chrono; |
858 | hours hr = hours(100); |
859 | std::cout << "100 hours expressed as hours = " << hr.count() << '\n'; |
860 | nanoseconds ns = hr; |
861 | std::cout << "100 hours expressed as nanoseconds = " << ns.count() << '\n'; |
862 | ns += hr; |
863 | std::cout << "200 hours expressed as nanoseconds = " << ns.count() << '\n'; |
864 | ns += hr; |
865 | std::cout << "300 hours expressed as nanoseconds = " << ns.count() << '\n'; |
866 | // hr = ns; // does not compile |
867 | std::cout << "hr = ns; // does not compile\n" ; |
868 | // hr * ns; // does not compile |
869 | std::cout << "hr * ns; // does not compile\n" ; |
870 | duration<double> fs(2.5); |
871 | std::cout << "duration<double> has count() = " << fs.count() << '\n'; |
872 | // seconds sec = fs; // does not compile |
873 | std::cout << "seconds sec = duration<double> won't compile\n" ; |
874 | seconds sec = duration_cast<seconds>(fd: fs); |
875 | std::cout << "seconds has count() = " << sec.count() << '\n'; |
876 | std::cout << "\n" ; |
877 | } |
878 | |
879 | // timeval clock demo |
880 | // Demonstrate the use of a timeval-like struct to be used as the representation |
881 | // type for both duraiton and time_point. |
882 | |
883 | namespace timeval_demo |
884 | { |
885 | |
886 | class xtime { |
887 | private: |
888 | long tv_sec; |
889 | long tv_usec; |
890 | |
891 | void fixup() { |
892 | if (tv_usec < 0) { |
893 | tv_usec += 1000000; |
894 | --tv_sec; |
895 | } |
896 | } |
897 | |
898 | public: |
899 | |
900 | explicit xtime(long sec, long usec) { |
901 | tv_sec = sec; |
902 | tv_usec = usec; |
903 | if (tv_usec < 0 || tv_usec >= 1000000) { |
904 | tv_sec += tv_usec / 1000000; |
905 | tv_usec %= 1000000; |
906 | fixup(); |
907 | } |
908 | } |
909 | |
910 | explicit xtime(long long usec) |
911 | { |
912 | tv_usec = static_cast<long>(usec % 1000000); |
913 | tv_sec = static_cast<long>(usec / 1000000); |
914 | fixup(); |
915 | } |
916 | |
917 | // explicit |
918 | operator long long() const {return static_cast<long long>(tv_sec) * 1000000 + tv_usec;} |
919 | |
920 | xtime& operator += (xtime rhs) { |
921 | tv_sec += rhs.tv_sec; |
922 | tv_usec += rhs.tv_usec; |
923 | if (tv_usec >= 1000000) { |
924 | tv_usec -= 1000000; |
925 | ++tv_sec; |
926 | } |
927 | return *this; |
928 | } |
929 | |
930 | xtime& operator -= (xtime rhs) { |
931 | tv_sec -= rhs.tv_sec; |
932 | tv_usec -= rhs.tv_usec; |
933 | fixup(); |
934 | return *this; |
935 | } |
936 | |
937 | xtime& operator %= (xtime rhs) { |
938 | long long t = tv_sec * 1000000 + tv_usec; |
939 | long long r = rhs.tv_sec * 1000000 + rhs.tv_usec; |
940 | t %= r; |
941 | tv_sec = static_cast<long>(t / 1000000); |
942 | tv_usec = static_cast<long>(t % 1000000); |
943 | fixup(); |
944 | return *this; |
945 | } |
946 | |
947 | friend xtime operator+(xtime x, xtime y) {return x += y;} |
948 | friend xtime operator-(xtime x, xtime y) {return x -= y;} |
949 | friend xtime operator%(xtime x, xtime y) {return x %= y;} |
950 | |
951 | friend bool operator==(xtime x, xtime y) |
952 | { return (x.tv_sec == y.tv_sec && x.tv_usec == y.tv_usec); } |
953 | |
954 | friend bool operator<(xtime x, xtime y) { |
955 | if (x.tv_sec == y.tv_sec) |
956 | return (x.tv_usec < y.tv_usec); |
957 | return (x.tv_sec < y.tv_sec); |
958 | } |
959 | |
960 | friend bool operator!=(xtime x, xtime y) { return !(x == y); } |
961 | friend bool operator> (xtime x, xtime y) { return y < x; } |
962 | friend bool operator<=(xtime x, xtime y) { return !(y < x); } |
963 | friend bool operator>=(xtime x, xtime y) { return !(x < y); } |
964 | |
965 | friend std::ostream& operator<<(std::ostream& os, xtime x) |
966 | {return os << '{' << x.tv_sec << ',' << x.tv_usec << '}';} |
967 | }; |
968 | |
969 | class xtime_clock |
970 | { |
971 | public: |
972 | typedef xtime rep; |
973 | typedef boost::micro period; |
974 | typedef boost::chrono::duration<rep, period> duration; |
975 | typedef boost::chrono::time_point<xtime_clock> time_point; |
976 | |
977 | static time_point now(); |
978 | }; |
979 | |
980 | xtime_clock::time_point |
981 | xtime_clock::now() |
982 | { |
983 | time_point t(duration(xtime(0))); |
984 | gettimeofday(tp: (timeval*)&t, 0); |
985 | return t; |
986 | } |
987 | |
988 | void test_xtime_clock() |
989 | { |
990 | using namespace boost::chrono; |
991 | std::cout << "timeval_demo system clock test\n" ; |
992 | std::cout << "sizeof xtime_clock::time_point = " << sizeof(xtime_clock::time_point) << '\n'; |
993 | std::cout << "sizeof xtime_clock::duration = " << sizeof(xtime_clock::duration) << '\n'; |
994 | std::cout << "sizeof xtime_clock::rep = " << sizeof(xtime_clock::rep) << '\n'; |
995 | xtime_clock::duration delay(milliseconds(5)); |
996 | xtime_clock::time_point start = xtime_clock::now(); |
997 | while (xtime_clock::now() - start <= delay) |
998 | { |
999 | } |
1000 | xtime_clock::time_point stop = xtime_clock::now(); |
1001 | xtime_clock::duration elapsed = stop - start; |
1002 | std::cout << "paused " << nanoseconds(elapsed).count() << " nanoseconds\n" ; |
1003 | } |
1004 | |
1005 | } // timeval_demo |
1006 | |
1007 | // Handle duration with resolution not known until run time |
1008 | |
1009 | namespace runtime_resolution |
1010 | { |
1011 | |
1012 | class duration |
1013 | { |
1014 | public: |
1015 | typedef long long rep; |
1016 | private: |
1017 | rep rep_; |
1018 | |
1019 | static const double ticks_per_nanosecond; |
1020 | |
1021 | public: |
1022 | typedef boost::chrono::duration<double, boost::nano> tonanosec; |
1023 | |
1024 | duration() {} // = default; |
1025 | explicit duration(const rep& r) : rep_(r) {} |
1026 | |
1027 | // conversions |
1028 | explicit duration(const tonanosec& d) |
1029 | : rep_(static_cast<rep>(d.count() * ticks_per_nanosecond)) {} |
1030 | |
1031 | // explicit |
1032 | operator tonanosec() const {return tonanosec(rep_/ticks_per_nanosecond);} |
1033 | |
1034 | // observer |
1035 | |
1036 | rep count() const {return rep_;} |
1037 | |
1038 | // arithmetic |
1039 | |
1040 | duration& operator+=(const duration& d) {rep_ += d.rep_; return *this;} |
1041 | duration& operator-=(const duration& d) {rep_ += d.rep_; return *this;} |
1042 | duration& operator*=(rep rhs) {rep_ *= rhs; return *this;} |
1043 | duration& operator/=(rep rhs) {rep_ /= rhs; return *this;} |
1044 | |
1045 | duration operator+() const {return *this;} |
1046 | duration operator-() const {return duration(-rep_);} |
1047 | duration& operator++() {++rep_; return *this;} |
1048 | duration operator++(int) {return duration(rep_++);} |
1049 | duration& operator--() {--rep_; return *this;} |
1050 | duration operator--(int) {return duration(rep_--);} |
1051 | |
1052 | friend duration operator+(duration x, duration y) {return x += y;} |
1053 | friend duration operator-(duration x, duration y) {return x -= y;} |
1054 | friend duration operator*(duration x, rep y) {return x *= y;} |
1055 | friend duration operator*(rep x, duration y) {return y *= x;} |
1056 | friend duration operator/(duration x, rep y) {return x /= y;} |
1057 | |
1058 | friend bool operator==(duration x, duration y) {return x.rep_ == y.rep_;} |
1059 | friend bool operator!=(duration x, duration y) {return !(x == y);} |
1060 | friend bool operator< (duration x, duration y) {return x.rep_ < y.rep_;} |
1061 | friend bool operator<=(duration x, duration y) {return !(y < x);} |
1062 | friend bool operator> (duration x, duration y) {return y < x;} |
1063 | friend bool operator>=(duration x, duration y) {return !(x < y);} |
1064 | }; |
1065 | |
1066 | static |
1067 | double |
1068 | init_duration() |
1069 | { |
1070 | //mach_timebase_info_data_t MachInfo; |
1071 | //mach_timebase_info(&MachInfo); |
1072 | //return static_cast<double>(MachInfo.denom) / MachInfo.numer; |
1073 | return static_cast<double>(1) / 1000; // Windows FILETIME is 1 per microsec |
1074 | } |
1075 | |
1076 | const double duration::ticks_per_nanosecond = init_duration(); |
1077 | |
1078 | class clock; |
1079 | |
1080 | class time_point |
1081 | { |
1082 | public: |
1083 | typedef runtime_resolution::clock clock; |
1084 | typedef long long rep; |
1085 | private: |
1086 | rep rep_; |
1087 | |
1088 | |
1089 | rep count() const {return rep_;} |
1090 | public: |
1091 | |
1092 | time_point() : rep_(0) {} |
1093 | explicit time_point(const duration& d) |
1094 | : rep_(d.count()) {} |
1095 | |
1096 | // arithmetic |
1097 | |
1098 | time_point& operator+=(const duration& d) {rep_ += d.count(); return *this;} |
1099 | time_point& operator-=(const duration& d) {rep_ -= d.count(); return *this;} |
1100 | |
1101 | friend time_point operator+(time_point x, duration y) {return x += y;} |
1102 | friend time_point operator+(duration x, time_point y) {return y += x;} |
1103 | friend time_point operator-(time_point x, duration y) {return x -= y;} |
1104 | friend duration operator-(time_point x, time_point y) {return duration(x.rep_ - y.rep_);} |
1105 | }; |
1106 | |
1107 | class clock |
1108 | { |
1109 | public: |
1110 | typedef duration::rep rep; |
1111 | typedef runtime_resolution::duration duration; |
1112 | typedef runtime_resolution::time_point time_point; |
1113 | |
1114 | static time_point now() |
1115 | { |
1116 | timeval tv; |
1117 | gettimeofday( tp: &tv, 0 ); |
1118 | return time_point(duration((static_cast<rep>(tv.tv_sec)<<32) | tv.tv_usec)); |
1119 | } |
1120 | }; |
1121 | |
1122 | void test() |
1123 | { |
1124 | using namespace boost::chrono; |
1125 | std::cout << "runtime_resolution test\n" ; |
1126 | clock::duration delay(boost::chrono::milliseconds(5)); |
1127 | clock::time_point start = clock::now(); |
1128 | while (clock::now() - start <= delay) |
1129 | ; |
1130 | clock::time_point stop = clock::now(); |
1131 | clock::duration elapsed = stop - start; |
1132 | std::cout << "paused " << nanoseconds(duration_cast<nanoseconds>(fd: duration::tonanosec(elapsed))).count() |
1133 | << " nanoseconds\n" ; |
1134 | } |
1135 | |
1136 | } // runtime_resolution |
1137 | |
1138 | // miscellaneous tests and demos: |
1139 | |
1140 | |
1141 | using namespace boost::chrono; |
1142 | |
1143 | void physics_function(duration<double> d) |
1144 | { |
1145 | std::cout << "d = " << d.count() << '\n'; |
1146 | } |
1147 | |
1148 | void drive_physics_function() |
1149 | { |
1150 | physics_function(d: nanoseconds(3)); |
1151 | physics_function(d: hours(3)); |
1152 | physics_function(d: duration<double>(2./3)); |
1153 | std::cout.precision(prec: 16); |
1154 | physics_function( d: hours(3) + nanoseconds(-3) ); |
1155 | } |
1156 | |
1157 | void test_range() |
1158 | { |
1159 | using namespace boost::chrono; |
1160 | hours h1 = hours(24 * ( 365 * 292 + 292/4)); |
1161 | nanoseconds n1 = h1 + nanoseconds(1); |
1162 | nanoseconds delta = n1 - h1; |
1163 | std::cout << "292 years of hours = " << h1.count() << "hr\n" ; |
1164 | std::cout << "Add a nanosecond = " << n1.count() << "ns\n" ; |
1165 | std::cout << "Find the difference = " << delta.count() << "ns\n" ; |
1166 | } |
1167 | |
1168 | void test_extended_range() |
1169 | { |
1170 | using namespace boost::chrono; |
1171 | hours h1 = hours(24 * ( 365 * 244000 + 244000/4)); |
1172 | /*auto*/ microseconds u1 = h1 + microseconds(1); |
1173 | /*auto*/ microseconds delta = u1 - h1; |
1174 | std::cout << "244,000 years of hours = " << h1.count() << "hr\n" ; |
1175 | std::cout << "Add a microsecond = " << u1.count() << "us\n" ; |
1176 | std::cout << "Find the difference = " << delta.count() << "us\n" ; |
1177 | } |
1178 | |
1179 | template <class Rep, class Period> |
1180 | void inspect_duration(boost::chrono::duration<Rep, Period> d, const std::string& name) |
1181 | { |
1182 | typedef boost::chrono::duration<Rep, Period> Duration; |
1183 | std::cout << "********* " << name << " *********\n" ; |
1184 | std::cout << "The period of " << name << " is " << (double)Period::num/Period::den << " seconds.\n" ; |
1185 | std::cout << "The frequency of " << name << " is " << (double)Period::den/Period::num << " Hz.\n" ; |
1186 | std::cout << "The representation is " ; |
1187 | if (boost::is_floating_point<Rep>::value) |
1188 | { |
1189 | std::cout << "floating point\n" ; |
1190 | std::cout << "The precision is the most significant " ; |
1191 | std::cout << std::numeric_limits<Rep>::digits10 << " decimal digits.\n" ; |
1192 | } |
1193 | else if (boost::is_integral<Rep>::value) |
1194 | { |
1195 | std::cout << "integral\n" ; |
1196 | d = Duration(Rep(1)); |
1197 | boost::chrono::duration<double> dsec = d; |
1198 | std::cout << "The precision is " << dsec.count() << " seconds.\n" ; |
1199 | } |
1200 | else |
1201 | { |
1202 | std::cout << "a class type\n" ; |
1203 | d = Duration(Rep(1)); |
1204 | boost::chrono::duration<double> dsec = d; |
1205 | std::cout << "The precision is " << dsec.count() << " seconds.\n" ; |
1206 | } |
1207 | d = Duration((std::numeric_limits<Rep>::max)()); |
1208 | using namespace boost::chrono; |
1209 | using namespace std; |
1210 | typedef duration<double, boost::ratio_multiply<boost::ratio<24*3652425,10000>, hours::period>::type> Years; |
1211 | Years years = d; |
1212 | std::cout << "The range is +/- " << years.count() << " years.\n" ; |
1213 | std::cout << "sizeof(" << name << ") = " << sizeof(d) << '\n'; |
1214 | } |
1215 | |
1216 | void inspect_all() |
1217 | { |
1218 | using namespace boost::chrono; |
1219 | std::cout.precision(prec: 6); |
1220 | inspect_duration(d: nanoseconds(), name: "nanoseconds" ); |
1221 | inspect_duration(d: microseconds(), name: "microseconds" ); |
1222 | inspect_duration(d: milliseconds(), name: "milliseconds" ); |
1223 | inspect_duration(d: seconds(), name: "seconds" ); |
1224 | inspect_duration(d: minutes(), name: "minutes" ); |
1225 | inspect_duration(d: hours(), name: "hours" ); |
1226 | inspect_duration(d: duration<double>(), name: "duration<double>" ); |
1227 | } |
1228 | |
1229 | void test_milliseconds() |
1230 | { |
1231 | using namespace boost::chrono; |
1232 | milliseconds ms(250); |
1233 | ms += milliseconds(1); |
1234 | milliseconds ms2(150); |
1235 | milliseconds msdiff = ms - ms2; |
1236 | if (msdiff == milliseconds(101)) |
1237 | std::cout << "success\n" ; |
1238 | else |
1239 | std::cout << "failure: " << msdiff.count() << '\n'; |
1240 | } |
1241 | |
1242 | using namespace std; |
1243 | using namespace boost::chrono; |
1244 | |
1245 | // Example round_up utility: converts d to To, rounding up for inexact conversions |
1246 | // Being able to *easily* write this function is a major feature! |
1247 | template <class To, class Rep, class Period> |
1248 | To |
1249 | round_up(duration<Rep, Period> d) |
1250 | { |
1251 | To result = duration_cast<To>(d); |
1252 | if (result < d) |
1253 | ++result; |
1254 | return result; |
1255 | } |
1256 | |
1257 | // demonstrate interaction with xtime-like facility: |
1258 | |
1259 | using namespace boost::chrono; |
1260 | |
1261 | struct xtime |
1262 | { |
1263 | long sec; |
1264 | unsigned long usec; |
1265 | }; |
1266 | |
1267 | template <class Rep, class Period> |
1268 | xtime |
1269 | to_xtime_truncate(duration<Rep, Period> d) |
1270 | { |
1271 | xtime xt; |
1272 | xt.sec = static_cast<long>(duration_cast<seconds>(d).count()); |
1273 | xt.usec = static_cast<long>(duration_cast<microseconds>(d - seconds(xt.sec)).count()); |
1274 | return xt; |
1275 | } |
1276 | |
1277 | template <class Rep, class Period> |
1278 | xtime |
1279 | to_xtime_round_up(duration<Rep, Period> d) |
1280 | { |
1281 | xtime xt; |
1282 | xt.sec = static_cast<long>(duration_cast<seconds>(d).count()); |
1283 | xt.usec = static_cast<unsigned long>(round_up<microseconds>(d - seconds(xt.sec)).count()); |
1284 | return xt; |
1285 | } |
1286 | |
1287 | microseconds |
1288 | from_xtime(xtime xt) |
1289 | { |
1290 | return seconds(xt.sec) + microseconds(xt.usec); |
1291 | } |
1292 | |
1293 | void print(xtime xt) |
1294 | { |
1295 | cout << '{' << xt.sec << ',' << xt.usec << "}\n" ; |
1296 | } |
1297 | |
1298 | void test_with_xtime() |
1299 | { |
1300 | cout << "test_with_xtime\n" ; |
1301 | xtime xt = to_xtime_truncate(d: seconds(3) + milliseconds(251)); |
1302 | print(xt); |
1303 | milliseconds ms = duration_cast<milliseconds>(fd: from_xtime(xt)); |
1304 | cout << ms.count() << " milliseconds\n" ; |
1305 | xt = to_xtime_round_up(d: ms); |
1306 | print(xt); |
1307 | xt = to_xtime_truncate(d: seconds(3) + nanoseconds(999)); |
1308 | print(xt); |
1309 | xt = to_xtime_round_up(d: seconds(3) + nanoseconds(999)); |
1310 | print(xt); |
1311 | } |
1312 | |
1313 | void test_system_clock() |
1314 | { |
1315 | cout << "system_clock test" << endl; |
1316 | system_clock::duration delay = milliseconds(5); |
1317 | system_clock::time_point start = system_clock::now(); |
1318 | while (system_clock::now() - start <= delay) |
1319 | ; |
1320 | system_clock::time_point stop = system_clock::now(); |
1321 | system_clock::duration elapsed = stop - start; |
1322 | cout << "paused " << nanoseconds(elapsed).count() << " nanoseconds\n" ; |
1323 | start = system_clock::now(); |
1324 | stop = system_clock::now(); |
1325 | cout << "system_clock resolution estimate: " << nanoseconds(stop-start).count() << " nanoseconds\n" ; |
1326 | } |
1327 | |
1328 | void test_steady_clock() |
1329 | { |
1330 | cout << "steady_clock test" << endl; |
1331 | steady_clock::duration delay = milliseconds(5); |
1332 | steady_clock::time_point start = steady_clock::now(); |
1333 | while (steady_clock::now() - start <= delay) |
1334 | ; |
1335 | steady_clock::time_point stop = steady_clock::now(); |
1336 | steady_clock::duration elapsed = stop - start; |
1337 | cout << "paused " << nanoseconds(elapsed).count() << " nanoseconds\n" ; |
1338 | start = steady_clock::now(); |
1339 | stop = steady_clock::now(); |
1340 | cout << "steady_clock resolution estimate: " << nanoseconds(stop-start).count() << " nanoseconds\n" ; |
1341 | } |
1342 | |
1343 | void test_hi_resolution_clock() |
1344 | { |
1345 | cout << "high_resolution_clock test" << endl; |
1346 | high_resolution_clock::duration delay = milliseconds(5); |
1347 | high_resolution_clock::time_point start = high_resolution_clock::now(); |
1348 | while (high_resolution_clock::now() - start <= delay) |
1349 | ; |
1350 | high_resolution_clock::time_point stop = high_resolution_clock::now(); |
1351 | high_resolution_clock::duration elapsed = stop - start; |
1352 | cout << "paused " << nanoseconds(elapsed).count() << " nanoseconds\n" ; |
1353 | start = high_resolution_clock::now(); |
1354 | stop = high_resolution_clock::now(); |
1355 | cout << "high_resolution_clock resolution estimate: " << nanoseconds(stop-start).count() << " nanoseconds\n" ; |
1356 | } |
1357 | |
1358 | //void test_mixed_clock() |
1359 | //{ |
1360 | // cout << "mixed clock test" << endl; |
1361 | // high_resolution_clock::time_point hstart = high_resolution_clock::now(); |
1362 | // cout << "Add 5 milliseconds to a high_resolution_clock::time_point\n"; |
1363 | // steady_clock::time_point mend = hstart + milliseconds(5); |
1364 | // bool b = hstart == mend; |
1365 | // system_clock::time_point sstart = system_clock::now(); |
1366 | // std::cout << "Subtracting system_clock::time_point from steady_clock::time_point doesn't compile\n"; |
1367 | //// mend - sstart; // doesn't compile |
1368 | // cout << "subtract high_resolution_clock::time_point from steady_clock::time_point" |
1369 | // " and add that to a system_clock::time_point\n"; |
1370 | // system_clock::time_point send = sstart + duration_cast<system_clock::duration>(mend - hstart); |
1371 | // cout << "subtract two system_clock::time_point's and output that in microseconds:\n"; |
1372 | // microseconds ms = send - sstart; |
1373 | // cout << ms.count() << " microseconds\n"; |
1374 | //} |
1375 | // |
1376 | //void test_c_mapping() |
1377 | //{ |
1378 | // cout << "C map test\n"; |
1379 | // using namespace boost::chrono; |
1380 | // system_clock::time_point t1 = system_clock::now(); |
1381 | // std::time_t c_time = system_clock::to_time_t(t1); |
1382 | // std::tm* tmptr = std::localtime(&c_time); |
1383 | // std::cout << "It is now " << tmptr->tm_hour << ':' << tmptr->tm_min << ':' << tmptr->tm_sec << ' ' |
1384 | // << tmptr->tm_year + 1900 << '-' << tmptr->tm_mon + 1 << '-' << tmptr->tm_mday << '\n'; |
1385 | // c_time = std::mktime(tmptr); |
1386 | // system_clock::time_point t2 = system_clock::from_time_t(c_time); |
1387 | // microseconds ms = t1 - t2; |
1388 | // std::cout << "Round-tripping through the C interface truncated the precision by " << ms.count() << " microseconds\n"; |
1389 | //} |
1390 | |
1391 | void test_duration_division() |
1392 | { |
1393 | cout << hours(3) / milliseconds(5) << '\n'; |
1394 | cout << milliseconds(5) / hours(3) << '\n'; |
1395 | cout << hours(1) / milliseconds(1) << '\n'; |
1396 | } |
1397 | |
1398 | namespace I_dont_like_the_default_duration_behavior |
1399 | { |
1400 | |
1401 | // Here's how you override the duration's default constructor to do anything you want (in this case zero) |
1402 | |
1403 | template <class R> |
1404 | class zero_default |
1405 | { |
1406 | public: |
1407 | typedef R rep; |
1408 | |
1409 | private: |
1410 | rep rep_; |
1411 | public: |
1412 | zero_default(rep i = 0) : rep_(i) {} |
1413 | operator rep() const {return rep_;} |
1414 | |
1415 | zero_default& operator+=(zero_default x) {rep_ += x.rep_; return *this;} |
1416 | zero_default& operator-=(zero_default x) {rep_ -= x.rep_; return *this;} |
1417 | zero_default& operator*=(zero_default x) {rep_ *= x.rep_; return *this;} |
1418 | zero_default& operator/=(zero_default x) {rep_ /= x.rep_; return *this;} |
1419 | |
1420 | zero_default operator+ () const {return *this;} |
1421 | zero_default operator- () const {return zero_default(-rep_);} |
1422 | zero_default& operator++() {++rep_; return *this;} |
1423 | zero_default operator++(int) {return zero_default(rep_++);} |
1424 | zero_default& operator--() {--rep_; return *this;} |
1425 | zero_default operator--(int) {return zero_default(rep_--);} |
1426 | |
1427 | friend zero_default operator+(zero_default x, zero_default y) {return x += y;} |
1428 | friend zero_default operator-(zero_default x, zero_default y) {return x -= y;} |
1429 | friend zero_default operator*(zero_default x, zero_default y) {return x *= y;} |
1430 | friend zero_default operator/(zero_default x, zero_default y) {return x /= y;} |
1431 | |
1432 | friend bool operator==(zero_default x, zero_default y) {return x.rep_ == y.rep_;} |
1433 | friend bool operator!=(zero_default x, zero_default y) {return !(x == y);} |
1434 | friend bool operator< (zero_default x, zero_default y) {return x.rep_ < y.rep_;} |
1435 | friend bool operator<=(zero_default x, zero_default y) {return !(y < x);} |
1436 | friend bool operator> (zero_default x, zero_default y) {return y < x;} |
1437 | friend bool operator>=(zero_default x, zero_default y) {return !(x < y);} |
1438 | }; |
1439 | |
1440 | typedef boost::chrono::duration<zero_default<long long>, boost::nano > nanoseconds; |
1441 | typedef boost::chrono::duration<zero_default<long long>, boost::micro > microseconds; |
1442 | typedef boost::chrono::duration<zero_default<long long>, boost::milli > milliseconds; |
1443 | typedef boost::chrono::duration<zero_default<long long> > seconds; |
1444 | typedef boost::chrono::duration<zero_default<long long>, boost::ratio<60> > minutes; |
1445 | typedef boost::chrono::duration<zero_default<long long>, boost::ratio<3600> > hours; |
1446 | |
1447 | void test() |
1448 | { |
1449 | milliseconds ms; |
1450 | cout << ms.count() << '\n'; |
1451 | } |
1452 | |
1453 | } // I_dont_like_the_default_duration_behavior |
1454 | |
1455 | // Build a min for two time_points |
1456 | |
1457 | template <class Rep, class Period> |
1458 | void |
1459 | print_duration(ostream& os, duration<Rep, Period> d) |
1460 | { |
1461 | os << d.count() << " * " << Period::num << '/' << Period::den << " seconds\n" ; |
1462 | } |
1463 | |
1464 | // Example min utility: returns the earliest time_point |
1465 | // Being able to *easily* write this function is a major feature! |
1466 | template <class Clock, class Duration1, class Duration2> |
1467 | inline |
1468 | typename boost::common_type<time_point<Clock, Duration1>, |
1469 | time_point<Clock, Duration2> >::type |
1470 | min BOOST_PREVENT_MACRO_SUBSTITUTION (time_point<Clock, Duration1> t1, time_point<Clock, Duration2> t2) |
1471 | { |
1472 | return t2 < t1 ? t2 : t1; |
1473 | } |
1474 | |
1475 | void test_min() |
1476 | { |
1477 | typedef time_point<system_clock, |
1478 | boost::common_type<system_clock::duration, seconds>::type> T1; |
1479 | typedef time_point<system_clock, |
1480 | boost::common_type<system_clock::duration, nanoseconds>::type> T2; |
1481 | typedef boost::common_type<T1, T2>::type T3; |
1482 | /*auto*/ T1 t1 = system_clock::now() + seconds(3); |
1483 | /*auto*/ T2 t2 = system_clock::now() + nanoseconds(3); |
1484 | /*auto*/ T3 t3 = (min)(t1, t2); |
1485 | print_duration(os&: cout, d: t1 - t3); |
1486 | print_duration(os&: cout, d: t2 - t3); |
1487 | } |
1488 | |
1489 | void explore_limits() |
1490 | { |
1491 | typedef duration<long long, boost::ratio_multiply<boost::ratio<24*3652425,10000>, |
1492 | hours::period>::type> Years; |
1493 | steady_clock::time_point t1( Years(250)); |
1494 | steady_clock::time_point t2(-Years(250)); |
1495 | // nanosecond resolution is likely to overflow. "up cast" to microseconds. |
1496 | // The "up cast" trades precision for range. |
1497 | microseconds d = time_point_cast<microseconds>(t: t1) - time_point_cast<microseconds>(t: t2); |
1498 | cout << d.count() << " microseconds\n" ; |
1499 | } |
1500 | |
1501 | void manipulate_clock_object(system_clock clock) |
1502 | { |
1503 | system_clock::duration delay = milliseconds(5); |
1504 | system_clock::time_point start = clock.now(); |
1505 | while (clock.now() - start <= delay) |
1506 | ; |
1507 | system_clock::time_point stop = clock.now(); |
1508 | system_clock::duration elapsed = stop - start; |
1509 | cout << "paused " << nanoseconds(elapsed).count() << " nanoseconds\n" ; |
1510 | }; |
1511 | |
1512 | template <long long speed> |
1513 | struct cycle_count |
1514 | { |
1515 | typedef typename boost::ratio_multiply<boost::ratio<speed>, boost::mega>::type frequency; // Mhz |
1516 | typedef typename boost::ratio_divide<boost::ratio<1>, frequency>::type period; |
1517 | typedef long long rep; |
1518 | typedef boost::chrono::duration<rep, period> duration; |
1519 | typedef boost::chrono::time_point<cycle_count> time_point; |
1520 | |
1521 | static time_point now() |
1522 | { |
1523 | static long long tick = 0; |
1524 | // return exact cycle count |
1525 | return time_point(duration(++tick)); // fake access to clock cycle count |
1526 | } |
1527 | }; |
1528 | |
1529 | template <long long speed> |
1530 | struct approx_cycle_count |
1531 | { |
1532 | static const long long frequency = speed * 1000000; // MHz |
1533 | typedef nanoseconds duration; |
1534 | typedef duration::rep rep; |
1535 | typedef duration::period period; |
1536 | static const long long nanosec_per_sec = period::den; |
1537 | typedef boost::chrono::time_point<approx_cycle_count> time_point; |
1538 | |
1539 | static time_point now() |
1540 | { |
1541 | static long long tick = 0; |
1542 | // return cycle count as an approximate number of nanoseconds |
1543 | // compute as if nanoseconds is only duration in the std::lib |
1544 | return time_point(duration(++tick * nanosec_per_sec / frequency)); |
1545 | } |
1546 | }; |
1547 | |
1548 | void cycle_count_delay() |
1549 | { |
1550 | { |
1551 | typedef cycle_count<400> clock; |
1552 | cout << "\nSimulated " << clock::frequency::num / boost::mega::num << "MHz clock which has a tick period of " |
1553 | << duration<double, boost::nano>(clock::duration(1)).count() << " nanoseconds\n" ; |
1554 | nanoseconds delayns(500); |
1555 | clock::duration delay = duration_cast<clock::duration>(fd: delayns); |
1556 | cout << "delay = " << delayns.count() << " nanoseconds which is " << delay.count() << " cycles\n" ; |
1557 | clock::time_point start = clock::now(); |
1558 | clock::time_point stop = start + delay; |
1559 | while (clock::now() < stop) // no multiplies or divides in this loop |
1560 | ; |
1561 | clock::time_point end = clock::now(); |
1562 | clock::duration elapsed = end - start; |
1563 | cout << "paused " << elapsed.count() << " cycles " ; |
1564 | cout << "which is " << duration_cast<nanoseconds>(fd: elapsed).count() << " nanoseconds\n" ; |
1565 | } |
1566 | { |
1567 | typedef approx_cycle_count<400> clock; |
1568 | cout << "\nSimulated " << clock::frequency / 1000000 << "MHz clock modeled with nanoseconds\n" ; |
1569 | clock::duration delay = nanoseconds(500); |
1570 | cout << "delay = " << delay.count() << " nanoseconds\n" ; |
1571 | clock::time_point start = clock::now(); |
1572 | clock::time_point stop = start + delay; |
1573 | while (clock::now() < stop) // 1 multiplication and 1 division in this loop |
1574 | ; |
1575 | clock::time_point end = clock::now(); |
1576 | clock::duration elapsed = end - start; |
1577 | cout << "paused " << elapsed.count() << " nanoseconds\n" ; |
1578 | } |
1579 | { |
1580 | typedef cycle_count<1500> clock; |
1581 | cout << "\nSimulated " << clock::frequency::num / boost::mega::num << "MHz clock which has a tick period of " |
1582 | << duration<double, boost::nano>(clock::duration(1)).count() << " nanoseconds\n" ; |
1583 | nanoseconds delayns(500); |
1584 | clock::duration delay = duration_cast<clock::duration>(fd: delayns); |
1585 | cout << "delay = " << delayns.count() << " nanoseconds which is " << delay.count() << " cycles\n" ; |
1586 | clock::time_point start = clock::now(); |
1587 | clock::time_point stop = start + delay; |
1588 | while (clock::now() < stop) // no multiplies or divides in this loop |
1589 | ; |
1590 | clock::time_point end = clock::now(); |
1591 | clock::duration elapsed = end - start; |
1592 | cout << "paused " << elapsed.count() << " cycles " ; |
1593 | cout << "which is " << duration_cast<nanoseconds>(fd: elapsed).count() << " nanoseconds\n" ; |
1594 | } |
1595 | { |
1596 | typedef approx_cycle_count<1500> clock; |
1597 | cout << "\nSimulated " << clock::frequency / 1000000 << "MHz clock modeled with nanoseconds\n" ; |
1598 | clock::duration delay = nanoseconds(500); |
1599 | cout << "delay = " << delay.count() << " nanoseconds\n" ; |
1600 | clock::time_point start = clock::now(); |
1601 | clock::time_point stop = start + delay; |
1602 | while (clock::now() < stop) // 1 multiplication and 1 division in this loop |
1603 | ; |
1604 | clock::time_point end = clock::now(); |
1605 | clock::duration elapsed = end - start; |
1606 | cout << "paused " << elapsed.count() << " nanoseconds\n" ; |
1607 | } |
1608 | } |
1609 | |
1610 | void test_special_values() |
1611 | { |
1612 | std::cout << "duration<unsigned>::min().count() = " << (duration<unsigned>::min)().count() << '\n'; |
1613 | std::cout << "duration<unsigned>::zero().count() = " << duration<unsigned>::zero().count() << '\n'; |
1614 | std::cout << "duration<unsigned>::max().count() = " << (duration<unsigned>::max)().count() << '\n'; |
1615 | std::cout << "duration<int>::min().count() = " << (duration<int>::min)().count() << '\n'; |
1616 | std::cout << "duration<int>::zero().count() = " << duration<int>::zero().count() << '\n'; |
1617 | std::cout << "duration<int>::max().count() = " << (duration<int>::max)().count() << '\n'; |
1618 | } |
1619 | |
1620 | int main() |
1621 | { |
1622 | basic_examples(); |
1623 | testStdUser(); |
1624 | testUser1(); |
1625 | testUser2(); |
1626 | drive_physics_function(); |
1627 | test_range(); |
1628 | test_extended_range(); |
1629 | inspect_all(); |
1630 | test_milliseconds(); |
1631 | test_with_xtime(); |
1632 | test_system_clock(); |
1633 | test_steady_clock(); |
1634 | test_hi_resolution_clock(); |
1635 | //test_mixed_clock(); |
1636 | timeval_demo::test_xtime_clock(); |
1637 | runtime_resolution::test(); |
1638 | //test_c_mapping(); |
1639 | test_duration_division(); |
1640 | I_dont_like_the_default_duration_behavior::test(); |
1641 | test_min(); |
1642 | inspect_duration(d: common_type<duration<double>, hours, microseconds>::type(), |
1643 | name: "common_type<duration<double>, hours, microseconds>::type" ); |
1644 | explore_limits(); |
1645 | manipulate_clock_object(clock: system_clock()); |
1646 | duration<double, boost::milli> d = milliseconds(3) * 2.5; |
1647 | inspect_duration(d: milliseconds(3) * 2.5, name: "milliseconds(3) * 2.5" ); |
1648 | cout << d.count() << '\n'; |
1649 | // milliseconds ms(3.5); // doesn't compile |
1650 | cout << "milliseconds ms(3.5) doesn't compile\n" ; |
1651 | cycle_count_delay(); |
1652 | test_special_values(); |
1653 | return 0; |
1654 | } |
1655 | |
1656 | |