intro/enum_simple: improve parsing for multi-level namespaces

This commit is contained in:
Danny Robson 2022-04-07 15:47:39 +10:00
parent 5dd58a93b3
commit 2d1374192f
2 changed files with 67 additions and 15 deletions

View File

@ -19,7 +19,7 @@ namespace cruft::introspection {
/// ///
/// It must include an enum literal. /// It must include an enum literal.
template <typename EnumT, EnumT Value> template <typename EnumT, EnumT Value>
static constexpr static consteval
std::string_view std::string_view
enum_pretty_function (void) enum_pretty_function (void)
{ {
@ -39,20 +39,22 @@ namespace cruft::introspection {
/// namespace. Testing is _essential_. /// namespace. Testing is _essential_.
template <typename EnumT, EnumT Value> template <typename EnumT, EnumT Value>
requires (std::is_enum_v<EnumT>) requires (std::is_enum_v<EnumT>)
constexpr std::string_view consteval std::string_view
to_string [[maybe_unused]] (void) to_string [[maybe_unused]] (void)
{ {
#if defined(__clang__) #if defined(__clang__)
// std::string_view cruft::introspection::detail::enum_pretty_function() [EnumT = enum_t, Value = main()::value0] // 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 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<EnumT, Value> (); auto const signature = detail::enum_pretty_function<EnumT, Value> ();
auto const comma = signature.find (','); 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 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; 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<char>]" // "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<char>]"
// //
// consteval std::string_view enum_pretty_function() [with EnumT = enum_t; EnumT Value = (enum_t)42; std::string_view = std::basic_string_view<char>] // consteval std::string_view enum_pretty_function() [with EnumT = enum_t; EnumT Value = (enum_t)42; std::string_view = std::basic_string_view<char>]
//
// "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<char>]"
auto const signature = detail::enum_pretty_function<EnumT, Value> (); auto const signature = detail::enum_pretty_function<EnumT, Value> ();
auto const semicolon0 = signature.find (';'); auto const semicolon0 = signature.find (';');
auto const semicolon1 = signature.find (';', semicolon0 + 1); 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); auto const equals = signature.find ('=', semicolon0);
// static_assert (equals > 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. // 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 // It should be possible to change this search range fairly easily, though
// for larger values you might run into compile time recursion limits. // for larger values you might run into compile time recursion limits.
static static constexpr
EnumT EnumT
from (std::string_view name) from (std::string_view name)
{ {
return _from<EnumT (0), EnumT (128)> (name); return _from<EnumT (0), EnumT (5)> (name);
} }
@ -147,7 +151,8 @@ namespace cruft::introspection {
} }
} }
static std::string_view static constexpr
std::string_view
to (EnumT val) to (EnumT val)
{ {
return _to<EnumT (0), EnumT (128)> (val); return _to<EnumT (0), EnumT (128)> (val);
@ -158,6 +163,7 @@ namespace cruft::introspection {
template <typename EnumT> template <typename EnumT>
requires (std::is_enum_v<EnumT>) requires (std::is_enum_v<EnumT>)
constexpr
EnumT EnumT
from_string (std::string_view str) from_string (std::string_view str)
{ {
@ -167,6 +173,7 @@ namespace cruft::introspection {
template <typename EnumT> template <typename EnumT>
requires (std::is_enum_v<EnumT>) requires (std::is_enum_v<EnumT>)
constexpr
std::string_view std::string_view
to_string (EnumT val) to_string (EnumT val)
{ {

View File

@ -4,18 +4,63 @@
#include <iostream> #include <iostream>
///////////////////////////////////////////////////////////////////////////////
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<enum_t> ("value1"), value1, "from_string, dynamic");
tap.expect_eq (cruft::introspection::to_string<enum_t, value1> (), "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<foo::bar::qux_t, foo::bar::qux1> ();
(void)val;
tap.expect_eq (
cruft::introspection::from_string<foo::bar::qux_t> ("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 int
main () main ()
{ {
cruft::TAP::logger tap; cruft::TAP::logger tap;
enum enum_t { value0 = 0, value1 = 1, value3 = 3, }; test_local (tap);
test_namespaced (tap);
std::cout << cruft::introspection::detail::enum_pretty_function<enum_t, value0> () << '\n';
tap.expect_eq (cruft::introspection::from_string<enum_t> ("value1"), value1, "from_string, dynamic");
tap.expect_eq (cruft::introspection::to_string<enum_t, value1> (), "value1", "to_string, static");
tap.expect_eq (cruft::introspection::to_string (value1), "value1", "to_string, dynamic");
return tap.status (); return tap.status ();
} }