Arbutils/src/Enum.hpp

115 lines
9.8 KiB
C++

#include <vector>
#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<u32>(*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<u32>(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<name> 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__);