Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add templated GameTicks strong type #21868

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
119 changes: 119 additions & 0 deletions src/openrct2/GameTicks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*****************************************************************************
* Copyright (c) 2014-2024 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/

#pragma once

#include "common.h"

// TODO: Move or remove these constants if
// we can use the constants defined
// in Context.h
namespace TickConversion
{
constexpr uint32_t kGameUpdateFPS = 40;
constexpr uint32_t kGameUpdateMs = 1000 / kGameUpdateFPS;

Check notice on line 20 in src/openrct2/GameTicks.h

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: note

'kGameUpdateMs' declared here

Check notice on line 20 in src/openrct2/GameTicks.h

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: note

'kGameUpdateMs' declared here
} // namespace TickConversion

template<typename T, typename Tag> struct GameTicks

Check notice on line 23 in src/openrct2/GameTicks.h

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: note

candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const GameTicks<unsigned int, GameTickTag>' for 1st argument

Check notice on line 23 in src/openrct2/GameTicks.h

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: note

candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'GameTicks<unsigned int, GameTickTag>' for 1st argument

Check notice on line 23 in src/openrct2/GameTicks.h

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: note

candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided
{
using ValueType = T;

ValueType Value;

static constexpr GameTicks FromSeconds(uint32_t seconds)
{
GameTicks result = FromMilliseconds(seconds * 1000);
return result;
}
static constexpr GameTicks FromMilliseconds(uint32_t milliseconds)
{
GameTicks<T, Tag> result;
result.Value = (milliseconds + (TickConversion::kGameUpdateTimeMs - 1)) /

Check failure on line 37 in src/openrct2/GameTicks.h

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: error

no member named 'kGameUpdateTimeMs' in namespace 'TickConversion'; did you mean 'kGameUpdateMs'? [clang-diagnostic-error]
TickConversion::kGameUpdateTimeMs /* 25 */;

Check failure on line 38 in src/openrct2/GameTicks.h

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: error

no member named 'kGameUpdateTimeMs' in namespace 'TickConversion'; did you mean 'kGameUpdateMs'? [clang-diagnostic-error]
return result;
}

constexpr void operator=(T rhs)
{
Value = rhs;
}

constexpr GameTicks& operator++()
{
++Value;
return *this;
}
constexpr GameTicks operator++(int)
{
GameTicks<T, Tag> temp = *this;
Value++;
return temp;
}
constexpr GameTicks& operator--()
{
--Value;
return *this;
}
constexpr GameTicks operator--(int)
{
GameTicks<T, Tag> temp = *this;
Value--;
return temp;
}

constexpr GameTicks operator+(GameTicks rhs) const
{
return GameTicks(Value + rhs.Value);
}
constexpr GameTicks operator-(GameTicks rhs) const
{
return GameTicks(Value - rhs.Value);
}
constexpr GameTicks operator*(GameTicks rhs) const
{
return GameTicks(Value * rhs.Value);
}
constexpr GameTicks operator/(GameTicks rhs) const
{
return GameTicks(Value / rhs.GameTicks);
}

constexpr GameTicks& operator+=(GameTicks rhs)
{
Value += rhs.Value;
return *this;
}
constexpr GameTicks& operator-=(GameTicks rhs)
{
Value -= rhs.Value;
return *this;
}

constexpr bool operator==(const GameTicks& rhs) const
{
return Value == rhs.Value;
}

constexpr bool operator!=(const GameTicks& rhs) const
{
return Value != rhs.Value;
}

constexpr bool operator<=>(const GameTicks& rhs) const
{
return Value <=> rhs.Value;
}

constexpr GameTicks& operator%(const GameTicks& rhs)
{
GameTicks result;
result.Value = Value % rhs.Value;
return result;
}
};
1 change: 1 addition & 0 deletions test/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ set(test_files
"${CMAKE_CURRENT_SOURCE_DIR}/S6ImportExportTests.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/SawyerCodingTest.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/StringTest.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GameTicksTest.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/TestData.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/TestData.h"
"${CMAKE_CURRENT_SOURCE_DIR}/tests.cpp"
Expand Down
131 changes: 131 additions & 0 deletions test/tests/GameTicksTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*****************************************************************************
* Copyright (c) 2014-2024 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/

#include <gtest/gtest.h>
#include <openrct2/GameTicks.h>

struct GameTickTag {};

using TestGameTick = GameTicks<uint32_t, GameTickTag>;

///////////////////////////////////////////////////////////////////////////////
// Tests for GameTicks<T, Tag>
///////////////////////////////////////////////////////////////////////////////

TEST(GameTicksTest, Construction)
{
TestGameTick tick(10);

Check failure on line 23 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: error

no matching constructor for initialization of 'TestGameTick' (aka 'GameTicks<unsigned int, GameTickTag>') [clang-diagnostic-error]
EXPECT_EQ(10, tick.Value);
}

TEST(GameTicksTest, FromSeconds)
{
TestGameTick actual = TestGameTick::FromMilliseconds(0);

Check notice on line 29 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: note

previous definition is here
EXPECT_EQ(0, actual.Value);

TestGameTick actual = TestGameTick::FromSeconds(1);

Check failure on line 32 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: error

redefinition of 'actual' [clang-diagnostic-error]
EXPECT_EQ(40, actual.Value);
}

TEST(GameTicksTest, FromMilliseconds)
{
TestGameTick actual = TestGameTick::FromMilliseconds(0);
EXPECT_EQ(0, actual.Value);

TestGameTick actual = TestGameTick::FromMilliseconds(1);

Check failure on line 41 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: error

redefinition of 'actual' [clang-diagnostic-error]
EXPECT_EQ(1, actual.Value);

TestGameTick actual = TestGameTick::FromMilliseconds(24);

Check failure on line 44 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: error

redefinition of 'actual' [clang-diagnostic-error]
EXPECT_EQ(1, actual.Value);

TestGameTick actual = TestGameTick::FromMilliseconds(1000);

Check failure on line 47 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: error

redefinition of 'actual' [clang-diagnostic-error]
EXPECT_EQ(40, actual.Value);
}

TEST(GameTicksTest, Addition)
{
TestGameTick tick1(10);

Check failure on line 53 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: error

no matching constructor for initialization of 'TestGameTick' (aka 'GameTicks<unsigned int, GameTickTag>') [clang-diagnostic-error]
TestGameTick tick2(20);

Check failure on line 54 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: error

no matching constructor for initialization of 'TestGameTick' (aka 'GameTicks<unsigned int, GameTickTag>') [clang-diagnostic-error]

TestGameTick actual = tick1 + tick2;

Check notice on line 56 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: note

in instantiation of member function 'GameTicks<unsigned int, GameTickTag>::operator+' requested here
EXPECT_EQ(30, actual.Value);
}

TEST(GameTicksTest, Subtraction)
{
TestGameTick tick1(10);

Check failure on line 62 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: error

no matching constructor for initialization of 'TestGameTick' (aka 'GameTicks<unsigned int, GameTickTag>') [clang-diagnostic-error]
TestGameTick tick2(20);

TestGameTick actual = tick2 - tick1;

Check notice on line 65 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: note

in instantiation of member function 'GameTicks<unsigned int, GameTickTag>::operator-' requested here
EXPECT_EQ(10, actual.Value);
}

TEST(GameTicksTest, Multiplication)
{
TestGameTick tick1(10);
TestGameTick tick2(20);

TestGameTick actual = tick1 * tick2;

Check notice on line 74 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: note

in instantiation of member function 'GameTicks<unsigned int, GameTickTag>::operator*' requested here
EXPECT_EQ(200, actual.Value);
}

TEST(GameTicksTest, Division)
{
TestGameTick tick1(10);
TestGameTick tick2(20);

TestGameTick actual = tick2 / tick1;

Check notice on line 83 in test/tests/GameTicksTests.cpp

View workflow job for this annotation

GitHub Actions / clang-tidy-check

clang-tidy: note

in instantiation of member function 'GameTicks<unsigned int, GameTickTag>::operator/' requested here
EXPECT_EQ(2, actual.Value);
}

TEST(GameTicksTest, Modulus)
{
TestGameTick tick1(10);
TestGameTick tick2(20);

TestGameTick actual = tick2 % tick1;
EXPECT_EQ(0, actual.Value);

TestGameTick tick3(3);
TestGameTick tick4(2);

TestGameTick actual = tick3 % tick4;
EXPECT_EQ(1, actual.Value);
}

TEST(GameTicksTest, IncrementDecrement)
{
TestGameTick tick(10);

++tick;
EXPECT_EQ(11, tick.Value);

tick++;
EXPECT_EQ(12, tick.Value);

--tick;
EXPECT_EQ(11, tick.Value);

tick--;
EXPECT_EQ(10, tick.Value);
}

TEST(GameTicksTest, Comparisons)
{
TestGameTick tick1(10);
TestGameTick tick2(20);
TestGameTick tick3(10);

EXPECT_TRUE(tick1 == tick3);
EXPECT_TRUE(tick1 != tick2);
EXPECT_TRUE(tick2 > tick1);
EXPECT_TRUE(tick1 < tick2);
EXPECT_TRUE(tick1 <= tick3);
EXPECT_TRUE(tick2 >= tick1);
}