191 lines
5.8 KiB
C++
191 lines
5.8 KiB
C++
/*
|
|
* Copyright 2017-present Facebook, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <chrono>
|
|
#include <stdexcept>
|
|
#include <type_traits>
|
|
|
|
#include <folly/Portability.h>
|
|
#include <folly/lang/Exception.h>
|
|
#include <folly/portability/Time.h>
|
|
|
|
/***
|
|
* include or backport:
|
|
* * std::chrono::ceil
|
|
* * std::chrono::floor
|
|
* * std::chrono::round
|
|
*/
|
|
|
|
#if __cpp_lib_chrono >= 201510 || _MSC_VER
|
|
|
|
namespace folly {
|
|
namespace chrono {
|
|
|
|
/* using override */ using std::chrono::ceil;
|
|
/* using override */ using std::chrono::floor;
|
|
/* using override */ using std::chrono::round;
|
|
} // namespace chrono
|
|
} // namespace folly
|
|
|
|
#else
|
|
|
|
namespace folly {
|
|
namespace chrono {
|
|
|
|
namespace detail {
|
|
|
|
// from: http://en.cppreference.com/w/cpp/chrono/duration/ceil, CC-BY-SA
|
|
template <typename T>
|
|
struct is_duration : std::false_type {};
|
|
template <typename Rep, typename Period>
|
|
struct is_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
|
|
|
|
template <typename To, typename Duration>
|
|
constexpr To ceil_impl(Duration const& d, To const& t) {
|
|
return t < d ? t + To{1} : t;
|
|
}
|
|
|
|
template <typename To, typename Duration>
|
|
constexpr To floor_impl(Duration const& d, To const& t) {
|
|
return t > d ? t - To{1} : t;
|
|
}
|
|
|
|
template <typename To, typename Diff>
|
|
constexpr To round_impl(To const& t0, To const& t1, Diff diff0, Diff diff1) {
|
|
return diff0 < diff1 ? t0 : diff1 < diff0 ? t1 : t0.count() & 1 ? t1 : t0;
|
|
}
|
|
|
|
template <typename To, typename Duration>
|
|
constexpr To round_impl(Duration const& d, To const& t0, To const& t1) {
|
|
return round_impl(t0, t1, d - t0, t1 - d);
|
|
}
|
|
|
|
template <typename To, typename Duration>
|
|
constexpr To round_impl(Duration const& d, To const& t0) {
|
|
return round_impl(d, t0, t0 + To{1});
|
|
}
|
|
} // namespace detail
|
|
|
|
// mimic: std::chrono::ceil, C++17
|
|
// from: http://en.cppreference.com/w/cpp/chrono/duration/ceil, CC-BY-SA
|
|
template <
|
|
typename To,
|
|
typename Rep,
|
|
typename Period,
|
|
typename = typename std::enable_if<detail::is_duration<To>::value>::type>
|
|
constexpr To ceil(std::chrono::duration<Rep, Period> const& d) {
|
|
return detail::ceil_impl(d, std::chrono::duration_cast<To>(d));
|
|
}
|
|
|
|
// mimic: std::chrono::ceil, C++17
|
|
// from: http://en.cppreference.com/w/cpp/chrono/time_point/ceil, CC-BY-SA
|
|
template <
|
|
typename To,
|
|
typename Clock,
|
|
typename Duration,
|
|
typename = typename std::enable_if<detail::is_duration<To>::value>::type>
|
|
constexpr std::chrono::time_point<Clock, To> ceil(
|
|
std::chrono::time_point<Clock, Duration> const& tp) {
|
|
return std::chrono::time_point<Clock, To>{ceil<To>(tp.time_since_epoch())};
|
|
}
|
|
|
|
// mimic: std::chrono::floor, C++17
|
|
// from: http://en.cppreference.com/w/cpp/chrono/duration/floor, CC-BY-SA
|
|
template <
|
|
typename To,
|
|
typename Rep,
|
|
typename Period,
|
|
typename = typename std::enable_if<detail::is_duration<To>::value>::type>
|
|
constexpr To floor(std::chrono::duration<Rep, Period> const& d) {
|
|
return detail::floor_impl(d, std::chrono::duration_cast<To>(d));
|
|
}
|
|
|
|
// mimic: std::chrono::floor, C++17
|
|
// from: http://en.cppreference.com/w/cpp/chrono/time_point/floor, CC-BY-SA
|
|
template <
|
|
typename To,
|
|
typename Clock,
|
|
typename Duration,
|
|
typename = typename std::enable_if<detail::is_duration<To>::value>::type>
|
|
constexpr std::chrono::time_point<Clock, To> floor(
|
|
std::chrono::time_point<Clock, Duration> const& tp) {
|
|
return std::chrono::time_point<Clock, To>{floor<To>(tp.time_since_epoch())};
|
|
}
|
|
|
|
// mimic: std::chrono::round, C++17
|
|
// from: http://en.cppreference.com/w/cpp/chrono/duration/round, CC-BY-SA
|
|
template <
|
|
typename To,
|
|
typename Rep,
|
|
typename Period,
|
|
typename = typename std::enable_if<
|
|
detail::is_duration<To>::value &&
|
|
!std::chrono::treat_as_floating_point<typename To::rep>::value>::type>
|
|
constexpr To round(std::chrono::duration<Rep, Period> const& d) {
|
|
return detail::round_impl(d, floor<To>(d));
|
|
}
|
|
|
|
// mimic: std::chrono::round, C++17
|
|
// from: http://en.cppreference.com/w/cpp/chrono/time_point/round, CC-BY-SA
|
|
template <
|
|
typename To,
|
|
typename Clock,
|
|
typename Duration,
|
|
typename = typename std::enable_if<
|
|
detail::is_duration<To>::value &&
|
|
!std::chrono::treat_as_floating_point<typename To::rep>::value>::type>
|
|
constexpr std::chrono::time_point<Clock, To> round(
|
|
std::chrono::time_point<Clock, Duration> const& tp) {
|
|
return std::chrono::time_point<Clock, To>{round<To>(tp.time_since_epoch())};
|
|
}
|
|
} // namespace chrono
|
|
} // namespace folly
|
|
|
|
#endif
|
|
|
|
namespace folly {
|
|
namespace chrono {
|
|
|
|
struct coarse_steady_clock {
|
|
using rep = std::chrono::milliseconds::rep;
|
|
using period = std::chrono::milliseconds::period;
|
|
using duration = std::chrono::duration<rep, period>;
|
|
using time_point = std::chrono::time_point<coarse_steady_clock, duration>;
|
|
constexpr static bool is_steady = true;
|
|
|
|
static time_point now() {
|
|
#ifndef CLOCK_MONOTONIC_COARSE
|
|
return time_point(std::chrono::duration_cast<duration>(
|
|
std::chrono::steady_clock::now().time_since_epoch()));
|
|
#else
|
|
timespec ts;
|
|
auto ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
|
|
if (ret != 0) {
|
|
throw_exception<std::runtime_error>(
|
|
"Error using CLOCK_MONOTONIC_COARSE.");
|
|
}
|
|
return time_point(std::chrono::duration_cast<duration>(
|
|
std::chrono::seconds(ts.tv_sec) +
|
|
std::chrono::nanoseconds(ts.tv_nsec)));
|
|
#endif
|
|
}
|
|
};
|
|
|
|
} // namespace chrono
|
|
} // namespace folly
|