2020-02-26 11:57:18 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <sstream>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <vector>
|
|
|
|
#include "MacroUtils.hpp"
|
|
|
|
|
|
|
|
#define ENUM_CASE(x, name) \
|
|
|
|
case name::x: \
|
|
|
|
return #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;
|
|
|
|
#
|
2020-03-12 18:28:26 +00:00
|
|
|
#define ENUM_GET_HIGHEST(x, name) \
|
|
|
|
if ((int64_t)name::x > highest) { \
|
|
|
|
highest = (int64_t)name::x; \
|
|
|
|
}
|
|
|
|
#
|
|
|
|
#define ENUM_GET_LOWEST(x, name) \
|
|
|
|
if ((int64_t)name::x < lowest) { \
|
|
|
|
lowest = (int64_t)name::x; \
|
|
|
|
}
|
|
|
|
#
|
2020-02-26 11:57:18 +00:00
|
|
|
#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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define ENUM(name, type, values...) \
|
|
|
|
enum class name : type { values }; \
|
|
|
|
class name##Helper { \
|
|
|
|
inline static uint32_t constexpr ConstHash(char const* input) { \
|
|
|
|
return *input ? static_cast<uint32_t>(*input) + 33 * ConstHash(input + 1) : 5381; \
|
|
|
|
} \
|
|
|
|
inline static constexpr char charToLower(const char c) { \
|
|
|
|
return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; \
|
|
|
|
} \
|
|
|
|
inline static uint32_t constexpr ConstHashCI(char const* input) { \
|
|
|
|
return charToLower(*input) ? static_cast<uint32_t>(charToLower(*input)) + 33 * ConstHashCI(input + 1) \
|
|
|
|
: 5381; \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
public: \
|
|
|
|
constexpr static const char* ToString(name value) { \
|
2020-03-11 10:49:56 +00:00
|
|
|
switch (value) { MACRO_UTILS_FOR_EACH(ENUM_CASE, name, values) } \
|
2020-04-10 17:51:35 +00:00
|
|
|
auto v = static_cast<int>(value); \
|
|
|
|
auto size = (int)((ceil(log10(v)) + 1) * sizeof(char)); \
|
2020-04-10 17:57:12 +00:00
|
|
|
char* snum = new char[size + 1]; \
|
2020-04-10 17:51:35 +00:00
|
|
|
sprintf(snum, "%d", v); \
|
|
|
|
return snum; \
|
2020-02-26 11:57:18 +00:00
|
|
|
} \
|
|
|
|
constexpr static name Parse(const char* input, bool caseInsensitive = false) { \
|
|
|
|
if (caseInsensitive) \
|
|
|
|
return ParseCaseInsensitive(input); \
|
2020-03-11 10:49:56 +00:00
|
|
|
switch (ConstHash(input)) { MACRO_UTILS_FOR_EACH(ENUM_PARSE_CASE, name, values) } \
|
2020-03-11 10:38:36 +00:00
|
|
|
throw std::runtime_error("Invalid " #name " string."); \
|
2020-02-26 11:57:18 +00:00
|
|
|
} \
|
|
|
|
constexpr static bool TryParse(const char* input, name& out, bool caseInsensitive = false) { \
|
|
|
|
if (caseInsensitive) \
|
|
|
|
return TryParseCaseInsensitive(input, out); \
|
2020-03-11 10:49:56 +00:00
|
|
|
switch (ConstHash(input)) { MACRO_UTILS_FOR_EACH(ENUM_TRY_PARSE_CASE, name, values) } \
|
2020-02-26 11:57:18 +00:00
|
|
|
return false; \
|
|
|
|
} \
|
2020-03-11 10:49:56 +00:00
|
|
|
static std::vector<name> GetValues() { return {MACRO_UTILS_FOR_EACH(ARRAY_NAME, name, values)}; } \
|
|
|
|
constexpr static name Last() { return name::MACRO_UTILS_GET_LAST(values); } \
|
|
|
|
constexpr static name First() { return name::MACRO_UTILS_GET_FIRST(values); } \
|
2020-03-12 18:28:26 +00:00
|
|
|
constexpr static name Highest() { \
|
|
|
|
int64_t highest = -9223372036854775807; \
|
|
|
|
MACRO_UTILS_FOR_EACH(ENUM_GET_HIGHEST, name, values) \
|
|
|
|
return (name)highest; \
|
|
|
|
} \
|
|
|
|
constexpr static name Lowest() { \
|
|
|
|
int64_t lowest = 9223372036854775807; \
|
|
|
|
MACRO_UTILS_FOR_EACH(ENUM_GET_LOWEST, name, values) \
|
|
|
|
return (name)lowest; \
|
|
|
|
} \
|
2020-02-26 11:57:18 +00:00
|
|
|
\
|
|
|
|
private: \
|
2020-03-11 10:38:36 +00:00
|
|
|
constexpr static name ParseCaseInsensitive(const char* input) { \
|
2020-03-11 10:49:56 +00:00
|
|
|
switch (ConstHashCI(input)) { MACRO_UTILS_FOR_EACH(ENUM_PARSE_CASE_INSENSITIVE, name, values) } \
|
2020-03-11 10:38:36 +00:00
|
|
|
throw std::runtime_error("Invalid " #name " string."); \
|
2020-02-26 11:57:18 +00:00
|
|
|
} \
|
2020-03-11 10:38:36 +00:00
|
|
|
constexpr static bool TryParseCaseInsensitive(const char* input, name& out) { \
|
2020-03-11 10:49:56 +00:00
|
|
|
switch (ConstHashCI(input)) { MACRO_UTILS_FOR_EACH(ENUM_TRY_PARSE_CASE_INSENSITIVE, name, values) } \
|
2020-02-26 11:57:18 +00:00
|
|
|
return false; \
|
|
|
|
} \
|
|
|
|
};
|