#include #include "MacroUtils.hpp" #include "StringView.hpp" #define ENUM_VALUE(x, value) x = value, # #define ENUM_CASE(x, name) \ case name::x: \ return ArbUt::StringViewLiteral(#x); # #define ENUM_PARSE_CASE(x, name) \ case ConstHash(#x): \ return name::x; # #define ENUM_TRY_PARSE_CASE(x, name) \ case ConstHash(#x): \ out = name::x; \ return true; # #define ENUM_PARSE_CASE_INSENSITIVE(x, name) \ case ConstHashCI(#x): \ return name::x; # #define ENUM_TRY_PARSE_CASE_INSENSITIVE(x, name) \ case ConstHashCI(#x): \ out = name::x; \ return true; # #define ENUM_GET_HIGHEST(x, name) \ if ((i64)name::x > highest) { \ highest = (i64)name::x; \ } # #define ENUM_GET_LOWEST(x, name) \ if ((i64)name::x < lowest) { \ lowest = (i64)name::x; \ } # #define ARRAY_NAME(x, name) name::x, /*! \def ENUM(name, type, values...) Generates an enum class inheriting from specified type with specified name. Also generates a useful helper class with static methods for use with the enum. */ #if defined(__clang__) #define ALLOW_UINTEGER_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow"))) #else #define ALLOW_UINTEGER_OVERFLOW #endif #define ENUM_WITH_START_VALUE(name, type, startValue, ...) \ enum class name : type { \ MACRO_UTILS_FOR_EACH_WITH_VALUE(ENUM_VALUE, startValue + ___MACRO_UTILS_NARGS(__VA_ARGS__) - 1, __VA_ARGS__) \ }; \ class name##Helper { \ ALLOW_UINTEGER_OVERFLOW \ inline static u32 constexpr ConstHash(char const* non_null input) noexcept { \ return *input ? static_cast(*input) + 33 * ConstHash(input + 1) : 5381; \ } \ inline static constexpr char charToLower(const char c) noexcept { \ return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; \ } \ ALLOW_UINTEGER_OVERFLOW \ inline static u32 constexpr ConstHashCI(char const* non_null input) noexcept { \ return charToLower(*input) ? static_cast(charToLower(*input)) + 33 * ConstHashCI(input + 1) : 5381; \ } \ \ public: \ constexpr static ArbUt::StringViewLiteral ToString(name value) noexcept { \ switch (value) { MACRO_UTILS_FOR_EACH(ENUM_CASE, name, __VA_ARGS__) } \ return "out of bounds"_cnc; \ } \ constexpr static name Parse(const char* non_null input, bool caseInsensitive = false) { \ if (caseInsensitive) \ return ParseCaseInsensitive(input); \ switch (ConstHash(input)) { MACRO_UTILS_FOR_EACH(ENUM_PARSE_CASE, name, __VA_ARGS__) } \ throw std::runtime_error("Invalid " #name " string."); \ } \ constexpr static bool TryParse(const char* non_null input, name& out, bool caseInsensitive = false) noexcept { \ if (caseInsensitive) \ return TryParseCaseInsensitive(input, out); \ switch (ConstHash(input)) { MACRO_UTILS_FOR_EACH(ENUM_TRY_PARSE_CASE, name, __VA_ARGS__) } \ return false; \ } \ static std::vector GetValues() noexcept { \ return {MACRO_UTILS_FOR_EACH(ARRAY_NAME, name, __VA_ARGS__)}; \ } \ constexpr static name Last() noexcept { return name::MACRO_UTILS_GET_LAST(__VA_ARGS__); } \ constexpr static name First() noexcept { return name::MACRO_UTILS_GET_FIRST(__VA_ARGS__); } \ constexpr static name Highest() noexcept { \ i64 highest = -9223372036854775807; \ MACRO_UTILS_FOR_EACH(ENUM_GET_HIGHEST, name, __VA_ARGS__) \ return (name)highest; \ } \ constexpr static name Lowest() noexcept { \ i64 lowest = 9223372036854775807; \ MACRO_UTILS_FOR_EACH(ENUM_GET_LOWEST, name, __VA_ARGS__) \ return (name)lowest; \ } \ \ private: \ constexpr static name ParseCaseInsensitive(const char* non_null input) { \ switch (ConstHashCI(input)) { MACRO_UTILS_FOR_EACH(ENUM_PARSE_CASE_INSENSITIVE, name, __VA_ARGS__) } \ throw std::runtime_error("Invalid " #name " string."); \ } \ constexpr static bool TryParseCaseInsensitive(const char* non_null input, name& out) noexcept { \ switch (ConstHashCI(input)) { MACRO_UTILS_FOR_EACH(ENUM_TRY_PARSE_CASE_INSENSITIVE, name, __VA_ARGS__) } \ return false; \ } \ }; #define ENUM(name, type, ...) ENUM_WITH_START_VALUE(name, type, 0, __VA_ARGS__);