From 50d496288f5a01f0a786462d819af72345da6869 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 6 Feb 2014 16:53:10 +0400 Subject: [PATCH] Compile time type info implementation added --- include/boost/type_index.hpp | 4 +- include/boost/type_index/ctti_type_index.ipp | 134 +++++++++++++++++ .../detail/compile_time_type_info.hpp | 139 ++++++++++++++++++ include/boost/type_index/stl_type_index.ipp | 6 +- test/Jamfile.v2 | 1 + 5 files changed, 279 insertions(+), 5 deletions(-) create mode 100644 include/boost/type_index/ctti_type_index.ipp create mode 100644 include/boost/type_index/detail/compile_time_type_info.hpp diff --git a/include/boost/type_index.hpp b/include/boost/type_index.hpp index 905be16..9fc8411 100644 --- a/include/boost/type_index.hpp +++ b/include/boost/type_index.hpp @@ -28,7 +28,7 @@ #if (!defined(BOOST_NO_RTTI) && !defined(BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY)) || defined(BOOST_MSVC) # include #else - +# include #endif namespace boost { namespace typeind { @@ -36,7 +36,7 @@ namespace boost { namespace typeind { #if (!defined(BOOST_NO_RTTI) && !defined(BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY)) || defined(BOOST_MSVC) typedef boost::typeind::detail::type_index_base type_index; #else - + typedef boost::typeind::detail::type_index_base type_index; #endif typedef type_index::type_info_t type_info; diff --git a/include/boost/type_index/ctti_type_index.ipp b/include/boost/type_index/ctti_type_index.ipp new file mode 100644 index 0000000..5aa7ee6 --- /dev/null +++ b/include/boost/type_index/ctti_type_index.ipp @@ -0,0 +1,134 @@ +// +// Copyright (c) Antony Polukhin, 2013-2014. +// +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_TYPE_INDEX_CTTI_TYPE_INDEX_IPP +#define BOOST_TYPE_INDEX_CTTI_TYPE_INDEX_IPP + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) +# pragma once +#endif + +/// \file stl_type_index.ipp +/// \brief Contains specialization of boost::type_index_base. +/// +/// boost::type_index_base class can be used as a drop-in replacement +/// for std::type_index. +/// +/// It is used in situations when RTTI is enabled or typeid() method is available. +/// When typeid() is not is disabled or BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY macro is defined boost::template_info +/// is usually used instead of it (some compilers allow calling typeid(T) +/// even if RTTI is disabled, those copilers will continue to use boost::type_info class). + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace typeind { namespace detail { + +struct ctti_data { + const char* const typename_; +}; + +template +inline const ctti_data& ctti_construct() BOOST_NOEXCEPT { + static const ctti_data result = { boost::detail::ctti::n() }; + return result; +} + + +template <> +template +type_index_base type_index_base::construct() BOOST_NOEXCEPT { + typedef BOOST_DEDUCED_TYPENAME boost::remove_reference::type no_ref_t; + typedef BOOST_DEDUCED_TYPENAME boost::remove_cv::type no_cvr_t; + return ctti_construct(); +} + + +template <> +template +type_index_base type_index_base::construct_with_cvr() BOOST_NOEXCEPT { + return ctti_construct(); +} + + +template <> +template +type_index_base type_index_base::construct_runtime(T& rtti_val) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, + "type_id_runtime(T&) and type_index::construct_runtime(T&) require RTTI"); + + return ctti_construct(); +} + + +template <> +template +type_index_base type_index_base::construct_runtime(T* rtti_val) { + BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, + "type_id_runtime(T*) and type_index::construct_runtime(T*) require RTTI"); + + return ctti_construct(); +} + + +template <> +const char* type_index_base::raw_name() const BOOST_NOEXCEPT { + return data_->typename_; +} + + +template <> +const char* type_index_base::name() const BOOST_NOEXCEPT { + return data_->typename_; +} + +template <> +std::string type_index_base::pretty_name() const { + std::size_t len = std::strlen(raw_name() + ctti_skip_size_at_end); + while (raw_name()[len - 1] == ' ') --len; // MSVC sometimes adds whitespaces + return std::string(raw_name(), len); +} + + +template <> +bool type_index_base::equal(const type_index_base& rhs) const BOOST_NOEXCEPT { + return raw_name() == rhs.raw_name() || !std::strcmp(raw_name(), rhs.raw_name()); +} + + +template <> +bool type_index_base::before(const type_index_base& rhs) const BOOST_NOEXCEPT { + return raw_name() != rhs.raw_name() && std::strcmp(raw_name(), rhs.raw_name()) < 0; +} + + +template <> +std::size_t type_index_base::hash_code() const BOOST_NOEXCEPT { + return boost::hash_range(raw_name(), raw_name() + std::strlen(raw_name() + detail::ctti_skip_size_at_end)); +} + + +}}} // namespace boost::typeind::detail + + +#endif // BOOST_TYPE_INDEX_CTTI_TYPE_INDEX_IPP + diff --git a/include/boost/type_index/detail/compile_time_type_info.hpp b/include/boost/type_index/detail/compile_time_type_info.hpp new file mode 100644 index 0000000..f3fff16 --- /dev/null +++ b/include/boost/type_index/detail/compile_time_type_info.hpp @@ -0,0 +1,139 @@ +// +// Copyright (c) Antony Polukhin, 2012-2014. +// +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_TYPE_INDEX_DETAIL_COMPILE_TIME_TYPE_INFO_HPP +#define BOOST_TYPE_INDEX_DETAIL_COMPILE_TIME_TYPE_INFO_HPP + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) +# pragma once +#endif + + +/// \file compile_time_type_info.hpp +/// \brief Contains implementation of boost::ctti class. +/// + +#include +#include + +namespace boost { namespace typeind { namespace detail { + +#if defined(BOOST_TYPE_INDEX_DOXYGEN_INVOKED) + +/// \def BOOST_TYPE_INDEX_FUNCTION_SIGNATURE +/// BOOST_TYPE_INDEX_FUNCTION_SIGNATURE is used by boost::template_info class to +/// deduce the name of a template parameter. If your compiler is not recognized +/// by the TypeIndex library and you wish to work with boost::template_info, you may +/// define this macro by yourself. +/// +/// BOOST_TYPE_INDEX_FUNCTION_SIGNATURE must be defined to a compiler specific macro, +/// that outputs the WHOLE function signature, including template parameters. +/// +/// If your compiler is not recognised and BOOST_TYPE_INDEX_FUNCTION_SIGNATURE is not defined, +/// then a compile-time error will arise at any attempt to use boost::template_info or +/// boost::template_index classes. +#define BOOST_TYPE_INDEX_FUNCTION_SIGNATURE BOOST_CURRENT_FUNCTION + +/// \def BOOST_TYPE_INDEX_CTTI_BEGIN_SKIP +/// +/// BOOST_TYPE_INDEX_FUNCTION_SIGNATURE, BOOST_TYPE_INDEX_CTTI_BEGIN_SKIP +/// and BOOST_TYPE_INDEX_CTTI_END_SKIP macroses are used for adding a +/// support for compilers, that by default are not recognized by TypeIndex library. +/// +/// See Compiler support for more info +#define BOOST_TYPE_INDEX_CTTI_BEGIN_SKIP 0 + +/// \def BOOST_TYPE_INDEX_CTTI_END_SKIP +/// +/// BOOST_TYPE_INDEX_FUNCTION_SIGNATURE, BOOST_TYPE_INDEX_CTTI_BEGIN_SKIP +/// and BOOST_TYPE_INDEX_CTTI_END_SKIP macroses are used for adding a +/// support for compilers, that by default are not recognized by TypeIndex library. +/// +/// See Compiler support for more info +#define BOOST_TYPE_INDEX_CTTI_END_SKIP 0 + +#elif defined(BOOST_TYPE_INDEX_CTTI_BEGIN_SKIP) && defined(BOOST_TYPE_INDEX_CTTI_END_SKIP) + // skip user specified bytes count + BOOST_STATIC_CONSTANT(std::size_t, ctti_skip_size_at_begin = BOOST_TYPE_INDEX_CTTI_BEGIN_SKIP); + // skip user specified bytes count + BOOST_STATIC_CONSTANT(std::size_t, ctti_skip_size_at_end = BOOST_TYPE_INDEX_CTTI_END_SKIP); +#elif defined _MSC_VER + // sizeof("const char *__cdecl boost::detail::ctti<") - 1 + BOOST_STATIC_CONSTANT(std::size_t, ctti_skip_size_at_begin = 40); + + // sizeof(">::n(void)") - 1 + BOOST_STATIC_CONSTANT(std::size_t, ctti_skip_size_at_end = 10); + +#elif defined __clang__ + // sizeof("static const char *boost::detail::ctti<") - 1 + BOOST_STATIC_CONSTANT(std::size_t, ctti_skip_size_at_begin = 39); + + // == sizeof(">::n()") - 1 + BOOST_STATIC_CONSTANT(std::size_t, ctti_skip_size_at_end = 6); +#elif defined __GNUC__ + // sizeof("static const char* boost::detail::ctti::n() [with T = ") - 1 + BOOST_STATIC_CONSTANT(std::size_t, ctti_skip_size_at_begin = 57); + + // == sizeof("]") - 1 + BOOST_STATIC_CONSTANT(std::size_t, ctti_skip_size_at_end = 1); + +#else + // TODO: Code for other platforms + BOOST_STATIC_CONSTANT(std::size_t, ctti_skip_size_at_begin = 0); // skip nothing + BOOST_STATIC_CONSTANT(std::size_t, ctti_skip_size_at_end = 0); // skip nothing +#endif + +}}} // namespace boost::typeind::detail + +namespace boost { namespace detail { + +/// Noncopyable type_info that does not require RTTI. +/// CTTI == Compile Time Type Info. +/// This name must be as short as posible, to avoid code bloat +template +struct ctti { + typedef T template_type; + typedef ctti this_type; + + /// Returns raw name. Must be as short, as possible, to avoid code bloat + static const char* n() BOOST_NOEXCEPT { + #if defined(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE) + return BOOST_TYPE_INDEX_FUNCTION_SIGNATURE + boost::typeind::detail::ctti_skip_size_at_begin; + #elif defined(__FUNCSIG__) + return __FUNCSIG__ + boost::typeind::detail::ctti_skip_size_at_begin; + #elif defined(__PRETTY_FUNCTION__) \ + || defined(__GNUC__) \ + || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) \ + || (defined(__ICC) && (__ICC >= 600)) \ + || defined(__ghs__) \ + || defined(__DMC__) + + return __PRETTY_FUNCTION__ + boost::typeind::detail::ctti_skip_size_at_begin; + #else + BOOST_STATIC_ASSERT_MSG( + sizeof(T) && false, + "TypeIndex library could not detect your compiler. " + "Please make the BOOST_TYPE_INDEX_FUNCTION_SIGNATURE macro use " + "correct compiler macro for getting the whole function name. " + "Do not forget to also define BOOST_TYPE_INDEX_CTTI_BEGIN_SKIP and " + "BOOST_TYPE_INDEX_CTTI_END_SKIP." + ); + #endif + } + + /// Returns raw name + static const char* name() BOOST_NOEXCEPT { + return this_type::n(); + } +}; + +}} // namespace boost::detail + +#endif // BOOST_TYPE_INDEX_DETAIL_COMPILE_TIME_TYPE_INFO_HPP + diff --git a/include/boost/type_index/stl_type_index.ipp b/include/boost/type_index/stl_type_index.ipp index 7b0c495..1ad7bca 100644 --- a/include/boost/type_index/stl_type_index.ipp +++ b/include/boost/type_index/stl_type_index.ipp @@ -75,7 +75,7 @@ type_index_base type_index_base::construct() BOO template <> template -const type_index_base& type_index_base::construct_with_cvr() BOOST_NOEXCEPT { +type_index_base type_index_base::construct_with_cvr() BOOST_NOEXCEPT { typedef typename boost::mpl::if_c< boost::is_reference::value || boost::is_const::value @@ -90,7 +90,7 @@ const type_index_base& type_index_base::construc template <> template -type_index_base& type_index_base::construct_runtime(T& rtti_val) BOOST_NOEXCEPT { +type_index_base type_index_base::construct_runtime(T& rtti_val) BOOST_NOEXCEPT { #ifdef BOOST_NO_RTTI BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, "type_id_runtime(T&) and type_index::construct_runtime(T&) require RTTI"); @@ -211,7 +211,7 @@ std::size_t type_index_base::hash_code() const BOOST_NOEXCEPT { #if _MSC_VER > 1600 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5 && defined(__GXX_EXPERIMENTAL_CXX0X__)) return data_->hash_code(); #else - return boost::hash_range(raw_name(), raw_name() + std::strlen(name())); + return boost::hash_range(raw_name(), raw_name() + std::strlen(raw_name())); #endif } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 5e634d9..bab28af 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -34,6 +34,7 @@ nortti = gcc:-fno-rtti clang:-fno-rtti off : type_index_test_no_rtti ] # [ run template_index_test.cpp $(tlib) ] # [ run testing_both.cpp $(tlib) ] # [ run testing_both_no_rtti.cpp $(tlib) : : : off ]