// 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 #include #include #include #include #include #include #include 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(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( t / 1000000UL); tp->tv_usec = static_cast( 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(d)).count(); } namespace this_thread { template void sleep_for(const boost::chrono::duration& d) { boost::chrono::microseconds t = boost::chrono::duration_cast(d); if (t < d) ++t; if (t > boost::chrono::microseconds(0)) std::cout << "sleep_for " << t.count() << " microseconds\n"; } template void sleep_until(const boost::chrono::time_point& t) { using namespace boost::chrono; typedef time_point Time; typedef system_clock::time_point SysTime; if (t > Clock::now()) { typedef typename boost::common_type::type D; /* auto */ D d = t - Clock::now(); microseconds us = duration_cast(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 bool try_lock_for(const boost::chrono::duration& d) { boost::chrono::microseconds t = boost::chrono::duration_cast(d); if (t <= boost::chrono::microseconds(0)) return try_lock(); std::cout << "try_lock_for " << t.count() << " microseconds\n"; return true; } template bool try_lock_until(const boost::chrono::time_point& t) { using namespace boost::chrono; typedef time_point Time; typedef system_clock::time_point SysTime; if (t <= Clock::now()) return try_lock(); typedef typename boost::common_type::type D; /* auto */ D d = t - Clock::now(); microseconds us = duration_cast(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 bool wait_for(mutex&, const boost::chrono::duration& d) { boost::chrono::microseconds t = boost::chrono::duration_cast(d); std::cout << "wait_for " << t.count() << " microseconds\n"; return true; } template bool wait_until(mutex&, const boost::chrono::time_point& t) { using namespace boost::chrono; typedef time_point Time; typedef system_clock::time_point SysTime; if (t <= Clock::now()) return false; typedef typename boost::common_type::type D; /* auto */ D d = t - Clock::now(); microseconds us = duration_cast(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(0.25)); this_thread::sleep_until(system_clock::now() + duration(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 length { public: typedef Ratio ratio; private: double len_; public: length() : len_(1) {} length(const double& len) : len_(len) {} // conversions template length(const length& d) : len_(d.count() * boost::ratio_divide::type::den / boost::ratio_divide::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 > meter; // set meter as "unity" typedef length centimeter; // 1/100 meter typedef length kilometer; // 1000 meters typedef length > inch; // 254/10000 meters // length takes ratio instead of two integral types so that definitions can be made like so: typedef length, inch::ratio>::type> foot; // 12 inchs typedef length, foot::ratio>::type> mile; // 5280 feet // Need a floating point definition of seconds typedef boost::chrono::duration seconds; // unity // Demo of (scientific) support for sub-nanosecond resolutions typedef boost::chrono::duration picosecond; // 10^-12 seconds typedef boost::chrono::duration femtosecond; // 10^-15 seconds typedef boost::chrono::duration 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 quantity { double q_; public: quantity() : q_(1) {} double get() const {return q_;} void set(double q) {q_ = q;} }; template <> class quantity, 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<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> > { 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> > Scalar; typedef quantity, boost::ratio<0> > Time; // second typedef quantity, boost::ratio<1> > Distance; // meter typedef quantity, boost::ratio<1> > Speed; // meter/second typedef quantity, boost::ratio<1> > Acceleration; // meter/second^2 template quantity::type, typename boost::ratio_subtract::type> operator/(const quantity& x, const quantity& y) { typedef quantity::type, typename boost::ratio_subtract::type> R; R r; r.set(x.get() / y.get()); return r; } template quantity::type, typename boost::ratio_add::type> operator*(const quantity& x, const quantity& y) { typedef quantity::type, typename boost::ratio_add::type> R; R r; r.set(x.get() * y.get()); return r; } template quantity operator+(const quantity& x, const quantity& y) { typedef quantity R; R r; r.set(x.get() + y.get()); return r; } template quantity operator-(const quantity& x, const quantity& y) { typedef quantity 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 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::value && std::is_signed::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 saturate::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 saturate& saturate::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 saturate& saturate::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 saturate& saturate::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 saturate& saturate::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, boost::pico > picoseconds; typedef boost::chrono::duration, boost::nano > nanoseconds; typedef boost::chrono::duration, boost::micro > microseconds; typedef boost::chrono::duration, boost::milli > milliseconds; typedef boost::chrono::duration > seconds; typedef boost::chrono::duration, boost::ratio< 60LL> > minutes; typedef boost::chrono::duration, boost::ratio< 3600LL> > hours; typedef boost::chrono::duration, boost::ratio< 86400LL> > days; typedef boost::chrono::duration, boost::ratio< 31556952LL> > years; typedef boost::chrono::duration, boost::ratio<31556952000LL> > millennium; } // User2 // Demonstrate custom promotion rules (needed only if there are no implicit conversions) namespace User2 { namespace detail { template ::value> struct promote_helper; template struct promote_helper, true> // integral { typedef typename boost::common_type::type rep; typedef User2::saturate type; }; template struct promote_helper, false> // floating { typedef T1 type; }; } } namespace boost { template struct common_type, User2::saturate > { typedef typename common_type::type rep; typedef User2::saturate type; }; template struct common_type > : User2::detail::promote_helper > {}; template struct common_type, T2> : User2::detail::promote_helper > {}; // Demonstrate specialization of duration_values: namespace chrono { template struct duration_values > { typedef User2::saturate 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(yr); std::cout << "200 million years ago encoded in days: " << d.count() << '\n'; millennium c = boost::chrono::duration_cast(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 fs(2.5); std::cout << "duration has count() = " << fs.count() << '\n'; // seconds sec = fs; // does not compile std::cout << "seconds sec = duration won't compile\n"; seconds sec = duration_cast(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(usec % 1000000); tv_sec = static_cast(usec / 1000000); fixup(); } // explicit operator long long() const {return static_cast(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(t / 1000000); tv_usec = static_cast(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 duration; typedef boost::chrono::time_point 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 tonanosec; duration() {} // = default; explicit duration(const rep& r) : rep_(r) {} // conversions explicit duration(const tonanosec& d) : rep_(static_cast(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(MachInfo.denom) / MachInfo.numer; return static_cast(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(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(duration::tonanosec(elapsed))).count() << " nanoseconds\n"; } } // runtime_resolution // miscellaneous tests and demos: using namespace boost::chrono; void physics_function(duration d) { std::cout << "d = " << d.count() << '\n'; } void drive_physics_function() { physics_function(nanoseconds(3)); physics_function(hours(3)); physics_function(duration(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 void inspect_duration(boost::chrono::duration d, const std::string& name) { typedef boost::chrono::duration 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::value) { std::cout << "floating point\n"; std::cout << "The precision is the most significant "; std::cout << std::numeric_limits::digits10 << " decimal digits.\n"; } else if (boost::is_integral::value) { std::cout << "integral\n"; d = Duration(Rep(1)); boost::chrono::duration 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 dsec = d; std::cout << "The precision is " << dsec.count() << " seconds.\n"; } d = Duration((std::numeric_limits::max)()); using namespace boost::chrono; using namespace std; typedef duration, 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(), "duration"); } 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 To round_up(duration d) { To result = duration_cast(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 xtime to_xtime_truncate(duration d) { xtime xt; xt.sec = static_cast(duration_cast(d).count()); xt.usec = static_cast(duration_cast(d - seconds(xt.sec)).count()); return xt; } template xtime to_xtime_round_up(duration d) { xtime xt; xt.sec = static_cast(duration_cast(d).count()); xt.usec = static_cast(round_up(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(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(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 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, boost::nano > nanoseconds; typedef boost::chrono::duration, boost::micro > microseconds; typedef boost::chrono::duration, boost::milli > milliseconds; typedef boost::chrono::duration > seconds; typedef boost::chrono::duration, boost::ratio<60> > minutes; typedef boost::chrono::duration, 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 void print_duration(ostream& os, duration 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 inline typename boost::common_type, time_point >::type min BOOST_PREVENT_MACRO_SUBSTITUTION (time_point t1, time_point t2) { return t2 < t1 ? t2 : t1; } void test_min() { typedef time_point::type> T1; typedef time_point::type> T2; typedef boost::common_type::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, 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(t1) - time_point_cast(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 struct cycle_count { typedef typename boost::ratio_multiply, boost::mega>::type frequency; // Mhz typedef typename boost::ratio_divide, frequency>::type period; typedef long long rep; typedef boost::chrono::duration duration; typedef boost::chrono::time_point 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 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 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(clock::duration(1)).count() << " nanoseconds\n"; nanoseconds delayns(500); clock::duration delay = duration_cast(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(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(clock::duration(1)).count() << " nanoseconds\n"; nanoseconds delayns(500); clock::duration delay = duration_cast(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(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::min().count() = " << (duration::min)().count() << '\n'; std::cout << "duration::zero().count() = " << duration::zero().count() << '\n'; std::cout << "duration::max().count() = " << (duration::max)().count() << '\n'; std::cout << "duration::min().count() = " << (duration::min)().count() << '\n'; std::cout << "duration::zero().count() = " << duration::zero().count() << '\n'; std::cout << "duration::max().count() = " << (duration::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, hours, microseconds>::type(), "common_type, hours, microseconds>::type"); explore_limits(); manipulate_clock_object(system_clock()); duration 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; }