From 85968753d70bf04cc54a393f8fcb61018e40177c Mon Sep 17 00:00:00 2001 From: Danilo Date: Sat, 23 Mar 2024 17:23:07 -0300 Subject: [PATCH] Implementa GameClock --- framework/CMakeLists.txt | 2 +- framework/csharp/timespan.hpp | 328 ++++++++++++++++++++++++++++++++ framework/forward.hpp | 1 + framework/game/clock.hpp | 24 +++ framework/game/time.hpp | 29 +-- framework/platform/clock-dx.cpp | 71 +++++++ framework/platform/clock-dx.hpp | 48 +++++ framework/platform/game-dx.cpp | 18 +- framework/platform/game-dx.hpp | 4 + framework/timespan.hpp | 231 ---------------------- 10 files changed, 501 insertions(+), 255 deletions(-) create mode 100644 framework/csharp/timespan.hpp create mode 100644 framework/game/clock.hpp create mode 100644 framework/platform/clock-dx.cpp create mode 100644 framework/platform/clock-dx.hpp delete mode 100644 framework/timespan.hpp diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index 9023348..348b7d6 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -3,7 +3,7 @@ # # Add source to this project's executable. -add_executable (xna WIN32 "xna.cpp" "xna.h" "platform/window-dx.cpp" "platform/device-dx.cpp" "platform/adapter-dx.cpp" "platform/swapchain-dx.cpp" "platform/rendertarget-dx.cpp" "platform/texture-dx.cpp" "platform/blendstate-dx.cpp" "platform/game-dx.cpp") +add_executable (xna WIN32 "xna.cpp" "xna.h" "platform/window-dx.cpp" "platform/device-dx.cpp" "platform/adapter-dx.cpp" "platform/swapchain-dx.cpp" "platform/rendertarget-dx.cpp" "platform/texture-dx.cpp" "platform/blendstate-dx.cpp" "platform/game-dx.cpp" "platform/clock-dx.cpp") if (CMAKE_VERSION VERSION_GREATER 3.12) set_property(TARGET xna PROPERTY CXX_STANDARD 20) diff --git a/framework/csharp/timespan.hpp b/framework/csharp/timespan.hpp new file mode 100644 index 0000000..7ccd96b --- /dev/null +++ b/framework/csharp/timespan.hpp @@ -0,0 +1,328 @@ +#ifndef XNA_CSHARP_TIMESPAN_HPP +#define XNA_CSHARP_TIMESPAN_HPP + +#include +#include +#include + +namespace xna { + struct TimeSpan { + static constexpr int64_t NanosecondsPerTick = 100; + static constexpr int64_t TicksPerMicrosecond = 10; + static constexpr int64_t TicksPerMillisecond = TicksPerMicrosecond * 1000; + static constexpr int64_t TicksPerSecond = TicksPerMillisecond * 1000; + static constexpr int64_t TicksPerMinute = TicksPerSecond * 60; + static constexpr int64_t TicksPerHour = TicksPerMinute * 60; + static constexpr int64_t TicksPerDay = TicksPerHour * 24; + static constexpr int64_t MicrosecondsPerMillisecond = TicksPerMillisecond / TicksPerMicrosecond; + static constexpr int64_t MicrosecondsPerSecond = TicksPerSecond / TicksPerMicrosecond; + static constexpr int64_t MicrosecondsPerMinute = TicksPerMinute / TicksPerMicrosecond; + static constexpr int64_t MicrosecondsPerHour = TicksPerHour / TicksPerMicrosecond; + static constexpr int64_t MicrosecondsPerDay = TicksPerDay / TicksPerMicrosecond; + static constexpr int64_t MillisecondsPerSecond = TicksPerSecond / TicksPerMillisecond; + static constexpr int64_t MillisecondsPerMinute = TicksPerMinute / TicksPerMillisecond; + static constexpr int64_t MillisecondsPerHour = TicksPerHour / TicksPerMillisecond; + static constexpr int64_t MillisecondsPerDay = TicksPerDay / TicksPerMillisecond; + static constexpr int64_t SecondsPerMinute = TicksPerMinute / TicksPerSecond; + static constexpr int64_t SecondsPerHour = TicksPerHour / TicksPerSecond; + static constexpr int64_t SecondsPerDay = TicksPerDay / TicksPerSecond; + static constexpr int64_t MinutesPerHour = TicksPerHour / TicksPerMinute; + static constexpr int64_t MinutesPerDay = TicksPerDay / TicksPerMinute; + static constexpr int64_t HoursPerDay = TicksPerDay / TicksPerHour; + static constexpr int64_t MinTicks = std::numeric_limits::min(); + static constexpr int64_t MaxTicks = std::numeric_limits::max(); + static constexpr int64_t MinMicroseconds = MinTicks / TicksPerMicrosecond; + static constexpr int64_t MaxMicroseconds = MaxTicks / TicksPerMicrosecond; + static constexpr int64_t MinMilliseconds = MinTicks / TicksPerMillisecond; + static constexpr int64_t MaxMilliseconds = MaxTicks / TicksPerMillisecond; + static constexpr int64_t MinSeconds = MinTicks / TicksPerSecond; + static constexpr int64_t MaxSeconds = MaxTicks / TicksPerSecond; + static constexpr int64_t MinMinutes = MinTicks / TicksPerMinute; + static constexpr int64_t MaxMinutes = MaxTicks / TicksPerMinute; + static constexpr int64_t MinHours = MinTicks / TicksPerHour; + static constexpr int64_t MaxHours = MaxTicks / TicksPerHour; + static constexpr int64_t MinDays = MinTicks / TicksPerDay; + static constexpr int64_t MaxDays = MaxTicks / TicksPerDay; + static constexpr int64_t TicksPerTenthSecond = TicksPerMillisecond * 100; + + static constexpr TimeSpan Zero() { return TimeSpan(); } + static constexpr TimeSpan MaxValue() { return TimeSpan(MaxTicks); } + static constexpr TimeSpan MinValue() { return TimeSpan(MinTicks); } + + constexpr TimeSpan() = default; + constexpr TimeSpan(int64_t ticks) : _ticks(ticks) {} + constexpr TimeSpan(int32_t hours, int32_t minutes, int32_t seconds) { + _ticks = TimeToTicks(hours, minutes, seconds); + } + constexpr TimeSpan(int32_t days, int32_t hours, int32_t minutes, int32_t seconds, int32_t milliseconds, int32_t microseconds = 0) { + _ticks = TimeToTicks(days, hours, minutes, seconds, milliseconds, microseconds); + } + + constexpr int64_t Ticks() const { return _ticks; } + constexpr int32_t Days() const { return static_cast(_ticks / TicksPerDay); } + constexpr int32_t Hours() const { return static_cast(_ticks / TicksPerHour % HoursPerDay); } + constexpr int32_t Milliseconds() const { return static_cast(_ticks / TicksPerMillisecond % MillisecondsPerSecond); } + constexpr int32_t Microseconds() const { return static_cast(_ticks / TicksPerMicrosecond % MicrosecondsPerMillisecond); } + constexpr int32_t Nanoseconds() const { return static_cast(_ticks % TicksPerMicrosecond * NanosecondsPerTick); } + constexpr int32_t Minutes() const { return static_cast(_ticks / TicksPerMinute % MinutesPerHour); } + constexpr int32_t Seconds() const { return static_cast(_ticks / TicksPerSecond % SecondsPerMinute); } + constexpr double TotalDays() const { return static_cast(_ticks) / TicksPerDay; } + constexpr double TotalHours() const { return static_cast(_ticks) / TicksPerHour; } + + constexpr double TotalMilliseconds() const { + double temp = static_cast(_ticks) / TicksPerMillisecond; + + if (temp > MaxMilliseconds) { + return MaxMilliseconds; + } + + if (temp < MinMilliseconds) { + return MinMilliseconds; + } + return temp; + } + + constexpr double TotalMicroseconds() const { return static_cast(_ticks) / TicksPerMicrosecond; } + constexpr double TotalNanoseconds() const { return static_cast(_ticks) * NanosecondsPerTick; } + constexpr double TotalMinutes() const { return static_cast(_ticks) / TicksPerMinute; } + constexpr double TotalSeconds() const { return static_cast(_ticks) / TicksPerSecond; } + + constexpr TimeSpan Add(TimeSpan const& ts) const { + int64_t result = _ticks + ts._ticks; + int64_t t1Sign = _ticks >> 63; + + if ((t1Sign == (ts._ticks >> 63)) && (t1Sign != (result >> 63))) { + return TimeSpan::Zero(); + //exception + } + + return result; + } + + static TimeSpan FromDays(double value) { + return Interval(value, TicksPerDay); + } + + constexpr TimeSpan Duration() const { + if (_ticks == MinTicks) { + return TimeSpan::Zero(); + } + + return TimeSpan(_ticks >= 0 ? _ticks : -_ticks); + } + + static constexpr TimeSpan FromUnits(int64_t units, int64_t ticksPerUnit, int64_t minUnits, int64_t maxUnits) { + if (units > maxUnits || units < minUnits) { + return TimeSpan::Zero(); + } + + return TimeSpan::FromTicks(units * ticksPerUnit); + } + + static constexpr TimeSpan FromDays(int32_t days) { + return FromUnits(days, TicksPerDay, MinDays, MaxDays); + } + + //TODO: Not implemented. + //static constexpr TimeSpan FromDays(int32_t days, int32_t hours = 0, int64_t minutes = 0, int64_t seconds = 0, int64_t milliseconds = 0, int64_t microseconds = 0); + + static constexpr TimeSpan FromHours(int32_t hours) { + return FromUnits(hours, TicksPerHour, MinHours, MaxHours); + } + + //TODO: Not implemented. + //static constexpr TimeSpan FromHours(int32_t hours, int64_t minutes = 0, int64_t seconds = 0, int64_t milliseconds = 0, int64_t microseconds = 0); + + static constexpr TimeSpan FromMinutes(int64_t minutes) { + return FromUnits(minutes, TicksPerMinute, MinMinutes, MaxMinutes); + } + + //TODO: Not implemented. + //static constexpr TimeSpan FromMinutes(int64_t minutes, int64_t seconds = 0, int64_t milliseconds = 0, int64_t microseconds = 0); + + static constexpr TimeSpan FromSeconds(int64_t seconds) { + return FromUnits(seconds, TicksPerSecond, MinSeconds, MaxSeconds); + } + + //TODO: Not implemented. + //static constexpr TimeSpan FromSeconds(int64_t seconds, int64_t milliseconds = 0, int64_t microseconds = 0); + + //TODO: Not implemented. + //static constexpr TimeSpan FromMilliseconds(int64_t milliseconds, int64_t microseconds = 0); + + static constexpr TimeSpan FromMicroseconds(int64_t microseconds) { + return FromUnits(microseconds, TicksPerMicrosecond, MinMicroseconds, MaxMicroseconds); + } + + static TimeSpan FromHours(double value) { + return Interval(value, TicksPerHour); + } + + static constexpr int64_t TimeToTicks(int32_t hour, int32_t minute, int32_t second) { + int64_t totalSeconds = + (hour * SecondsPerHour) + + (minute * SecondsPerMinute) + + second; + + //exception + if (totalSeconds > MaxSeconds) { + return MaxValue()._ticks; + } + else if (totalSeconds < MinSeconds) { + return MinValue()._ticks; + } + + return totalSeconds * TicksPerSecond; + } + + static TimeSpan FromMilliseconds(double value) { + return Interval(value, TicksPerMillisecond); + } + + static TimeSpan FromMicroseconds(double value) { + return Interval(value, TicksPerMicrosecond); + } + + static TimeSpan FromMinutes(double value) { + return Interval(value, TicksPerMinute); + } + + constexpr TimeSpan Negate() const { + if (_ticks == MinTicks) { + return MinTicks; + } + + return -_ticks; + } + + static TimeSpan FromSeconds(double value) { + return Interval(value, TicksPerSecond); + } + + constexpr TimeSpan Subtract(TimeSpan const& ts) const { + int64_t result = _ticks - ts._ticks; + int64_t t1Sign = _ticks >> 63; + + if ((t1Sign != (ts._ticks >> 63)) && (t1Sign != (result >> 63))) { + return TimeSpan::Zero(); + //exception + } + + return result; + } + + TimeSpan Multiply(double factor) const { + if (isnan(factor)) { + return TimeSpan::Zero(); + //exception + } + + const auto ticks = std::round(_ticks * factor); + return IntervalFromDoubleTicks(ticks); + } + + TimeSpan Divide(double divisor) const { + if (isnan(divisor)) { + return TimeSpan::Zero(); + //exception + } + + const auto ticks = std::round(_ticks / divisor); + return IntervalFromDoubleTicks(ticks); + } + + constexpr double Divide(TimeSpan const& ts) const { + return _ticks / static_cast(ts._ticks); + } + + static constexpr TimeSpan FromTicks(int64_t value) { + return TimeSpan(value); + } + + static constexpr int64_t TimeToTicks(int32_t days, int32_t hours, int32_t minutes, int32_t seconds, int32_t milliseconds, int32_t microseconds) { + int64_t totalMicroseconds = + (days * MicrosecondsPerDay) + + (hours * MicrosecondsPerHour) + + (minutes * MicrosecondsPerMinute) + + (seconds * MicrosecondsPerSecond) + + (milliseconds * MicrosecondsPerMillisecond) + + microseconds; + + //exception + if (totalMicroseconds > MaxMicroseconds) { + return MaxValue()._ticks; + } + else if (totalMicroseconds < MinMicroseconds) { + return MinValue()._ticks; + } + + return totalMicroseconds * TicksPerMicrosecond; + } + + constexpr bool operator==(TimeSpan const& other) const { + return _ticks == other._ticks; + } + + constexpr TimeSpan operator-() const { + return Negate(); + } + + friend constexpr TimeSpan operator-(TimeSpan const& a, TimeSpan const& b) { + return a.Subtract(b); + } + + friend constexpr TimeSpan operator+(TimeSpan const& a, TimeSpan const& b) { + return a.Add(b); + } + + friend TimeSpan operator*(TimeSpan const& a, double factor) { + return a.Multiply(factor); + } + + friend TimeSpan operator*(double factor, TimeSpan const& b) { + return b.Multiply(factor); + } + + friend double operator/(TimeSpan const& a, TimeSpan const& b) { + return a.Divide(b); + } + + friend TimeSpan operator<(TimeSpan const& a, TimeSpan const& b) { + return a._ticks < b._ticks; + } + + friend TimeSpan operator<=(TimeSpan const& a, TimeSpan const& b) { + return a._ticks <= b._ticks; + } + + private: + int64_t _ticks{ 0 }; + + static TimeSpan Interval(double value, double scale) { + if (isnan(value)) { + //exception + return TimeSpan::Zero(); + } + + return IntervalFromDoubleTicks(value * scale); + } + + static constexpr TimeSpan IntervalFromDoubleTicks(double ticks) { + if ((ticks > MaxTicks) || (ticks < MinTicks) || isnan(ticks)) { + //exception + return TimeSpan::Zero(); + } + + if (ticks == MaxTicks) { + return MaxValue(); + } + + return TimeSpan(static_cast(ticks)); + } + + //TODO: Not implemented. + //static TimeSpan FromMicroseconds(__int128 microseconds); + }; +} + +#endif \ No newline at end of file diff --git a/framework/forward.hpp b/framework/forward.hpp index 2ef39b6..05b8592 100644 --- a/framework/forward.hpp +++ b/framework/forward.hpp @@ -28,6 +28,7 @@ namespace xna { class Game; class GameComponent; class GameComponentCollection; + class GameClock; class GameTime; class GameWindow; class IDrawable; diff --git a/framework/game/clock.hpp b/framework/game/clock.hpp new file mode 100644 index 0000000..c899e82 --- /dev/null +++ b/framework/game/clock.hpp @@ -0,0 +1,24 @@ +#ifndef XNA_GAME_CLOCK_HPP +#define XNA_GAME_CLOCK_HPP + +#include "../types.hpp" +#include "../forward.hpp" +#include "../enums.hpp" +#include "../csharp/timespan.hpp" + +namespace xna { + class IGameClock { + public: + virtual ~IGameClock() {} + + virtual void Start() = 0; + virtual void Resume() = 0; + virtual void Reset() = 0; + virtual void Suspend() = 0; + virtual void Stop() = 0; + virtual TimeSpan ElapsedTime() = 0; + virtual TimeSpan TotalTime() = 0; + }; +} + +#endif \ No newline at end of file diff --git a/framework/game/time.hpp b/framework/game/time.hpp index 295e0c5..6488cac 100644 --- a/framework/game/time.hpp +++ b/framework/game/time.hpp @@ -3,34 +3,21 @@ #include "../forward.hpp" #include "../types.hpp" -#include "../timespan.hpp" +#include "../csharp/timespan.hpp" namespace xna { class GameTime { public: constexpr GameTime() = default; - constexpr GameTime(const TimeSpan& elapsedGameTime, bool isRunningSlowly, const TimeSpan& totalGameTime) : - _elapsedGameTime(elapsedGameTime), - _isRunningSlowly(isRunningSlowly), - _totalGameTime(totalGameTime) { } + constexpr GameTime(const TimeSpan& elapsedGameTime, const TimeSpan& totalGameTime, bool isRunningSlowly) : + ElapsedGameTime(elapsedGameTime), + IsRunningSlowly(isRunningSlowly), + TotalGameTime(totalGameTime) { } - constexpr TimeSpan ElapsedGameTime() const { - return _elapsedGameTime; - } - - constexpr bool IsRunningSlowly() const { - return _isRunningSlowly; - } - - constexpr TimeSpan TotalGameTime() const { - return _totalGameTime; - } - - private: - TimeSpan _elapsedGameTime{ 0 }; - bool _isRunningSlowly{ false }; - TimeSpan _totalGameTime{ 0 }; + TimeSpan ElapsedGameTime{ 0 }; + bool IsRunningSlowly{ false }; + TimeSpan TotalGameTime{ 0 }; }; } diff --git a/framework/platform/clock-dx.cpp b/framework/platform/clock-dx.cpp new file mode 100644 index 0000000..9258429 --- /dev/null +++ b/framework/platform/clock-dx.cpp @@ -0,0 +1,71 @@ +#include "clock-dx.hpp" +#include + +namespace xna { + void GameClock::Reset() { + _start = ClockNow(); + _end = std::chrono::steady_clock::time_point(); + _stopped = false; + _suspended = false; + } + + void GameClock::Start() { + Reset(); + _total = 0; + _start = ClockNow(); + } + + void GameClock::Resume() { + if (_stopped) + return; + + if (_suspended) { + auto elapsed = _end - _start; + auto now = ClockNow(); + + _start = now - elapsed; + _suspended = false; + } + else { + _start = ClockNow(); + } + } + + void GameClock::Suspend() { + if (_suspended || _stopped) + return; + + _end = ClockNow(); + _suspended = true; + } + + void GameClock::Stop() { + Reset(); + _total = 0; + _stopped = true; + } + + TimeSpan GameClock::ElapsedTime() { + if (_stopped) return TimeSpan(); + + if (!_suspended) { + _end = ClockNow(); + } + + auto nano = GetNanoseconds(_start, _end); + return TimeSpan::FromSeconds(nano / 1'000'000'000.0); + } + + TimeSpan GameClock::TotalTime() { + if (_stopped) return TimeSpan(); + + if (!_suspended) { + _end = ClockNow(); + } + + auto nano = GetNanoseconds(_start, _end); + _total += nano; + + return TimeSpan::FromSeconds(_total / 1'000'000'000.0); + } +} \ No newline at end of file diff --git a/framework/platform/clock-dx.hpp b/framework/platform/clock-dx.hpp new file mode 100644 index 0000000..e8addd1 --- /dev/null +++ b/framework/platform/clock-dx.hpp @@ -0,0 +1,48 @@ +#ifndef XNA_PLATFORM_CLOCK_DX_HPP +#define XNA_PLATFORM_CLOCK_DX_HPP + +#include "../game/clock.hpp" +#include + +namespace xna { + using SteadyClock = std::chrono::steady_clock; + + class GameClock : public IGameClock { + public: + virtual ~GameClock() override {} + virtual void Reset() override; + virtual void Start() override; + virtual void Resume() override; + virtual void Suspend() override; + virtual void Stop() override; + virtual TimeSpan ElapsedTime() override; + virtual TimeSpan TotalTime() override; + + inline SteadyClock::time_point ClockNow() { + return SteadyClock::now(); + } + + constexpr long long GetNanoseconds(SteadyClock::time_point start, SteadyClock::time_point end) { + return std::chrono::duration_cast(end - start).count(); + } + + constexpr long long GetMicroseconds(SteadyClock::time_point start, SteadyClock::time_point end) { + return std::chrono::duration_cast(end - start).count(); + } + + constexpr long long GetMilliSeconds(SteadyClock::time_point start, SteadyClock::time_point end) { + return std::chrono::duration_cast(end - start).count(); + } + + private: + SteadyClock _clock; + SteadyClock::time_point _start; + SteadyClock::time_point _end; + long long _total{ 0 }; + bool _suspended{ false }; + bool _stopped { false }; + static constexpr double _millisecondMask = 100'000'000.0; + }; +} + +#endif \ No newline at end of file diff --git a/framework/platform/game-dx.cpp b/framework/platform/game-dx.cpp index 189f18a..963990d 100644 --- a/framework/platform/game-dx.cpp +++ b/framework/platform/game-dx.cpp @@ -2,6 +2,7 @@ #include "window-dx.hpp" #include "device-dx.hpp" #include "Windows.h" +#include "../game/time.hpp" namespace xna { Game::Game() { @@ -27,7 +28,8 @@ namespace xna { } int Game::startLoop() { - MSG msg{}; + MSG msg{}; + _clock.Start(); do { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) @@ -37,14 +39,26 @@ namespace xna { } else { GameTime gt; + + gt.ElapsedGameTime = _clock.ElapsedTime(); + gt.TotalGameTime = _clock.TotalTime(); + auto ml = gt.ElapsedGameTime.Milliseconds(); + this->Update(gt); + _graphicsDevice->Clear(); + + gt.ElapsedGameTime = _clock.ElapsedTime(); + gt.TotalGameTime = _clock.TotalTime(); + ml = gt.ElapsedGameTime.Milliseconds(); + this->Draw(gt); + _graphicsDevice->Present(); } } while (msg.message != WM_QUIT); - return msg.wParam; + return static_cast(msg.wParam); } } diff --git a/framework/platform/game-dx.hpp b/framework/platform/game-dx.hpp index 8a6b327..45eada4 100644 --- a/framework/platform/game-dx.hpp +++ b/framework/platform/game-dx.hpp @@ -2,6 +2,7 @@ #define XNA_PLATFORM_GAME_DX_HPP #include "../game/game.hpp" +#include "clock-dx.hpp" #include "dxgi.h" #include "d3d11.h" @@ -25,6 +26,9 @@ namespace xna { PGameWindow _gameWindow{ nullptr }; PGraphicsDevice _graphicsDevice{ nullptr }; + GameClock _clock{}; + GameTime _currentGameTime{}; + int startLoop(); }; } diff --git a/framework/timespan.hpp b/framework/timespan.hpp deleted file mode 100644 index 37bba98..0000000 --- a/framework/timespan.hpp +++ /dev/null @@ -1,231 +0,0 @@ -#ifndef XNA_TIMESPAN_HPP -#define XNA_TIMESPAN_HPP - -#include -#include -#include "types.hpp" - -namespace xna { - struct TimeSpan { - static constexpr Long TicksPerMillisecond{ 10000 }; - static constexpr Long TicksPerSecond{ TicksPerMillisecond * 1000 }; - static constexpr Long TicksPerMinute{ TicksPerSecond * 60 }; - static constexpr Long TicksPerHour{ TicksPerMinute * 60 }; - static constexpr Long TicksPerDay{ TicksPerHour * 24 }; - - constexpr TimeSpan() = default; - constexpr TimeSpan(Long ticks) : - _ticks(ticks) {} - constexpr TimeSpan(Int hours, Int minutes, Int seconds) : - _ticks(TimeToTicks(hours, minutes, seconds)) {} - constexpr TimeSpan(Int days, Int hours, Int minutes, Int seconds) : - _ticks(DayToTicks(days, hours, minutes, seconds, 0)) {} - constexpr TimeSpan(Int days, Int hours, Int minutes, Int seconds, Int milliseconds) : - _ticks(DayToTicks(days, hours, minutes, seconds, milliseconds)) {} - - constexpr TimeSpan operator -(TimeSpan const& t) { - return TimeSpan(-t._ticks); - } - - constexpr TimeSpan operator +(TimeSpan const& t) { - return t; - } - - constexpr friend TimeSpan operator +(TimeSpan const& t1, TimeSpan const& t2) { - return t1.Add(t2); - } - - constexpr friend TimeSpan operator -(TimeSpan const& t1, TimeSpan const& t2) { - return t1.Subtract(t2); - } - - constexpr friend bool operator ==(TimeSpan const& t1, TimeSpan const& t2) { - return t1._ticks == t2._ticks; - } - - constexpr friend bool operator !=(TimeSpan const& t1, TimeSpan const& t2) { - return t1._ticks != t2._ticks; - } - - constexpr friend bool operator <(TimeSpan const& t1, TimeSpan const& t2) { - return t1._ticks < t2._ticks; - } - - constexpr friend bool operator <=(TimeSpan const& t1, TimeSpan const& t2) { - return t1._ticks <= t2._ticks; - } - - constexpr friend bool operator >(TimeSpan const& t1, TimeSpan const& t2) { - return t1._ticks > t2._ticks; - } - - constexpr friend bool operator >=(TimeSpan const& t1, TimeSpan const& t2) { - return t1._ticks >= t2._ticks; - } - - static constexpr TimeSpan Zero() { - return TimeSpan(); - } - - static constexpr TimeSpan MaxValue() { - return TimeSpan(std::numeric_limits::max()); - } - - static constexpr TimeSpan MinValue() { - return TimeSpan(std::numeric_limits::min()); - } - - static constexpr Int Compare(TimeSpan const& t1, TimeSpan const& t2) { - if (t1._ticks > t2._ticks) - return 1; - - if (t1._ticks < t2._ticks) - return -1; - - return 0; - } - - static constexpr TimeSpan FromDays(double value) { - return Interval(value, MillisPerDay); - } - - static constexpr TimeSpan FromHours(double value) { - return Interval(value, MillisPerHour); - } - - static constexpr TimeSpan Interval(double value, Int scale) { - double tmp = value * scale; - double millis = tmp + (value >= 0 ? 0.5 : -0.5); - - return TimeSpan(static_cast(millis) * TicksPerMillisecond); - } - - static constexpr TimeSpan FromMilliseconds(double value) { - return Interval(value, 1); - } - - static constexpr TimeSpan FromMinutes(double value) { - return Interval(value, MillisPerMinute); - } - - static constexpr TimeSpan FromSeconds(double value) { - return Interval(value, MillisPerSecond); - } - - static constexpr TimeSpan FromTicks(Long value) { - return TimeSpan(value); - } - - constexpr Long Ticks() const { return _ticks; } - constexpr Int Days() const { return static_cast(_ticks / TicksPerDay); } - constexpr Int Hours() const { return static_cast((_ticks / TicksPerHour) % 24); } - constexpr Int Milliseconds() const { return static_cast((_ticks / TicksPerMillisecond) % 1000); } - constexpr Int Minutes() const { return static_cast((_ticks / TicksPerMinute) % 60); } - constexpr Int Seconds() const { return static_cast((_ticks / TicksPerSecond) % 60); } - constexpr double TotalDays() const { return static_cast(_ticks) * DaysPerTick; } - constexpr double TotalHours() const { return static_cast(_ticks) * HoursPerTick; } - - constexpr double TotalMilliseconds() const { - double temp = static_cast(_ticks) * MillisecondsPerTick; - - if (temp > MaxMilliSeconds) - return static_cast(MaxMilliSeconds); - - if (temp < MinMilliSeconds) - return static_cast(MinMilliSeconds); - - return temp; - } - - constexpr double TotalMinutes() const { return static_cast(_ticks) * MinutesPerTick; } - constexpr double TotalSeconds() const { return static_cast(_ticks) * SecondsPerTick; } - - constexpr TimeSpan Add(TimeSpan const& ts) const { - Long result = _ticks + ts._ticks; - - if ((_ticks >> 63 == ts._ticks >> 63) && (_ticks >> 63 != result >> 63)) { - return TimeSpan(result, true); - } - - return TimeSpan(result); - } - - constexpr TimeSpan Duration() const { - if (Ticks() == TimeSpan::MinValue().Ticks()) { - return TimeSpan(Ticks(), true); - } - - return TimeSpan(_ticks >= 0 ? _ticks : -_ticks); - } - - constexpr bool Equals(TimeSpan other) const { - return _ticks == other._ticks; - } - - constexpr TimeSpan Negate() const { - if (Ticks() == TimeSpan::MinValue().Ticks()) { - return TimeSpan(Ticks(), true); - } - - return TimeSpan(-_ticks); - } - - constexpr TimeSpan Subtract(TimeSpan const& ts) const { - Long result = _ticks - ts._ticks; - - if ((_ticks >> 63 != ts._ticks >> 63) && (_ticks >> 63 != result >> 63)) { - return TimeSpan(result, true); - } - - return TimeSpan(result); - } - - constexpr bool HasOverflowException() { - return hasOverflowException; - } - - private: - constexpr TimeSpan(Long ticks, bool overflow) : - _ticks(ticks), - hasOverflowException(overflow) { - } - - static constexpr double MillisecondsPerTick = 1.0 / TicksPerMillisecond; - static constexpr double SecondsPerTick = 1.0 / TicksPerSecond; - static constexpr double MinutesPerTick = 1.0 / TicksPerMinute; - static constexpr double HoursPerTick = 1.0 / TicksPerHour; - static constexpr double DaysPerTick = 1.0 / TicksPerDay; - static constexpr Int MillisPerSecond = 1000; - static constexpr Int MillisPerMinute = MillisPerSecond * 60; - static constexpr Int MillisPerHour = MillisPerMinute * 60; - static constexpr Int MillisPerDay = MillisPerHour * 24; - static constexpr Long MaxSeconds = std::numeric_limits::max() / TicksPerSecond; - static constexpr Long MinSeconds = std::numeric_limits::min() / TicksPerSecond; - static constexpr Long MaxMilliSeconds = std::numeric_limits::max() / TicksPerMillisecond; - static constexpr Long MinMilliSeconds = std::numeric_limits::min() / TicksPerMillisecond; - static constexpr Long TicksPerTenthSecond = TicksPerMillisecond * 100; - - bool hasOverflowException{ false }; - Long _ticks{ 0 }; - - constexpr static Long TimeToTicks(Int const& hour, Int const& minute, Int const& second) { - Long totalSeconds = - static_cast(hour) * 3600 + - static_cast(minute) * 60 + - static_cast(second); - - return totalSeconds * TicksPerSecond; - } - - constexpr static Long DayToTicks(Int days, Int hours, Int minutes, Int seconds, Int milliseconds) { - Long totalMilliSeconds = - (static_cast(days) * 3600 * 24 + - static_cast(hours) * 3600 + - static_cast(minutes) * 60 + seconds) * 1000 + milliseconds; - - return totalMilliSeconds * TicksPerMillisecond; - } - }; -} - -#endif \ No newline at end of file