Skip to content

Instantly share code, notes, and snippets.

@rtm223
Last active September 1, 2022 22:47
Show Gist options
  • Save rtm223/6ec11db4d9e67a16d3cc355378e2ae96 to your computer and use it in GitHub Desktop.
Save rtm223/6ec11db4d9e67a16d3cc355378e2ae96 to your computer and use it in GitHub Desktop.
cpp Enum Operators (for class enums)
// Copyright (c) Richard Meredith AB. All Rights Reserved
// ReSharper disable once CppMissingIncludeGuard
//
// Adds all(?) overloads for Scoped Enumerations (Enum Classes).
// Multiple inclusions allowed. #define TEnum (and any options) for each
//
// Usage:
// namespace MyNameSpace // namespace optional
// {
// enum class EMyEnum : uint8
// {
// Value,
// Value2,
// };
// }
//
// #define TEnum MyNamespace::EMyEnum
// #include "Math/RTMEnumOperators.h" // ReSharper disable once CppUnusedIncludeDirective
//
// Optional defines:
// #define FORCE_UINT64_ENUM // forces all operations to be done on uint64 values (default is underlying type of TEnum, e.g. uint8 for example above)
//
//
// Usage with UENUMs:
// Differs because of UHT requirement of having .generated.h Last. Alternatively the three lines to include the enum operators can be in a separate header file
//
// #include "CoreMinimal.h"
// // Other #includes go here
//
// enum class EMyEnum : uint8;
// #define TEnum EMyEnum
// #include "Math/RTMEnumOperators.h" // ReSharper disable once CppUnusedIncludeDirective
//
// #include "EMyEnum.generated.h"
//
// UENUM()
// enum class EMyEnum : uint8
// {
// Value,
// Value2,
// };
#ifdef TEnum
#ifdef FORCE_UINT64_ENUM
#undef FORCE_UINT64_ENUM
#define ENUM_CAST(x) static_cast<uint64>(x)
#else
#define ENUM_CAST(x) static_cast<std::underlying_type_t<TEnum>>(x)
#endif
#define ENUM_NAME_STRINGIFY(x) #x
#define ENUM_NAME_TO_STRING(x) ENUM_NAME_STRINGIFY(x)
#define ENUM_NAME ENUM_NAME_TO_STRING(TEnum)
static_assert(std::is_enum_v<TEnum>, ENUM_NAME " must be Enum Type");
FORCEINLINE bool operator==(TEnum a, TEnum b) { return ENUM_CAST(a) == ENUM_CAST(b); }
template<typename TOther> FORCEINLINE bool operator==(TOther a, TEnum b) { return ENUM_CAST(a) == ENUM_CAST(b); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, bool> operator==(TEnum a, TOther b) { return ENUM_CAST(a) == ENUM_CAST(b); }
FORCEINLINE bool operator!=(TEnum a, TEnum b) { return ENUM_CAST(a) != ENUM_CAST(b); }
template<typename TOther> FORCEINLINE bool operator!=(TEnum a, TOther b) { return static_cast<TOther>(a) != b; }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, bool> operator!=(TOther a, TEnum b) { return ENUM_CAST(a) != ENUM_CAST(b); }
FORCEINLINE bool operator<(TEnum a, TEnum b) { return ENUM_CAST(a) < ENUM_CAST(b); }
template<typename TOther> FORCEINLINE bool operator<(TEnum a, TOther b) { return ENUM_CAST(a) < ENUM_CAST(b); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, bool> operator<(TOther a, TEnum b) { return ENUM_CAST(a) < ENUM_CAST(b); }
FORCEINLINE bool operator<=(TEnum a, TEnum b) { return ENUM_CAST(a) <= ENUM_CAST(b); }
template<typename TOther> FORCEINLINE bool operator<=(TEnum a, TOther b) { return ENUM_CAST(a) <= ENUM_CAST(b); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, bool> operator<=(TOther a, TEnum b) { return ENUM_CAST(a) <= ENUM_CAST(b); }
FORCEINLINE bool operator>(TEnum a, TEnum b) { return ENUM_CAST(a) > ENUM_CAST(b); }
template<typename TOther> FORCEINLINE bool operator>(TEnum a, TOther b) { return ENUM_CAST(a) > ENUM_CAST(b); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, bool> operator>(TOther a, TEnum b) { return ENUM_CAST(a) > ENUM_CAST(b); }
FORCEINLINE bool operator>=(TEnum a, TEnum b) { return ENUM_CAST(a) >= ENUM_CAST(b); }
template<typename TOther> FORCEINLINE bool operator>=(TEnum a, TOther b) { return ENUM_CAST(a) >= ENUM_CAST(b); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, bool> operator>=(TOther a, TEnum b) { return ENUM_CAST(a) >= ENUM_CAST(b); }
FORCEINLINE TEnum operator+(TEnum a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) + ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE TEnum operator+(TEnum a, TOther b) { return static_cast<TEnum>(ENUM_CAST(a) + ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, TEnum> operator+(TOther a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) + ENUM_CAST(b)); }
FORCEINLINE TEnum operator -(TEnum a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) - ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE TEnum operator-(TEnum a, TOther b) { return static_cast<TEnum>(ENUM_CAST(a) - ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, TEnum> operator-(TOther a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) - ENUM_CAST(b)); }
FORCEINLINE TEnum operator*(TEnum a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) * ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE TEnum operator*(TEnum a, TOther b) { return static_cast<TEnum>(ENUM_CAST(a) * ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, TEnum> operator*(TOther a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) * ENUM_CAST(b)); }
FORCEINLINE TEnum operator/(TEnum a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) * ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE TEnum operator/(TEnum a, TOther b) { return static_cast<TEnum>(ENUM_CAST(a) * ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, TEnum> operator/(TOther a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) * ENUM_CAST(b)); }
FORCEINLINE TEnum operator %(TEnum a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) % ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE TEnum operator %(TEnum a, TOther b) { return static_cast<TEnum>(ENUM_CAST(a) % ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, TEnum> operator %(TOther a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) % ENUM_CAST(b)); }
FORCEINLINE TEnum operator&(TEnum a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) & ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE TEnum operator &(TEnum a, TOther b) { return static_cast<TEnum>(ENUM_CAST(a) & ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, TEnum> operator &(TOther a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) & ENUM_CAST(b)); }
FORCEINLINE TEnum operator|(TEnum a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) | ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE TEnum operator |(TEnum a, TOther b) { return static_cast<TEnum>(ENUM_CAST(a) | ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, TEnum> operator |(TOther a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) | ENUM_CAST(b)); }
FORCEINLINE TEnum operator^(TEnum a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) ^ ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE TEnum operator ^(TEnum a, TOther b) { return static_cast<TEnum>(ENUM_CAST(a) ^ ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE std::enable_if_t<!std::is_enum_v<TOther>, TEnum> operator ^(TOther a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) ^ ENUM_CAST(b)); }
FORCEINLINE TEnum operator~(TEnum a) { return static_cast<TEnum>(~ENUM_CAST(a)); }
FORCEINLINE TEnum operator<<(TEnum a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) << ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE TEnum operator<<(TEnum a, TOther b) { return static_cast<TEnum>(ENUM_CAST(a) << ENUM_CAST(b)); }
FORCEINLINE TEnum operator>>(TEnum a, TEnum b) { return static_cast<TEnum>(ENUM_CAST(a) >> ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE TEnum operator>>(TEnum a, TOther b) { return static_cast<TEnum>(ENUM_CAST(a) >> ENUM_CAST(b)); }
template<typename TOther> FORCEINLINE TEnum& operator+=(TEnum& a, TOther b) { return a = a + b; }
template<typename TOther> FORCEINLINE TEnum& operator-=(TEnum& a, TOther b) { return a = a - b; }
template<typename TOther> FORCEINLINE TEnum& operator*=(TEnum& a, TOther b) { return a = a * b; }
template<typename TOther> FORCEINLINE TEnum& operator/=(TEnum& a, TOther b) { return a = a / b; }
template<typename TOther> FORCEINLINE TEnum& operator%=(TEnum& a, TOther b) { return a = a % b; }
template<typename TOther> FORCEINLINE TEnum& operator&=(TEnum& a, TOther b) { return a = a & b; }
template<typename TOther> FORCEINLINE TEnum& operator|=(TEnum& a, TOther b) { return a = a | b; }
template<typename TOther> FORCEINLINE TEnum& operator^=(TEnum& a, TOther b) { return a = a ^ b; }
template<typename TOther> FORCEINLINE TEnum& operator<<=(TEnum& a, TOther b) { return a = a << b; }
template<typename TOther> FORCEINLINE TEnum& operator>>=(TEnum& a, TOther b) { return a = a >> b; }
FORCEINLINE TEnum& operator ++(TEnum& a) { return a = a + 1; }
FORCEINLINE TEnum operator ++(TEnum& a, int)
{
auto b = a;
a = a + 1;
return b;
}
FORCEINLINE TEnum& operator --(TEnum& a) { return a = a - 1; }
FORCEINLINE TEnum operator --(TEnum& a, int)
{
auto b = a;
a = a - 1;
return b;
}
FORCEINLINE bool HasAllFlags(TEnum mask, TEnum testBits) { return testBits == (mask & testBits); }
template<typename TOther> FORCEINLINE bool HasAllFlags(TEnum mask, TOther testBits) { return testBits == (mask & testBits); }
template<typename TOther> FORCEINLINE bool HasAllFlags(TOther mask, TEnum testBits) { return testBits == (mask & testBits); }
FORCEINLINE bool HasAnyFlags(TEnum mask, TEnum testBits) { return 0 != (mask & testBits); }
template<typename TOther> FORCEINLINE bool HasAnyFlags(TEnum mask, TOther testBits) { return 0 != (mask & testBits); }
template<typename TOther> FORCEINLINE bool HasAnyFlags(TOther mask, TEnum testBits) { return 0 != (mask & testBits); }
FORCEINLINE bool HasFlag(TEnum mask, TEnum flag) { return HasAnyFlags(mask, flag); }
template<typename TOther> FORCEINLINE bool HasFlag(TEnum mask, TOther flag) { return HasAnyFlags(mask, flag); }
template<typename TOther> FORCEINLINE bool HasFlag(TOther mask, TEnum flag) { return HasAnyFlags(mask, flag); }
#undef ENUM_CAST
#undef TEnum
#undef ENUM_NAME_STRINGIFY
#undef ENUM_NAME_TO_STRING
#undef ENUM_NAME
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment