From 57cfe8d72905778e3fc0722b32785ba8fe669619 Mon Sep 17 00:00:00 2001 From: Yaraslau Tamashevich Date: Sat, 3 Aug 2024 19:34:30 +0300 Subject: [PATCH] add string_to_enum example --- .github/DockerClang | 1 + README.md | 18 ++++++++++++++++-- include/form/form.h | 46 +++++++++++++++++++++++++++++++++++++-------- include/form/util.h | 7 +++++++ src/test.cpp | 3 ++- src/test.h | 21 +++++++++++++++------ 6 files changed, 79 insertions(+), 17 deletions(-) diff --git a/.github/DockerClang b/.github/DockerClang index 9bf1f43..cf5e788 100644 --- a/.github/DockerClang +++ b/.github/DockerClang @@ -11,6 +11,7 @@ RUN wget https://apt.llvm.org/llvm.sh RUN chmod +x llvm.sh RUN ./llvm.sh 19 RUN git clone -b p2996 https://github.com/bloomberg/clang-p2996.git +RUN cd /clang-p2996 && git reset HEAD~1 --hard RUN cmake -S /clang-p2996/llvm \ -B build \ -G Ninja \ diff --git a/README.md b/README.md index 4a20e4b..34d78be 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ > Collection of static reflection usage examples - [Enum to string](https://github.com/Yaraslaut/form#enum-to-string) +- [String to enum](https://github.com/Yaraslaut/form#string-to-enum) - [Variant type to string](https://github.com/Yaraslaut/form#variant-type-to-string) - [Padding check at compile time](https://github.com/Yaraslaut/form#padding-check-at-compile-time) - [Create variant of all types inside the namespace](https://github.com/Yaraslaut/form#create-variant-of-all-types-inside-the-namespace) @@ -53,6 +54,21 @@ void EnumToString() { } ``` + +## String to enum +Transform string directly to enum + +``` c++ + +enum class Color { red, green, blue }; + +void EnumToString() { + auto color = form::string_to_enum("red"); +} + +``` + + ## Padding check at compile time Calculate padding at compile time and enforce zero padding via concepts @@ -88,7 +104,6 @@ void PaddingCheck() { ``` - ## Create variant of all types inside the namespace ``` c++ @@ -99,7 +114,6 @@ struct ClearHistoryAndReset {}; using list_variant = [:form::util::create_variant(^list):]; ``` - ## Variant type to string ``` c++ diff --git a/include/form/form.h b/include/form/form.h index b693b2d..fd9c3a9 100644 --- a/include/form/form.h +++ b/include/form/form.h @@ -10,6 +10,30 @@ namespace form { +namespace detail { +using namespace form; + +template +constexpr Inner string_to_enum(std::string_view value) { + Inner result{}; + + constexpr auto enum_type = [](this auto self, Check) { + if constexpr (std::is_enum_v) { + return ^Check; + } else { + return self(typename Check::value_type{}); + } + }(Inner{}); + + [:util::expand(std::meta::enumerators_of(enum_type)):] >> [&] { + if (value == util::name_of(e)) { + result = [:e:]; + } + }; + return result; +} +} // namespace detail + template constexpr std::string variant_type_to_string(E value) { std::string out = ""; [:util::expand(template_arguments_of(^E)):] >> [&] { @@ -38,6 +62,18 @@ constexpr std::string enum_to_string(E value, auto transformation) { return transformation(enum_to_string(value)); } +template + requires std::is_enum_v +constexpr std::optional string_to_enum(std::string_view value) { + return detail::string_to_enum>(value); +} + +template + requires std::is_enum_v +constexpr E string_to_enum_no_check(std::string_view value) { + return detail::string_to_enum(value); +} + template bool compare(T const &lhs, T const &rhs) { bool result = true; if constexpr (std::is_arithmetic_v) @@ -79,8 +115,9 @@ template void run_tests() { std::invoke_result_t, bool>) { if ([:mem:]()) std::format_to(std::back_inserter(out), "{}", "\N{FIRE}"); - else + else { std::format_to(std::back_inserter(out), "{}", "\N{PILE OF POO}"); + } } else { [:mem:](); std::format_to(std::back_inserter(out), "{}", "\N{FOUR LEAF CLOVER}"); @@ -95,13 +132,6 @@ template void run_tests() { } } -template constexpr void print_members() { - std::println("Members of: {}", util::name_of(^T)); - [:util::expand(nonstatic_data_members_of(^T)):] >> [&] { - std::println("{}", util::name_of(mem)); - }; -} - template consteval std::size_t get_padding() { std::size_t pointer{offset_of(nonstatic_data_members_of(^S)[0]).bytes}; diff --git a/include/form/util.h b/include/form/util.h index bed5d31..f84573c 100644 --- a/include/form/util.h +++ b/include/form/util.h @@ -106,4 +106,11 @@ std::string_view get_before(std::string_view str, std::string_view delim) { return str.substr(0, pos); } +template constexpr void print_members() { + std::println("Members of: {}", util::name_of(^T)); + [:util::expand(nonstatic_data_members_of(^T)):] >> [&] { + std::println("{}", util::name_of(mem)); + }; +} + } // namespace form::util diff --git a/src/test.cpp b/src/test.cpp index 1c932d0..b278002 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -1,6 +1,7 @@ #include "test.h" int main() { - form::run_tests<^form::tests>(); form::run_tests<^form::examples>(); + form::run_tests<^form::tests>(); + return 0; } diff --git a/src/test.h b/src/test.h index 3a56ba0..0f6de65 100644 --- a/src/test.h +++ b/src/test.h @@ -11,7 +11,9 @@ namespace log { template inline void println(std::format_string fmt, Args &&...args) { +#if 0 std::println(fmt, std::forward(args)...); +#endif } } // namespace log @@ -169,7 +171,7 @@ struct ConfigEntries { // ConfigEntry strong_entry; }; -namespace detail { +namespace helper { template struct CreateUniqueT; @@ -182,7 +184,7 @@ template constexpr auto CreateClass() { } // clang-format on -} // namespace detail +} // namespace helper namespace form_same_as { template int foo(T) { return -1; } @@ -204,14 +206,12 @@ void testZ() { deserialize(z); } -void testPrintMembers() { form::print_members(); } - void testCreateClass() { - using hidden_type = [:detail::CreateClass>():]; + using hidden_type = [:helper::CreateClass>():]; constexpr hidden_type value{}; constexpr auto refl_of_value = ^value; - form::print_members<[:type_of(refl_of_value):]>(); + // util::print_members<[:type_of(refl_of_value):]>(); } void testAA() { @@ -406,6 +406,15 @@ bool EnumToStringWithTransform() { return res; } +bool StringToEnum() { + bool res = true; + res &= form::string_to_enum("red").value() == Color::red; + res &= form::string_to_enum("green").value() == Color::green; + res &= form::string_to_enum("blue").value() == Color::blue; + res &= form::string_to_enum_no_check("asdf") == Color::red; + return res; +} + void PaddingCheck() { foo(struct_with_padding{});