introspection: split the header into functional groups
This commit is contained in:
parent
43b8e8f6f2
commit
04de102789
@ -398,8 +398,12 @@ list (
|
||||
hash/xxhash.hpp
|
||||
init.cpp
|
||||
init.hpp
|
||||
introspection.cpp
|
||||
introspection.hpp
|
||||
introspection/enum.cpp
|
||||
introspection/enum.hpp
|
||||
introspection/name.cpp
|
||||
introspection/name.hpp
|
||||
introspection/type.cpp
|
||||
introspection/type.hpp
|
||||
io.cpp
|
||||
io.hpp
|
||||
iterator/cast.hpp
|
||||
|
14
cmdopt.hpp
14
cmdopt.hpp
@ -6,10 +6,10 @@
|
||||
* Copyright 2013-2016 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef CRUFT_UTIL_CMDLINE_HPP
|
||||
#define CRUFT_UTIL_CMDLINE_HPP
|
||||
#pragma once
|
||||
|
||||
#include "introspection.hpp"
|
||||
#include "introspection/name.hpp"
|
||||
#include "introspection/enum.hpp"
|
||||
#include "iterator/infix.hpp"
|
||||
|
||||
#include <exception>
|
||||
@ -156,7 +156,7 @@ namespace cruft::cmdopt {
|
||||
{
|
||||
static const std::string EXAMPLE =
|
||||
std::string {"<"} +
|
||||
std::string {type_name<T> ()} +
|
||||
std::string {cruft::introspection::name::bare<T> ()} +
|
||||
std::string {">"};
|
||||
|
||||
return EXAMPLE;
|
||||
@ -168,8 +168,8 @@ namespace cruft::cmdopt {
|
||||
{
|
||||
static const std::string EXAMPLE = [] (void) {
|
||||
std::ostringstream os;
|
||||
std::copy (std::cbegin (enum_traits<T>::names),
|
||||
std::cend (enum_traits<T>::names),
|
||||
std::copy (std::cbegin (introspection::enum_traits<T>::names),
|
||||
std::cend (introspection::enum_traits<T>::names),
|
||||
iterator::infix_iterator<const char*> (os, "|"));
|
||||
return os.str ();
|
||||
} ();
|
||||
@ -360,5 +360,3 @@ namespace cruft::cmdopt {
|
||||
std::vector<entry> m_options;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -3,7 +3,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
|
||||
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#include "introspection.hpp"
|
||||
#include "./enum.hpp"
|
@ -8,128 +8,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "std.hpp"
|
||||
#include "algo/search.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cruft/util/preprocessor.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace cruft {
|
||||
template <typename T>
|
||||
constexpr
|
||||
std::string_view type_name_with_namespace (void)
|
||||
{
|
||||
std::string_view pretty_function (__PRETTY_FUNCTION__);
|
||||
|
||||
#ifdef __clang__
|
||||
// PRETTY_FUNCTION = std::string_view cruft::type_name() [T = std::__1::vector<int, std::__1::allocator<int> >]
|
||||
|
||||
std::string_view const prefix = "[T = ";
|
||||
#elif defined(__GNUC__)
|
||||
// PRETTY_FUNCTION = "constexpr std::string_view cruft::type_name() [with T = std::__debug::vector<int>; std::string_view = std::basic_string_view<char>]"
|
||||
|
||||
std::string_view prefix = "[with T = ";
|
||||
#else
|
||||
#error "Unsupported compiler"
|
||||
#endif
|
||||
|
||||
// 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 in the function signature too and so requires the
|
||||
// delimiting ';' as a suffix.
|
||||
char const suffixes[] = ";]";
|
||||
auto const type_end = std::find_first_of (
|
||||
type_begin,
|
||||
pretty_function.end (),
|
||||
std::begin (suffixes),
|
||||
std::end (suffixes)
|
||||
);
|
||||
|
||||
// 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, '<', '>');
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
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"; }
|
||||
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"; }
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
struct type_char;
|
||||
|
||||
template <> struct type_char<float > { static constexpr char value = 'f'; };
|
||||
template <> struct type_char<double> { static constexpr char value = 'd'; };
|
||||
|
||||
template <> struct type_char< int8_t> { static constexpr char value = 'i'; };
|
||||
template <> struct type_char< int16_t> { static constexpr char value = 'i'; };
|
||||
template <> struct type_char< int32_t> { static constexpr char value = 'i'; };
|
||||
template <> struct type_char< int64_t> { static constexpr char value = 'i'; };
|
||||
|
||||
template <> struct type_char< uint8_t> { static constexpr char value = 'u'; };
|
||||
template <> struct type_char<uint16_t> { static constexpr char value = 'u'; };
|
||||
template <> struct type_char<uint32_t> { static constexpr char value = 'u'; };
|
||||
template <> struct type_char<uint64_t> { static constexpr char value = 'u'; };
|
||||
|
||||
template <typename T>
|
||||
constexpr auto type_char_v = type_char<T>::value;
|
||||
|
||||
namespace cruft::introspection {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// Lists valid values of an enumeration
|
||||
///
|
||||
@ -141,7 +24,7 @@ namespace cruft {
|
||||
/// values: static const std::array<value_type,value_count>
|
||||
template <
|
||||
typename E
|
||||
>
|
||||
>
|
||||
struct enum_traits;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -156,7 +39,7 @@ namespace cruft {
|
||||
/// from it we can avoid this problem. Revist this solution at clang-4.0.
|
||||
|
||||
#define INTROSPECTION_ENUM_DECL(NS,E, ...) \
|
||||
namespace cruft { \
|
||||
namespace cruft::introspection { \
|
||||
struct PASTE(__enum_traits_,E) { \
|
||||
using value_type = ::NS::E; \
|
||||
\
|
||||
@ -186,17 +69,17 @@ namespace cruft {
|
||||
#define INTROSPECTION_ENUM_IMPL(NS,E, ...) \
|
||||
const \
|
||||
std::array< \
|
||||
cruft::enum_traits<::NS::E>::value_type, \
|
||||
cruft::enum_traits<::NS::E>::value_count \
|
||||
> PASTE(cruft::__enum_traits_,E)::values = { \
|
||||
cruft::introspection::enum_traits<::NS::E>::value_type, \
|
||||
cruft::introspection::enum_traits<::NS::E>::value_count \
|
||||
> PASTE(cruft::introspection::__enum_traits_,E)::values = { \
|
||||
MAP1(NAMESPACE_LIST, ::NS::E, __VA_ARGS__) \
|
||||
}; \
|
||||
\
|
||||
const \
|
||||
std::array< \
|
||||
const char*, \
|
||||
cruft::enum_traits<::NS::E>::value_count \
|
||||
> PASTE(cruft::__enum_traits_,E)::names = { \
|
||||
cruft::introspection::enum_traits<::NS::E>::value_count \
|
||||
> PASTE(cruft::introspection::__enum_traits_,E)::names = { \
|
||||
MAP0(STRINGIZE_LIST, __VA_ARGS__) \
|
||||
};
|
||||
|
||||
@ -213,38 +96,38 @@ namespace cruft {
|
||||
///
|
||||
/// For trivial enumerations INTROSPECTION_ENUM may be easier to use.
|
||||
|
||||
#define INTROSPECTION_ENUM_ISTREAM(NS,E) \
|
||||
std::istream& \
|
||||
::NS::operator>> (std::istream &is, ::NS::E &e) \
|
||||
{ \
|
||||
using traits = ::cruft::enum_traits<::NS::E>; \
|
||||
\
|
||||
std::string name; \
|
||||
is >> name; \
|
||||
\
|
||||
std::transform (std::begin (name), \
|
||||
std::end (name), \
|
||||
std::begin (name), \
|
||||
::toupper); \
|
||||
\
|
||||
auto name_pos = std::find ( \
|
||||
std::cbegin (traits::names), \
|
||||
std::cend (traits::names), \
|
||||
name \
|
||||
); \
|
||||
\
|
||||
if (name_pos == std::cend (traits::names)) { \
|
||||
is.setstate (std::istream::failbit); \
|
||||
} else { \
|
||||
auto d = std::distance ( \
|
||||
std::begin (traits::names), \
|
||||
name_pos \
|
||||
); \
|
||||
\
|
||||
e = traits::values[d]; \
|
||||
} \
|
||||
\
|
||||
return is; \
|
||||
#define INTROSPECTION_ENUM_ISTREAM(NS,E) \
|
||||
std::istream& \
|
||||
::NS::operator>> (std::istream &is, ::NS::E &e) \
|
||||
{ \
|
||||
using traits = ::cruft::introspection::enum_traits<::NS::E>; \
|
||||
\
|
||||
std::string name; \
|
||||
is >> name; \
|
||||
\
|
||||
std::transform (std::begin (name), \
|
||||
std::end (name), \
|
||||
std::begin (name), \
|
||||
::toupper); \
|
||||
\
|
||||
auto name_pos = std::find ( \
|
||||
std::cbegin (traits::names), \
|
||||
std::cend (traits::names), \
|
||||
name \
|
||||
); \
|
||||
\
|
||||
if (name_pos == std::cend (traits::names)) { \
|
||||
is.setstate (std::istream::failbit); \
|
||||
} else { \
|
||||
auto d = std::distance ( \
|
||||
std::begin (traits::names), \
|
||||
name_pos \
|
||||
); \
|
||||
\
|
||||
e = traits::values[d]; \
|
||||
} \
|
||||
\
|
||||
return is; \
|
||||
}
|
||||
|
||||
|
||||
@ -253,35 +136,36 @@ namespace cruft {
|
||||
///
|
||||
/// Expects to be called from outside all namespaces.
|
||||
///
|
||||
/// The user is responsible for specialising the ::cruft::enum_traits<NS::E>
|
||||
/// parameters which are used to drive the implementation (eg, through
|
||||
/// INTROSPECTION_ENUM_DECL, and INTROSPECTION_ENUM_IMPL).
|
||||
/// The user is responsible for specialising the
|
||||
/// ::cruft::introspection:;enum_traits<NS::E> parameters which are used
|
||||
/// to drive the implementation (eg, through INTROSPECTION_ENUM_DECL,
|
||||
/// and INTROSPECTION_ENUM_IMPL).
|
||||
///
|
||||
/// For trivial enumerations INTROSPECTION_ENUM may be easier to use.
|
||||
#define INTROSPECTION_ENUM_OSTREAM(NS,E) \
|
||||
std::ostream& \
|
||||
::NS::operator<< (std::ostream &os, ::NS::E e) \
|
||||
{ \
|
||||
using traits = ::cruft::enum_traits<::NS::E>; \
|
||||
\
|
||||
auto val_pos = std::find ( \
|
||||
std::cbegin (traits::values), \
|
||||
std::cend (traits::values), \
|
||||
e \
|
||||
); \
|
||||
\
|
||||
if (val_pos == std::cend (traits::values)) { \
|
||||
os.setstate (std::ostream::failbit); \
|
||||
} else { \
|
||||
auto d = std::distance ( \
|
||||
std::cbegin (traits::values), \
|
||||
val_pos \
|
||||
); \
|
||||
\
|
||||
os << traits::names[d]; \
|
||||
} \
|
||||
\
|
||||
return os; \
|
||||
#define INTROSPECTION_ENUM_OSTREAM(NS,E) \
|
||||
std::ostream& \
|
||||
::NS::operator<< (std::ostream &os, ::NS::E e) \
|
||||
{ \
|
||||
using traits = ::cruft::introspection::enum_traits<::NS::E>;\
|
||||
\
|
||||
auto val_pos = std::find ( \
|
||||
std::cbegin (traits::values), \
|
||||
std::cend (traits::values), \
|
||||
e \
|
||||
); \
|
||||
\
|
||||
if (val_pos == std::cend (traits::values)) { \
|
||||
os.setstate (std::ostream::failbit); \
|
||||
} else { \
|
||||
auto d = std::distance ( \
|
||||
std::cbegin (traits::values), \
|
||||
val_pos \
|
||||
); \
|
||||
\
|
||||
os << traits::names[d]; \
|
||||
} \
|
||||
\
|
||||
return os; \
|
||||
}
|
||||
|
||||
|
||||
@ -318,153 +202,4 @@ namespace cruft {
|
||||
INTROSPECTION_ENUM_IMPL(detail_intr_enum,E,__VA_ARGS__) \
|
||||
INTROSPECTION_ENUM_ISTREAM(detail_intr_enum,E) \
|
||||
INTROSPECTION_ENUM_OSTREAM(detail_intr_enum,E)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// Describes a single member variable in a type availabe for introspection
|
||||
///
|
||||
/// K: target class
|
||||
/// R: member type
|
||||
/// M: pointer-to-member
|
||||
template <
|
||||
class K,
|
||||
typename R,
|
||||
R K::*M
|
||||
>
|
||||
struct field
|
||||
{
|
||||
typedef K klass;
|
||||
typedef R type;
|
||||
|
||||
static const std::string name;
|
||||
|
||||
static const R& get (const K &k) { return k.*M; }
|
||||
static R& get ( K &k) { return k.*M; }
|
||||
static R& get ( K &&) = delete;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// Holds the fields of a type available for introspection
|
||||
///
|
||||
/// Specialise the following type struct with a 'fields' tuple of the
|
||||
/// members that should be accessed like below:
|
||||
///
|
||||
/// struct foo { int a; int b; };
|
||||
///
|
||||
/// template <> struct type<foo>
|
||||
/// {
|
||||
/// typedef std::tuple<
|
||||
/// field<foo,int,&foo::a>,
|
||||
/// field<foo,int,&foo::b>
|
||||
/// > fields;
|
||||
/// };
|
||||
///
|
||||
/// template <> const std::string field<foo,int,&foo::a>::name = "a";
|
||||
/// template <> const std::string field<foo,int,&foo::b>::name = "b";
|
||||
|
||||
template <class K>
|
||||
struct type { };
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// traits class which converts an introspected type to a tuple
|
||||
///
|
||||
/// K: target class
|
||||
|
||||
template <typename K>
|
||||
struct type_tuple;
|
||||
|
||||
template <
|
||||
typename ...T
|
||||
> struct type_tuple<
|
||||
std::tuple<T...>
|
||||
> {
|
||||
typedef std::tuple<T...> type;
|
||||
};
|
||||
|
||||
|
||||
template <
|
||||
typename K,
|
||||
typename I = typename std::make_index_sequence<
|
||||
std::tuple_size<
|
||||
typename type<K>::fields
|
||||
>::value
|
||||
>
|
||||
> struct _type_tuple;
|
||||
|
||||
template <
|
||||
typename K,
|
||||
size_t ...I
|
||||
> struct _type_tuple <
|
||||
K,
|
||||
std::index_sequence<I...>
|
||||
> {
|
||||
typedef std::tuple<
|
||||
typename std::tuple_element<
|
||||
I,
|
||||
typename type<K>::fields
|
||||
>::type::type...
|
||||
> type;
|
||||
};
|
||||
|
||||
|
||||
template <
|
||||
typename K
|
||||
> struct type_tuple {
|
||||
typedef typename _type_tuple<K>::type type;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace detail {
|
||||
template <
|
||||
typename K,
|
||||
typename I = typename std::make_index_sequence<
|
||||
std::tuple_size<
|
||||
typename type<K>::fields
|
||||
>::value
|
||||
>
|
||||
>
|
||||
struct _as_tuple;
|
||||
|
||||
template <
|
||||
typename K,
|
||||
size_t ...I
|
||||
>
|
||||
struct _as_tuple <
|
||||
K,
|
||||
std::index_sequence<I...>
|
||||
>
|
||||
{
|
||||
static typename type_tuple<K>::type
|
||||
make (const K &k)
|
||||
{
|
||||
return std::make_tuple (
|
||||
std::tuple_element<I, typename type<K>::fields>::type::get (k)...
|
||||
);
|
||||
}
|
||||
|
||||
static auto make (K&&) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
/// Convert an introspection capable class instance into a tuple instance
|
||||
///
|
||||
/// K: source class
|
||||
template <typename K>
|
||||
auto
|
||||
as_tuple (const K &k)
|
||||
{
|
||||
return detail::_as_tuple<K>::make (k);
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
auto as_tuple (K &_k)
|
||||
{
|
||||
const K &k = _k;
|
||||
return as_tuple (k);
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
auto as_tuple (K&&) = delete;
|
||||
}
|
9
introspection/name.cpp
Normal file
9
introspection/name.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2019-2020 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#include "./name.hpp"
|
124
introspection/name.hpp
Normal file
124
introspection/name.hpp
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2019-2020 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../algo/search.hpp"
|
||||
#include "../std.hpp"
|
||||
|
||||
#include <string_view>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace cruft::introspection::name {
|
||||
template <typename T>
|
||||
constexpr
|
||||
std::string_view full (void)
|
||||
{
|
||||
std::string_view pretty_function (__PRETTY_FUNCTION__);
|
||||
|
||||
#ifdef __clang__
|
||||
// PRETTY_FUNCTION = std::string_view cruft::type_name() [T = std::__1::vector<int, std::__1::allocator<int> >]
|
||||
|
||||
std::string_view const prefix = "[T = ";
|
||||
#elif defined(__GNUC__)
|
||||
// PRETTY_FUNCTION = "constexpr std::string_view cruft::type_name() [with T = std::__debug::vector<int>; std::string_view = std::basic_string_view<char>]"
|
||||
|
||||
std::string_view prefix = "[with T = ";
|
||||
#else
|
||||
#error "Unsupported compiler"
|
||||
#endif
|
||||
|
||||
// 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 in the function signature too and so requires the
|
||||
// delimiting ';' as a suffix.
|
||||
char const suffixes[] = ";]";
|
||||
auto const type_end = std::find_first_of (
|
||||
type_begin,
|
||||
pretty_function.end (),
|
||||
std::begin (suffixes),
|
||||
std::end (suffixes)
|
||||
);
|
||||
|
||||
// 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, '<', '>');
|
||||
|
||||
return std::string_view (
|
||||
type_begin,
|
||||
std::distance (type_begin, template_end)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
constexpr
|
||||
std::string_view bare (void)
|
||||
{
|
||||
|
||||
auto const fullname = full<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 bare<i08> (void) { return "i08"; }
|
||||
template <> constexpr std::string_view bare<i16> (void) { return "i16"; }
|
||||
template <> constexpr std::string_view bare<i32> (void) { return "i32"; }
|
||||
template <> constexpr std::string_view bare<i64> (void) { return "i64"; }
|
||||
|
||||
template <> constexpr std::string_view bare<u08> (void) { return "u08"; }
|
||||
template <> constexpr std::string_view bare<u16> (void) { return "u16"; }
|
||||
template <> constexpr std::string_view bare<u32> (void) { return "u32"; }
|
||||
template <> constexpr std::string_view bare<u64> (void) { return "u64"; }
|
||||
|
||||
template <> constexpr std::string_view bare<f32> (void) { return "f32"; }
|
||||
template <> constexpr std::string_view bare<f64> (void) { return "f64"; }
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
struct type_char;
|
||||
|
||||
template <> struct type_char<float > { static constexpr char value = 'f'; };
|
||||
template <> struct type_char<double> { static constexpr char value = 'd'; };
|
||||
|
||||
template <> struct type_char< int8_t> { static constexpr char value = 'i'; };
|
||||
template <> struct type_char< int16_t> { static constexpr char value = 'i'; };
|
||||
template <> struct type_char< int32_t> { static constexpr char value = 'i'; };
|
||||
template <> struct type_char< int64_t> { static constexpr char value = 'i'; };
|
||||
|
||||
template <> struct type_char< uint8_t> { static constexpr char value = 'u'; };
|
||||
template <> struct type_char<uint16_t> { static constexpr char value = 'u'; };
|
||||
template <> struct type_char<uint32_t> { static constexpr char value = 'u'; };
|
||||
template <> struct type_char<uint64_t> { static constexpr char value = 'u'; };
|
||||
|
||||
template <typename T>
|
||||
constexpr auto type_char_v = type_char<T>::value;
|
||||
}
|
0
introspection/type.cpp
Normal file
0
introspection/type.cpp
Normal file
164
introspection/type.hpp
Normal file
164
introspection/type.hpp
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace cruft::introspection {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// Describes a single member variable in a type availabe for introspection
|
||||
///
|
||||
/// K: target class
|
||||
/// R: member type
|
||||
/// M: pointer-to-member
|
||||
template <
|
||||
class K,
|
||||
typename R,
|
||||
R K::*M
|
||||
>
|
||||
struct field
|
||||
{
|
||||
typedef K klass;
|
||||
typedef R type;
|
||||
|
||||
static const std::string name;
|
||||
|
||||
static const R& get (const K &k) { return k.*M; }
|
||||
static R& get ( K &k) { return k.*M; }
|
||||
static R& get ( K &&) = delete;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// Holds the fields of a type available for introspection
|
||||
///
|
||||
/// Specialise the following type struct with a 'fields' tuple of the
|
||||
/// members that should be accessed like below:
|
||||
///
|
||||
/// struct foo { int a; int b; };
|
||||
///
|
||||
/// template <> struct type<foo>
|
||||
/// {
|
||||
/// typedef std::tuple<
|
||||
/// field<foo,int,&foo::a>,
|
||||
/// field<foo,int,&foo::b>
|
||||
/// > fields;
|
||||
/// };
|
||||
///
|
||||
/// template <> const std::string field<foo,int,&foo::a>::name = "a";
|
||||
/// template <> const std::string field<foo,int,&foo::b>::name = "b";
|
||||
|
||||
template <class K>
|
||||
struct type { };
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// traits class which converts an introspected type to a tuple
|
||||
///
|
||||
/// K: target class
|
||||
|
||||
template <typename K>
|
||||
struct type_tuple;
|
||||
|
||||
template <
|
||||
typename ...T
|
||||
> struct type_tuple<
|
||||
std::tuple<T...>
|
||||
> {
|
||||
typedef std::tuple<T...> type;
|
||||
};
|
||||
|
||||
|
||||
template <
|
||||
typename K,
|
||||
typename I = typename std::make_index_sequence<
|
||||
std::tuple_size<
|
||||
typename type<K>::fields
|
||||
>::value
|
||||
>
|
||||
> struct _type_tuple;
|
||||
|
||||
template <
|
||||
typename K,
|
||||
size_t ...I
|
||||
> struct _type_tuple <
|
||||
K,
|
||||
std::index_sequence<I...>
|
||||
> {
|
||||
typedef std::tuple<
|
||||
typename std::tuple_element<
|
||||
I,
|
||||
typename type<K>::fields
|
||||
>::type::type...
|
||||
> type;
|
||||
};
|
||||
|
||||
|
||||
template <
|
||||
typename K
|
||||
> struct type_tuple {
|
||||
typedef typename _type_tuple<K>::type type;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace detail {
|
||||
template <
|
||||
typename K,
|
||||
typename I = typename std::make_index_sequence<
|
||||
std::tuple_size<
|
||||
typename type<K>::fields
|
||||
>::value
|
||||
>
|
||||
>
|
||||
struct _as_tuple;
|
||||
|
||||
template <
|
||||
typename K,
|
||||
size_t ...I
|
||||
>
|
||||
struct _as_tuple <
|
||||
K,
|
||||
std::index_sequence<I...>
|
||||
>
|
||||
{
|
||||
static typename type_tuple<K>::type
|
||||
make (const K &k)
|
||||
{
|
||||
return std::make_tuple (
|
||||
std::tuple_element<I, typename type<K>::fields>::type::get (k)...
|
||||
);
|
||||
}
|
||||
|
||||
static auto make (K&&) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
/// Convert an introspection capable class instance into a tuple instance
|
||||
///
|
||||
/// K: source class
|
||||
template <typename K>
|
||||
auto
|
||||
as_tuple (const K &k)
|
||||
{
|
||||
return detail::_as_tuple<K>::make (k);
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
auto as_tuple (K &_k)
|
||||
{
|
||||
const K &k = _k;
|
||||
return as_tuple (k);
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
auto as_tuple (K&&) = delete;
|
||||
}
|
@ -11,7 +11,7 @@
|
||||
#include "fwd.hpp"
|
||||
|
||||
#include "../view.hpp"
|
||||
#include "../introspection.hpp"
|
||||
#include "../introspection/name.hpp"
|
||||
#include "../log.hpp"
|
||||
|
||||
#include <map>
|
||||
@ -181,7 +181,10 @@ namespace cruft::parse::enumeration {
|
||||
});
|
||||
|
||||
if (!success)
|
||||
LOG_WARN ("duplicate parse setup for %! was ignored", cruft::type_name<EnumT> ());
|
||||
LOG_WARN (
|
||||
"duplicate parse setup for %! was ignored",
|
||||
cruft::introspection::name::bare<EnumT> ()
|
||||
);
|
||||
|
||||
return cookie {};
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "log/log.hpp"
|
||||
#include "introspection.hpp"
|
||||
#include "introspection/name.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
@ -58,10 +58,18 @@ namespace cruft {
|
||||
);
|
||||
|
||||
if (success) {
|
||||
LOG_INFO ("Registered %! for %!", key, cruft::type_name<FactoryT> ());
|
||||
LOG_INFO (
|
||||
"Registered %! for %!",
|
||||
key,
|
||||
cruft::introspection::name::full<FactoryT> ()
|
||||
);
|
||||
return cookie { key };
|
||||
} {
|
||||
LOG_ERROR ("Unable to register %! for %!", key, cruft::type_name<FactoryT> ());
|
||||
LOG_ERROR (
|
||||
"Unable to register %! for %!",
|
||||
key,
|
||||
cruft::introspection::name::full<FactoryT> ()
|
||||
);
|
||||
throw std::runtime_error ("Unable to register type");
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "hash/table.hpp"
|
||||
|
||||
#include "tap.hpp"
|
||||
#include "introspection.hpp"
|
||||
#include "introspection/name.hpp"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -36,7 +36,7 @@ void test_type (cruft::TAP::logger &tap)
|
||||
tap.expect (
|
||||
pos == std::end (results),
|
||||
"no equal elements, %!",
|
||||
cruft::type_name<ValueT> ()
|
||||
cruft::introspection::name::bare<ValueT> ()
|
||||
);
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ void test_type (cruft::TAP::logger &tap)
|
||||
tap.expect (
|
||||
success,
|
||||
"equal counts at bit positions, %!",
|
||||
cruft::type_name<ValueT> ()
|
||||
cruft::introspection::name::bare<ValueT> ()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "introspection.hpp"
|
||||
#include "introspection/name.hpp"
|
||||
#include "introspection/type.hpp"
|
||||
#include "std.hpp"
|
||||
|
||||
#include "tap.hpp"
|
||||
@ -42,7 +43,7 @@ struct templated_with_enum { };
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// define introspection data
|
||||
namespace cruft
|
||||
namespace cruft::introspection
|
||||
{
|
||||
template <>
|
||||
struct type<foo>
|
||||
@ -79,7 +80,7 @@ int main ()
|
||||
// Ensure tuples are mapped to themselves with type_tuple::type
|
||||
{
|
||||
using src_t = std::tuple<int>;
|
||||
using dst_t = typename cruft::type_tuple<src_t>::type;
|
||||
using dst_t = typename cruft::introspection::type_tuple<src_t>::type;
|
||||
|
||||
tap.expect (std::is_same<src_t, dst_t>::value, "static identity type_tuple");
|
||||
}
|
||||
@ -87,32 +88,32 @@ int main ()
|
||||
// Check member extraction from a simple POD structure.
|
||||
{
|
||||
foo d_foo { 7, 42.0 };
|
||||
auto f_tuple = cruft::as_tuple (d_foo);
|
||||
auto f_tuple = cruft::introspection::as_tuple (d_foo);
|
||||
|
||||
tap.expect (cruft::equal (d_foo.a, std::get<0> (f_tuple)) &&
|
||||
cruft::equal (d_foo.b, std::get<1> (f_tuple)),
|
||||
"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::introspection::name::bare<i08> ()), "i08", "i08 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::introspection::name::bare<i16> ()), "i16", "i16 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::introspection::name::bare<i32> ()), "i32", "i32 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::introspection::name::bare<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::introspection::name::bare<u08> ()), "u08", "u08 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::introspection::name::bare<u16> ()), "u16", "u16 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::introspection::name::bare<u32> ()), "u32", "u32 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::introspection::name::bare<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::introspection::name::bare<f32> ()), "f32", "f32 type_name");
|
||||
tap.expect_eq (cruft::view (cruft::introspection::name::bare<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", "de-namespaced struct type_name");
|
||||
tap.expect_eq (cruft::view (cruft::introspection::name::bare<foo> ()), "foo", "struct type_name");
|
||||
tap.expect_eq (cruft::view (cruft::introspection::name::bare<bar::qux> ()), "qux", "de-namespaced struct type_name");
|
||||
|
||||
tap.expect (
|
||||
equal (
|
||||
cruft::type_name_with_namespace<bar::qux> (),
|
||||
cruft::introspection::name::full<bar::qux> (),
|
||||
std::string_view ("bar::qux")
|
||||
),
|
||||
"namespaced struct"
|
||||
@ -120,38 +121,38 @@ int main ()
|
||||
|
||||
tap.expect (
|
||||
equal (
|
||||
cruft::type_name_with_namespace<bar::templated_qux<int>> (),
|
||||
cruft::introspection::name::full<bar::templated_qux<int>> (),
|
||||
std::string_view ("bar::templated_qux<int>")
|
||||
),
|
||||
"namespaced templated struct"
|
||||
);
|
||||
|
||||
tap.expect_eq (
|
||||
cruft::type_name<templated_with_type<int>> (),
|
||||
cruft::introspection::name::full<templated_with_type<int>> (),
|
||||
std::string_view {"templated_with_type<int>"},
|
||||
"templated_with_type"
|
||||
);
|
||||
|
||||
tap.expect_eq (
|
||||
cruft::type_name<templated_with_type<int, int>> (),
|
||||
cruft::introspection::name::full<templated_with_type<int, int>> (),
|
||||
std::string_view {"templated_with_type<int, int>"},
|
||||
"templated_with_type"
|
||||
);
|
||||
|
||||
tap.expect_eq (
|
||||
cruft::type_name<templated_with_type<templated_with_type<int>>> (),
|
||||
cruft::introspection::name::full<templated_with_type<templated_with_type<int>>> (),
|
||||
std::string_view {"templated_with_type<templated_with_type<int> >"},
|
||||
"templated_with_type"
|
||||
);
|
||||
|
||||
tap.expect_eq (
|
||||
cruft::type_name<templated_with_value<-1>> (),
|
||||
cruft::introspection::name::full<templated_with_value<-1>> (),
|
||||
std::string_view {"templated_with_value<-1>"},
|
||||
"templated_with_value"
|
||||
);
|
||||
|
||||
tap.expect_eq (
|
||||
cruft::type_name<templated_with_enum<FOO>> (),
|
||||
cruft::introspection::name::full<templated_with_enum<FOO>> (),
|
||||
std::string_view {"templated_with_enum<FOO>"},
|
||||
"templated_with_enum"
|
||||
);
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "tap.hpp"
|
||||
#include "maths.hpp"
|
||||
#include "types/string.hpp"
|
||||
#include "introspection.hpp"
|
||||
#include "introspection/name.hpp"
|
||||
|
||||
|
||||
/// //////////////////////////////////////////////////////////////////////////////
|
||||
@ -40,7 +40,7 @@ test_buckets (cruft::TAP::logger &tap, Args&& ...args)
|
||||
std::find_if (std::cbegin (buckets),
|
||||
std::cend (buckets),
|
||||
[] (auto v) { return v < EXPECTED * 7 / 8; }) == std::cend (buckets),
|
||||
"bucket counts for %s", cruft::type_name<GeneratorT> ()
|
||||
"bucket counts for %s", cruft::introspection::name::full<GeneratorT> ()
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user