1 //
2 // detail/chrono_time_traits.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #ifndef BOOST_ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP
12 #define BOOST_ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include <boost/asio/detail/cstdint.hpp>
19 
20 #include <boost/asio/detail/push_options.hpp>
21 
22 namespace boost {
23 namespace asio {
24 namespace detail {
25 
26 // Helper template to compute the greatest common divisor.
27 template <int64_t v1, int64_t v2>
28 struct gcd { enum { value = gcd<v2, v1 % v2>::value }; };
29 
30 template <int64_t v1>
31 struct gcd<v1, 0> { enum { value = v1 }; };
32 
33 // Adapts std::chrono clocks for use with a deadline timer.
34 template <typename Clock, typename WaitTraits>
35 struct chrono_time_traits
36 {
37   // The clock type.
38   typedef Clock clock_type;
39 
40   // The duration type of the clock.
41   typedef typename clock_type::duration duration_type;
42 
43   // The time point type of the clock.
44   typedef typename clock_type::time_point time_type;
45 
46   // The period of the clock.
47   typedef typename duration_type::period period_type;
48 
49   // Get the current time.
nowboost::asio::detail::chrono_time_traits50   static time_type now()
51   {
52     return clock_type::now();
53   }
54 
55   // Add a duration to a time.
addboost::asio::detail::chrono_time_traits56   static time_type add(const time_type& t, const duration_type& d)
57   {
58     const time_type epoch;
59     if (t >= epoch)
60     {
61       if ((time_type::max)() - t < d)
62         return (time_type::max)();
63     }
64     else // t < epoch
65     {
66       if (-(t - (time_type::min)()) > d)
67         return (time_type::min)();
68     }
69 
70     return t + d;
71   }
72 
73   // Subtract one time from another.
subtractboost::asio::detail::chrono_time_traits74   static duration_type subtract(const time_type& t1, const time_type& t2)
75   {
76     const time_type epoch;
77     if (t1 >= epoch)
78     {
79       if (t2 >= epoch)
80       {
81         return t1 - t2;
82       }
83       else if (t2 == (time_type::min)())
84       {
85         return (duration_type::max)();
86       }
87       else if ((time_type::max)() - t1 < epoch - t2)
88       {
89         return (duration_type::max)();
90       }
91       else
92       {
93         return t1 - t2;
94       }
95     }
96     else // t1 < epoch
97     {
98       if (t2 < epoch)
99       {
100         return t1 - t2;
101       }
102       else if (t1 == (time_type::min)())
103       {
104         return (duration_type::min)();
105       }
106       else if ((time_type::max)() - t2 < epoch - t1)
107       {
108         return (duration_type::min)();
109       }
110       else
111       {
112         return -(t2 - t1);
113       }
114     }
115   }
116 
117   // Test whether one time is less than another.
less_thanboost::asio::detail::chrono_time_traits118   static bool less_than(const time_type& t1, const time_type& t2)
119   {
120     return t1 < t2;
121   }
122 
123   // Implement just enough of the posix_time::time_duration interface to supply
124   // what the timer_queue requires.
125   class posix_time_duration
126   {
127   public:
posix_time_duration(const duration_type & d)128     explicit posix_time_duration(const duration_type& d)
129       : d_(d)
130     {
131     }
132 
ticks() const133     int64_t ticks() const
134     {
135       return d_.count();
136     }
137 
total_seconds() const138     int64_t total_seconds() const
139     {
140       return duration_cast<1, 1>();
141     }
142 
total_milliseconds() const143     int64_t total_milliseconds() const
144     {
145       return duration_cast<1, 1000>();
146     }
147 
total_microseconds() const148     int64_t total_microseconds() const
149     {
150       return duration_cast<1, 1000000>();
151     }
152 
153   private:
154     template <int64_t Num, int64_t Den>
duration_cast() const155     int64_t duration_cast() const
156     {
157       const int64_t num1 = period_type::num / gcd<period_type::num, Num>::value;
158       const int64_t num2 = Num / gcd<period_type::num, Num>::value;
159 
160       const int64_t den1 = period_type::den / gcd<period_type::den, Den>::value;
161       const int64_t den2 = Den / gcd<period_type::den, Den>::value;
162 
163       const int64_t num = num1 * den2;
164       const int64_t den = num2 * den1;
165 
166       if (num == 1 && den == 1)
167         return ticks();
168       else if (num != 1 && den == 1)
169         return ticks() * num;
170       else if (num == 1 && period_type::den != 1)
171         return ticks() / den;
172       else
173         return ticks() * num / den;
174     }
175 
176     duration_type d_;
177   };
178 
179   // Convert to POSIX duration type.
to_posix_durationboost::asio::detail::chrono_time_traits180   static posix_time_duration to_posix_duration(const duration_type& d)
181   {
182     return posix_time_duration(WaitTraits::to_wait_duration(d));
183   }
184 };
185 
186 } // namespace detail
187 } // namespace asio
188 } // namespace boost
189 
190 #include <boost/asio/detail/pop_options.hpp>
191 
192 #endif // BOOST_ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP
193