diff --git a/src/Core/Enum.hpp b/src/Core/Enum.hpp index 1403760..f8f2dc2 100644 --- a/src/Core/Enum.hpp +++ b/src/Core/Enum.hpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include "Exceptions/NotReachableException.hpp" #include "MacroUtils.hpp" @@ -12,10 +12,20 @@ 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 ARRAY_NAME(x, name) name::x, #define ENUM(name, type, values...) \ @@ -33,21 +43,31 @@ } \ \ public: \ - static std::string ToString(name value) { \ + constexpr static const char* ToString(name value) { \ switch (value) { FOR_EACH(ENUM_CASE, name, values) } \ throw NotReachableException(); \ } \ - static name Parse(const std::string& input, bool caseInsensitive = false) { \ + constexpr static name Parse(const char* input, bool caseInsensitive = false) { \ if (caseInsensitive) \ return ParseCaseInsensitive(input); \ - switch (ConstHash(input.c_str())) { FOR_EACH(ENUM_PARSE_CASE, name, values) } \ - throw CreatureException("String '" + input + "' could not be parsed as " #name); \ + switch (ConstHash(input)) { FOR_EACH(ENUM_PARSE_CASE, name, values) } \ + throw CreatureException("Invalid AttackCategory string."); \ + } \ + constexpr static bool TryParse(const char* input, name& out, bool caseInsensitive = false) { \ + if (caseInsensitive) \ + return TryParseCaseInsensitive(input, out); \ + switch (ConstHash(input)) { FOR_EACH(ENUM_TRY_PARSE_CASE, name, values) } \ + return false; \ } \ static std::vector GetValues() { return {FOR_EACH(ARRAY_NAME, name, values)}; } \ \ private: \ - static name ParseCaseInsensitive(const std::string& input) { \ - switch (ConstHashCI(input.c_str())) { FOR_EACH(ENUM_PARSE_CASE_INSENSITIVE, name, values) } \ - throw CreatureException("String '" + input + "' could not be parsed as " #name); \ + static name ParseCaseInsensitive(const char* input) { \ + switch (ConstHashCI(input)) { FOR_EACH(ENUM_PARSE_CASE_INSENSITIVE, name, values) } \ + throw CreatureException("Invalid AttackCategory string."); \ + } \ + static bool TryParseCaseInsensitive(const char* input, name& out) { \ + switch (ConstHashCI(input)) { FOR_EACH(ENUM_TRY_PARSE_CASE_INSENSITIVE, name, values) } \ + return false; \ } \ }; diff --git a/tests/EnumTests.cpp b/tests/EnumTests.cpp index f94fea8..6278b66 100644 --- a/tests/EnumTests.cpp +++ b/tests/EnumTests.cpp @@ -13,6 +13,18 @@ TEST_CASE("Parse Enum case sensitive", "[Utilities]") { CHECK_THROWS(TestEnumHelper::Parse("val1")); } +TEST_CASE("Try Parse Enum case sensitive", "[Utilities]") { + TestEnum v = static_cast(255); + REQUIRE(TestEnumHelper::TryParse("Val1", v)); + CHECK(v == TestEnum::Val1); + REQUIRE(TestEnumHelper::TryParse("Val2", v)); + CHECK(v == TestEnum::Val2); + REQUIRE(TestEnumHelper::TryParse("Val3", v)); + CHECK(v == TestEnum::Val3); + CHECK_FALSE(TestEnumHelper::TryParse("Val4", v)); + CHECK_FALSE(TestEnumHelper::TryParse("val1", v)); +} + TEST_CASE("Parse Enum case insensitive", "[Utilities]") { CHECK(TestEnumHelper::Parse("Val1", true) == TestEnum::Val1); CHECK(TestEnumHelper::Parse("Val2", true) == TestEnum::Val2); @@ -23,6 +35,23 @@ TEST_CASE("Parse Enum case insensitive", "[Utilities]") { CHECK_THROWS(TestEnumHelper::Parse("Val4", true)); } +TEST_CASE("Try Parse Enum case insensitive", "[Utilities]") { + TestEnum v = static_cast(255); + REQUIRE(TestEnumHelper::TryParse("Val1", v, true)); + CHECK(v == TestEnum::Val1); + REQUIRE(TestEnumHelper::TryParse("Val2", v, true)); + CHECK(v == TestEnum::Val2); + REQUIRE(TestEnumHelper::TryParse("Val3", v, true)); + CHECK(v == TestEnum::Val3); + REQUIRE(TestEnumHelper::TryParse("val1", v, true)); + CHECK(v == TestEnum::Val1); + REQUIRE(TestEnumHelper::TryParse("vAL2", v, true)); + CHECK(v == TestEnum::Val2); + REQUIRE(TestEnumHelper::TryParse("VaL3", v, true)); + CHECK(v == TestEnum::Val3); + CHECK_FALSE(TestEnumHelper::TryParse("Val4", v, true)); +} + TEST_CASE("Enum To String", "[Utilities]") { CHECK(TestEnumHelper::ToString(TestEnum::Val1) == "Val1"); CHECK(TestEnumHelper::ToString(TestEnum::Val2) == "Val2");