/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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 #include #include #include #include #include #include /*** * include or backport: * * std::chrono::ceil * * std::chrono::floor * * std::chrono::round */ #if __cpp_lib_chrono >= 201510 || _LIBCPP_STD_VER > 14 || _MSC_VER namespace folly { namespace chrono { /* using override */ using std::chrono::abs; /* 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 struct is_duration : std::false_type {}; template struct is_duration> : std::true_type {}; template constexpr To ceil_impl(Duration const& d, To const& t) { return t < d ? t + To{1} : t; } template constexpr To floor_impl(Duration const& d, To const& t) { return t > d ? t - To{1} : t; } template 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 constexpr To round_impl(Duration const& d, To const& t0, To const& t1) { return round_impl(t0, t1, d - t0, t1 - d); } template constexpr To round_impl(Duration const& d, To const& t0) { return round_impl(d, t0, t0 + To{1}); } } // namespace detail // mimic: std::chrono::abs, C++17 template < typename Rep, typename Period, typename = typename std::enable_if< std::chrono::duration::min() < std::chrono::duration::zero()>::type> constexpr std::chrono::duration abs( std::chrono::duration const& d) { return d < std::chrono::duration::zero() ? -d : d; } // 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::value>::type> constexpr To ceil(std::chrono::duration const& d) { return detail::ceil_impl(d, std::chrono::duration_cast(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::value>::type> constexpr std::chrono::time_point ceil( std::chrono::time_point const& tp) { return std::chrono::time_point{ceil(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::value>::type> constexpr To floor(std::chrono::duration const& d) { return detail::floor_impl(d, std::chrono::duration_cast(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::value>::type> constexpr std::chrono::time_point floor( std::chrono::time_point const& tp) { return std::chrono::time_point{floor(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::value && !std::chrono::treat_as_floating_point::value>::type> constexpr To round(std::chrono::duration const& d) { return detail::round_impl(d, floor(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::value && !std::chrono::treat_as_floating_point::value>::type> constexpr std::chrono::time_point round( std::chrono::time_point const& tp) { return std::chrono::time_point{round(tp.time_since_epoch())}; } } // namespace chrono } // namespace folly #endif namespace folly { namespace chrono { // steady_clock_spec // // All clocks with this spec share epoch and tick rate. struct steady_clock_spec {}; // system_clock_spec // // All clocks with this spec share epoch and tick rate. struct system_clock_spec {}; // clock_traits // // Detects and reexports per-clock traits. // // Specializeable for clocks for which trait detection fails.. template struct clock_traits { private: template using detect_spec_ = typename C::folly_spec; public: using spec = detected_or_t; }; template <> struct clock_traits { using spec = steady_clock_spec; }; template <> struct clock_traits { using spec = system_clock_spec; }; struct coarse_steady_clock { using folly_spec = steady_clock_spec; using duration = std::chrono::steady_clock::duration; using rep = duration::rep; using period = duration::period; using time_point = std::chrono::time_point; constexpr static bool is_steady = true; static time_point now() noexcept { #ifndef CLOCK_MONOTONIC_COARSE auto time = std::chrono::steady_clock::now().time_since_epoch(); #else timespec ts; int ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); if (kIsDebug && (ret != 0)) { throw_exception( "Error using CLOCK_MONOTONIC_COARSE."); } auto time = std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec); #endif return time_point(std::chrono::duration_cast(time)); } }; struct coarse_system_clock { using folly_spec = system_clock_spec; using duration = std::chrono::system_clock::duration; using rep = duration::rep; using period = duration::period; using time_point = std::chrono::time_point; constexpr static bool is_steady = false; static time_point now() noexcept { #ifndef CLOCK_REALTIME_COARSE auto time = std::chrono::system_clock::now().time_since_epoch(); #else timespec ts; int ret = clock_gettime(CLOCK_REALTIME_COARSE, &ts); if (kIsDebug && (ret != 0)) { throw_exception("Error using CLOCK_REALTIME_COARSE."); } auto time = std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec); #endif return time_point(std::chrono::duration_cast(time)); } static std::time_t to_time_t(const time_point& t) noexcept { auto d = t.time_since_epoch(); return std::chrono::duration_cast(d).count(); } static time_point from_time_t(std::time_t t) noexcept { return time_point( std::chrono::duration_cast(std::chrono::seconds(t))); } }; } // namespace chrono } // namespace folly