From 199be3213afe157c9f88ae45c69794f741d374a0 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 20 Apr 2015 17:51:00 +1000 Subject: [PATCH] introspection: add simple static introspection types --- Makefile.am | 3 + introspection.cpp | 17 +++++ introspection.hpp | 144 +++++++++++++++++++++++++++++++++++++++++ test/introspection.cpp | 43 ++++++++++++ 4 files changed, 207 insertions(+) create mode 100644 introspection.cpp create mode 100644 introspection.hpp create mode 100644 test/introspection.cpp diff --git a/Makefile.am b/Makefile.am index a54a3a02..f7a29386 100644 --- a/Makefile.am +++ b/Makefile.am @@ -75,6 +75,8 @@ UTIL_FILES = \ hash/sha1.hpp \ image.cpp \ image.hpp \ + introspection.cpp \ + introspection.hpp \ io.cpp \ io.hpp \ io.ipp \ @@ -265,6 +267,7 @@ TEST_BIN = \ test/hmac \ test/hotp \ test/hton \ + test/introspection \ test/ip \ test/json_types \ test/ray \ diff --git a/introspection.cpp b/introspection.cpp new file mode 100644 index 00000000..18ed32bd --- /dev/null +++ b/introspection.cpp @@ -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 + */ + +#include "introspection.hpp" diff --git a/introspection.hpp b/introspection.hpp new file mode 100644 index 00000000..4a3f60bb --- /dev/null +++ b/introspection.hpp @@ -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 + */ + +#ifndef __UTIL_INTROSPECTION_HPP +#define __UTIL_INTROSPECTION_HPP + +#include "variadic.hpp" + +#include +#include +#include + +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 + /// { + /// typedef std::tuple< + /// field, + /// field + /// > fields; + /// }; + /// + /// template <> const std::string field::name = "a"; + /// template <> const std::string field::name = "b"; + + template + 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::fields + >::value + >::type + > + struct type_tuple; + + + template < + typename K, + size_t ...I + > + struct type_tuple< + K, + indices + > + { + typedef std::tuple< + typename std::tuple_element< + I, + typename type::fields + >::type::type... + > type; + }; + + /////////////////////////////////////////////////////////////////////////// + namespace detail { + template < + typename K, + typename I = typename make_indices< + std::tuple_size< + typename type::fields + >::value + >::type + > + struct _as_tuple; + + template < + typename K, + size_t ...I + > + struct _as_tuple < + K, + indices + > + { + static typename type_tuple::type + make (const K &k) + { + return std::make_tuple ( + std::tuple_element::fields>::type::get (k)... + ); + } + }; + } + + /// Convert an introspection capable class instance into a tuple instance + /// + /// K: source class + template + auto + as_tuple (const K &k) + { + return detail::_as_tuple::make (k); + } +} + +#endif diff --git a/test/introspection.cpp b/test/introspection.cpp new file mode 100644 index 00000000..06662d8a --- /dev/null +++ b/test/introspection.cpp @@ -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 + { + typedef std::tuple< + field, + field + > fields; + }; + + template <> const std::string field::name = "a"; + template <> const std::string field::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"); +}