1 | /* |
2 | * Copyright 2017-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <chrono> |
20 | #include <stdexcept> |
21 | #include <type_traits> |
22 | |
23 | #include <folly/Portability.h> |
24 | #include <folly/lang/Exception.h> |
25 | #include <folly/portability/Time.h> |
26 | |
27 | /*** |
28 | * include or backport: |
29 | * * std::chrono::ceil |
30 | * * std::chrono::floor |
31 | * * std::chrono::round |
32 | */ |
33 | |
34 | #if __cpp_lib_chrono >= 201510 || _MSC_VER |
35 | |
36 | namespace folly { |
37 | namespace chrono { |
38 | |
39 | /* using override */ using std::chrono::ceil; |
40 | /* using override */ using std::chrono::floor; |
41 | /* using override */ using std::chrono::round; |
42 | } // namespace chrono |
43 | } // namespace folly |
44 | |
45 | #else |
46 | |
47 | namespace folly { |
48 | namespace chrono { |
49 | |
50 | namespace detail { |
51 | |
52 | // from: http://en.cppreference.com/w/cpp/chrono/duration/ceil, CC-BY-SA |
53 | template <typename T> |
54 | struct is_duration : std::false_type {}; |
55 | template <typename Rep, typename Period> |
56 | struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type {}; |
57 | |
58 | template <typename To, typename Duration> |
59 | constexpr To ceil_impl(Duration const& d, To const& t) { |
60 | return t < d ? t + To{1} : t; |
61 | } |
62 | |
63 | template <typename To, typename Duration> |
64 | constexpr To floor_impl(Duration const& d, To const& t) { |
65 | return t > d ? t - To{1} : t; |
66 | } |
67 | |
68 | template <typename To, typename Diff> |
69 | constexpr To round_impl(To const& t0, To const& t1, Diff diff0, Diff diff1) { |
70 | return diff0 < diff1 ? t0 : diff1 < diff0 ? t1 : t0.count() & 1 ? t1 : t0; |
71 | } |
72 | |
73 | template <typename To, typename Duration> |
74 | constexpr To round_impl(Duration const& d, To const& t0, To const& t1) { |
75 | return round_impl(t0, t1, d - t0, t1 - d); |
76 | } |
77 | |
78 | template <typename To, typename Duration> |
79 | constexpr To round_impl(Duration const& d, To const& t0) { |
80 | return round_impl(d, t0, t0 + To{1}); |
81 | } |
82 | } // namespace detail |
83 | |
84 | // mimic: std::chrono::ceil, C++17 |
85 | // from: http://en.cppreference.com/w/cpp/chrono/duration/ceil, CC-BY-SA |
86 | template < |
87 | typename To, |
88 | typename Rep, |
89 | typename Period, |
90 | typename = typename std::enable_if<detail::is_duration<To>::value>::type> |
91 | constexpr To ceil(std::chrono::duration<Rep, Period> const& d) { |
92 | return detail::ceil_impl(d, std::chrono::duration_cast<To>(d)); |
93 | } |
94 | |
95 | // mimic: std::chrono::ceil, C++17 |
96 | // from: http://en.cppreference.com/w/cpp/chrono/time_point/ceil, CC-BY-SA |
97 | template < |
98 | typename To, |
99 | typename Clock, |
100 | typename Duration, |
101 | typename = typename std::enable_if<detail::is_duration<To>::value>::type> |
102 | constexpr std::chrono::time_point<Clock, To> ceil( |
103 | std::chrono::time_point<Clock, Duration> const& tp) { |
104 | return std::chrono::time_point<Clock, To>{ceil<To>(tp.time_since_epoch())}; |
105 | } |
106 | |
107 | // mimic: std::chrono::floor, C++17 |
108 | // from: http://en.cppreference.com/w/cpp/chrono/duration/floor, CC-BY-SA |
109 | template < |
110 | typename To, |
111 | typename Rep, |
112 | typename Period, |
113 | typename = typename std::enable_if<detail::is_duration<To>::value>::type> |
114 | constexpr To floor(std::chrono::duration<Rep, Period> const& d) { |
115 | return detail::floor_impl(d, std::chrono::duration_cast<To>(d)); |
116 | } |
117 | |
118 | // mimic: std::chrono::floor, C++17 |
119 | // from: http://en.cppreference.com/w/cpp/chrono/time_point/floor, CC-BY-SA |
120 | template < |
121 | typename To, |
122 | typename Clock, |
123 | typename Duration, |
124 | typename = typename std::enable_if<detail::is_duration<To>::value>::type> |
125 | constexpr std::chrono::time_point<Clock, To> floor( |
126 | std::chrono::time_point<Clock, Duration> const& tp) { |
127 | return std::chrono::time_point<Clock, To>{floor<To>(tp.time_since_epoch())}; |
128 | } |
129 | |
130 | // mimic: std::chrono::round, C++17 |
131 | // from: http://en.cppreference.com/w/cpp/chrono/duration/round, CC-BY-SA |
132 | template < |
133 | typename To, |
134 | typename Rep, |
135 | typename Period, |
136 | typename = typename std::enable_if< |
137 | detail::is_duration<To>::value && |
138 | !std::chrono::treat_as_floating_point<typename To::rep>::value>::type> |
139 | constexpr To round(std::chrono::duration<Rep, Period> const& d) { |
140 | return detail::round_impl(d, floor<To>(d)); |
141 | } |
142 | |
143 | // mimic: std::chrono::round, C++17 |
144 | // from: http://en.cppreference.com/w/cpp/chrono/time_point/round, CC-BY-SA |
145 | template < |
146 | typename To, |
147 | typename Clock, |
148 | typename Duration, |
149 | typename = typename std::enable_if< |
150 | detail::is_duration<To>::value && |
151 | !std::chrono::treat_as_floating_point<typename To::rep>::value>::type> |
152 | constexpr std::chrono::time_point<Clock, To> round( |
153 | std::chrono::time_point<Clock, Duration> const& tp) { |
154 | return std::chrono::time_point<Clock, To>{round<To>(tp.time_since_epoch())}; |
155 | } |
156 | } // namespace chrono |
157 | } // namespace folly |
158 | |
159 | #endif |
160 | |
161 | namespace folly { |
162 | namespace chrono { |
163 | |
164 | struct coarse_steady_clock { |
165 | using rep = std::chrono::milliseconds::rep; |
166 | using period = std::chrono::milliseconds::period; |
167 | using duration = std::chrono::duration<rep, period>; |
168 | using time_point = std::chrono::time_point<coarse_steady_clock, duration>; |
169 | constexpr static bool is_steady = true; |
170 | |
171 | static time_point now() noexcept { |
172 | #ifndef CLOCK_MONOTONIC_COARSE |
173 | return time_point(std::chrono::duration_cast<duration>( |
174 | std::chrono::steady_clock::now().time_since_epoch())); |
175 | #else |
176 | timespec ts; |
177 | auto ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); |
178 | if (kIsDebug && (ret != 0)) { |
179 | throw_exception<std::runtime_error>( |
180 | "Error using CLOCK_MONOTONIC_COARSE." ); |
181 | } |
182 | |
183 | return time_point(std::chrono::duration_cast<duration>( |
184 | std::chrono::seconds(ts.tv_sec) + |
185 | std::chrono::nanoseconds(ts.tv_nsec))); |
186 | #endif |
187 | } |
188 | }; |
189 | |
190 | } // namespace chrono |
191 | } // namespace folly |
192 | |