1
0
mirror of https://github.com/borgesdan/xn65 synced 2024-12-29 21:54:47 +01:00

Implementa GameClock

This commit is contained in:
Danilo 2024-03-23 17:23:07 -03:00
parent 42e202f06e
commit 85968753d7
10 changed files with 501 additions and 255 deletions

View File

@ -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)

View File

@ -0,0 +1,328 @@
#ifndef XNA_CSHARP_TIMESPAN_HPP
#define XNA_CSHARP_TIMESPAN_HPP
#include <limits>
#include <cstdint>
#include <cmath>
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<int64_t>::min();
static constexpr int64_t MaxTicks = std::numeric_limits<int64_t>::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<int32_t>(_ticks / TicksPerDay); }
constexpr int32_t Hours() const { return static_cast<int32_t>(_ticks / TicksPerHour % HoursPerDay); }
constexpr int32_t Milliseconds() const { return static_cast<int32_t>(_ticks / TicksPerMillisecond % MillisecondsPerSecond); }
constexpr int32_t Microseconds() const { return static_cast<int32_t>(_ticks / TicksPerMicrosecond % MicrosecondsPerMillisecond); }
constexpr int32_t Nanoseconds() const { return static_cast<int32_t>(_ticks % TicksPerMicrosecond * NanosecondsPerTick); }
constexpr int32_t Minutes() const { return static_cast<int32_t>(_ticks / TicksPerMinute % MinutesPerHour); }
constexpr int32_t Seconds() const { return static_cast<int32_t>(_ticks / TicksPerSecond % SecondsPerMinute); }
constexpr double TotalDays() const { return static_cast<double>(_ticks) / TicksPerDay; }
constexpr double TotalHours() const { return static_cast<double>(_ticks) / TicksPerHour; }
constexpr double TotalMilliseconds() const {
double temp = static_cast<double>(_ticks) / TicksPerMillisecond;
if (temp > MaxMilliseconds) {
return MaxMilliseconds;
}
if (temp < MinMilliseconds) {
return MinMilliseconds;
}
return temp;
}
constexpr double TotalMicroseconds() const { return static_cast<double>(_ticks) / TicksPerMicrosecond; }
constexpr double TotalNanoseconds() const { return static_cast<double>(_ticks) * NanosecondsPerTick; }
constexpr double TotalMinutes() const { return static_cast<double>(_ticks) / TicksPerMinute; }
constexpr double TotalSeconds() const { return static_cast<double>(_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<double>(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<int64_t>(ticks));
}
//TODO: Not implemented.
//static TimeSpan FromMicroseconds(__int128 microseconds);
};
}
#endif

View File

@ -28,6 +28,7 @@ namespace xna {
class Game;
class GameComponent;
class GameComponentCollection;
class GameClock;
class GameTime;
class GameWindow;
class IDrawable;

24
framework/game/clock.hpp Normal file
View File

@ -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

View File

@ -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 };
};
}

View File

@ -0,0 +1,71 @@
#include "clock-dx.hpp"
#include <Windows.h>
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);
}
}

View File

@ -0,0 +1,48 @@
#ifndef XNA_PLATFORM_CLOCK_DX_HPP
#define XNA_PLATFORM_CLOCK_DX_HPP
#include "../game/clock.hpp"
#include <chrono>
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<std::chrono::nanoseconds>(end - start).count();
}
constexpr long long GetMicroseconds(SteadyClock::time_point start, SteadyClock::time_point end) {
return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
}
constexpr long long GetMilliSeconds(SteadyClock::time_point start, SteadyClock::time_point end) {
return std::chrono::duration_cast<std::chrono::milliseconds>(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

View File

@ -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<int>(msg.wParam);
}
}

View File

@ -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();
};
}

View File

@ -1,231 +0,0 @@
#ifndef XNA_TIMESPAN_HPP
#define XNA_TIMESPAN_HPP
#include <limits>
#include <cstdint>
#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<Long>::max());
}
static constexpr TimeSpan MinValue() {
return TimeSpan(std::numeric_limits<Long>::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<Long>(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<Int>(_ticks / TicksPerDay); }
constexpr Int Hours() const { return static_cast<Int>((_ticks / TicksPerHour) % 24); }
constexpr Int Milliseconds() const { return static_cast<Int>((_ticks / TicksPerMillisecond) % 1000); }
constexpr Int Minutes() const { return static_cast<Int>((_ticks / TicksPerMinute) % 60); }
constexpr Int Seconds() const { return static_cast<Int>((_ticks / TicksPerSecond) % 60); }
constexpr double TotalDays() const { return static_cast<double>(_ticks) * DaysPerTick; }
constexpr double TotalHours() const { return static_cast<double>(_ticks) * HoursPerTick; }
constexpr double TotalMilliseconds() const {
double temp = static_cast<double>(_ticks) * MillisecondsPerTick;
if (temp > MaxMilliSeconds)
return static_cast<double>(MaxMilliSeconds);
if (temp < MinMilliSeconds)
return static_cast<double>(MinMilliSeconds);
return temp;
}
constexpr double TotalMinutes() const { return static_cast<double>(_ticks) * MinutesPerTick; }
constexpr double TotalSeconds() const { return static_cast<double>(_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<Long>::max() / TicksPerSecond;
static constexpr Long MinSeconds = std::numeric_limits<Long>::min() / TicksPerSecond;
static constexpr Long MaxMilliSeconds = std::numeric_limits<Long>::max() / TicksPerMillisecond;
static constexpr Long MinMilliSeconds = std::numeric_limits<Long>::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<Long>(hour) * 3600 +
static_cast<Long>(minute) * 60 +
static_cast<Long>(second);
return totalSeconds * TicksPerSecond;
}
constexpr static Long DayToTicks(Int days, Int hours, Int minutes, Int seconds, Int milliseconds) {
Long totalMilliSeconds =
(static_cast<Long>(days) * 3600 * 24 +
static_cast<Long>(hours) * 3600 +
static_cast<Long>(minutes) * 60 + seconds) * 1000 + milliseconds;
return totalMilliSeconds * TicksPerMillisecond;
}
};
}
#endif