1// saturating.cpp ----------------------------------------------------------//
2
3// Copyright 2008 Howard Hinnant
4// Copyright 2008 Beman Dawes
5// Copyright 2009 Vicente J. Botet Escriba
6
7// Distributed under the Boost Software License, Version 1.0.
8// See http://www.boost.org/LICENSE_1_0.txt
9
10/*
11This code was extracted by Vicente J. Botet Escriba from Beman Dawes time2_demo.cpp which
12was derived by Beman Dawes from Howard Hinnant's time2_demo prototype.
13Many thanks to Howard for making his code available under the Boost license.
14The original code was modified to conform to Boost conventions and to section
1520.9 Time utilities [time] of the C++ committee's working paper N2798.
16See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf.
17
18time2_demo contained this comment:
19
20 Much thanks to Andrei Alexandrescu,
21 Walter Brown,
22 Peter Dimov,
23 Jeff Garland,
24 Terry Golubiewski,
25 Daniel Krugler,
26 Anthony Williams.
27*/
28
29#define _CRT_SECURE_NO_WARNINGS // disable VC++ foolishness
30
31#include <boost/chrono/chrono.hpp>
32#include <boost/type_traits.hpp>
33
34#include <iostream>
35
36//////////////////////////////////////////////////////////
37//////////////////// User2 Example ///////////////////////
38//////////////////////////////////////////////////////////
39
40// Demonstrate User2:
41// A "saturating" signed integral type is developed. This type has +/- infinity and a nan
42// (like IEEE floating point) but otherwise obeys signed integral arithmetic.
43// This class is subsequently used as the rep in boost::chrono::duration to demonstrate a
44// duration class that does not silently ignore overflow.
45#include <ostream>
46#include <stdexcept>
47#include <climits>
48
49namespace User2
50{
51
52template <class I>
53class saturate
54{
55public:
56 typedef I int_type;
57
58 static const int_type nan = int_type(int_type(1) << (sizeof(int_type) * CHAR_BIT - 1));
59 static const int_type neg_inf = nan + 1;
60 static const int_type pos_inf = -neg_inf;
61private:
62 int_type i_;
63
64// static_assert(std::is_integral<int_type>::value && std::is_signed<int_type>::value,
65// "saturate only accepts signed integral types");
66// static_assert(nan == -nan && neg_inf < pos_inf,
67// "saturate assumes two's complement hardware for signed integrals");
68
69public:
70 saturate() : i_(nan) {}
71 explicit saturate(int_type i) : i_(i) {}
72 // explicit
73 operator int_type() const;
74
75 saturate& operator+=(saturate x);
76 saturate& operator-=(saturate x) {return *this += -x;}
77 saturate& operator*=(saturate x);
78 saturate& operator/=(saturate x);
79 saturate& operator%=(saturate x);
80
81 saturate operator- () const {return saturate(-i_);}
82 saturate& operator++() {*this += saturate(int_type(1)); return *this;}
83 saturate operator++(int) {saturate tmp(*this); ++(*this); return tmp;}
84 saturate& operator--() {*this -= saturate(int_type(1)); return *this;}
85 saturate operator--(int) {saturate tmp(*this); --(*this); return tmp;}
86
87 friend saturate operator+(saturate x, saturate y) {return x += y;}
88 friend saturate operator-(saturate x, saturate y) {return x -= y;}
89 friend saturate operator*(saturate x, saturate y) {return x *= y;}
90 friend saturate operator/(saturate x, saturate y) {return x /= y;}
91 friend saturate operator%(saturate x, saturate y) {return x %= y;}
92
93 friend bool operator==(saturate x, saturate y)
94 {
95 if (x.i_ == nan || y.i_ == nan)
96 return false;
97 return x.i_ == y.i_;
98 }
99
100 friend bool operator!=(saturate x, saturate y) {return !(x == y);}
101
102 friend bool operator<(saturate x, saturate y)
103 {
104 if (x.i_ == nan || y.i_ == nan)
105 return false;
106 return x.i_ < y.i_;
107 }
108
109 friend bool operator<=(saturate x, saturate y)
110 {
111 if (x.i_ == nan || y.i_ == nan)
112 return false;
113 return x.i_ <= y.i_;
114 }
115
116 friend bool operator>(saturate x, saturate y)
117 {
118 if (x.i_ == nan || y.i_ == nan)
119 return false;
120 return x.i_ > y.i_;
121 }
122
123 friend bool operator>=(saturate x, saturate y)
124 {
125 if (x.i_ == nan || y.i_ == nan)
126 return false;
127 return x.i_ >= y.i_;
128 }
129
130 friend std::ostream& operator<<(std::ostream& os, saturate s)
131 {
132 switch (s.i_)
133 {
134 case pos_inf:
135 return os << "inf";
136 case nan:
137 return os << "nan";
138 case neg_inf:
139 return os << "-inf";
140 };
141 return os << s.i_;
142 }
143};
144
145template <class I>
146saturate<I>::operator I() const
147{
148 switch (i_)
149 {
150 case nan:
151 case neg_inf:
152 case pos_inf:
153 throw std::out_of_range("saturate special value can not convert to int_type");
154 }
155 return i_;
156}
157
158template <class I>
159saturate<I>&
160saturate<I>::operator+=(saturate x)
161{
162 switch (i_)
163 {
164 case pos_inf:
165 switch (x.i_)
166 {
167 case neg_inf:
168 case nan:
169 i_ = nan;
170 }
171 return *this;
172 case nan:
173 return *this;
174 case neg_inf:
175 switch (x.i_)
176 {
177 case pos_inf:
178 case nan:
179 i_ = nan;
180 }
181 return *this;
182 }
183 switch (x.i_)
184 {
185 case pos_inf:
186 case neg_inf:
187 case nan:
188 i_ = x.i_;
189 return *this;
190 }
191 if (x.i_ >= 0)
192 {
193 if (i_ < pos_inf - x.i_)
194 i_ += x.i_;
195 else
196 i_ = pos_inf;
197 return *this;
198 }
199 if (i_ > neg_inf - x.i_)
200 i_ += x.i_;
201 else
202 i_ = neg_inf;
203 return *this;
204}
205
206template <class I>
207saturate<I>&
208saturate<I>::operator*=(saturate x)
209{
210 switch (i_)
211 {
212 case 0:
213 switch (x.i_)
214 {
215 case pos_inf:
216 case neg_inf:
217 case nan:
218 i_ = nan;
219 }
220 return *this;
221 case pos_inf:
222 switch (x.i_)
223 {
224 case nan:
225 case 0:
226 i_ = nan;
227 return *this;
228 }
229 if (x.i_ < 0)
230 i_ = neg_inf;
231 return *this;
232 case nan:
233 return *this;
234 case neg_inf:
235 switch (x.i_)
236 {
237 case nan:
238 case 0:
239 i_ = nan;
240 return *this;
241 }
242 if (x.i_ < 0)
243 i_ = pos_inf;
244 return *this;
245 }
246 switch (x.i_)
247 {
248 case 0:
249 i_ = 0;
250 return *this;
251 case nan:
252 i_ = nan;
253 return *this;
254 case pos_inf:
255 if (i_ < 0)
256 i_ = neg_inf;
257 else
258 i_ = pos_inf;
259 return *this;
260 case neg_inf:
261 if (i_ < 0)
262 i_ = pos_inf;
263 else
264 i_ = neg_inf;
265 return *this;
266 }
267 int s = (i_ < 0 ? -1 : 1) * (x.i_ < 0 ? -1 : 1);
268 i_ = i_ < 0 ? -i_ : i_;
269 int_type x_i_ = x.i_ < 0 ? -x.i_ : x.i_;
270 if (i_ <= pos_inf / x_i_)
271 i_ *= x_i_;
272 else
273 i_ = pos_inf;
274 i_ *= s;
275 return *this;
276}
277
278template <class I>
279saturate<I>&
280saturate<I>::operator/=(saturate x)
281{
282 switch (x.i_)
283 {
284 case pos_inf:
285 case neg_inf:
286 switch (i_)
287 {
288 case pos_inf:
289 case neg_inf:
290 case nan:
291 i_ = nan;
292 break;
293 default:
294 i_ = 0;
295 break;
296 }
297 return *this;
298 case nan:
299 i_ = nan;
300 return *this;
301 case 0:
302 switch (i_)
303 {
304 case pos_inf:
305 case neg_inf:
306 case nan:
307 return *this;
308 case 0:
309 i_ = nan;
310 return *this;
311 }
312 if (i_ > 0)
313 i_ = pos_inf;
314 else
315 i_ = neg_inf;
316 return *this;
317 }
318 switch (i_)
319 {
320 case 0:
321 case nan:
322 return *this;
323 case pos_inf:
324 case neg_inf:
325 if (x.i_ < 0)
326 i_ = -i_;
327 return *this;
328 }
329 i_ /= x.i_;
330 return *this;
331}
332
333template <class I>
334saturate<I>&
335saturate<I>::operator%=(saturate x)
336{
337// *this -= *this / x * x; // definition
338 switch (x.i_)
339 {
340 case nan:
341 case neg_inf:
342 case 0:
343 case pos_inf:
344 i_ = nan;
345 return *this;
346 }
347 switch (i_)
348 {
349 case neg_inf:
350 case pos_inf:
351 i_ = nan;
352 case nan:
353 return *this;
354 }
355 i_ %= x.i_;
356 return *this;
357}
358
359// Demo overflow-safe integral durations ranging from picoseconds resolution to millennium resolution
360typedef boost::chrono::duration<saturate<long long>, boost::pico > picoseconds;
361typedef boost::chrono::duration<saturate<long long>, boost::nano > nanoseconds;
362typedef boost::chrono::duration<saturate<long long>, boost::micro > microseconds;
363typedef boost::chrono::duration<saturate<long long>, boost::milli > milliseconds;
364typedef boost::chrono::duration<saturate<long long> > seconds;
365typedef boost::chrono::duration<saturate<long long>, boost::ratio< 60LL> > minutes;
366typedef boost::chrono::duration<saturate<long long>, boost::ratio< 3600LL> > hours;
367typedef boost::chrono::duration<saturate<long long>, boost::ratio< 86400LL> > days;
368typedef boost::chrono::duration<saturate<long long>, boost::ratio< 31556952LL> > years;
369typedef boost::chrono::duration<saturate<long long>, boost::ratio<31556952000LL> > millennium;
370
371} // User2
372
373// Demonstrate custom promotion rules (needed only if there are no implicit conversions)
374namespace User2 { namespace detail {
375
376template <class T1, class T2, bool = boost::is_integral<T1>::value>
377struct promote_helper;
378
379template <class T1, class T2>
380struct promote_helper<T1, saturate<T2>, true> // integral
381{
382 typedef typename boost::common_type<T1, T2>::type rep;
383 typedef User2::saturate<rep> type;
384};
385
386template <class T1, class T2>
387struct promote_helper<T1, saturate<T2>, false> // floating
388{
389 typedef T1 type;
390};
391
392} }
393
394namespace boost
395{
396
397template <class T1, class T2>
398struct common_type<User2::saturate<T1>, User2::saturate<T2> >
399{
400 typedef typename common_type<T1, T2>::type rep;
401 typedef User2::saturate<rep> type;
402};
403
404template <class T1, class T2>
405struct common_type<T1, User2::saturate<T2> >
406 : User2::detail::promote_helper<T1, User2::saturate<T2> > {};
407
408template <class T1, class T2>
409struct common_type<User2::saturate<T1>, T2>
410 : User2::detail::promote_helper<T2, User2::saturate<T1> > {};
411
412
413// Demonstrate specialization of duration_values:
414
415namespace chrono {
416
417template <class I>
418struct duration_values<User2::saturate<I> >
419{
420 typedef User2::saturate<I> Rep;
421public:
422 static Rep zero() {return Rep(0);}
423 static Rep max BOOST_PREVENT_MACRO_SUBSTITUTION () {return Rep(Rep::pos_inf-1);}
424 static Rep min BOOST_PREVENT_MACRO_SUBSTITUTION () {return -(max)();}
425};
426
427} // namespace chrono
428
429} // namespace boost
430
431#include <iostream>
432
433void testUser2()
434{
435 std::cout << "*************\n";
436 std::cout << "* testUser2 *\n";
437 std::cout << "*************\n";
438 using namespace User2;
439 typedef seconds::rep sat;
440 years yr(sat(100));
441 std::cout << "100 years expressed as years = " << yr.count() << '\n';
442 nanoseconds ns = yr;
443 std::cout << "100 years expressed as nanoseconds = " << ns.count() << '\n';
444 ns += yr;
445 std::cout << "200 years expressed as nanoseconds = " << ns.count() << '\n';
446 ns += yr;
447 std::cout << "300 years expressed as nanoseconds = " << ns.count() << '\n';
448// yr = ns; // does not compile
449 std::cout << "yr = ns; // does not compile\n";
450// picoseconds ps1 = yr; // does not compile, compile-time overflow in ratio arithmetic
451 std::cout << "ps = yr; // does not compile\n";
452 ns = yr;
453 picoseconds ps = ns;
454 std::cout << "100 years expressed as picoseconds = " << ps.count() << '\n';
455 ps = ns / sat(1000);
456 std::cout << "0.1 years expressed as picoseconds = " << ps.count() << '\n';
457 yr = years(sat(-200000000));
458 std::cout << "200 million years ago encoded in years: " << yr.count() << '\n';
459 days d = boost::chrono::duration_cast<days>(fd: yr);
460 std::cout << "200 million years ago encoded in days: " << d.count() << '\n';
461 millennium c = boost::chrono::duration_cast<millennium>(fd: yr);
462 std::cout << "200 million years ago encoded in millennium: " << c.count() << '\n';
463 std::cout << "Demonstrate \"uninitialized protection\" behavior:\n";
464 seconds sec;
465 for (++sec; sec < seconds(sat(10)); ++sec)
466 ;
467 std::cout << sec.count() << '\n';
468 std::cout << "\n";
469}
470
471void testStdUser()
472{
473 std::cout << "***************\n";
474 std::cout << "* testStdUser *\n";
475 std::cout << "***************\n";
476 using namespace boost::chrono;
477 hours hr = hours(100);
478 std::cout << "100 hours expressed as hours = " << hr.count() << '\n';
479 nanoseconds ns = hr;
480 std::cout << "100 hours expressed as nanoseconds = " << ns.count() << '\n';
481 ns += hr;
482 std::cout << "200 hours expressed as nanoseconds = " << ns.count() << '\n';
483 ns += hr;
484 std::cout << "300 hours expressed as nanoseconds = " << ns.count() << '\n';
485// hr = ns; // does not compile
486 std::cout << "hr = ns; // does not compile\n";
487// hr * ns; // does not compile
488 std::cout << "hr * ns; // does not compile\n";
489 duration<double> fs(2.5);
490 std::cout << "duration<double> has count() = " << fs.count() << '\n';
491// seconds sec = fs; // does not compile
492 std::cout << "seconds sec = duration<double> won't compile\n";
493 seconds sec = duration_cast<seconds>(fd: fs);
494 std::cout << "seconds has count() = " << sec.count() << '\n';
495 std::cout << "\n";
496}
497
498
499int main()
500{
501 testStdUser();
502 testUser2();
503 return 0;
504}
505
506

source code of boost/libs/chrono/example/saturating.cpp