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