///////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // This file implements the eastl::chrono specification which is part of the // standard STL date and time library. eastl::chrono implements all the // mechanisms required to capture and manipulate times retrieved from the // provided clocks. It implements the all of the features to allow type safe // durations to be used in code. /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_CHRONO_H #define EASTL_CHRONO_H #if defined(EA_PRAGMA_ONCE_SUPPORTED) #pragma once #endif #include #include #include #include // TODO: move to platform specific cpp or header file #if defined EA_PLATFORM_MICROSOFT EA_DISABLE_ALL_VC_WARNINGS() #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #undef NOMINMAX #define NOMINMAX #include #ifdef min #undef min #endif #ifdef max #undef max #endif EA_RESTORE_ALL_VC_WARNINGS() #endif #if defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW) // Nothing to do #elif defined(EA_PLATFORM_SONY) #include #include #elif defined(EA_PLATFORM_APPLE) #include #elif defined(EA_PLATFORM_POSIX) || defined(EA_PLATFORM_MINGW) || defined(EA_PLATFORM_ANDROID) // Posix means Linux, Unix, and Macintosh OSX, among others (including Linux-based mobile platforms). #if defined(EA_PLATFORM_MINGW) #include #endif #include #if (defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC)) #include #else #include #include #endif #endif namespace eastl { namespace chrono { /////////////////////////////////////////////////////////////////////////////// // treat_as_floating_point /////////////////////////////////////////////////////////////////////////////// template struct treat_as_floating_point : is_floating_point {}; /////////////////////////////////////////////////////////////////////////////// // 20.12.4, duration_values /////////////////////////////////////////////////////////////////////////////// template struct duration_values { public: EASTL_FORCE_INLINE static EA_CONSTEXPR Rep zero() { return Rep(0); } EASTL_FORCE_INLINE static EA_CONSTEXPR Rep max() { return eastl::numeric_limits::max(); } EASTL_FORCE_INLINE static EA_CONSTEXPR Rep min() { return eastl::numeric_limits::lowest(); } }; /////////////////////////////////////////////////////////////////////////////// // duration fwd_decl /////////////////////////////////////////////////////////////////////////////// template > class duration; namespace Internal { /////////////////////////////////////////////////////////////////////////////// // IsRatio /////////////////////////////////////////////////////////////////////////////// template struct IsRatio : eastl::false_type {}; template struct IsRatio> : eastl::true_type {}; template struct IsRatio> : eastl::true_type {}; template struct IsRatio> : eastl::true_type {}; template struct IsRatio> : eastl::true_type {}; /////////////////////////////////////////////////////////////////////////////// // IsDuration /////////////////////////////////////////////////////////////////////////////// template struct IsDuration : eastl::false_type{}; template struct IsDuration> : eastl::true_type{}; template struct IsDuration> : eastl::true_type{}; template struct IsDuration> : eastl::true_type{}; template struct IsDuration> : eastl::true_type{}; /////////////////////////////////////////////////////////////////////////////// // RatioGCD /////////////////////////////////////////////////////////////////////////////// template struct RatioGCD { static_assert(IsRatio::value, "Period1 is not a eastl::ratio type"); static_assert(IsRatio::value, "Period2 is not a eastl::ratio type"); typedef ratio::value, eastl::Internal::lcm::value> type; }; }; /////////////////////////////////////////////////////////////////////////////// // 20.12.5.7, duration_cast /////////////////////////////////////////////////////////////////////////////// namespace Internal { template ::type, typename CommonRep = typename eastl::decay::type>::type, bool = CommonPeriod::num == 1, bool = CommonPeriod::den == 1> struct DurationCastImpl; template struct DurationCastImpl { inline static ToDuration DoCast(const FromDuration& fd) { return ToDuration(static_cast(fd.count())); } }; template struct DurationCastImpl { inline static ToDuration DoCast(const FromDuration& d) { return ToDuration(static_cast(static_cast(d.count()) * static_cast(CommonPeriod::num))); } }; template struct DurationCastImpl { inline static ToDuration DoCast(const FromDuration& d) { return ToDuration(static_cast(static_cast(d.count()) / static_cast(CommonPeriod::den))); } }; template struct DurationCastImpl { inline static ToDuration DoCast(const FromDuration& d) { return ToDuration(static_cast(static_cast(d.count()) * static_cast(CommonPeriod::num) / static_cast(CommonPeriod::den))); } }; }; // namespace Internal /////////////////////////////////////////////////////////////////////////////// // duration_cast /////////////////////////////////////////////////////////////////////////////// template inline typename eastl::enable_if::value, ToDuration>::type duration_cast(const duration& d) { typedef typename duration::this_type FromDuration; return Internal::DurationCastImpl::DoCast(d); } /////////////////////////////////////////////////////////////////////////////// // duration /////////////////////////////////////////////////////////////////////////////// template class duration { Rep mRep; public: typedef Rep rep; typedef Period period; typedef duration this_type; #if defined(EA_COMPILER_NO_DEFAULTED_FUNCTIONS) EA_CONSTEXPR duration() : mRep() {} duration(const duration& other) : mRep(Rep(other.mRep)) {} duration& operator=(const duration& other) { mRep = other.mRep; return *this; } #else EA_CONSTEXPR duration() = default; duration(const duration&) = default; duration& operator=(const duration&) = default; #endif /////////////////////////////////////////////////////////////////////////////// // conversion constructors /////////////////////////////////////////////////////////////////////////////// template inline EA_CONSTEXPR explicit duration( const Rep2& rep2, typename eastl::enable_if::value && (treat_as_floating_point::value || !treat_as_floating_point::value)>::type** = 0) : mRep(static_cast(rep2)) {} template EA_CONSTEXPR duration(const duration& d2, typename eastl::enable_if::value || (eastl::ratio_divide::type::den == 1 && !treat_as_floating_point::value), void>::type** = 0) : mRep(duration_cast(d2).count()) {} /////////////////////////////////////////////////////////////////////////////// // returns the count of ticks /////////////////////////////////////////////////////////////////////////////// EA_CONSTEXPR Rep count() const { return mRep; } /////////////////////////////////////////////////////////////////////////////// // static accessors of special duration values /////////////////////////////////////////////////////////////////////////////// EA_CONSTEXPR inline static duration zero() { return duration(duration_values::zero()); } EA_CONSTEXPR inline static duration min() { return duration(duration_values::min()); } EA_CONSTEXPR inline static duration max() { return duration(duration_values::max()); } /////////////////////////////////////////////////////////////////////////////// // const arithmetic operations /////////////////////////////////////////////////////////////////////////////// EA_CONSTEXPR inline duration operator+() const { return *this; } EA_CONSTEXPR inline duration operator-() const { return duration(0-mRep); } /////////////////////////////////////////////////////////////////////////////// // arithmetic operations /////////////////////////////////////////////////////////////////////////////// inline duration operator++(int) { return duration(mRep++); } inline duration operator--(int) { return duration(mRep--); } inline duration& operator++() { ++mRep; return *this; } inline duration& operator--() { --mRep; return *this; } inline duration& operator+=(const duration& d) { mRep += d.count(); return *this; } inline duration& operator-=(const duration& d) { mRep -= d.count(); return *this; } inline duration& operator*=(const Rep& rhs) { mRep *= rhs; return *this; } inline duration& operator/=(const Rep& rhs) { mRep /= rhs; return *this; } inline duration& operator%=(const Rep& rhs) { mRep %= rhs; return *this; } inline duration& operator%=(const duration& d) { mRep %= d.count(); return *this; } }; /////////////////////////////////////////////////////////////////////////////// // 20.12.5.5, arithmetic operations with durations as arguments /////////////////////////////////////////////////////////////////////////////// template typename eastl::common_type, duration>::type EASTL_FORCE_INLINE operator+(const duration& lhs, const duration& rhs) { typedef typename eastl::common_type, duration>::type common_duration_t; return common_duration_t(common_duration_t(lhs).count() + common_duration_t(rhs).count()); } template typename eastl::common_type, duration>::type EASTL_FORCE_INLINE operator-(const duration& lhs, const duration& rhs) { typedef typename eastl::common_type, duration>::type common_duration_t; return common_duration_t(common_duration_t(lhs).count() - common_duration_t(rhs).count()); } template duration::type, Period1> EASTL_FORCE_INLINE operator*(const duration& lhs, const Rep2& rhs) { typedef typename duration, Period1>::type common_duration_t; return common_duration_t(common_duration_t(lhs).count() * rhs); } template duration::type, Period2> EASTL_FORCE_INLINE operator*(const Rep1& lhs, const duration& rhs) { typedef duration::type, Period2> common_duration_t; return common_duration_t(lhs * common_duration_t(rhs).count()); } template duration::type, Period1> EASTL_FORCE_INLINE operator/(const duration& lhs, const Rep2& rhs) { typedef duration::type, Period1> common_duration_t; return common_duration_t(common_duration_t(lhs).count() / rhs); } template typename eastl::common_type, duration>::type EASTL_FORCE_INLINE operator/(const duration& lhs, const duration& rhs) { typedef typename eastl::common_type, duration>::type common_duration_t; return common_duration_t(common_duration_t(lhs).count() / common_duration_t(rhs).count()); } template duration::type, Period1> EASTL_FORCE_INLINE operator%(const duration& lhs, const Rep2& rhs) { typedef duration::type, Period1> common_duration_t; return common_duration_t(common_duration_t(lhs).count() % rhs); } template typename eastl::common_type, duration>::type EASTL_FORCE_INLINE operator%(const duration& lhs, const duration& rhs) { typedef typename eastl::common_type, duration>::type common_duration_t; return common_duration_t(common_duration_t(lhs).count() % common_duration_t(rhs).count()); } /////////////////////////////////////////////////////////////////////////////// // 20.12.5.6, compares two durations /////////////////////////////////////////////////////////////////////////////// template EASTL_FORCE_INLINE bool operator==(const duration& lhs, const duration& rhs) { typedef typename eastl::common_type, duration>::type common_duration_t; return common_duration_t(lhs).count() == common_duration_t(rhs).count(); } template EASTL_FORCE_INLINE bool operator<(const duration& lhs, const duration& rhs) { typedef typename eastl::common_type, duration>::type common_duration_t; return common_duration_t(lhs).count() < common_duration_t(rhs).count(); } template EASTL_FORCE_INLINE bool operator!=(const duration& lhs, const duration& rhs) { return !(lhs == rhs); } template EASTL_FORCE_INLINE bool operator<=(const duration& lhs, const duration& rhs) { return !(rhs < lhs); } template EASTL_FORCE_INLINE bool operator>(const duration& lhs, const duration& rhs) { return rhs < lhs; } template EASTL_FORCE_INLINE bool operator>=(const duration& lhs, const duration& rhs) { return !(lhs < rhs); } /////////////////////////////////////////////////////////////////////////////// // standard duration units /////////////////////////////////////////////////////////////////////////////// typedef duration nanoseconds; typedef duration microseconds; typedef duration milliseconds; typedef duration seconds; typedef duration> minutes; typedef duration> hours; /////////////////////////////////////////////////////////////////////////////// // 20.12.6, time_point /////////////////////////////////////////////////////////////////////////////// template class time_point { Duration mDuration; public: typedef Clock clock; typedef Duration duration; typedef typename Duration::rep rep; typedef typename Duration::period period; inline EA_CONSTEXPR time_point() : mDuration(Duration::zero()) {} EA_CONSTEXPR explicit time_point(const Duration& other) : mDuration(other) {} template inline EA_CONSTEXPR time_point( const time_point& t, typename eastl::enable_if::value>::type** = 0) : mDuration(t.time_since_epoch()) {} EA_CONSTEXPR Duration time_since_epoch() const { return mDuration; } time_point& operator+=(const Duration& d) { mDuration += d; return *this; } time_point& operator-=(const Duration& d) { mDuration -= d; return *this; } static EA_CONSTEXPR time_point min() { return time_point(Duration::min()); } static EA_CONSTEXPR time_point max() { return time_point(Duration::max()); } }; /////////////////////////////////////////////////////////////////////////////// // 20.12.6.5, time_point arithmetic /////////////////////////////////////////////////////////////////////////////// template inline EA_CONSTEXPR time_point>::type> operator+(const time_point& lhs, const duration& rhs) { typedef time_point>::type> common_timepoint_t; return common_timepoint_t(lhs.time_since_epoch() + rhs); } template inline EA_CONSTEXPR time_point>::type> operator+(const duration& lhs, const time_point& rhs) { typedef time_point>::type> common_timepoint_t; return common_timepoint_t(lhs + rhs.time_since_epoch()); } template inline EA_CONSTEXPR time_point>::type> operator-(const time_point& lhs, const duration& rhs) { typedef time_point>::type> common_timepoint_t; return common_timepoint_t(lhs.time_since_epoch() - rhs); } template inline EA_CONSTEXPR typename eastl::common_type::type operator-( const time_point& lhs, const time_point& rhs) { return lhs.time_since_epoch() - rhs.time_since_epoch(); } template inline EA_CONSTEXPR bool operator==(const time_point& lhs, const time_point& rhs) { return lhs.time_since_epoch() == rhs.time_since_epoch(); } template inline EA_CONSTEXPR bool operator!=(const time_point& lhs, const time_point& rhs) { return !(lhs == rhs); } template inline EA_CONSTEXPR bool operator<(const time_point& lhs, const time_point& rhs) { return lhs.time_since_epoch() < rhs.time_since_epoch(); } template inline EA_CONSTEXPR bool operator<=(const time_point& lhs, const time_point& rhs) { return !(rhs < lhs); } template inline EA_CONSTEXPR bool operator>(const time_point& lhs, const time_point& rhs) { return rhs < lhs; } template inline EA_CONSTEXPR bool operator>=(const time_point& lhs, const time_point& rhs) { return !(lhs < rhs); } /////////////////////////////////////////////////////////////////////////////// // 20.12.6.7, time_point_cast /////////////////////////////////////////////////////////////////////////////// template EA_CONSTEXPR time_point time_point_cast( const time_point& t, typename eastl::enable_if::value>::type** = 0) { return time_point(duration_cast(t.time_since_epoch())); } /////////////////////////////////////////////////////////////////////////////// // 20.12.7, clocks /////////////////////////////////////////////////////////////////////////////// namespace Internal { #if defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW) #define EASTL_NS_PER_TICK 1 #elif defined EA_PLATFORM_SONY #define EASTL_NS_PER_TICK _XTIME_NSECS_PER_TICK #elif defined EA_PLATFORM_POSIX #define EASTL_NS_PER_TICK _XTIME_NSECS_PER_TICK #else #define EASTL_NS_PER_TICK 100 #endif #if defined(EA_PLATFORM_POSIX) typedef chrono::nanoseconds::period SystemClock_Period; typedef chrono::nanoseconds::period SteadyClock_Period; #else typedef eastl::ratio_multiply, nano>::type SystemClock_Period; typedef eastl::ratio_multiply, nano>::type SteadyClock_Period; #endif /////////////////////////////////////////////////////////////////////////////// // Internal::GetTicks /////////////////////////////////////////////////////////////////////////////// inline uint64_t GetTicks() { #if defined EA_PLATFORM_MICROSOFT auto queryFrequency = [] { LARGE_INTEGER frequency; QueryPerformanceFrequency(&frequency); return double(1000000000.0L / frequency.QuadPart); // nanoseconds per tick }; auto queryCounter = [] { LARGE_INTEGER counter; QueryPerformanceCounter(&counter); return counter.QuadPart; }; EA_DISABLE_VC_WARNING(4640) // warning C4640: construction of local static object is not thread-safe (VS2013) static auto frequency = queryFrequency(); // cache cpu frequency on first call EA_RESTORE_VC_WARNING() return uint64_t(frequency * queryCounter()); #elif defined EA_PLATFORM_SONY return sceKernelGetProcessTimeCounter(); #elif defined(EA_PLATFORM_APPLE) return mach_absolute_time(); #elif defined(EA_PLATFORM_POSIX) // Posix means Linux, Unix, and Macintosh OSX, among others (including Linux-based mobile platforms). #if (defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC)) timespec ts; int result = clock_gettime(CLOCK_MONOTONIC, &ts); if(result == EINVAL ) result = clock_gettime(CLOCK_REALTIME, &ts); const uint64_t nNanoseconds = (uint64_t)ts.tv_nsec + ((uint64_t)ts.tv_sec * UINT64_C(1000000000)); return nNanoseconds; #else struct timeval tv; gettimeofday(&tv, NULL); const uint64_t nMicroseconds = (uint64_t)tv.tv_usec + ((uint64_t)tv.tv_sec * 1000000); return nMicroseconds; #endif #else #error "chrono not implemented for platform" #endif } } // namespace Internal /////////////////////////////////////////////////////////////////////////////// // system_clock /////////////////////////////////////////////////////////////////////////////// class system_clock { public: typedef long long rep; // signed arithmetic type representing the number of ticks in the clock's duration typedef Internal::SystemClock_Period period; typedef chrono::duration duration; // duration, capable of representing negative durations typedef chrono::time_point time_point; // true if the time between ticks is always increases monotonically EA_CONSTEXPR_OR_CONST static bool is_steady = false; // returns a time point representing the current point in time. static time_point now() EA_NOEXCEPT { return time_point(duration(Internal::GetTicks())); } }; /////////////////////////////////////////////////////////////////////////////// // steady_clock /////////////////////////////////////////////////////////////////////////////// class steady_clock { public: typedef long long rep; // signed arithmetic type representing the number of ticks in the clock's duration typedef Internal::SteadyClock_Period period; typedef chrono::duration duration; // duration, capable of representing negative durations typedef chrono::time_point time_point; // true if the time between ticks is always increases monotonically EA_CONSTEXPR_OR_CONST static bool is_steady = true; // returns a time point representing the current point in time. static time_point now() EA_NOEXCEPT { return time_point(duration(Internal::GetTicks())); } }; /////////////////////////////////////////////////////////////////////////////// // high_resolution_clock /////////////////////////////////////////////////////////////////////////////// typedef system_clock high_resolution_clock; } // namespace chrono /////////////////////////////////////////////////////////////////////////////// // duration common_type specialization /////////////////////////////////////////////////////////////////////////////// template struct common_type, chrono::duration> { typedef chrono::duration::type>::type, typename chrono::Internal::RatioGCD::type> type; }; /////////////////////////////////////////////////////////////////////////////// // time_point common_type specialization /////////////////////////////////////////////////////////////////////////////// template struct common_type, chrono::time_point> { typedef chrono::time_point::type> type; }; /////////////////////////////////////////////////////////////////////////////// // chrono_literals /////////////////////////////////////////////////////////////////////////////// #if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED EA_DISABLE_VC_WARNING(4455) // disable warning C4455: literal suffix identifiers that do not start with an underscore are reserved inline namespace literals { inline namespace chrono_literals { /////////////////////////////////////////////////////////////////////////////// // integer chrono literals /////////////////////////////////////////////////////////////////////////////// EA_CONSTEXPR chrono::hours operator"" h(unsigned long long h) { return chrono::hours(h); } EA_CONSTEXPR chrono::minutes operator"" min(unsigned long long m) { return chrono::minutes(m); } EA_CONSTEXPR chrono::seconds operator"" s(unsigned long long s) { return chrono::seconds(s); } EA_CONSTEXPR chrono::milliseconds operator"" ms(unsigned long long ms) { return chrono::milliseconds(ms); } EA_CONSTEXPR chrono::microseconds operator"" us(unsigned long long us) { return chrono::microseconds(us); } EA_CONSTEXPR chrono::nanoseconds operator"" ns(unsigned long long ns) { return chrono::nanoseconds(ns); } /////////////////////////////////////////////////////////////////////////////// // float chrono literals /////////////////////////////////////////////////////////////////////////////// EA_CONSTEXPR chrono::duration> operator"" h(long double h) { return chrono::duration>(h); } EA_CONSTEXPR chrono::duration> operator"" min(long double m) { return chrono::duration>(m); } EA_CONSTEXPR chrono::duration operator"" s(long double s) { return chrono::duration(s); } EA_CONSTEXPR chrono::duration operator"" ms(long double ms) { return chrono::duration(ms); } EA_CONSTEXPR chrono::duration operator"" us(long double us) { return chrono::duration(us); } EA_CONSTEXPR chrono::duration operator"" ns(long double ns) { return chrono::duration(ns); } } // namespace chrono_literals }// namespace literals EA_RESTORE_VC_WARNING() // warning: 4455 #endif } // namespace eastl #if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED namespace chrono { using namespace eastl::literals::chrono_literals; } // namespace chrono #endif #endif