164 lines
3.8 KiB
C++
164 lines
3.8 KiB
C++
/*
|
|
* 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;
|
|
} |