introspection: work around clang static constexpr arrays
This commit is contained in:
parent
74f7bc2e1a
commit
9116404f30
@ -18,21 +18,23 @@
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
constexpr const char* ::util::type_name<bool>::value;
|
constexpr const char ::util::detail::type_name_bool::value[];
|
||||||
|
constexpr const char ::util::detail::type_name_char::value[];
|
||||||
|
constexpr const char ::util::detail::type_name_voidp::value[];
|
||||||
|
|
||||||
constexpr const char* ::util::type_name< int8_t>::value;
|
constexpr const char ::util::detail::type_name_u08::value[];
|
||||||
constexpr const char* ::util::type_name< int16_t>::value;
|
constexpr const char ::util::detail::type_name_u16::value[];
|
||||||
constexpr const char* ::util::type_name< int32_t>::value;
|
constexpr const char ::util::detail::type_name_u32::value[];
|
||||||
constexpr const char* ::util::type_name< int64_t>::value;
|
constexpr const char ::util::detail::type_name_u64::value[];
|
||||||
|
|
||||||
constexpr const char* ::util::type_name< uint8_t>::value;
|
constexpr const char ::util::detail::type_name_s08::value[];
|
||||||
constexpr const char* ::util::type_name<uint16_t>::value;
|
constexpr const char ::util::detail::type_name_s16::value[];
|
||||||
constexpr const char* ::util::type_name<uint32_t>::value;
|
constexpr const char ::util::detail::type_name_s32::value[];
|
||||||
constexpr const char* ::util::type_name<uint64_t>::value;
|
constexpr const char ::util::detail::type_name_s64::value[];
|
||||||
|
|
||||||
constexpr const char* ::util::type_name<float>::value;
|
constexpr const char ::util::detail::type_name_f32::value[];
|
||||||
constexpr const char* ::util::type_name<double>::value;
|
constexpr const char ::util::detail::type_name_f64::value[];
|
||||||
|
|
||||||
constexpr const char* ::util::type_name<std::string>::value;
|
constexpr const char ::util::detail::type_name_string::value[];
|
||||||
constexpr const char* ::util::type_name<char*>::value;
|
constexpr const char ::util::detail::type_name_cstring::value[];
|
||||||
constexpr const char* ::util::type_name<const char*>::value;
|
constexpr const char ::util::detail::type_name_const_cstring::value[];
|
||||||
|
@ -26,36 +26,48 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
// XXX: we should be using a const char[] here, but clang-3.9 will not
|
// XXX: clang-3.9/clang-4.0 will not instantiate static constexpr member
|
||||||
// instantiate array values within template specialisations.
|
// variables from class specialisations, so we have to use detail classes
|
||||||
|
// to hold the variables and instantiate _those_ members instead.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct type_name;
|
struct type_name;
|
||||||
|
|
||||||
template <> struct type_name<bool> { static constexpr const char *value = "bool"; };
|
#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 { };
|
||||||
|
|
||||||
template <> struct type_name<char> { static constexpr const char *value = "char"; };
|
CLANG_WORKAROUND(bool,bool,"bool")
|
||||||
template <> struct type_name<void*> { static constexpr const char *value = "void*"; };
|
CLANG_WORKAROUND(char,char,"char")
|
||||||
|
CLANG_WORKAROUND(void*,voidp,"void*")
|
||||||
|
|
||||||
template <> struct type_name< int8_t> { static constexpr const char *value = "int8"; };
|
CLANG_WORKAROUND( uint8_t, u08, "u08")
|
||||||
template <> struct type_name< int16_t> { static constexpr const char *value = "int16"; };
|
CLANG_WORKAROUND(uint16_t, u16, "u16")
|
||||||
template <> struct type_name< int32_t> { static constexpr const char *value = "int32"; };
|
CLANG_WORKAROUND(uint32_t, u32, "u32")
|
||||||
template <> struct type_name< int64_t> { static constexpr const char *value = "int64"; };
|
CLANG_WORKAROUND(uint64_t, u64, "u64")
|
||||||
|
|
||||||
template <> struct type_name< uint8_t> { static constexpr const char *value = "uint8"; };
|
CLANG_WORKAROUND( int8_t, s08, "s08")
|
||||||
template <> struct type_name<uint16_t> { static constexpr const char *value = "uint16"; };
|
CLANG_WORKAROUND(int16_t, s16, "s16")
|
||||||
template <> struct type_name<uint32_t> { static constexpr const char *value = "uint32"; };
|
CLANG_WORKAROUND(int32_t, s32, "s32")
|
||||||
template <> struct type_name<uint64_t> { static constexpr const char *value = "uint64"; };
|
CLANG_WORKAROUND(int64_t, s64, "s64")
|
||||||
|
|
||||||
template <> struct type_name<float > { static constexpr const char *value = "float32"; };
|
CLANG_WORKAROUND(float, f32, "f32")
|
||||||
template <> struct type_name<double > { static constexpr const char *value = "float64"; };
|
CLANG_WORKAROUND(double, f64, "f64")
|
||||||
|
|
||||||
template <> struct type_name<std::string> { static constexpr const char *value = "string"; };
|
CLANG_WORKAROUND(const char*, const_cstring, "cstring")
|
||||||
template <> struct type_name<char*> { static constexpr const char *value = "cstring"; };
|
CLANG_WORKAROUND(char*, cstring, "cstring")
|
||||||
template <> struct type_name<const char*> { static constexpr const char *value = "cstring"; };
|
CLANG_WORKAROUND(std::string, string, "string")
|
||||||
|
|
||||||
|
#undef CLANG_WORKAROUND
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr
|
constexpr
|
||||||
const char* type_name_v = type_name<T>::value;
|
auto type_name_v = type_name<T>::value;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const char*
|
const char*
|
||||||
@ -67,42 +79,47 @@ namespace util {
|
|||||||
/// Lists valid values of an enumeration
|
/// Lists valid values of an enumeration
|
||||||
///
|
///
|
||||||
/// E: enumeration type
|
/// E: enumeration type
|
||||||
template <
|
|
||||||
typename E
|
|
||||||
>
|
|
||||||
struct enum_traits {
|
|
||||||
/// Specialisations must provide the following constexpr:
|
|
||||||
///
|
///
|
||||||
|
/// Specialisations must provide the following constexpr:
|
||||||
/// value_type: typename
|
/// value_type: typename
|
||||||
/// value_count: size_t
|
/// value_count: size_t
|
||||||
/// values: static const std::array<value_type,value_count>
|
/// values: static const std::array<value_type,value_count>
|
||||||
};
|
template <
|
||||||
|
typename E
|
||||||
|
>
|
||||||
|
struct enum_traits;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/// Defines specialisations for introspection data structures for an
|
/// Defines specialisations for introspection data structures for an
|
||||||
/// enum E, in namespace NS, with variadic values __VA_ARGS__.
|
/// enum E, in namespace NS, with variadic values __VA_ARGS__.
|
||||||
///
|
///
|
||||||
/// Expects to be caleld from outside all namespaces.
|
/// Expects to be caleld from outside all namespaces.
|
||||||
|
///
|
||||||
|
/// XXX: If we define the constexpr fields in a template specialised class
|
||||||
|
/// clang has trouble instantiating them (with std=c++1z) resulting in
|
||||||
|
/// undefined symbols at link time. By using a simple struct and inheriting
|
||||||
|
/// from it we can avoid this problem. Revist this solution at clang-4.0.
|
||||||
|
|
||||||
#define INTROSPECTION_ENUM_DECL(NS,E, ...) \
|
#define INTROSPECTION_ENUM_DECL(NS,E, ...) \
|
||||||
namespace util { \
|
namespace util { \
|
||||||
template <> \
|
struct PASTE(__enum_traits_,E) { \
|
||||||
struct enum_traits<::NS::E> { \
|
|
||||||
using value_type = ::NS::E; \
|
using value_type = ::NS::E; \
|
||||||
\
|
\
|
||||||
static constexpr \
|
static constexpr \
|
||||||
size_t value_count = VA_ARGS_COUNT(__VA_ARGS__); \
|
size_t value_count = VA_ARGS_COUNT(__VA_ARGS__); \
|
||||||
\
|
\
|
||||||
static constexpr \
|
static const \
|
||||||
std::array<value_type,value_count> \
|
std::array<value_type,value_count> \
|
||||||
values = { \
|
values; \
|
||||||
MAP1(NAMESPACE_LIST, ::NS::E, __VA_ARGS__) \
|
\
|
||||||
|
static const \
|
||||||
|
std::array<const char*,value_count> \
|
||||||
|
names; \
|
||||||
}; \
|
}; \
|
||||||
\
|
\
|
||||||
static constexpr \
|
template <> \
|
||||||
std::array<const char*,value_count> \
|
struct enum_traits<::NS::E> : public PASTE(__enum_traits_,E) \
|
||||||
names = { MAP(STRINGIZE_LIST, __VA_ARGS__) }; \
|
{ }; \
|
||||||
}; \
|
|
||||||
\
|
\
|
||||||
template <> \
|
template <> \
|
||||||
struct type_name<::NS::E> { \
|
struct type_name<::NS::E> { \
|
||||||
@ -116,20 +133,23 @@ namespace util {
|
|||||||
/// Declares specialisations for introspection data structures for an
|
/// Declares specialisations for introspection data structures for an
|
||||||
/// enum E, in namespace NS, with variadic values __VA_ARGS__.
|
/// enum E, in namespace NS, with variadic values __VA_ARGS__.
|
||||||
///
|
///
|
||||||
/// Expects to be caleld from outside all namespaces.
|
/// Expects to be called from outside all namespaces.
|
||||||
|
|
||||||
#define INTROSPECTION_ENUM_IMPL(NS,E, ...) \
|
#define INTROSPECTION_ENUM_IMPL(NS,E, ...) \
|
||||||
constexpr \
|
constexpr \
|
||||||
std::array< \
|
std::array< \
|
||||||
util::enum_traits<::NS::E>::value_type, \
|
util::enum_traits<::NS::E>::value_type, \
|
||||||
util::enum_traits<::NS::E>::value_count \
|
util::enum_traits<::NS::E>::value_count \
|
||||||
> util::enum_traits<::NS::E>::values; \
|
> PASTE(util::__enum_traits_,E)::values = { \
|
||||||
|
MAP1(NAMESPACE_LIST, ::NS::E, __VA_ARGS__) \
|
||||||
|
}; \
|
||||||
\
|
\
|
||||||
constexpr \
|
const \
|
||||||
std::array< \
|
std::array< \
|
||||||
const char*, \
|
const char*, \
|
||||||
util::enum_traits<::NS::E>::value_count \
|
util::enum_traits<::NS::E>::value_count \
|
||||||
> util::enum_traits<::NS::E>::names; \
|
> PASTE(util::__enum_traits_,E)::names = { \
|
||||||
|
MAP(STRINGIZE_LIST, __VA_ARGS__) \
|
||||||
|
}; \
|
||||||
\
|
\
|
||||||
constexpr \
|
constexpr \
|
||||||
const char util::type_name<::NS::E>::ns[]; \
|
const char util::type_name<::NS::E>::ns[]; \
|
||||||
|
Loading…
Reference in New Issue
Block a user