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
36namespace folly {
37namespace 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
47namespace folly {
48namespace chrono {
49
50namespace detail {
51
52// from: http://en.cppreference.com/w/cpp/chrono/duration/ceil, CC-BY-SA
53template <typename T>
54struct is_duration : std::false_type {};
55template <typename Rep, typename Period>
56struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
57
58template <typename To, typename Duration>
59constexpr To ceil_impl(Duration const& d, To const& t) {
60 return t < d ? t + To{1} : t;
61}
62
63template <typename To, typename Duration>
64constexpr To floor_impl(Duration const& d, To const& t) {
65 return t > d ? t - To{1} : t;
66}
67
68template <typename To, typename Diff>
69constexpr 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
73template <typename To, typename Duration>
74constexpr To round_impl(Duration const& d, To const& t0, To const& t1) {
75 return round_impl(t0, t1, d - t0, t1 - d);
76}
77
78template <typename To, typename Duration>
79constexpr 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
86template <
87 typename To,
88 typename Rep,
89 typename Period,
90 typename = typename std::enable_if<detail::is_duration<To>::value>::type>
91constexpr 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
97template <
98 typename To,
99 typename Clock,
100 typename Duration,
101 typename = typename std::enable_if<detail::is_duration<To>::value>::type>
102constexpr 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
109template <
110 typename To,
111 typename Rep,
112 typename Period,
113 typename = typename std::enable_if<detail::is_duration<To>::value>::type>
114constexpr 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
120template <
121 typename To,
122 typename Clock,
123 typename Duration,
124 typename = typename std::enable_if<detail::is_duration<To>::value>::type>
125constexpr 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
132template <
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>
139constexpr 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
145template <
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>
152constexpr 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
161namespace folly {
162namespace chrono {
163
164struct 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