diff --git a/include/SFML/System/Time.hpp b/include/SFML/System/Time.hpp index bfe9dc888..b856408c5 100644 --- a/include/SFML/System/Time.hpp +++ b/include/SFML/System/Time.hpp @@ -50,6 +50,13 @@ public: //////////////////////////////////////////////////////////// constexpr Time(); + //////////////////////////////////////////////////////////// + /// \brief Construct from std::chrono::duration + /// + //////////////////////////////////////////////////////////// + template + constexpr Time(const std::chrono::duration& duration); + //////////////////////////////////////////////////////////// /// \brief Return the time value as a number of seconds /// @@ -80,6 +87,23 @@ public: //////////////////////////////////////////////////////////// constexpr Int64 asMicroseconds() const; + //////////////////////////////////////////////////////////// + /// \brief Return the time value as a std::chorono::duration + /// + /// \return Time in microseconds + /// + //////////////////////////////////////////////////////////// + constexpr std::chrono::microseconds toDuration() const; + + //////////////////////////////////////////////////////////// + /// \brief Implicit conversion to std::chrono::duration + /// + /// \return Duration in microseconds + /// + //////////////////////////////////////////////////////////// + template + constexpr operator std::chrono::duration() const; + //////////////////////////////////////////////////////////// // Static member data //////////////////////////////////////////////////////////// @@ -90,17 +114,6 @@ private: friend constexpr Time milliseconds(Int32); friend constexpr Time microseconds(Int64); - //////////////////////////////////////////////////////////// - /// \brief Construct from a number of microseconds - /// - /// This function is internal. To construct time values, - /// use sf::seconds, sf::milliseconds or sf::microseconds instead. - /// - /// \param microseconds Number of microseconds - /// - //////////////////////////////////////////////////////////// - constexpr explicit Time(Int64 microseconds); - private: //////////////////////////////////////////////////////////// // Member data @@ -450,7 +463,10 @@ constexpr Time& operator%=(Time& left, Time right); /// It allows to define a time value either as a number of /// seconds, milliseconds or microseconds. It also works the /// other way round: you can read a time value as either -/// a number of seconds, milliseconds or microseconds. +/// a number of seconds, milliseconds or microseconds. It +/// even interoperates with the header. You can +/// construct an sf::Time from a chrono::duration and read +/// any sf::Time as a chrono::duration. /// /// By using such a flexible interface, the API doesn't /// impose any fixed type or resolution for time values, @@ -473,6 +489,9 @@ constexpr Time& operator%=(Time& left, Time right); /// /// sf::Time t3 = sf::microseconds(-800000); /// float sec = t3.asSeconds(); // -0.8 +/// +/// sf::Time t4 = std::chrono::milliseconds(250); +/// std::chrono::microseconds micro2 = t4.toDuration(); // 250000us /// \endcode /// /// \code diff --git a/include/SFML/System/Time.inl b/include/SFML/System/Time.inl index ed26cac39..213bba1d4 100644 --- a/include/SFML/System/Time.inl +++ b/include/SFML/System/Time.inl @@ -29,6 +29,13 @@ constexpr Time::Time() : m_microseconds(0) } +//////////////////////////////////////////////////////////// +template +constexpr Time::Time(const std::chrono::duration& duration) : m_microseconds(duration) +{ +} + + //////////////////////////////////////////////////////////// constexpr float Time::asSeconds() const { @@ -51,29 +58,38 @@ constexpr Int64 Time::asMicroseconds() const //////////////////////////////////////////////////////////// -constexpr Time::Time(Int64 microseconds) : m_microseconds(microseconds) +constexpr std::chrono::microseconds Time::toDuration() const { + return m_microseconds; +} + + +//////////////////////////////////////////////////////////// +template +constexpr Time::operator std::chrono::duration() const +{ + return m_microseconds; } //////////////////////////////////////////////////////////// constexpr Time seconds(float amount) { - return Time(static_cast(amount * 1000000)); + return Time(std::chrono::duration_cast(std::chrono::duration(amount))); } //////////////////////////////////////////////////////////// constexpr Time milliseconds(Int32 amount) { - return Time(static_cast(amount) * 1000); + return Time(std::chrono::milliseconds(amount)); } //////////////////////////////////////////////////////////// constexpr Time microseconds(Int64 amount) { - return Time(amount); + return Time(std::chrono::microseconds(amount)); } diff --git a/src/SFML/System/Clock.cpp b/src/SFML/System/Clock.cpp index 727a17076..0f56c8b10 100644 --- a/src/SFML/System/Clock.cpp +++ b/src/SFML/System/Clock.cpp @@ -60,7 +60,7 @@ Time Clock::durationToTime(Clock::ClockImpl::duration duration) { using std::chrono::duration_cast; using std::chrono::microseconds; - return sf::microseconds(duration_cast(duration).count()); + return duration_cast(duration); } } // namespace sf diff --git a/test/System/Time.cpp b/test/System/Time.cpp index 6f9cb5c9d..b5f1642f2 100644 --- a/test/System/Time.cpp +++ b/test/System/Time.cpp @@ -4,6 +4,21 @@ #include +using namespace std::chrono_literals; + +// Use StringMaker to avoid opening namespace std +namespace doctest +{ +template +struct StringMaker> +{ + static String convert(const std::chrono::duration& duration) + { + return toString(std::chrono::microseconds(duration).count()) + "us"; + } +}; +} // namespace doctest + TEST_CASE("sf::Time class - [system]") { SUBCASE("Construction") @@ -50,6 +65,89 @@ TEST_CASE("sf::Time class - [system]") CHECK(time.asMilliseconds() == 987); CHECK(time.asMicroseconds() == 987'654); } + + SUBCASE("Convert from chrono duration") + { + { + const sf::Time time = 3min; + CHECK(time.asSeconds() == 180.f); + CHECK(time.asMilliseconds() == 180'000); + CHECK(time.asMicroseconds() == 180'000'000); + } + { + const sf::Time time = 1s; + CHECK(time.asSeconds() == 1.f); + CHECK(time.asMilliseconds() == 1'000); + CHECK(time.asMicroseconds() == 1'000'000); + } + { + const sf::Time time = 10ms; + CHECK(time.asSeconds() == 0.01f); + CHECK(time.asMilliseconds() == 10); + CHECK(time.asMicroseconds() == 10'000); + } + { + const sf::Time time = 2048us; + CHECK(time.asSeconds() == 0.002048f); + CHECK(time.asMilliseconds() == 2); + CHECK(time.asMicroseconds() == 2048); + } + } + } + + SUBCASE("toDuration()") + { + CHECK(sf::seconds(0).toDuration() == 0s); + CHECK(sf::milliseconds(0).toDuration() == 0ms); + CHECK(sf::microseconds(0).toDuration() == 0us); + + CHECK(sf::seconds(-1).toDuration() == -1s); + CHECK(sf::milliseconds(-1).toDuration() == -1ms); + CHECK(sf::microseconds(-1).toDuration() == -1us); + + CHECK(sf::seconds(1).toDuration() == 1s); + CHECK(sf::milliseconds(1).toDuration() == 1ms); + CHECK(sf::microseconds(1).toDuration() == 1us); + + CHECK(sf::seconds(-10).toDuration() == -10s); + CHECK(sf::milliseconds(-10).toDuration() == -10ms); + CHECK(sf::microseconds(-10).toDuration() == -10us); + + CHECK(sf::seconds(10).toDuration() == 10s); + CHECK(sf::milliseconds(10).toDuration() == 10ms); + CHECK(sf::microseconds(10).toDuration() == 10us); + + CHECK(sf::Time(1s).toDuration() == 1s); + CHECK(sf::Time(1ms).toDuration() == 1ms); + CHECK(sf::Time(1us).toDuration() == 1us); + } + + SUBCASE("Implicit conversion to duration") + { + const auto toDuration = [](const std::chrono::microseconds& duration) { return duration; }; + CHECK(toDuration(sf::seconds(0)) == 0s); + CHECK(toDuration(sf::milliseconds(0)) == 0ms); + CHECK(toDuration(sf::microseconds(0)) == 0us); + + CHECK(toDuration(sf::seconds(-1)) == -1s); + CHECK(toDuration(sf::milliseconds(-1)) == -1ms); + CHECK(toDuration(sf::microseconds(-1)) == -1us); + + CHECK(toDuration(sf::seconds(1)) == 1s); + CHECK(toDuration(sf::milliseconds(1)) == 1ms); + CHECK(toDuration(sf::microseconds(1)) == 1us); + + CHECK(toDuration(sf::seconds(-10)) == -10s); + CHECK(toDuration(sf::milliseconds(-10)) == -10ms); + CHECK(toDuration(sf::microseconds(-10)) == -10us); + + CHECK(toDuration(sf::seconds(10)) == 10s); + CHECK(toDuration(sf::milliseconds(10)) == 10ms); + CHECK(toDuration(sf::microseconds(10)) == 10us); + + CHECK(toDuration(sf::Time(1s)) == 1s); + CHECK(toDuration(sf::Time(1ms)) == 1ms); + CHECK(toDuration(sf::Time(1us)) == 1us); } SUBCASE("Zero time")