introspection: use __FUNCTION__ parsing method for type_name queries
This commit is contained in:
parent
1cd107d27e
commit
71c44b3293
@ -137,7 +137,7 @@ namespace cruft::cmdopt {
|
||||
{
|
||||
static const std::string EXAMPLE =
|
||||
std::string {"<"} +
|
||||
std::string {to_string<T> ()} +
|
||||
std::string {type_name<T> ()} +
|
||||
std::string {">"};
|
||||
|
||||
return EXAMPLE;
|
||||
|
@ -6,74 +6,86 @@
|
||||
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_INTROSPECTION_HPP
|
||||
#define __UTIL_INTROSPECTION_HPP
|
||||
#pragma once
|
||||
|
||||
#include "std.hpp"
|
||||
#include "variadic.hpp"
|
||||
|
||||
#include <cruft/util/preprocessor.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace cruft {
|
||||
// clang#18781: clang-3.9/clang-4.0 will not instantiate static constexpr
|
||||
// member variables from class specialisations, so we have to use detail
|
||||
// classes to hold the variables and instantiate _those_ members instead.
|
||||
template <typename T>
|
||||
struct type_name;
|
||||
|
||||
#define CLANG_WORKAROUND(TYPE,TAG,NAME) \
|
||||
namespace detail { \
|
||||
struct type_name_##TAG { \
|
||||
static constexpr const char value[] = (NAME); \
|
||||
}; \
|
||||
} \
|
||||
\
|
||||
template <> \
|
||||
struct type_name<TYPE> : public detail::type_name_##TAG { };
|
||||
|
||||
CLANG_WORKAROUND(bool,bool,"bool")
|
||||
CLANG_WORKAROUND(char,char,"char")
|
||||
CLANG_WORKAROUND(void*,voidp,"void*")
|
||||
|
||||
CLANG_WORKAROUND( uint8_t, u08, "u08")
|
||||
CLANG_WORKAROUND(uint16_t, u16, "u16")
|
||||
CLANG_WORKAROUND(uint32_t, u32, "u32")
|
||||
CLANG_WORKAROUND(uint64_t, u64, "u64")
|
||||
|
||||
CLANG_WORKAROUND( int8_t, s08, "i08")
|
||||
CLANG_WORKAROUND(int16_t, s16, "i16")
|
||||
CLANG_WORKAROUND(int32_t, s32, "i32")
|
||||
CLANG_WORKAROUND(int64_t, s64, "i64")
|
||||
|
||||
CLANG_WORKAROUND(float, f32, "f32")
|
||||
CLANG_WORKAROUND(double, f64, "f64")
|
||||
|
||||
CLANG_WORKAROUND(const char*, const_cstring, "cstring")
|
||||
CLANG_WORKAROUND(char*, cstring, "cstring")
|
||||
CLANG_WORKAROUND(std::string, string, "string")
|
||||
CLANG_WORKAROUND(std::filesystem::path, path, "path");
|
||||
|
||||
CLANG_WORKAROUND(std::byte, byte, "byte");
|
||||
|
||||
#undef CLANG_WORKAROUND
|
||||
|
||||
template <typename T>
|
||||
constexpr
|
||||
auto type_name_v = type_name<T>::value;
|
||||
std::string_view type_name (void)
|
||||
{
|
||||
std::string_view pretty_function (__PRETTY_FUNCTION__);
|
||||
|
||||
template <typename T>
|
||||
const char*
|
||||
to_string (void)
|
||||
{ return type_name_v<T>; }
|
||||
#ifdef __clang__
|
||||
std::string_view const prefix = "[T = ";
|
||||
#elif defined(__GNUC__)
|
||||
std::string_view prefix = "[with T = ";
|
||||
#else
|
||||
#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 (
|
||||
pretty_function.begin (),
|
||||
pretty_function.end (),
|
||||
prefix.begin (),
|
||||
prefix.end ()
|
||||
);
|
||||
|
||||
// Find the point the type name ends. Both use ']', but gcc lists
|
||||
// std::string_view too and so requires the delimiting ';' as a suffix.
|
||||
char const suffixes[] = ";]";
|
||||
auto const type_end = std::find_first_of (
|
||||
ns_begin,
|
||||
pretty_function.end (),
|
||||
std::begin (suffixes),
|
||||
std::end (suffixes)
|
||||
);
|
||||
|
||||
// Find the end of any namespace symbols
|
||||
auto const ns_symbol = std::find (
|
||||
std::make_reverse_iterator (type_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, type_end);
|
||||
return std::string_view (data, size);
|
||||
}
|
||||
|
||||
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"; }
|
||||
template <> constexpr std::string_view type_name<i64> (void) { return "i64"; }
|
||||
|
||||
template <> constexpr std::string_view type_name<u08> (void) { return "u08"; }
|
||||
template <> constexpr std::string_view type_name<u16> (void) { return "u16"; }
|
||||
template <> constexpr std::string_view type_name<u32> (void) { return "u32"; }
|
||||
template <> constexpr std::string_view type_name<u64> (void) { return "u64"; }
|
||||
|
||||
template <> constexpr std::string_view type_name<f32> (void) { return "f32"; }
|
||||
template <> constexpr std::string_view type_name<f64> (void) { return "f64"; }
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -141,12 +153,6 @@ namespace cruft {
|
||||
template <> \
|
||||
struct enum_traits<::NS::E> : public PASTE(__enum_traits_,E) \
|
||||
{ }; \
|
||||
\
|
||||
template <> \
|
||||
struct type_name<::NS::E> { \
|
||||
static constexpr const char ns[] = #NS; \
|
||||
static constexpr const char value[] = #E; \
|
||||
}; \
|
||||
} \
|
||||
|
||||
|
||||
@ -440,5 +446,3 @@ namespace cruft {
|
||||
template <typename K>
|
||||
auto as_tuple (K&&) = delete;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,11 @@
|
||||
#include "introspection.hpp"
|
||||
#include "tap.hpp"
|
||||
#include "std.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "tap.hpp"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// simple test struct of scalars
|
||||
struct foo
|
||||
{
|
||||
@ -11,6 +15,14 @@ struct foo
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
namespace bar {
|
||||
struct qux {
|
||||
short c;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// define introspection data
|
||||
namespace cruft
|
||||
{
|
||||
@ -51,5 +63,21 @@ int main ()
|
||||
"dynamic member access after conversion to tuple");
|
||||
}
|
||||
|
||||
tap.expect_eq (cruft::view (cruft::type_name<i08> ()), "i08", "i08 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::type_name<i16> ()), "i16", "i16 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::type_name<i32> ()), "i32", "i32 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::type_name<i64> ()), "i64", "i64 type_name");
|
||||
|
||||
tap.expect_eq (cruft::view (cruft::type_name<u08> ()), "u08", "u08 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::type_name<u16> ()), "u16", "u16 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::type_name<u32> ()), "u32", "u32 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::type_name<u64> ()), "u64", "u64 type_name");
|
||||
|
||||
tap.expect_eq (cruft::view (cruft::type_name<f32> ()), "f32", "f32 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<bar::qux> ()), "qux", "namespaced struct type_name");
|
||||
|
||||
return tap.status ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user