Adds test drivers for concurrent hash maps
[folly.git] / folly / Chrono.h
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/portability/Time.h>
25
26 /***
27  *  include or backport:
28  *  * std::chrono::ceil
29  *  * std::chrono::floor
30  *  * std::chrono::round
31  */
32
33 #if __cpp_lib_chrono >= 201510 || _MSC_VER
34
35 namespace folly {
36 namespace chrono {
37
38 /* using override */ using std::chrono::ceil;
39 /* using override */ using std::chrono::floor;
40 /* using override */ using std::chrono::round;
41 }
42 }
43
44 #else
45
46 namespace folly {
47 namespace chrono {
48
49 namespace detail {
50
51 //  from: http://en.cppreference.com/w/cpp/chrono/duration/ceil, CC-BY-SA
52 template <typename T>
53 struct is_duration : std::false_type {};
54 template <typename Rep, typename Period>
55 struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
56
57 template <typename To, typename Duration>
58 constexpr To ceil_impl(Duration const& d, To const& t) {
59   return t < d ? t + To{1} : t;
60 }
61
62 template <typename To, typename Duration>
63 constexpr To floor_impl(Duration const& d, To const& t) {
64   return t > d ? t - To{1} : t;
65 }
66
67 template <typename To, typename Diff>
68 constexpr To round_impl(To const& t0, To const& t1, Diff diff0, Diff diff1) {
69   return diff0 < diff1 ? t0 : diff1 < diff0 ? t1 : t0.count() & 1 ? t1 : t0;
70 }
71
72 template <typename To, typename Duration>
73 constexpr To round_impl(Duration const& d, To const& t0, To const& t1) {
74   return round_impl(t0, t1, d - t0, t1 - d);
75 }
76
77 template <typename To, typename Duration>
78 constexpr To round_impl(Duration const& d, To const& t0) {
79   return round_impl(d, t0, t0 + To{1});
80 }
81 } // namespace detail
82
83 //  mimic: std::chrono::ceil, C++17
84 //  from: http://en.cppreference.com/w/cpp/chrono/duration/ceil, CC-BY-SA
85 template <
86     typename To,
87     typename Rep,
88     typename Period,
89     typename = typename std::enable_if<detail::is_duration<To>::value>::type>
90 constexpr To ceil(std::chrono::duration<Rep, Period> const& d) {
91   return detail::ceil_impl(d, std::chrono::duration_cast<To>(d));
92 }
93
94 //  mimic: std::chrono::ceil, C++17
95 //  from: http://en.cppreference.com/w/cpp/chrono/time_point/ceil, CC-BY-SA
96 template <
97     typename To,
98     typename Clock,
99     typename Duration,
100     typename = typename std::enable_if<detail::is_duration<To>::value>::type>
101 constexpr std::chrono::time_point<Clock, To> ceil(
102     std::chrono::time_point<Clock, Duration> const& tp) {
103   return std::chrono::time_point<Clock, To>{ceil<To>(tp.time_since_epoch())};
104 }
105
106 //  mimic: std::chrono::floor, C++17
107 //  from: http://en.cppreference.com/w/cpp/chrono/duration/floor, CC-BY-SA
108 template <
109     typename To,
110     typename Rep,
111     typename Period,
112     typename = typename std::enable_if<detail::is_duration<To>::value>::type>
113 constexpr To floor(std::chrono::duration<Rep, Period> const& d) {
114   return detail::floor_impl(d, std::chrono::duration_cast<To>(d));
115 }
116
117 //  mimic: std::chrono::floor, C++17
118 //  from: http://en.cppreference.com/w/cpp/chrono/time_point/floor, CC-BY-SA
119 template <
120     typename To,
121     typename Clock,
122     typename Duration,
123     typename = typename std::enable_if<detail::is_duration<To>::value>::type>
124 constexpr std::chrono::time_point<Clock, To> floor(
125     std::chrono::time_point<Clock, Duration> const& tp) {
126   return std::chrono::time_point<Clock, To>{floor<To>(tp.time_since_epoch())};
127 }
128
129 //  mimic: std::chrono::round, C++17
130 //  from: http://en.cppreference.com/w/cpp/chrono/duration/round, CC-BY-SA
131 template <
132     typename To,
133     typename Rep,
134     typename Period,
135     typename = typename std::enable_if<
136         detail::is_duration<To>::value &&
137         !std::chrono::treat_as_floating_point<typename To::rep>::value>::type>
138 constexpr To round(std::chrono::duration<Rep, Period> const& d) {
139   return detail::round_impl(d, floor<To>(d));
140 }
141
142 //  mimic: std::chrono::round, C++17
143 //  from: http://en.cppreference.com/w/cpp/chrono/time_point/round, CC-BY-SA
144 template <
145     typename To,
146     typename Clock,
147     typename Duration,
148     typename = typename std::enable_if<
149         detail::is_duration<To>::value &&
150         !std::chrono::treat_as_floating_point<typename To::rep>::value>::type>
151 constexpr std::chrono::time_point<Clock, To> round(
152     std::chrono::time_point<Clock, Duration> const& tp) {
153   return std::chrono::time_point<Clock, To>{round<To>(tp.time_since_epoch())};
154 }
155 } // namespace chrono
156 } // namespace folly
157
158 #endif
159
160 namespace folly {
161 namespace chrono {
162 namespace detail {
163 [[noreturn]] FOLLY_NOINLINE inline void throw_coarse_steady_clock_now_exn() {
164   throw std::runtime_error("Error using CLOCK_MONOTONIC_COARSE.");
165 }
166 } // namespace detail
167
168 struct coarse_steady_clock {
169   using rep = std::chrono::milliseconds::rep;
170   using period = std::chrono::milliseconds::period;
171   using duration = std::chrono::duration<rep, period>;
172   using time_point = std::chrono::time_point<coarse_steady_clock, duration>;
173   constexpr static bool is_steady = true;
174
175   static time_point now() {
176 #ifndef CLOCK_MONOTONIC_COARSE
177     return time_point(std::chrono::duration_cast<duration>(
178         std::chrono::steady_clock::now().time_since_epoch()));
179 #else
180     timespec ts;
181     auto ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
182     if (ret != 0) {
183       detail::throw_coarse_steady_clock_now_exn();
184     }
185     return time_point(std::chrono::duration_cast<duration>(
186         std::chrono::seconds(ts.tv_sec) +
187         std::chrono::nanoseconds(ts.tv_nsec)));
188 #endif
189   }
190 };
191 } // namespace chrono
192 } // namespace folly