From 2d1374192fa8065922eab8d7fd598714440769e3 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 7 Apr 2022 15:47:39 +1000 Subject: [PATCH] intro/enum_simple: improve parsing for multi-level namespaces --- introspection/enum_simple.hpp | 23 ++++++++---- test/introspection/enum_simple.cpp | 59 ++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/introspection/enum_simple.hpp b/introspection/enum_simple.hpp index 42b4680e..bab755ee 100644 --- a/introspection/enum_simple.hpp +++ b/introspection/enum_simple.hpp @@ -19,7 +19,7 @@ namespace cruft::introspection { /// /// It must include an enum literal. template - static constexpr + static consteval std::string_view enum_pretty_function (void) { @@ -39,20 +39,22 @@ namespace cruft::introspection { /// namespace. Testing is _essential_. template requires (std::is_enum_v) - constexpr std::string_view + consteval std::string_view to_string [[maybe_unused]] (void) { #if defined(__clang__) // std::string_view cruft::introspection::detail::enum_pretty_function() [EnumT = enum_t, Value = main()::value0] // // std::string_view enum_pretty_function() [EnumT = enum_t, Value = (enum_t)42] + // + // "std::string_view cruft::introspection::detail::enum_pretty_function() [EnumT = enum_t, Value = test_local(cruft::TAP::logger &)::value0]" auto const signature = detail::enum_pretty_function (); auto const comma = signature.find (','); - auto const coloncolon = signature.find ("::", comma + 1); - auto const equals = signature.find ('=', comma + 1); auto const close = signature.find (']', comma + 1); + auto const coloncolon = signature.rfind ("::", close); + auto const equals = signature.find ('=', comma + 1); auto const first = coloncolon == std::string_view::npos ? equals + 2 : coloncolon + 2; @@ -64,11 +66,13 @@ namespace cruft::introspection { // "constexpr std::string_view cruft::introspection::detail::enum_pretty_function() [with EnumT = main()::enum_t; EnumT Value = main::value1; std::string_view = std::basic_string_view]" // // consteval std::string_view enum_pretty_function() [with EnumT = enum_t; EnumT Value = (enum_t)42; std::string_view = std::basic_string_view] + // + // "constexpr std::string_view cruft::introspection::detail::enum_pretty_function() [with EnumT = test_local(cruft::TAP::logger&)::enum_t; EnumT Value = test_local::value0; std::string_view = std::basic_string_view]" auto const signature = detail::enum_pretty_function (); auto const semicolon0 = signature.find (';'); auto const semicolon1 = signature.find (';', semicolon0 + 1); - auto const coloncolon = signature.find ("::", semicolon0 + 1); + auto const coloncolon = signature.rfind ("::", semicolon1); auto const equals = signature.find ('=', semicolon0); // static_assert (equals > semicolon0); @@ -121,11 +125,11 @@ namespace cruft::introspection { // If the bounds here are incorrect then the result will never be found. // It should be possible to change this search range fairly easily, though // for larger values you might run into compile time recursion limits. - static + static constexpr EnumT from (std::string_view name) { - return _from (name); + return _from (name); } @@ -147,7 +151,8 @@ namespace cruft::introspection { } } - static std::string_view + static constexpr + std::string_view to (EnumT val) { return _to (val); @@ -158,6 +163,7 @@ namespace cruft::introspection { template requires (std::is_enum_v) + constexpr EnumT from_string (std::string_view str) { @@ -167,6 +173,7 @@ namespace cruft::introspection { template requires (std::is_enum_v) + constexpr std::string_view to_string (EnumT val) { diff --git a/test/introspection/enum_simple.cpp b/test/introspection/enum_simple.cpp index 5804bd8b..c53788b8 100644 --- a/test/introspection/enum_simple.cpp +++ b/test/introspection/enum_simple.cpp @@ -4,18 +4,63 @@ #include +/////////////////////////////////////////////////////////////////////////////// +namespace foo::bar { + enum qux_t { + qux0, + qux1, + }; +} + + +//----------------------------------------------------------------------------- +static void +test_local (cruft::TAP::logger &tap) +{ + enum enum_t { value0 = 0, value1 = 1, value3 = 3, }; + + tap.expect_eq (cruft::introspection::from_string ("value1"), value1, "from_string, dynamic"); + tap.expect_eq (cruft::introspection::to_string (), "value1", "to_string, static"); + tap.expect_eq (cruft::introspection::to_string (value1), "value1", "to_string, dynamic"); +} + + +//----------------------------------------------------------------------------- +static void +test_namespaced (cruft::TAP::logger &tap) +{ + auto const val = cruft::introspection::to_string (); + (void)val; + + tap.expect_eq ( + cruft::introspection::from_string ("qux1"), + foo::bar::qux1, + "namespaced: from_string, dynamic" + ); + tap.expect_eq ( + cruft::introspection::to_string< + foo::bar::qux_t, + foo::bar::qux1 + > (), + "qux1", + "namespaced: to_string, static" + ); + tap.expect_eq ( + cruft::introspection::to_string(foo::bar::qux1), + "qux1", + "namespaced: to-string, dynamic" + ); +} + + +//----------------------------------------------------------------------------- int main () { cruft::TAP::logger tap; - enum enum_t { value0 = 0, value1 = 1, value3 = 3, }; - - std::cout << cruft::introspection::detail::enum_pretty_function () << '\n'; - - tap.expect_eq (cruft::introspection::from_string ("value1"), value1, "from_string, dynamic"); - tap.expect_eq (cruft::introspection::to_string (), "value1", "to_string, static"); - tap.expect_eq (cruft::introspection::to_string (value1), "value1", "to_string, dynamic"); + test_local (tap); + test_namespaced (tap); return tap.status (); } \ No newline at end of file