| // time2_demo.cpp ----------------------------------------------------------// |
| |
| // Copyright 2008 Howard Hinnant |
| // Copyright 2008 Beman Dawes |
| |
| // Distributed under the Boost Software License, Version 1.0. |
| // See http://www.boost.org/LICENSE_1_0.txt |
| |
| /* |
| |
| This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype. |
| Many thanks to Howard for making his code available under the Boost license. |
| The original code was modified to conform to Boost conventions and to section |
| 20.9 Time utilities [time] of the C++ committee's working paper N2798. |
| See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf. |
| |
| time2_demo contained this comment: |
| |
| Much thanks to Andrei Alexandrescu, |
| Walter Brown, |
| Peter Dimov, |
| Jeff Garland, |
| Terry Golubiewski, |
| Daniel Krugler, |
| Anthony Williams. |
| */ |
| |
| #define _CRT_SECURE_NO_WARNINGS // disable VC++ foolishness |
| |
| #include <boost/chrono/chrono.hpp> |
| #include <boost/type_traits.hpp> |
| |
| #include <cassert> |
| #include <climits> |
| #include <iostream> |
| #include <ostream> |
| #include <stdexcept> |
| |
| #include <windows.h> |
| |
| namespace |
| { |
| //struct timeval { |
| // long tv_sec; /* seconds */ |
| // long tv_usec; /* and microseconds */ |
| //}; |
| |
| int gettimeofday(struct timeval * tp, void *) |
| { |
| FILETIME ft; |
| ::GetSystemTimeAsFileTime( &ft ); // never fails |
| long long t = (static_cast<long long>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; |
| # if !defined( BOOST_MSVC ) || BOOST_MSVC > 1300 // > VC++ 7.0 |
| t -= 116444736000000000LL; |
| # else |
| t -= 116444736000000000; |
| # endif |
| t /= 10; // microseconds |
| tp->tv_sec = static_cast<long>( t / 1000000UL); |
| tp->tv_usec = static_cast<long>( t % 1000000UL); |
| return 0; |
| } |
| } // unnamed namespace |
| |
| ////////////////////////////////////////////////////////// |
| ///////////// simulated thread interface ///////////////// |
| ////////////////////////////////////////////////////////// |
| |
| |
| namespace std { |
| |
| void __print_time(boost::chrono::system_clock::time_point t) |
| { |
| using namespace boost::chrono; |
| time_t c_time = system_clock::to_time_t(t); |
| std::tm* tmptr = std::localtime(&c_time); |
| system_clock::duration d = t.time_since_epoch(); |
| std::cout << tmptr->tm_hour << ':' << tmptr->tm_min << ':' << tmptr->tm_sec |
| << '.' << (d - duration_cast<seconds>(d)).count(); |
| } |
| |
| namespace this_thread { |
| |
| template <class Rep, class Period> |
| void sleep_for(const boost::chrono::duration<Rep, Period>& d) |
| { |
| boost::chrono::microseconds t = boost::chrono::duration_cast<boost::chrono::microseconds>(d); |
| if (t < d) |
| ++t; |
| if (t > boost::chrono::microseconds(0)) |
| std::cout << "sleep_for " << t.count() << " microseconds\n"; |
| } |
| |
| template <class Clock, class Duration> |
| void sleep_until(const boost::chrono::time_point<Clock, Duration>& t) |
| { |
| using namespace boost::chrono; |
| typedef time_point<Clock, Duration> Time; |
| typedef system_clock::time_point SysTime; |
| if (t > Clock::now()) |
| { |
| typedef typename boost::common_type<typename Time::duration, |
| typename SysTime::duration>::type D; |
| /* auto */ D d = t - Clock::now(); |
| microseconds us = duration_cast<microseconds>(d); |
| if (us < d) |
| ++us; |
| SysTime st = system_clock::now() + us; |
| std::cout << "sleep_until "; |
| __print_time(st); |
| std::cout << " which is " << (st - system_clock::now()).count() << " microseconds away\n"; |
| } |
| } |
| |
| } // this_thread |
| |
| struct mutex {}; |
| |
| struct timed_mutex |
| { |
| bool try_lock() {std::cout << "timed_mutex::try_lock()\n"; return true;} |
| |
| template <class Rep, class Period> |
| bool try_lock_for(const boost::chrono::duration<Rep, Period>& d) |
| { |
| boost::chrono::microseconds t = boost::chrono::duration_cast<boost::chrono::microseconds>(d); |
| if (t <= boost::chrono::microseconds(0)) |
| return try_lock(); |
| std::cout << "try_lock_for " << t.count() << " microseconds\n"; |
| return true; |
| } |
| |
| template <class Clock, class Duration> |
| bool try_lock_until(const boost::chrono::time_point<Clock, Duration>& t) |
| { |
| using namespace boost::chrono; |
| typedef time_point<Clock, Duration> Time; |
| typedef system_clock::time_point SysTime; |
| if (t <= Clock::now()) |
| return try_lock(); |
| typedef typename boost::common_type<typename Time::duration, |
| typename Clock::duration>::type D; |
| /* auto */ D d = t - Clock::now(); |
| microseconds us = duration_cast<microseconds>(d); |
| SysTime st = system_clock::now() + us; |
| std::cout << "try_lock_until "; |
| __print_time(st); |
| std::cout << " which is " << (st - system_clock::now()).count() |
| << " microseconds away\n"; |
| return true; |
| } |
| }; |
| |
| struct condition_variable |
| { |
| template <class Rep, class Period> |
| bool wait_for(mutex&, const boost::chrono::duration<Rep, Period>& d) |
| { |
| boost::chrono::microseconds t = boost::chrono::duration_cast<boost::chrono::microseconds>(d); |
| std::cout << "wait_for " << t.count() << " microseconds\n"; |
| return true; |
| } |
| |
| template <class Clock, class Duration> |
| bool wait_until(mutex&, const boost::chrono::time_point<Clock, Duration>& t) |
| { |
| using namespace boost::chrono; |
| typedef time_point<Clock, Duration> Time; |
| typedef system_clock::time_point SysTime; |
| if (t <= Clock::now()) |
| return false; |
| typedef typename boost::common_type<typename Time::duration, |
| typename Clock::duration>::type D; |
| /* auto */ D d = t - Clock::now(); |
| microseconds us = duration_cast<microseconds>(d); |
| SysTime st = system_clock::now() + us; |
| std::cout << "wait_until "; |
| __print_time(st); |
| std::cout << " which is " << (st - system_clock::now()).count() |
| << " microseconds away\n"; |
| return true; |
| } |
| }; |
| |
| } // namespace std |
| |
| ////////////////////////////////////////////////////////// |
| //////////// Simple sleep and wait examples ////////////// |
| ////////////////////////////////////////////////////////// |
| |
| std::mutex m; |
| std::timed_mutex mut; |
| std::condition_variable cv; |
| |
| void basic_examples() |
| { |
| std::cout << "Running basic examples\n"; |
| using namespace std; |
| using namespace boost::chrono; |
| system_clock::time_point time_limit = system_clock::now() + seconds(4) + milliseconds(500); |
| this_thread::sleep_for(seconds(3)); |
| this_thread::sleep_for(nanoseconds(300)); |
| this_thread::sleep_until(time_limit); |
| // this_thread::sleep_for(time_limit); // desired compile-time error |
| // this_thread::sleep_until(seconds(3)); // desired compile-time error |
| mut.try_lock_for(milliseconds(30)); |
| mut.try_lock_until(time_limit); |
| // mut.try_lock_for(time_limit); // desired compile-time error |
| // mut.try_lock_until(milliseconds(30)); // desired compile-time error |
| cv.wait_for(m, minutes(1)); // real code would put this in a loop |
| cv.wait_until(m, time_limit); // real code would put this in a loop |
| // For those who prefer floating point |
| this_thread::sleep_for(duration<double>(0.25)); |
| this_thread::sleep_until(system_clock::now() + duration<double>(1.5)); |
| } |
| |
| ////////////////////////////////////////////////////////// |
| //////////////////// User1 Example /////////////////////// |
| ////////////////////////////////////////////////////////// |
| |
| namespace User1 |
| { |
| // Example type-safe "physics" code interoperating with boost::chrono::duration types |
| // and taking advantage of the boost::ratio infrastructure and design philosophy. |
| |
| // length - mimics boost::chrono::duration except restricts representation to double. |
| // Uses boost::ratio facilities for length units conversions. |
| |
| template <class Ratio> |
| class length |
| { |
| public: |
| typedef Ratio ratio; |
| private: |
| double len_; |
| public: |
| |
| length() : len_(1) {} |
| length(const double& len) : len_(len) {} |
| |
| // conversions |
| template <class R> |
| length(const length<R>& d) |
| : len_(d.count() * boost::ratio_divide<Ratio, R>::type::den / |
| boost::ratio_divide<Ratio, R>::type::num) {} |
| |
| // observer |
| |
| double count() const {return len_;} |
| |
| // arithmetic |
| |
| length& operator+=(const length& d) {len_ += d.count(); return *this;} |
| length& operator-=(const length& d) {len_ -= d.count(); return *this;} |
| |
| length operator+() const {return *this;} |
| length operator-() const {return length(-len_);} |
| |
| length& operator*=(double rhs) {len_ *= rhs; return *this;} |
| length& operator/=(double rhs) {len_ /= rhs; return *this;} |
| }; |
| |
| // Sparse sampling of length units |
| typedef length<boost::ratio<1> > meter; // set meter as "unity" |
| typedef length<boost::centi> centimeter; // 1/100 meter |
| typedef length<boost::kilo> kilometer; // 1000 meters |
| typedef length<boost::ratio<254, 10000> > inch; // 254/10000 meters |
| // length takes ratio instead of two integral types so that definitions can be made like so: |
| typedef length<boost::ratio_multiply<boost::ratio<12>, inch::ratio>::type> foot; // 12 inchs |
| typedef length<boost::ratio_multiply<boost::ratio<5280>, foot::ratio>::type> mile; // 5280 feet |
| |
| // Need a floating point definition of seconds |
| typedef boost::chrono::duration<double> seconds; // unity |
| // Demo of (scientific) support for sub-nanosecond resolutions |
| typedef boost::chrono::duration<double, boost::pico> picosecond; // 10^-12 seconds |
| typedef boost::chrono::duration<double, boost::femto> femtosecond; // 10^-15 seconds |
| typedef boost::chrono::duration<double, boost::atto> attosecond; // 10^-18 seconds |
| |
| // A very brief proof-of-concept for SIUnits-like library |
| // Hard-wired to floating point seconds and meters, but accepts other units (shown in testUser1()) |
| template <class R1, class R2> |
| class quantity |
| { |
| double q_; |
| public: |
| quantity() : q_(1) {} |
| |
| double get() const {return q_;} |
| void set(double q) {q_ = q;} |
| }; |
| |
| template <> |
| class quantity<boost::ratio<1>, boost::ratio<0> > |
| { |
| double q_; |
| public: |
| quantity() : q_(1) {} |
| quantity(seconds d) : q_(d.count()) {} // note: only User1::seconds needed here |
| |
| double get() const {return q_;} |
| void set(double q) {q_ = q;} |
| }; |
| |
| template <> |
| class quantity<boost::ratio<0>, boost::ratio<1> > |
| { |
| double q_; |
| public: |
| quantity() : q_(1) {} |
| quantity(meter d) : q_(d.count()) {} // note: only User1::meter needed here |
| |
| double get() const {return q_;} |
| void set(double q) {q_ = q;} |
| }; |
| |
| template <> |
| class quantity<boost::ratio<0>, boost::ratio<0> > |
| { |
| double q_; |
| public: |
| quantity() : q_(1) {} |
| quantity(double d) : q_(d) {} |
| |
| double get() const {return q_;} |
| void set(double q) {q_ = q;} |
| }; |
| |
| // Example SI-Units |
| typedef quantity<boost::ratio<0>, boost::ratio<0> > Scalar; |
| typedef quantity<boost::ratio<1>, boost::ratio<0> > Time; // second |
| typedef quantity<boost::ratio<0>, boost::ratio<1> > Distance; // meter |
| typedef quantity<boost::ratio<-1>, boost::ratio<1> > Speed; // meter/second |
| typedef quantity<boost::ratio<-2>, boost::ratio<1> > Acceleration; // meter/second^2 |
| |
| template <class R1, class R2, class R3, class R4> |
| quantity<typename boost::ratio_subtract<R1, R3>::type, typename boost::ratio_subtract<R2, R4>::type> |
| operator/(const quantity<R1, R2>& x, const quantity<R3, R4>& y) |
| { |
| typedef quantity<typename boost::ratio_subtract<R1, R3>::type, typename boost::ratio_subtract<R2, R4>::type> R; |
| R r; |
| r.set(x.get() / y.get()); |
| return r; |
| } |
| |
| template <class R1, class R2, class R3, class R4> |
| quantity<typename boost::ratio_add<R1, R3>::type, typename boost::ratio_add<R2, R4>::type> |
| operator*(const quantity<R1, R2>& x, const quantity<R3, R4>& y) |
| { |
| typedef quantity<typename boost::ratio_add<R1, R3>::type, typename boost::ratio_add<R2, R4>::type> R; |
| R r; |
| r.set(x.get() * y.get()); |
| return r; |
| } |
| |
| template <class R1, class R2> |
| quantity<R1, R2> |
| operator+(const quantity<R1, R2>& x, const quantity<R1, R2>& y) |
| { |
| typedef quantity<R1, R2> R; |
| R r; |
| r.set(x.get() + y.get()); |
| return r; |
| } |
| |
| template <class R1, class R2> |
| quantity<R1, R2> |
| operator-(const quantity<R1, R2>& x, const quantity<R1, R2>& y) |
| { |
| typedef quantity<R1, R2> R; |
| R r; |
| r.set(x.get() - y.get()); |
| return r; |
| } |
| |
| // Example type-safe physics function |
| Distance |
| compute_distance(Speed v0, Time t, Acceleration a) |
| { |
| return v0 * t + Scalar(.5) * a * t * t; // if a units mistake is made here it won't compile |
| } |
| |
| } // User1 |
| |
| |
| // Exercise example type-safe physics function and show interoperation |
| // of custom time durations (User1::seconds) and standard time durations (std::hours). |
| // Though input can be arbitrary (but type-safe) units, output is always in SI-units |
| // (a limitation of the simplified Units lib demoed here). |
| void testUser1() |
| { |
| std::cout << "*************\n"; |
| std::cout << "* testUser1 *\n"; |
| std::cout << "*************\n"; |
| User1::Distance d( User1::mile(110) ); |
| User1::Time t( boost::chrono::hours(2) ); |
| User1::Speed s = d / t; |
| std::cout << "Speed = " << s.get() << " meters/sec\n"; |
| User1::Acceleration a = User1::Distance( User1::foot(32.2) ) / User1::Time() / User1::Time(); |
| std::cout << "Acceleration = " << a.get() << " meters/sec^2\n"; |
| User1::Distance df = compute_distance(s, User1::Time( User1::seconds(0.5) ), a); |
| std::cout << "Distance = " << df.get() << " meters\n"; |
| std::cout << "There are " << User1::mile::ratio::den << '/' << User1::mile::ratio::num << " miles/meter"; |
| User1::meter mt = 1; |
| User1::mile mi = mt; |
| std::cout << " which is approximately " << mi.count() << '\n'; |
| std::cout << "There are " << User1::mile::ratio::num << '/' << User1::mile::ratio::den << " meters/mile"; |
| mi = 1; |
| mt = mi; |
| std::cout << " which is approximately " << mt.count() << '\n'; |
| User1::attosecond as(1); |
| User1::seconds sec = as; |
| std::cout << "1 attosecond is " << sec.count() << " seconds\n"; |
| std::cout << "sec = as; // compiles\n"; |
| sec = User1::seconds(1); |
| as = sec; |
| std::cout << "1 second is " << as.count() << " attoseconds\n"; |
| std::cout << "as = sec; // compiles\n"; |
| std::cout << "\n"; |
| } |
| |
| ////////////////////////////////////////////////////////// |
| //////////////////// User2 Example /////////////////////// |
| ////////////////////////////////////////////////////////// |
| |
| // Demonstrate User2: |
| // A "saturating" signed integral type is developed. This type has +/- infinity and a nan |
| // (like IEEE floating point) but otherwise obeys signed integral arithmetic. |
| // This class is subsequently used as the rep in boost::chrono::duration to demonstrate a |
| // duration class that does not silently ignore overflow. |
| |
| namespace User2 |
| { |
| |
| template <class I> |
| class saturate |
| { |
| public: |
| typedef I int_type; |
| |
| static const int_type nan = int_type(int_type(1) << (sizeof(int_type) * CHAR_BIT - 1)); |
| static const int_type neg_inf = nan + 1; |
| static const int_type pos_inf = -neg_inf; |
| private: |
| int_type i_; |
| |
| // static_assert(std::is_integral<int_type>::value && std::is_signed<int_type>::value, |
| // "saturate only accepts signed integral types"); |
| // static_assert(nan == -nan && neg_inf < pos_inf, |
| // "saturate assumes two's complement hardware for signed integrals"); |
| |
| public: |
| saturate() : i_(nan) {} |
| explicit saturate(int_type i) : i_(i) {} |
| // explicit |
| operator int_type() const; |
| |
| saturate& operator+=(saturate x); |
| saturate& operator-=(saturate x) {return *this += -x;} |
| saturate& operator*=(saturate x); |
| saturate& operator/=(saturate x); |
| saturate& operator%=(saturate x); |
| |
| saturate operator- () const {return saturate(-i_);} |
| saturate& operator++() {*this += saturate(int_type(1)); return *this;} |
| saturate operator++(int) {saturate tmp(*this); ++(*this); return tmp;} |
| saturate& operator--() {*this -= saturate(int_type(1)); return *this;} |
| saturate operator--(int) {saturate tmp(*this); --(*this); return tmp;} |
| |
| friend saturate operator+(saturate x, saturate y) {return x += y;} |
| friend saturate operator-(saturate x, saturate y) {return x -= y;} |
| friend saturate operator*(saturate x, saturate y) {return x *= y;} |
| friend saturate operator/(saturate x, saturate y) {return x /= y;} |
| friend saturate operator%(saturate x, saturate y) {return x %= y;} |
| |
| friend bool operator==(saturate x, saturate y) |
| { |
| if (x.i_ == nan || y.i_ == nan) |
| return false; |
| return x.i_ == y.i_; |
| } |
| |
| friend bool operator!=(saturate x, saturate y) {return !(x == y);} |
| |
| friend bool operator<(saturate x, saturate y) |
| { |
| if (x.i_ == nan || y.i_ == nan) |
| return false; |
| return x.i_ < y.i_; |
| } |
| |
| friend bool operator<=(saturate x, saturate y) |
| { |
| if (x.i_ == nan || y.i_ == nan) |
| return false; |
| return x.i_ <= y.i_; |
| } |
| |
| friend bool operator>(saturate x, saturate y) |
| { |
| if (x.i_ == nan || y.i_ == nan) |
| return false; |
| return x.i_ > y.i_; |
| } |
| |
| friend bool operator>=(saturate x, saturate y) |
| { |
| if (x.i_ == nan || y.i_ == nan) |
| return false; |
| return x.i_ >= y.i_; |
| } |
| |
| friend std::ostream& operator<<(std::ostream& os, saturate s) |
| { |
| switch (s.i_) |
| { |
| case pos_inf: |
| return os << "inf"; |
| case nan: |
| return os << "nan"; |
| case neg_inf: |
| return os << "-inf"; |
| }; |
| return os << s.i_; |
| } |
| }; |
| |
| template <class I> |
| saturate<I>::operator int_type() const |
| { |
| switch (i_) |
| { |
| case nan: |
| case neg_inf: |
| case pos_inf: |
| throw std::out_of_range("saturate special value can not convert to int_type"); |
| } |
| return i_; |
| } |
| |
| template <class I> |
| saturate<I>& |
| saturate<I>::operator+=(saturate x) |
| { |
| switch (i_) |
| { |
| case pos_inf: |
| switch (x.i_) |
| { |
| case neg_inf: |
| case nan: |
| i_ = nan; |
| } |
| return *this; |
| case nan: |
| return *this; |
| case neg_inf: |
| switch (x.i_) |
| { |
| case pos_inf: |
| case nan: |
| i_ = nan; |
| } |
| return *this; |
| } |
| switch (x.i_) |
| { |
| case pos_inf: |
| case neg_inf: |
| case nan: |
| i_ = x.i_; |
| return *this; |
| } |
| if (x.i_ >= 0) |
| { |
| if (i_ < pos_inf - x.i_) |
| i_ += x.i_; |
| else |
| i_ = pos_inf; |
| return *this; |
| } |
| if (i_ > neg_inf - x.i_) |
| i_ += x.i_; |
| else |
| i_ = neg_inf; |
| return *this; |
| } |
| |
| template <class I> |
| saturate<I>& |
| saturate<I>::operator*=(saturate x) |
| { |
| switch (i_) |
| { |
| case 0: |
| switch (x.i_) |
| { |
| case pos_inf: |
| case neg_inf: |
| case nan: |
| i_ = nan; |
| } |
| return *this; |
| case pos_inf: |
| switch (x.i_) |
| { |
| case nan: |
| case 0: |
| i_ = nan; |
| return *this; |
| } |
| if (x.i_ < 0) |
| i_ = neg_inf; |
| return *this; |
| case nan: |
| return *this; |
| case neg_inf: |
| switch (x.i_) |
| { |
| case nan: |
| case 0: |
| i_ = nan; |
| return *this; |
| } |
| if (x.i_ < 0) |
| i_ = pos_inf; |
| return *this; |
| } |
| switch (x.i_) |
| { |
| case 0: |
| i_ = 0; |
| return *this; |
| case nan: |
| i_ = nan; |
| return *this; |
| case pos_inf: |
| if (i_ < 0) |
| i_ = neg_inf; |
| else |
| i_ = pos_inf; |
| return *this; |
| case neg_inf: |
| if (i_ < 0) |
| i_ = pos_inf; |
| else |
| i_ = neg_inf; |
| return *this; |
| } |
| int s = (i_ < 0 ? -1 : 1) * (x.i_ < 0 ? -1 : 1); |
| i_ = i_ < 0 ? -i_ : i_; |
| int_type x_i_ = x.i_ < 0 ? -x.i_ : x.i_; |
| if (i_ <= pos_inf / x_i_) |
| i_ *= x_i_; |
| else |
| i_ = pos_inf; |
| i_ *= s; |
| return *this; |
| } |
| |
| template <class I> |
| saturate<I>& |
| saturate<I>::operator/=(saturate x) |
| { |
| switch (x.i_) |
| { |
| case pos_inf: |
| case neg_inf: |
| switch (i_) |
| { |
| case pos_inf: |
| case neg_inf: |
| case nan: |
| i_ = nan; |
| break; |
| default: |
| i_ = 0; |
| break; |
| } |
| return *this; |
| case nan: |
| i_ = nan; |
| return *this; |
| case 0: |
| switch (i_) |
| { |
| case pos_inf: |
| case neg_inf: |
| case nan: |
| return *this; |
| case 0: |
| i_ = nan; |
| return *this; |
| } |
| if (i_ > 0) |
| i_ = pos_inf; |
| else |
| i_ = neg_inf; |
| return *this; |
| } |
| switch (i_) |
| { |
| case 0: |
| case nan: |
| return *this; |
| case pos_inf: |
| case neg_inf: |
| if (x.i_ < 0) |
| i_ = -i_; |
| return *this; |
| } |
| i_ /= x.i_; |
| return *this; |
| } |
| |
| template <class I> |
| saturate<I>& |
| saturate<I>::operator%=(saturate x) |
| { |
| // *this -= *this / x * x; // definition |
| switch (x.i_) |
| { |
| case nan: |
| case neg_inf: |
| case 0: |
| case pos_inf: |
| i_ = nan; |
| return *this; |
| } |
| switch (i_) |
| { |
| case neg_inf: |
| case pos_inf: |
| i_ = nan; |
| case nan: |
| return *this; |
| } |
| i_ %= x.i_; |
| return *this; |
| } |
| |
| // Demo overflow-safe integral durations ranging from picoseconds resolution to millennium resolution |
| typedef boost::chrono::duration<saturate<long long>, boost::pico > picoseconds; |
| typedef boost::chrono::duration<saturate<long long>, boost::nano > nanoseconds; |
| typedef boost::chrono::duration<saturate<long long>, boost::micro > microseconds; |
| typedef boost::chrono::duration<saturate<long long>, boost::milli > milliseconds; |
| typedef boost::chrono::duration<saturate<long long> > seconds; |
| typedef boost::chrono::duration<saturate<long long>, boost::ratio< 60LL> > minutes; |
| typedef boost::chrono::duration<saturate<long long>, boost::ratio< 3600LL> > hours; |
| typedef boost::chrono::duration<saturate<long long>, boost::ratio< 86400LL> > days; |
| typedef boost::chrono::duration<saturate<long long>, boost::ratio< 31556952LL> > years; |
| typedef boost::chrono::duration<saturate<long long>, boost::ratio<31556952000LL> > millennium; |
| |
| } // User2 |
| |
| // Demonstrate custom promotion rules (needed only if there are no implicit conversions) |
| namespace User2 { namespace detail { |
| |
| template <class T1, class T2, bool = boost::is_integral<T1>::value> |
| struct promote_helper; |
| |
| template <class T1, class T2> |
| struct promote_helper<T1, saturate<T2>, true> // integral |
| { |
| typedef typename boost::common_type<T1, T2>::type rep; |
| typedef User2::saturate<rep> type; |
| }; |
| |
| template <class T1, class T2> |
| struct promote_helper<T1, saturate<T2>, false> // floating |
| { |
| typedef T1 type; |
| }; |
| |
| } } |
| |
| namespace boost |
| { |
| |
| template <class T1, class T2> |
| struct common_type<User2::saturate<T1>, User2::saturate<T2> > |
| { |
| typedef typename common_type<T1, T2>::type rep; |
| typedef User2::saturate<rep> type; |
| }; |
| |
| template <class T1, class T2> |
| struct common_type<T1, User2::saturate<T2> > |
| : User2::detail::promote_helper<T1, User2::saturate<T2> > {}; |
| |
| template <class T1, class T2> |
| struct common_type<User2::saturate<T1>, T2> |
| : User2::detail::promote_helper<T2, User2::saturate<T1> > {}; |
| |
| |
| // Demonstrate specialization of duration_values: |
| |
| namespace chrono { |
| |
| template <class I> |
| struct duration_values<User2::saturate<I> > |
| { |
| typedef User2::saturate<I> Rep; |
| public: |
| static Rep zero() {return Rep(0);} |
| static Rep max BOOST_PREVENT_MACRO_SUBSTITUTION () {return Rep(Rep::pos_inf-1);} |
| static Rep min BOOST_PREVENT_MACRO_SUBSTITUTION () {return -(max) ();} |
| }; |
| |
| } // namespace chrono |
| |
| } // namespace boost |
| |
| |
| void testUser2() |
| { |
| std::cout << "*************\n"; |
| std::cout << "* testUser2 *\n"; |
| std::cout << "*************\n"; |
| using namespace User2; |
| typedef seconds::rep sat; |
| years yr(sat(100)); |
| std::cout << "100 years expressed as years = " << yr.count() << '\n'; |
| nanoseconds ns = yr; |
| std::cout << "100 years expressed as nanoseconds = " << ns.count() << '\n'; |
| ns += yr; |
| std::cout << "200 years expressed as nanoseconds = " << ns.count() << '\n'; |
| ns += yr; |
| std::cout << "300 years expressed as nanoseconds = " << ns.count() << '\n'; |
| // yr = ns; // does not compile |
| std::cout << "yr = ns; // does not compile\n"; |
| // picoseconds ps1 = yr; // does not compile, compile-time overflow in ratio arithmetic |
| std::cout << "ps = yr; // does not compile\n"; |
| ns = yr; |
| picoseconds ps = ns; |
| std::cout << "100 years expressed as picoseconds = " << ps.count() << '\n'; |
| ps = ns / sat(1000); |
| std::cout << "0.1 years expressed as picoseconds = " << ps.count() << '\n'; |
| yr = years(sat(-200000000)); |
| std::cout << "200 million years ago encoded in years: " << yr.count() << '\n'; |
| days d = boost::chrono::duration_cast<days>(yr); |
| std::cout << "200 million years ago encoded in days: " << d.count() << '\n'; |
| millennium c = boost::chrono::duration_cast<millennium>(yr); |
| std::cout << "200 million years ago encoded in millennium: " << c.count() << '\n'; |
| std::cout << "Demonstrate \"uninitialized protection\" behavior:\n"; |
| seconds sec; |
| for (++sec; sec < seconds(sat(10)); ++sec) |
| ; |
| std::cout << sec.count() << '\n'; |
| std::cout << "\n"; |
| } |
| |
| void testStdUser() |
| { |
| std::cout << "***************\n"; |
| std::cout << "* testStdUser *\n"; |
| std::cout << "***************\n"; |
| using namespace boost::chrono; |
| hours hr = hours(100); |
| std::cout << "100 hours expressed as hours = " << hr.count() << '\n'; |
| nanoseconds ns = hr; |
| std::cout << "100 hours expressed as nanoseconds = " << ns.count() << '\n'; |
| ns += hr; |
| std::cout << "200 hours expressed as nanoseconds = " << ns.count() << '\n'; |
| ns += hr; |
| std::cout << "300 hours expressed as nanoseconds = " << ns.count() << '\n'; |
| // hr = ns; // does not compile |
| std::cout << "hr = ns; // does not compile\n"; |
| // hr * ns; // does not compile |
| std::cout << "hr * ns; // does not compile\n"; |
| duration<double> fs(2.5); |
| std::cout << "duration<double> has count() = " << fs.count() << '\n'; |
| // seconds sec = fs; // does not compile |
| std::cout << "seconds sec = duration<double> won't compile\n"; |
| seconds sec = duration_cast<seconds>(fs); |
| std::cout << "seconds has count() = " << sec.count() << '\n'; |
| std::cout << "\n"; |
| } |
| |
| // timeval clock demo |
| // Demonstrate the use of a timeval-like struct to be used as the representation |
| // type for both duraiton and time_point. |
| |
| namespace timeval_demo |
| { |
| |
| class xtime { |
| private: |
| long tv_sec; |
| long tv_usec; |
| |
| void fixup() { |
| if (tv_usec < 0) { |
| tv_usec += 1000000; |
| --tv_sec; |
| } |
| } |
| |
| public: |
| |
| explicit xtime(long sec, long usec) { |
| tv_sec = sec; |
| tv_usec = usec; |
| if (tv_usec < 0 || tv_usec >= 1000000) { |
| tv_sec += tv_usec / 1000000; |
| tv_usec %= 1000000; |
| fixup(); |
| } |
| } |
| |
| explicit xtime(long long usec) |
| { |
| tv_usec = static_cast<long>(usec % 1000000); |
| tv_sec = static_cast<long>(usec / 1000000); |
| fixup(); |
| } |
| |
| // explicit |
| operator long long() const {return static_cast<long long>(tv_sec) * 1000000 + tv_usec;} |
| |
| xtime& operator += (xtime rhs) { |
| tv_sec += rhs.tv_sec; |
| tv_usec += rhs.tv_usec; |
| if (tv_usec >= 1000000) { |
| tv_usec -= 1000000; |
| ++tv_sec; |
| } |
| return *this; |
| } |
| |
| xtime& operator -= (xtime rhs) { |
| tv_sec -= rhs.tv_sec; |
| tv_usec -= rhs.tv_usec; |
| fixup(); |
| return *this; |
| } |
| |
| xtime& operator %= (xtime rhs) { |
| long long t = tv_sec * 1000000 + tv_usec; |
| long long r = rhs.tv_sec * 1000000 + rhs.tv_usec; |
| t %= r; |
| tv_sec = static_cast<long>(t / 1000000); |
| tv_usec = static_cast<long>(t % 1000000); |
| fixup(); |
| return *this; |
| } |
| |
| friend xtime operator+(xtime x, xtime y) {return x += y;} |
| friend xtime operator-(xtime x, xtime y) {return x -= y;} |
| friend xtime operator%(xtime x, xtime y) {return x %= y;} |
| |
| friend bool operator==(xtime x, xtime y) |
| { return (x.tv_sec == y.tv_sec && x.tv_usec == y.tv_usec); } |
| |
| friend bool operator<(xtime x, xtime y) { |
| if (x.tv_sec == y.tv_sec) |
| return (x.tv_usec < y.tv_usec); |
| return (x.tv_sec < y.tv_sec); |
| } |
| |
| friend bool operator!=(xtime x, xtime y) { return !(x == y); } |
| friend bool operator> (xtime x, xtime y) { return y < x; } |
| friend bool operator<=(xtime x, xtime y) { return !(y < x); } |
| friend bool operator>=(xtime x, xtime y) { return !(x < y); } |
| |
| friend std::ostream& operator<<(std::ostream& os, xtime x) |
| {return os << '{' << x.tv_sec << ',' << x.tv_usec << '}';} |
| }; |
| |
| class xtime_clock |
| { |
| public: |
| typedef xtime rep; |
| typedef boost::micro period; |
| typedef boost::chrono::duration<rep, period> duration; |
| typedef boost::chrono::time_point<xtime_clock> time_point; |
| |
| static time_point now(); |
| }; |
| |
| xtime_clock::time_point |
| xtime_clock::now() |
| { |
| time_point t(duration(xtime(0))); |
| gettimeofday((timeval*)&t, 0); |
| return t; |
| } |
| |
| void test_xtime_clock() |
| { |
| using namespace boost::chrono; |
| std::cout << "timeval_demo system clock test\n"; |
| std::cout << "sizeof xtime_clock::time_point = " << sizeof(xtime_clock::time_point) << '\n'; |
| std::cout << "sizeof xtime_clock::duration = " << sizeof(xtime_clock::duration) << '\n'; |
| std::cout << "sizeof xtime_clock::rep = " << sizeof(xtime_clock::rep) << '\n'; |
| xtime_clock::duration delay(milliseconds(5)); |
| xtime_clock::time_point start = xtime_clock::now(); |
| while (xtime_clock::now() - start <= delay) |
| { |
| } |
| xtime_clock::time_point stop = xtime_clock::now(); |
| xtime_clock::duration elapsed = stop - start; |
| std::cout << "paused " << nanoseconds(elapsed).count() << " nanoseconds\n"; |
| } |
| |
| } // timeval_demo |
| |
| // Handle duration with resolution not known until run time |
| |
| namespace runtime_resolution |
| { |
| |
| class duration |
| { |
| public: |
| typedef long long rep; |
| private: |
| rep rep_; |
| |
| static const double ticks_per_nanosecond; |
| |
| public: |
| typedef boost::chrono::duration<double, boost::nano> tonanosec; |
| |
| duration() {} // = default; |
| explicit duration(const rep& r) : rep_(r) {} |
| |
| // conversions |
| explicit duration(const tonanosec& d) |
| : rep_(static_cast<rep>(d.count() * ticks_per_nanosecond)) {} |
| |
| // explicit |
| operator tonanosec() const {return tonanosec(rep_/ticks_per_nanosecond);} |
| |
| // observer |
| |
| rep count() const {return rep_;} |
| |
| // arithmetic |
| |
| duration& operator+=(const duration& d) {rep_ += d.rep_; return *this;} |
| duration& operator-=(const duration& d) {rep_ += d.rep_; return *this;} |
| duration& operator*=(rep rhs) {rep_ *= rhs; return *this;} |
| duration& operator/=(rep rhs) {rep_ /= rhs; return *this;} |
| |
| duration operator+() const {return *this;} |
| duration operator-() const {return duration(-rep_);} |
| duration& operator++() {++rep_; return *this;} |
| duration operator++(int) {return duration(rep_++);} |
| duration& operator--() {--rep_; return *this;} |
| duration operator--(int) {return duration(rep_--);} |
| |
| friend duration operator+(duration x, duration y) {return x += y;} |
| friend duration operator-(duration x, duration y) {return x -= y;} |
| friend duration operator*(duration x, rep y) {return x *= y;} |
| friend duration operator*(rep x, duration y) {return y *= x;} |
| friend duration operator/(duration x, rep y) {return x /= y;} |
| |
| friend bool operator==(duration x, duration y) {return x.rep_ == y.rep_;} |
| friend bool operator!=(duration x, duration y) {return !(x == y);} |
| friend bool operator< (duration x, duration y) {return x.rep_ < y.rep_;} |
| friend bool operator<=(duration x, duration y) {return !(y < x);} |
| friend bool operator> (duration x, duration y) {return y < x;} |
| friend bool operator>=(duration x, duration y) {return !(x < y);} |
| }; |
| |
| static |
| double |
| init_duration() |
| { |
| //mach_timebase_info_data_t MachInfo; |
| //mach_timebase_info(&MachInfo); |
| //return static_cast<double>(MachInfo.denom) / MachInfo.numer; |
| return static_cast<double>(1) / 1000; // Windows FILETIME is 1 per microsec |
| } |
| |
| const double duration::ticks_per_nanosecond = init_duration(); |
| |
| class clock; |
| |
| class time_point |
| { |
| public: |
| typedef runtime_resolution::clock clock; |
| typedef long long rep; |
| private: |
| rep rep_; |
| |
| |
| rep count() const {return rep_;} |
| public: |
| |
| time_point() : rep_(0) {} |
| explicit time_point(const duration& d) |
| : rep_(d.count()) {} |
| |
| // arithmetic |
| |
| time_point& operator+=(const duration& d) {rep_ += d.count(); return *this;} |
| time_point& operator-=(const duration& d) {rep_ -= d.count(); return *this;} |
| |
| friend time_point operator+(time_point x, duration y) {return x += y;} |
| friend time_point operator+(duration x, time_point y) {return y += x;} |
| friend time_point operator-(time_point x, duration y) {return x -= y;} |
| friend duration operator-(time_point x, time_point y) {return duration(x.rep_ - y.rep_);} |
| }; |
| |
| class clock |
| { |
| public: |
| typedef duration::rep rep; |
| typedef runtime_resolution::duration duration; |
| typedef runtime_resolution::time_point time_point; |
| |
| static time_point now() |
| { |
| timeval tv; |
| gettimeofday( &tv, 0 ); |
| return time_point(duration((static_cast<rep>(tv.tv_sec)<<32) | tv.tv_usec)); |
| } |
| }; |
| |
| void test() |
| { |
| using namespace boost::chrono; |
| std::cout << "runtime_resolution test\n"; |
| clock::duration delay(boost::chrono::milliseconds(5)); |
| clock::time_point start = clock::now(); |
| while (clock::now() - start <= delay) |
| ; |
| clock::time_point stop = clock::now(); |
| clock::duration elapsed = stop - start; |
| std::cout << "paused " << nanoseconds(duration_cast<nanoseconds>(duration::tonanosec(elapsed))).count() |
| << " nanoseconds\n"; |
| } |
| |
| } // runtime_resolution |
| |
| // miscellaneous tests and demos: |
| |
| |
| using namespace boost::chrono; |
| |
| void physics_function(duration<double> d) |
| { |
| std::cout << "d = " << d.count() << '\n'; |
| } |
| |
| void drive_physics_function() |
| { |
| physics_function(nanoseconds(3)); |
| physics_function(hours(3)); |
| physics_function(duration<double>(2./3)); |
| std::cout.precision(16); |
| physics_function( hours(3) + nanoseconds(-3) ); |
| } |
| |
| void test_range() |
| { |
| using namespace boost::chrono; |
| hours h1 = hours(24 * ( 365 * 292 + 292/4)); |
| nanoseconds n1 = h1 + nanoseconds(1); |
| nanoseconds delta = n1 - h1; |
| std::cout << "292 years of hours = " << h1.count() << "hr\n"; |
| std::cout << "Add a nanosecond = " << n1.count() << "ns\n"; |
| std::cout << "Find the difference = " << delta.count() << "ns\n"; |
| } |
| |
| void test_extended_range() |
| { |
| using namespace boost::chrono; |
| hours h1 = hours(24 * ( 365 * 244000 + 244000/4)); |
| /*auto*/ microseconds u1 = h1 + microseconds(1); |
| /*auto*/ microseconds delta = u1 - h1; |
| std::cout << "244,000 years of hours = " << h1.count() << "hr\n"; |
| std::cout << "Add a microsecond = " << u1.count() << "us\n"; |
| std::cout << "Find the difference = " << delta.count() << "us\n"; |
| } |
| |
| template <class Rep, class Period> |
| void inspect_duration(boost::chrono::duration<Rep, Period> d, const std::string& name) |
| { |
| typedef boost::chrono::duration<Rep, Period> Duration; |
| std::cout << "********* " << name << " *********\n"; |
| std::cout << "The period of " << name << " is " << (double)Period::num/Period::den << " seconds.\n"; |
| std::cout << "The frequency of " << name << " is " << (double)Period::den/Period::num << " Hz.\n"; |
| std::cout << "The representation is "; |
| if (boost::is_floating_point<Rep>::value) |
| { |
| std::cout << "floating point\n"; |
| std::cout << "The precision is the most significant "; |
| std::cout << std::numeric_limits<Rep>::digits10 << " decimal digits.\n"; |
| } |
| else if (boost::is_integral<Rep>::value) |
| { |
| std::cout << "integral\n"; |
| d = Duration(Rep(1)); |
| boost::chrono::duration<double> dsec = d; |
| std::cout << "The precision is " << dsec.count() << " seconds.\n"; |
| } |
| else |
| { |
| std::cout << "a class type\n"; |
| d = Duration(Rep(1)); |
| boost::chrono::duration<double> dsec = d; |
| std::cout << "The precision is " << dsec.count() << " seconds.\n"; |
| } |
| d = Duration((std::numeric_limits<Rep>::max)()); |
| using namespace boost::chrono; |
| using namespace std; |
| typedef duration<double, boost::ratio_multiply<boost::ratio<24*3652425,10000>, hours::period>::type> Years; |
| Years years = d; |
| std::cout << "The range is +/- " << years.count() << " years.\n"; |
| std::cout << "sizeof(" << name << ") = " << sizeof(d) << '\n'; |
| } |
| |
| void inspect_all() |
| { |
| using namespace boost::chrono; |
| std::cout.precision(6); |
| inspect_duration(nanoseconds(), "nanoseconds"); |
| inspect_duration(microseconds(), "microseconds"); |
| inspect_duration(milliseconds(), "milliseconds"); |
| inspect_duration(seconds(), "seconds"); |
| inspect_duration(minutes(), "minutes"); |
| inspect_duration(hours(), "hours"); |
| inspect_duration(duration<double>(), "duration<double>"); |
| } |
| |
| void test_milliseconds() |
| { |
| using namespace boost::chrono; |
| milliseconds ms(250); |
| ms += milliseconds(1); |
| milliseconds ms2(150); |
| milliseconds msdiff = ms - ms2; |
| if (msdiff == milliseconds(101)) |
| std::cout << "success\n"; |
| else |
| std::cout << "failure: " << msdiff.count() << '\n'; |
| } |
| |
| using namespace std; |
| using namespace boost::chrono; |
| |
| // Example round_up utility: converts d to To, rounding up for inexact conversions |
| // Being able to *easily* write this function is a major feature! |
| template <class To, class Rep, class Period> |
| To |
| round_up(duration<Rep, Period> d) |
| { |
| To result = duration_cast<To>(d); |
| if (result < d) |
| ++result; |
| return result; |
| } |
| |
| // demonstrate interaction with xtime-like facility: |
| |
| using namespace boost::chrono; |
| |
| struct xtime |
| { |
| long sec; |
| unsigned long usec; |
| }; |
| |
| template <class Rep, class Period> |
| xtime |
| to_xtime_truncate(duration<Rep, Period> d) |
| { |
| xtime xt; |
| xt.sec = static_cast<long>(duration_cast<seconds>(d).count()); |
| xt.usec = static_cast<long>(duration_cast<microseconds>(d - seconds(xt.sec)).count()); |
| return xt; |
| } |
| |
| template <class Rep, class Period> |
| xtime |
| to_xtime_round_up(duration<Rep, Period> d) |
| { |
| xtime xt; |
| xt.sec = static_cast<long>(duration_cast<seconds>(d).count()); |
| xt.usec = static_cast<unsigned long>(round_up<microseconds>(d - seconds(xt.sec)).count()); |
| return xt; |
| } |
| |
| microseconds |
| from_xtime(xtime xt) |
| { |
| return seconds(xt.sec) + microseconds(xt.usec); |
| } |
| |
| void print(xtime xt) |
| { |
| cout << '{' << xt.sec << ',' << xt.usec << "}\n"; |
| } |
| |
| void test_with_xtime() |
| { |
| cout << "test_with_xtime\n"; |
| xtime xt = to_xtime_truncate(seconds(3) + milliseconds(251)); |
| print(xt); |
| milliseconds ms = duration_cast<milliseconds>(from_xtime(xt)); |
| cout << ms.count() << " milliseconds\n"; |
| xt = to_xtime_round_up(ms); |
| print(xt); |
| xt = to_xtime_truncate(seconds(3) + nanoseconds(999)); |
| print(xt); |
| xt = to_xtime_round_up(seconds(3) + nanoseconds(999)); |
| print(xt); |
| } |
| |
| void test_system_clock() |
| { |
| cout << "system_clock test" << endl; |
| system_clock::duration delay = milliseconds(5); |
| system_clock::time_point start = system_clock::now(); |
| while (system_clock::now() - start <= delay) |
| ; |
| system_clock::time_point stop = system_clock::now(); |
| system_clock::duration elapsed = stop - start; |
| cout << "paused " << nanoseconds(elapsed).count() << " nanoseconds\n"; |
| start = system_clock::now(); |
| stop = system_clock::now(); |
| cout << "system_clock resolution estimate: " << nanoseconds(stop-start).count() << " nanoseconds\n"; |
| } |
| |
| void test_steady_clock() |
| { |
| cout << "steady_clock test" << endl; |
| steady_clock::duration delay = milliseconds(5); |
| steady_clock::time_point start = steady_clock::now(); |
| while (steady_clock::now() - start <= delay) |
| ; |
| steady_clock::time_point stop = steady_clock::now(); |
| steady_clock::duration elapsed = stop - start; |
| cout << "paused " << nanoseconds(elapsed).count() << " nanoseconds\n"; |
| start = steady_clock::now(); |
| stop = steady_clock::now(); |
| cout << "steady_clock resolution estimate: " << nanoseconds(stop-start).count() << " nanoseconds\n"; |
| } |
| |
| void test_hi_resolution_clock() |
| { |
| cout << "high_resolution_clock test" << endl; |
| high_resolution_clock::duration delay = milliseconds(5); |
| high_resolution_clock::time_point start = high_resolution_clock::now(); |
| while (high_resolution_clock::now() - start <= delay) |
| ; |
| high_resolution_clock::time_point stop = high_resolution_clock::now(); |
| high_resolution_clock::duration elapsed = stop - start; |
| cout << "paused " << nanoseconds(elapsed).count() << " nanoseconds\n"; |
| start = high_resolution_clock::now(); |
| stop = high_resolution_clock::now(); |
| cout << "high_resolution_clock resolution estimate: " << nanoseconds(stop-start).count() << " nanoseconds\n"; |
| } |
| |
| //void test_mixed_clock() |
| //{ |
| // cout << "mixed clock test" << endl; |
| // high_resolution_clock::time_point hstart = high_resolution_clock::now(); |
| // cout << "Add 5 milliseconds to a high_resolution_clock::time_point\n"; |
| // steady_clock::time_point mend = hstart + milliseconds(5); |
| // bool b = hstart == mend; |
| // system_clock::time_point sstart = system_clock::now(); |
| // std::cout << "Subtracting system_clock::time_point from steady_clock::time_point doesn't compile\n"; |
| //// mend - sstart; // doesn't compile |
| // cout << "subtract high_resolution_clock::time_point from steady_clock::time_point" |
| // " and add that to a system_clock::time_point\n"; |
| // system_clock::time_point send = sstart + duration_cast<system_clock::duration>(mend - hstart); |
| // cout << "subtract two system_clock::time_point's and output that in microseconds:\n"; |
| // microseconds ms = send - sstart; |
| // cout << ms.count() << " microseconds\n"; |
| //} |
| // |
| //void test_c_mapping() |
| //{ |
| // cout << "C map test\n"; |
| // using namespace boost::chrono; |
| // system_clock::time_point t1 = system_clock::now(); |
| // std::time_t c_time = system_clock::to_time_t(t1); |
| // std::tm* tmptr = std::localtime(&c_time); |
| // std::cout << "It is now " << tmptr->tm_hour << ':' << tmptr->tm_min << ':' << tmptr->tm_sec << ' ' |
| // << tmptr->tm_year + 1900 << '-' << tmptr->tm_mon + 1 << '-' << tmptr->tm_mday << '\n'; |
| // c_time = std::mktime(tmptr); |
| // system_clock::time_point t2 = system_clock::from_time_t(c_time); |
| // microseconds ms = t1 - t2; |
| // std::cout << "Round-tripping through the C interface truncated the precision by " << ms.count() << " microseconds\n"; |
| //} |
| |
| void test_duration_division() |
| { |
| cout << hours(3) / milliseconds(5) << '\n'; |
| cout << milliseconds(5) / hours(3) << '\n'; |
| cout << hours(1) / milliseconds(1) << '\n'; |
| } |
| |
| namespace I_dont_like_the_default_duration_behavior |
| { |
| |
| // Here's how you override the duration's default constructor to do anything you want (in this case zero) |
| |
| template <class R> |
| class zero_default |
| { |
| public: |
| typedef R rep; |
| |
| private: |
| rep rep_; |
| public: |
| zero_default(rep i = 0) : rep_(i) {} |
| operator rep() const {return rep_;} |
| |
| zero_default& operator+=(zero_default x) {rep_ += x.rep_; return *this;} |
| zero_default& operator-=(zero_default x) {rep_ -= x.rep_; return *this;} |
| zero_default& operator*=(zero_default x) {rep_ *= x.rep_; return *this;} |
| zero_default& operator/=(zero_default x) {rep_ /= x.rep_; return *this;} |
| |
| zero_default operator+ () const {return *this;} |
| zero_default operator- () const {return zero_default(-rep_);} |
| zero_default& operator++() {++rep_; return *this;} |
| zero_default operator++(int) {return zero_default(rep_++);} |
| zero_default& operator--() {--rep_; return *this;} |
| zero_default operator--(int) {return zero_default(rep_--);} |
| |
| friend zero_default operator+(zero_default x, zero_default y) {return x += y;} |
| friend zero_default operator-(zero_default x, zero_default y) {return x -= y;} |
| friend zero_default operator*(zero_default x, zero_default y) {return x *= y;} |
| friend zero_default operator/(zero_default x, zero_default y) {return x /= y;} |
| |
| friend bool operator==(zero_default x, zero_default y) {return x.rep_ == y.rep_;} |
| friend bool operator!=(zero_default x, zero_default y) {return !(x == y);} |
| friend bool operator< (zero_default x, zero_default y) {return x.rep_ < y.rep_;} |
| friend bool operator<=(zero_default x, zero_default y) {return !(y < x);} |
| friend bool operator> (zero_default x, zero_default y) {return y < x;} |
| friend bool operator>=(zero_default x, zero_default y) {return !(x < y);} |
| }; |
| |
| typedef boost::chrono::duration<zero_default<long long>, boost::nano > nanoseconds; |
| typedef boost::chrono::duration<zero_default<long long>, boost::micro > microseconds; |
| typedef boost::chrono::duration<zero_default<long long>, boost::milli > milliseconds; |
| typedef boost::chrono::duration<zero_default<long long> > seconds; |
| typedef boost::chrono::duration<zero_default<long long>, boost::ratio<60> > minutes; |
| typedef boost::chrono::duration<zero_default<long long>, boost::ratio<3600> > hours; |
| |
| void test() |
| { |
| milliseconds ms; |
| cout << ms.count() << '\n'; |
| } |
| |
| } // I_dont_like_the_default_duration_behavior |
| |
| // Build a min for two time_points |
| |
| template <class Rep, class Period> |
| void |
| print_duration(ostream& os, duration<Rep, Period> d) |
| { |
| os << d.count() << " * " << Period::num << '/' << Period::den << " seconds\n"; |
| } |
| |
| // Example min utility: returns the earliest time_point |
| // Being able to *easily* write this function is a major feature! |
| template <class Clock, class Duration1, class Duration2> |
| inline |
| typename boost::common_type<time_point<Clock, Duration1>, |
| time_point<Clock, Duration2> >::type |
| min BOOST_PREVENT_MACRO_SUBSTITUTION (time_point<Clock, Duration1> t1, time_point<Clock, Duration2> t2) |
| { |
| return t2 < t1 ? t2 : t1; |
| } |
| |
| void test_min() |
| { |
| typedef time_point<system_clock, |
| boost::common_type<system_clock::duration, seconds>::type> T1; |
| typedef time_point<system_clock, |
| boost::common_type<system_clock::duration, nanoseconds>::type> T2; |
| typedef boost::common_type<T1, T2>::type T3; |
| /*auto*/ T1 t1 = system_clock::now() + seconds(3); |
| /*auto*/ T2 t2 = system_clock::now() + nanoseconds(3); |
| /*auto*/ T3 t3 = (min)(t1, t2); |
| print_duration(cout, t1 - t3); |
| print_duration(cout, t2 - t3); |
| } |
| |
| void explore_limits() |
| { |
| typedef duration<long long, boost::ratio_multiply<boost::ratio<24*3652425,10000>, |
| hours::period>::type> Years; |
| steady_clock::time_point t1( Years(250)); |
| steady_clock::time_point t2(-Years(250)); |
| // nanosecond resolution is likely to overflow. "up cast" to microseconds. |
| // The "up cast" trades precision for range. |
| microseconds d = time_point_cast<microseconds>(t1) - time_point_cast<microseconds>(t2); |
| cout << d.count() << " microseconds\n"; |
| } |
| |
| void manipulate_clock_object(system_clock clock) |
| { |
| system_clock::duration delay = milliseconds(5); |
| system_clock::time_point start = clock.now(); |
| while (clock.now() - start <= delay) |
| ; |
| system_clock::time_point stop = clock.now(); |
| system_clock::duration elapsed = stop - start; |
| cout << "paused " << nanoseconds(elapsed).count() << " nanoseconds\n"; |
| }; |
| |
| template <long long speed> |
| struct cycle_count |
| { |
| typedef typename boost::ratio_multiply<boost::ratio<speed>, boost::mega>::type frequency; // Mhz |
| typedef typename boost::ratio_divide<boost::ratio<1>, frequency>::type period; |
| typedef long long rep; |
| typedef boost::chrono::duration<rep, period> duration; |
| typedef boost::chrono::time_point<cycle_count> time_point; |
| |
| static time_point now() |
| { |
| static long long tick = 0; |
| // return exact cycle count |
| return time_point(duration(++tick)); // fake access to clock cycle count |
| } |
| }; |
| |
| template <long long speed> |
| struct approx_cycle_count |
| { |
| static const long long frequency = speed * 1000000; // MHz |
| typedef nanoseconds duration; |
| typedef duration::rep rep; |
| typedef duration::period period; |
| static const long long nanosec_per_sec = period::den; |
| typedef boost::chrono::time_point<approx_cycle_count> time_point; |
| |
| static time_point now() |
| { |
| static long long tick = 0; |
| // return cycle count as an approximate number of nanoseconds |
| // compute as if nanoseconds is only duration in the std::lib |
| return time_point(duration(++tick * nanosec_per_sec / frequency)); |
| } |
| }; |
| |
| void cycle_count_delay() |
| { |
| { |
| typedef cycle_count<400> clock; |
| cout << "\nSimulated " << clock::frequency::num / boost::mega::num << "MHz clock which has a tick period of " |
| << duration<double, boost::nano>(clock::duration(1)).count() << " nanoseconds\n"; |
| nanoseconds delayns(500); |
| clock::duration delay = duration_cast<clock::duration>(delayns); |
| cout << "delay = " << delayns.count() << " nanoseconds which is " << delay.count() << " cycles\n"; |
| clock::time_point start = clock::now(); |
| clock::time_point stop = start + delay; |
| while (clock::now() < stop) // no multiplies or divides in this loop |
| ; |
| clock::time_point end = clock::now(); |
| clock::duration elapsed = end - start; |
| cout << "paused " << elapsed.count() << " cycles "; |
| cout << "which is " << duration_cast<nanoseconds>(elapsed).count() << " nanoseconds\n"; |
| } |
| { |
| typedef approx_cycle_count<400> clock; |
| cout << "\nSimulated " << clock::frequency / 1000000 << "MHz clock modeled with nanoseconds\n"; |
| clock::duration delay = nanoseconds(500); |
| cout << "delay = " << delay.count() << " nanoseconds\n"; |
| clock::time_point start = clock::now(); |
| clock::time_point stop = start + delay; |
| while (clock::now() < stop) // 1 multiplication and 1 division in this loop |
| ; |
| clock::time_point end = clock::now(); |
| clock::duration elapsed = end - start; |
| cout << "paused " << elapsed.count() << " nanoseconds\n"; |
| } |
| { |
| typedef cycle_count<1500> clock; |
| cout << "\nSimulated " << clock::frequency::num / boost::mega::num << "MHz clock which has a tick period of " |
| << duration<double, boost::nano>(clock::duration(1)).count() << " nanoseconds\n"; |
| nanoseconds delayns(500); |
| clock::duration delay = duration_cast<clock::duration>(delayns); |
| cout << "delay = " << delayns.count() << " nanoseconds which is " << delay.count() << " cycles\n"; |
| clock::time_point start = clock::now(); |
| clock::time_point stop = start + delay; |
| while (clock::now() < stop) // no multiplies or divides in this loop |
| ; |
| clock::time_point end = clock::now(); |
| clock::duration elapsed = end - start; |
| cout << "paused " << elapsed.count() << " cycles "; |
| cout << "which is " << duration_cast<nanoseconds>(elapsed).count() << " nanoseconds\n"; |
| } |
| { |
| typedef approx_cycle_count<1500> clock; |
| cout << "\nSimulated " << clock::frequency / 1000000 << "MHz clock modeled with nanoseconds\n"; |
| clock::duration delay = nanoseconds(500); |
| cout << "delay = " << delay.count() << " nanoseconds\n"; |
| clock::time_point start = clock::now(); |
| clock::time_point stop = start + delay; |
| while (clock::now() < stop) // 1 multiplication and 1 division in this loop |
| ; |
| clock::time_point end = clock::now(); |
| clock::duration elapsed = end - start; |
| cout << "paused " << elapsed.count() << " nanoseconds\n"; |
| } |
| } |
| |
| void test_special_values() |
| { |
| std::cout << "duration<unsigned>::min().count() = " << (duration<unsigned>::min)().count() << '\n'; |
| std::cout << "duration<unsigned>::zero().count() = " << duration<unsigned>::zero().count() << '\n'; |
| std::cout << "duration<unsigned>::max().count() = " << (duration<unsigned>::max)().count() << '\n'; |
| std::cout << "duration<int>::min().count() = " << (duration<int>::min)().count() << '\n'; |
| std::cout << "duration<int>::zero().count() = " << duration<int>::zero().count() << '\n'; |
| std::cout << "duration<int>::max().count() = " << (duration<int>::max)().count() << '\n'; |
| } |
| |
| int main() |
| { |
| basic_examples(); |
| testStdUser(); |
| testUser1(); |
| testUser2(); |
| drive_physics_function(); |
| test_range(); |
| test_extended_range(); |
| inspect_all(); |
| test_milliseconds(); |
| test_with_xtime(); |
| test_system_clock(); |
| test_steady_clock(); |
| test_hi_resolution_clock(); |
| //test_mixed_clock(); |
| timeval_demo::test_xtime_clock(); |
| runtime_resolution::test(); |
| //test_c_mapping(); |
| test_duration_division(); |
| I_dont_like_the_default_duration_behavior::test(); |
| test_min(); |
| inspect_duration(common_type<duration<double>, hours, microseconds>::type(), |
| "common_type<duration<double>, hours, microseconds>::type"); |
| explore_limits(); |
| manipulate_clock_object(system_clock()); |
| duration<double, boost::milli> d = milliseconds(3) * 2.5; |
| inspect_duration(milliseconds(3) * 2.5, "milliseconds(3) * 2.5"); |
| cout << d.count() << '\n'; |
| // milliseconds ms(3.5); // doesn't compile |
| cout << "milliseconds ms(3.5) doesn't compile\n"; |
| cycle_count_delay(); |
| test_special_values(); |
| return 0; |
| } |
| |