introspection: split the header into functional groups

This commit is contained in:
Danny Robson 2020-09-24 15:41:58 +10:00
parent 43b8e8f6f2
commit 04de102789
13 changed files with 426 additions and 380 deletions

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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
View 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
View 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
View File

164
introspection/type.hpp Normal file
View 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;
}

View File

@ -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 {};
}

View File

@ -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");
}
}

View File

@ -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> ()
);
}
}

View File

@ -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"
);

View File

@ -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> ()
);
}