Add conversions between sf::Time and std::chrono::durations

This commit is contained in:
Chris Thrasher 2022-06-16 17:34:52 -06:00 committed by Lukas Dürrenberger
parent ebb2d9d186
commit 8561101b11
4 changed files with 150 additions and 17 deletions

View File

@ -50,6 +50,13 @@ public:
////////////////////////////////////////////////////////////
constexpr Time();
////////////////////////////////////////////////////////////
/// \brief Construct from std::chrono::duration
///
////////////////////////////////////////////////////////////
template <typename Rep, typename Period>
constexpr Time(const std::chrono::duration<Rep, Period>& 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 <typename Rep, typename Period>
constexpr operator std::chrono::duration<Rep, Period>() 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 <chrono> 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

View File

@ -29,6 +29,13 @@ constexpr Time::Time() : m_microseconds(0)
}
////////////////////////////////////////////////////////////
template <typename Rep, typename Period>
constexpr Time::Time(const std::chrono::duration<Rep, Period>& 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 <typename Rep, typename Period>
constexpr Time::operator std::chrono::duration<Rep, Period>() const
{
return m_microseconds;
}
////////////////////////////////////////////////////////////
constexpr Time seconds(float amount)
{
return Time(static_cast<Int64>(amount * 1000000));
return Time(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<float>(amount)));
}
////////////////////////////////////////////////////////////
constexpr Time milliseconds(Int32 amount)
{
return Time(static_cast<Int64>(amount) * 1000);
return Time(std::chrono::milliseconds(amount));
}
////////////////////////////////////////////////////////////
constexpr Time microseconds(Int64 amount)
{
return Time(amount);
return Time(std::chrono::microseconds(amount));
}

View File

@ -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<microseconds>(duration).count());
return duration_cast<microseconds>(duration);
}
} // namespace sf

View File

@ -4,6 +4,21 @@
#include <SystemUtil.hpp>
using namespace std::chrono_literals;
// Use StringMaker to avoid opening namespace std
namespace doctest
{
template <typename Rep, typename Period>
struct StringMaker<std::chrono::duration<Rep, Period>>
{
static String convert(const std::chrono::duration<Rep, Period>& 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")