summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/chrono/example/saturating.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/chrono/example/saturating.cpp')
-rw-r--r--src/boost/libs/chrono/example/saturating.cpp505
1 files changed, 505 insertions, 0 deletions
diff --git a/src/boost/libs/chrono/example/saturating.cpp b/src/boost/libs/chrono/example/saturating.cpp
new file mode 100644
index 000000000..b7c7ba1f2
--- /dev/null
+++ b/src/boost/libs/chrono/example/saturating.cpp
@@ -0,0 +1,505 @@
+// saturating.cpp ----------------------------------------------------------//
+
+// Copyright 2008 Howard Hinnant
+// Copyright 2008 Beman Dawes
+// Copyright 2009 Vicente J. Botet Escriba
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+/*
+This code was extracted by Vicente J. Botet Escriba from Beman Dawes time2_demo.cpp which
+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 <iostream>
+
+//////////////////////////////////////////////////////////
+//////////////////// 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.
+#include <ostream>
+#include <stdexcept>
+#include <climits>
+
+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 I() 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
+
+#include <iostream>
+
+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";
+}
+
+
+int main()
+{
+ testStdUser();
+ testUser2();
+ return 0;
+}
+