Last active
April 8, 2018 21:57
-
-
Save Broxzier/bbd86d9503ffaaadd02f2f4dffc6ca37 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// header_1.h ===== | |
enum class SurfacePropertyMasks | |
{ | |
SlopeRaisedCornersMask = 0b0001111, | |
SlopeDiagonalFlag = 0b00010000, | |
SlopeMask = SlopeRaisedCornersMask | SlopeDiagonalFlag, | |
EdgeStyleMask = 0b11100000, | |
SurfaceWaterHeightMask = 0b00011111, | |
SurfaceTerrainMask = 0b11100000, | |
}; | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// header_2.h ===== | |
enum class RideEntryFlags | |
{ | |
VehicleTabScaleHalf = 1 << 0, | |
NoInversions = 1 << 1, | |
NoBankedTrack = 1 << 2, | |
PlayDepartSound = 1 << 3, | |
AlternativeSwingMode1 = 1 << 4, | |
AlternativeRotationMode1 = 1 << 5, // Twist type rotation ride | |
AlternativeRotationMode2 = 1 << 6, // Lifting arm rotation ride (enterprise) | |
Flag7 = 1 << 7, | |
PlaySplashSound = 1 << 8, | |
PlaySplashSoundSlide = 1 << 9, | |
CoveredRide = 1 << 10, | |
LimitAirtimeBonus = 1 << 11, | |
SeparateRideNameDeprecated = 1 << 12, // Always set with SEPARATERIDE, and deprecated in favour of it. | |
SeparateRideDeprecated = 1 << 13, // Made redundant by ride groups | |
CannotBreakDown = 1 << 14, | |
DisableLastOperatingMode = 1 << 15, | |
Flag16 = 1 << 16, | |
DisableFirstTwoOperatingModes = 1 << 17, | |
Flag18 = 1 << 18, | |
DisableColourTab = 1 << 19, | |
AlternativeSwingMode2 = 1 << 20, // Must be set with swing mode 1 as well. | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <openrct2/core/Guard.hpp> | |
#include <openrct2/util/EnumClassHelper.hpp> | |
#include "header_1.h" | |
#include "header_2.h" | |
enum class UnrecognizedEnumClass | |
{ | |
Value = 1, | |
}; | |
void TestFunc() | |
{ | |
// For both implementations a compilation error is thrown for unrecognized enum class types | |
auto ttt = UnrecognizedEnumClass::Value; | |
ttt |= UnrecognizedEnumClass::Value; // error C2893: Failed to specialize function template 'enable_if<_Test,_Ty>::type operator |=(T &,T)' | |
ttt &= UnrecognizedEnumClass::Value; // (static_assert) error C2338: Type is not an openrct2 enum class | |
// For recognized enum class types however, the bitwise operator overloads can be used | |
RideEntryFlags rideFlags = RideEntryFlags::NoBankedTrack; | |
rideFlags |= RideEntryFlags::CoveredRide; | |
// But only with the same type (can be desirable, but would requite a lot of refactoring) | |
auto val = rideFlags & unsigned char(1); // error C2782: template parameter is ambiguous | |
// The return value is also a strong type | |
if (rideFlags & RideEntryFlags::NoBankedTrack); // error C2451: conditional expression of type 'RideEntryFlags' is illegal | |
if(static_cast<bool>(rideFlags & RideEntryFlags::NoBankedTrack)); // This works | |
// Edge case: doesn't work well with volatile (not used though), but can probably be worked around with more type_traits | |
volatile auto surfaceFlags = SurfacePropertyMasks::SlopeRaisedCornersMask & SurfacePropertyMasks::SlopeDiagonalFlag; | |
surfaceFlags &= SurfacePropertyMasks::SlopeDiagonalFlag; // error C2782: converting `volatile SurfacePropertyMasks` to `SurfacePropertyMasks` | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Forward declare types | |
enum class RideEntryFlags; | |
enum class SurfacePropertyMasks; | |
//enum class FootpathEntryFlags; | |
// clang-format off | |
// Sets value to 'true_type' for the enum classes listed, 'false_type' otherwise | |
template <typename T> | |
struct is_openrct2_enum_class : std::bool_constant< | |
std::is_same<T, RideEntryFlags>::value || | |
std::is_same<T, SurfacePropertyMasks>::value// || | |
//std::is_same<T, FootpathEntryFlags>::value | |
> | |
{ | |
}; | |
// clang-format on | |
// First option: only define the bitwise operators when the types match | |
// Gives complicated looking compiler error when a type doesn't match | |
template <typename T> | |
inline constexpr typename std::enable_if_t<is_openrct2_enum_class<T>::value, T> operator|(T lhs, T rhs) | |
{ | |
return static_cast<T>(static_cast<std::size_t>(lhs) | static_cast<std::size_t>(rhs)); | |
} | |
template <typename T> | |
inline constexpr typename std::enable_if_t<is_openrct2_enum_class<T>::value, T&> operator|=(T & lhs, T rhs) | |
{ | |
lhs = lhs | rhs; | |
return lhs; | |
} | |
// Second option: Always defines the function, and use static_assert to make sure the type match (much cleaner compilation error) | |
template <typename T> | |
inline constexpr T operator&(T lhs, T rhs) | |
{ | |
static_assert(is_openrct2_enum_class<T>::value, "Type is not an openrct2 enum class"); | |
return static_cast<T>(static_cast<std::size_t>(lhs) & static_cast<std::size_t>(rhs)); | |
} | |
template <typename T> | |
inline constexpr T & operator&=(T & lhs, T rhs) | |
{ | |
static_assert(is_openrct2_enum_class<T>::value, "Type is not an openrct2 enum class"); | |
lhs = lhs & rhs; | |
return lhs; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment