libcruft-util/introspection/type.hpp

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