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 {
template <typename T>
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)
);
// 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)
);
}
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
);
// 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);
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<i16> (void) { return "i16"; }
template <> constexpr std::string_view type_name<i32> (void) { return "i32"; }

View File

@ -19,6 +19,9 @@ namespace bar {
struct qux {
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 ()
{
@ -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<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 (
cruft::type_name<templated_with_type<int>> (),