From 43b8e8f6f26af5dde465441486c7d9b4c7e586c9 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Sep 2020 14:40:56 +1000 Subject: [PATCH] introspection: add type_name_with_namespace --- introspection.hpp | 66 ++++++++++++++++++++++++------------------ test/introspection.cpp | 34 +++++++++++++++++++++- 2 files changed, 71 insertions(+), 29 deletions(-) diff --git a/introspection.hpp b/introspection.hpp index 58ba4739..99ab70bb 100644 --- a/introspection.hpp +++ b/introspection.hpp @@ -27,7 +27,7 @@ namespace cruft { template constexpr - std::string_view type_name (void) + std::string_view type_name_with_namespace (void) { std::string_view pretty_function (__PRETTY_FUNCTION__); @@ -43,49 +43,59 @@ namespace cruft { #error "Unsupported compiler" #endif - // Find the location where the type begins. It will also mark the start of - // the type's namespace if the type has one. - auto const ns_begin = std::search ( + // Find the location where the type begins. + auto const type_begin = std::search ( pretty_function.begin (), pretty_function.end (), prefix.begin (), prefix.end () - ); + ) + prefix.size (); // Find the point the type name ends. Both use ']', but gcc lists - // std::string_view too and so requires the delimiting ';' as a suffix. + // std::string_view in the function signature too and so requires the + // delimiting ';' as a suffix. char const suffixes[] = ";]"; auto const type_end = std::find_first_of ( - ns_begin, + type_begin, pretty_function.end (), std::begin (suffixes), - std::end (suffixes) + std::end (suffixes) ); - // Find the start of the first template parameter (or the end of the - // string otherwise), and the end of the template parameters for this - // type. - // - // This cursor will be used to limit the scope of the namespace removal - // we're about to do. - auto const first_template = std::find (ns_begin, type_end, '<'); - auto const end_first_template = cruft::search::balanced (first_template, type_end, '<', '>'); + // Find the start of the first template parameter so we can cut it out. + // If this isn't present we end up with a pointer to the end of the + // type string which is the end of the type anyway. + auto const template_start = std::find (type_begin, type_end, '<'); + auto const template_end = cruft::search::balanced (template_start, type_end, '<', '>'); - // Find the end of any namespace symbols - auto const ns_symbol = std::find ( - std::make_reverse_iterator (first_template), - std::make_reverse_iterator (ns_begin), - ':' + return std::string_view ( + type_begin, + std::distance (type_begin, template_end) ); - - // Compute the start of the symbol's type and return a view over this. - auto const data = ns_symbol != std::make_reverse_iterator (ns_begin) - ? &*ns_symbol + 1 - : ns_begin + prefix.size (); - auto const size = std::distance (data, end_first_template); - return std::string_view (data, size); } + + template + constexpr + std::string_view type_name (void) + { + + auto const fullname = type_name_with_namespace (); + + constexpr char const namespace_symbol[] = "::"; + auto const last_namespace_pos = std::search ( + std::rbegin (fullname), + std::rend (fullname), + namespace_symbol + 0, + namespace_symbol + 2 + ); + + auto const length = std::distance (std::rbegin (fullname), last_namespace_pos); + auto const offset = fullname.size () - length; + return std::string_view (fullname.data () + offset, length); + } + + template <> constexpr std::string_view type_name (void) { return "i08"; } template <> constexpr std::string_view type_name (void) { return "i16"; } template <> constexpr std::string_view type_name (void) { return "i32"; } diff --git a/test/introspection.cpp b/test/introspection.cpp index 29a4b8ae..ef3920a6 100644 --- a/test/introspection.cpp +++ b/test/introspection.cpp @@ -19,6 +19,9 @@ namespace bar { struct qux { short c; }; + + template + struct templated_qux { }; } @@ -55,6 +58,19 @@ namespace cruft } +//----------------------------------------------------------------------------- +template +static +bool +equal (A &&a, B &&b) +{ + return std::equal ( + std::begin (a), std::end (a), + std::begin (b), std::end (b) + ); +} + + //----------------------------------------------------------------------------- int main () { @@ -92,7 +108,23 @@ int main () tap.expect_eq (cruft::view (cruft::type_name ()), "f64", "f64 type_name"); tap.expect_eq (cruft::view (cruft::type_name ()), "foo", "struct type_name"); - tap.expect_eq (cruft::view (cruft::type_name ()), "qux", "namespaced struct type_name"); + tap.expect_eq (cruft::view (cruft::type_name ()), "qux", "de-namespaced struct type_name"); + + tap.expect ( + equal ( + cruft::type_name_with_namespace (), + std::string_view ("bar::qux") + ), + "namespaced struct" + ); + + tap.expect ( + equal ( + cruft::type_name_with_namespace> (), + std::string_view ("bar::templated_qux") + ), + "namespaced templated struct" + ); tap.expect_eq ( cruft::type_name> (),