introspection: add type_name_with_namespace

This commit is contained in:
Danny Robson 2020-09-24 14:40:56 +10:00
parent 43f5db1cc1
commit 43b8e8f6f2
2 changed files with 71 additions and 29 deletions

View File

@ -27,7 +27,7 @@
namespace cruft { namespace cruft {
template <typename T> template <typename T>
constexpr constexpr
std::string_view type_name (void) std::string_view type_name_with_namespace (void)
{ {
std::string_view pretty_function (__PRETTY_FUNCTION__); std::string_view pretty_function (__PRETTY_FUNCTION__);
@ -43,49 +43,59 @@ namespace cruft {
#error "Unsupported compiler" #error "Unsupported compiler"
#endif #endif
// Find the location where the type begins. It will also mark the start of // Find the location where the type begins.
// the type's namespace if the type has one. auto const type_begin = std::search (
auto const ns_begin = std::search (
pretty_function.begin (), pretty_function.begin (),
pretty_function.end (), pretty_function.end (),
prefix.begin (), prefix.begin (),
prefix.end () prefix.end ()
); ) + prefix.size ();
// Find the point the type name ends. Both use ']', but gcc lists // 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[] = ";]"; char const suffixes[] = ";]";
auto const type_end = std::find_first_of ( auto const type_end = std::find_first_of (
ns_begin, type_begin,
pretty_function.end (), pretty_function.end (),
std::begin (suffixes), std::begin (suffixes),
std::end (suffixes) std::end (suffixes)
); );
// Find the start of the first template parameter (or the end of the // Find the start of the first template parameter so we can cut it out.
// string otherwise), and the end of the template parameters for this // If this isn't present we end up with a pointer to the end of the
// type. // type string which is the end of the type anyway.
// auto const template_start = std::find (type_begin, type_end, '<');
// This cursor will be used to limit the scope of the namespace removal auto const template_end = cruft::search::balanced (template_start, type_end, '<', '>');
// 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 end of any namespace symbols return std::string_view (
auto const ns_symbol = std::find ( type_begin,
std::make_reverse_iterator (first_template), std::distance (type_begin, template_end)
std::make_reverse_iterator (ns_begin),
':'
); );
// 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 <typename T>
constexpr
std::string_view type_name (void)
{
auto const fullname = type_name_with_namespace<T> ();
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<i08> (void) { return "i08"; } template <> constexpr std::string_view type_name<i08> (void) { return "i08"; }
template <> constexpr std::string_view type_name<i16> (void) { return "i16"; } template <> constexpr std::string_view type_name<i16> (void) { return "i16"; }
template <> constexpr std::string_view type_name<i32> (void) { return "i32"; } template <> constexpr std::string_view type_name<i32> (void) { return "i32"; }

View File

@ -19,6 +19,9 @@ namespace bar {
struct qux { struct qux {
short c; short c;
}; };
template <typename>
struct templated_qux { };
} }
@ -55,6 +58,19 @@ namespace cruft
} }
//-----------------------------------------------------------------------------
template <typename A, typename B>
static
bool
equal (A &&a, B &&b)
{
return std::equal (
std::begin (a), std::end (a),
std::begin (b), std::end (b)
);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
int main () int main ()
{ {
@ -92,7 +108,23 @@ int main ()
tap.expect_eq (cruft::view (cruft::type_name<f64> ()), "f64", "f64 type_name"); tap.expect_eq (cruft::view (cruft::type_name<f64> ()), "f64", "f64 type_name");
tap.expect_eq (cruft::view (cruft::type_name<foo> ()), "foo", "struct type_name"); tap.expect_eq (cruft::view (cruft::type_name<foo> ()), "foo", "struct type_name");
tap.expect_eq (cruft::view (cruft::type_name<bar::qux> ()), "qux", "namespaced struct type_name"); tap.expect_eq (cruft::view (cruft::type_name<bar::qux> ()), "qux", "de-namespaced struct type_name");
tap.expect (
equal (
cruft::type_name_with_namespace<bar::qux> (),
std::string_view ("bar::qux")
),
"namespaced struct"
);
tap.expect (
equal (
cruft::type_name_with_namespace<bar::templated_qux<int>> (),
std::string_view ("bar::templated_qux<int>")
),
"namespaced templated struct"
);
tap.expect_eq ( tap.expect_eq (
cruft::type_name<templated_with_type<int>> (), cruft::type_name<templated_with_type<int>> (),