1 | /* |
2 | * Copyright (c) Facebook, Inc. and its affiliates. |
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 || _LIBCPP_STD_VER > 14 || _MSC_VER |
35 | |
36 | namespace folly { |
37 | namespace chrono { |
38 | |
39 | /* using override */ using std::chrono::abs; |
40 | /* using override */ using std::chrono::ceil; |
41 | /* using override */ using std::chrono::floor; |
42 | /* using override */ using std::chrono::round; |
43 | } // namespace chrono |
44 | } // namespace folly |
45 | |
46 | #else |
47 | |
48 | namespace folly { |
49 | namespace chrono { |
50 | |
51 | namespace detail { |
52 | |
53 | // from: http://en.cppreference.com/w/cpp/chrono/duration/ceil, CC-BY-SA |
54 | template <typename T> |
55 | struct is_duration : std::false_type {}; |
56 | template <typename Rep, typename Period> |
57 | struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type {}; |
58 | |
59 | template <typename To, typename Duration> |
60 | constexpr To ceil_impl(Duration const& d, To const& t) { |
61 | return t < d ? t + To{1} : t; |
62 | } |
63 | |
64 | template <typename To, typename Duration> |
65 | constexpr To floor_impl(Duration const& d, To const& t) { |
66 | return t > d ? t - To{1} : t; |
67 | } |
68 | |
69 | template <typename To, typename Diff> |
70 | constexpr To round_impl(To const& t0, To const& t1, Diff diff0, Diff diff1) { |
71 | return diff0 < diff1 ? t0 : diff1 < diff0 ? t1 : t0.count() & 1 ? t1 : t0; |
72 | } |
73 | |
74 | template <typename To, typename Duration> |
75 | constexpr To round_impl(Duration const& d, To const& t0, To const& t1) { |
76 | return round_impl(t0, t1, d - t0, t1 - d); |
77 | } |
78 | |
79 | template <typename To, typename Duration> |
80 | constexpr To round_impl(Duration const& d, To const& t0) { |
81 | return round_impl(d, t0, t0 + To{1}); |
82 | } |
83 | } // namespace detail |
84 | |
85 | // mimic: std::chrono::abs, C++17 |
86 | template < |
87 | typename Rep, |
88 | typename Period, |
89 | typename = typename std::enable_if< |
90 | std::chrono::duration<Rep, Period>::min() < |
91 | std::chrono::duration<Rep, Period>::zero()>::type> |
92 | constexpr std::chrono::duration<Rep, Period> abs( |
93 | std::chrono::duration<Rep, Period> const& d) { |
94 | return d < std::chrono::duration<Rep, Period>::zero() ? -d : d; |
95 | } |
96 | |
97 | // mimic: std::chrono::ceil, C++17 |
98 | // from: http://en.cppreference.com/w/cpp/chrono/duration/ceil, CC-BY-SA |
99 | template < |
100 | typename To, |
101 | typename Rep, |
102 | typename Period, |
103 | typename = typename std::enable_if<detail::is_duration<To>::value>::type> |
104 | constexpr To ceil(std::chrono::duration<Rep, Period> const& d) { |
105 | return detail::ceil_impl(d, std::chrono::duration_cast<To>(d)); |
106 | } |
107 | |
108 | // mimic: std::chrono::ceil, C++17 |
109 | // from: http://en.cppreference.com/w/cpp/chrono/time_point/ceil, CC-BY-SA |
110 | template < |
111 | typename To, |
112 | typename Clock, |
113 | typename Duration, |
114 | typename = typename std::enable_if<detail::is_duration<To>::value>::type> |
115 | constexpr std::chrono::time_point<Clock, To> ceil( |
116 | std::chrono::time_point<Clock, Duration> const& tp) { |
117 | return std::chrono::time_point<Clock, To>{ceil<To>(tp.time_since_epoch())}; |
118 | } |
119 | |
120 | // mimic: std::chrono::floor, C++17 |
121 | // from: http://en.cppreference.com/w/cpp/chrono/duration/floor, CC-BY-SA |
122 | template < |
123 | typename To, |
124 | typename Rep, |
125 | typename Period, |
126 | typename = typename std::enable_if<detail::is_duration<To>::value>::type> |
127 | constexpr To floor(std::chrono::duration<Rep, Period> const& d) { |
128 | return detail::floor_impl(d, std::chrono::duration_cast<To>(d)); |
129 | } |
130 | |
131 | // mimic: std::chrono::floor, C++17 |
132 | // from: http://en.cppreference.com/w/cpp/chrono/time_point/floor, CC-BY-SA |
133 | template < |
134 | typename To, |
135 | typename Clock, |
136 | typename Duration, |
137 | typename = typename std::enable_if<detail::is_duration<To>::value>::type> |
138 | constexpr std::chrono::time_point<Clock, To> floor( |
139 | std::chrono::time_point<Clock, Duration> const& tp) { |
140 | return std::chrono::time_point<Clock, To>{floor<To>(tp.time_since_epoch())}; |
141 | } |
142 | |
143 | // mimic: std::chrono::round, C++17 |
144 | // from: http://en.cppreference.com/w/cpp/chrono/duration/round, CC-BY-SA |
145 | template < |
146 | typename To, |
147 | typename Rep, |
148 | typename Period, |
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 To round(std::chrono::duration<Rep, Period> const& d) { |
153 | return detail::round_impl(d, floor<To>(d)); |
154 | } |
155 | |
156 | // mimic: std::chrono::round, C++17 |
157 | // from: http://en.cppreference.com/w/cpp/chrono/time_point/round, CC-BY-SA |
158 | template < |
159 | typename To, |
160 | typename Clock, |
161 | typename Duration, |
162 | typename = typename std::enable_if< |
163 | detail::is_duration<To>::value && |
164 | !std::chrono::treat_as_floating_point<typename To::rep>::value>::type> |
165 | constexpr std::chrono::time_point<Clock, To> round( |
166 | std::chrono::time_point<Clock, Duration> const& tp) { |
167 | return std::chrono::time_point<Clock, To>{round<To>(tp.time_since_epoch())}; |
168 | } |
169 | } // namespace chrono |
170 | } // namespace folly |
171 | |
172 | #endif |
173 | |
174 | namespace folly { |
175 | namespace chrono { |
176 | |
177 | struct coarse_steady_clock { |
178 | using rep = std::chrono::milliseconds::rep; |
179 | using period = std::chrono::milliseconds::period; |
180 | using duration = std::chrono::duration<rep, period>; |
181 | using time_point = std::chrono::time_point<coarse_steady_clock, duration>; |
182 | constexpr static bool is_steady = true; |
183 | |
184 | static time_point now() noexcept { |
185 | #ifndef CLOCK_MONOTONIC_COARSE |
186 | return time_point(std::chrono::duration_cast<duration>( |
187 | std::chrono::steady_clock::now().time_since_epoch())); |
188 | #else |
189 | timespec ts; |
190 | auto ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); |
191 | if (kIsDebug && (ret != 0)) { |
192 | throw_exception<std::runtime_error>( |
193 | "Error using CLOCK_MONOTONIC_COARSE." ); |
194 | } |
195 | |
196 | return time_point(std::chrono::duration_cast<duration>( |
197 | std::chrono::seconds(ts.tv_sec) + |
198 | std::chrono::nanoseconds(ts.tv_nsec))); |
199 | #endif |
200 | } |
201 | }; |
202 | |
203 | } // namespace chrono |
204 | } // namespace folly |
205 | |