introspection: add simple static introspection types

This commit is contained in:
Danny Robson 2015-04-20 17:51:00 +10:00
parent fa8387252e
commit 199be3213a
4 changed files with 207 additions and 0 deletions

View File

@ -75,6 +75,8 @@ UTIL_FILES = \
hash/sha1.hpp \ hash/sha1.hpp \
image.cpp \ image.cpp \
image.hpp \ image.hpp \
introspection.cpp \
introspection.hpp \
io.cpp \ io.cpp \
io.hpp \ io.hpp \
io.ipp \ io.ipp \
@ -265,6 +267,7 @@ TEST_BIN = \
test/hmac \ test/hmac \
test/hotp \ test/hotp \
test/hton \ test/hton \
test/introspection \
test/ip \ test/ip \
test/json_types \ test/json_types \
test/ray \ test/ray \

17
introspection.cpp Normal file
View File

@ -0,0 +1,17 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "introspection.hpp"

144
introspection.hpp Normal file
View File

@ -0,0 +1,144 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_INTROSPECTION_HPP
#define __UTIL_INTROSPECTION_HPP
#include "variadic.hpp"
#include <cstddef>
#include <string>
#include <tuple>
namespace util {
///////////////////////////////////////////////////////////////////////////
/// 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; }
};
///////////////////////////////////////////////////////////////////////////
/// 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,
typename I = typename make_indices<
std::tuple_size<
typename type<K>::fields
>::value
>::type
>
struct type_tuple;
template <
typename K,
size_t ...I
>
struct type_tuple<
K,
indices<I...>
>
{
typedef std::tuple<
typename std::tuple_element<
I,
typename type<K>::fields
>::type::type...
> type;
};
///////////////////////////////////////////////////////////////////////////
namespace detail {
template <
typename K,
typename I = typename make_indices<
std::tuple_size<
typename type<K>::fields
>::value
>::type
>
struct _as_tuple;
template <
typename K,
size_t ...I
>
struct _as_tuple <
K,
indices<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)...
);
}
};
}
/// 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);
}
}
#endif

43
test/introspection.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "introspection.hpp"
#include "tap.hpp"
//-----------------------------------------------------------------------------
// simple test struct of scalars
struct foo
{
int a;
float b;
};
//-----------------------------------------------------------------------------
// define introspection data
namespace util
{
template <>
struct type<foo>
{
typedef std::tuple<
field<foo,int,&foo::a>,
field<foo,float,&foo::b>
> fields;
};
template <> const std::string field<foo,int,&foo::a>::name = "a";
template <> const std::string field<foo,float,&foo::b>::name = "b";
}
//-----------------------------------------------------------------------------
int
main ()
{
util::TAP::logger tap;
foo d_foo { 7, 42.0 };
auto f_tuple = util::as_tuple (d_foo);
tap.expect (exactly_equal (d_foo.a, std::get<0> (f_tuple)) &&
exactly_equal (d_foo.b, std::get<1> (f_tuple)),
"member access after conversion to tuple");
}