Compile time type info implementation added

This commit is contained in:
Antony Polukhin
2014-02-06 16:53:10 +04:00
parent 3daeab38fa
commit 50d496288f
5 changed files with 279 additions and 5 deletions

View File

@@ -28,7 +28,7 @@
#if (!defined(BOOST_NO_RTTI) && !defined(BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY)) || defined(BOOST_MSVC)
# include <boost/type_index/stl_type_index.ipp>
#else
# include <boost/type_index/ctti_type_index.ipp>
#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<std::type_info> type_index;
#else
typedef boost::typeind::detail::type_index_base<boost::typeind::detail::ctti_data> type_index;
#endif
typedef type_index::type_info_t type_info;

View File

@@ -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<std::type_info>.
///
/// boost::type_index_base<std::type_info> 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 <boost/type_index/type_index_base.hpp>
#include <boost/type_index/detail/compile_time_type_info.hpp>
#include <cstring>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/is_reference.hpp>
#include <boost/type_traits/is_volatile.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/mpl/if.hpp>
#include <boost/detail/no_exceptions_support.hpp>
#include <boost/functional/hash_fwd.hpp>
namespace boost { namespace typeind { namespace detail {
struct ctti_data {
const char* const typename_;
};
template <class T>
inline const ctti_data& ctti_construct() BOOST_NOEXCEPT {
static const ctti_data result = { boost::detail::ctti<T>::n() };
return result;
}
template <>
template <class T>
type_index_base<ctti_data> type_index_base<ctti_data>::construct() BOOST_NOEXCEPT {
typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type no_ref_t;
typedef BOOST_DEDUCED_TYPENAME boost::remove_cv<no_ref_t>::type no_cvr_t;
return ctti_construct<no_cvr_t>();
}
template <>
template <class T>
type_index_base<ctti_data> type_index_base<ctti_data>::construct_with_cvr() BOOST_NOEXCEPT {
return ctti_construct<T>();
}
template <>
template <class T>
type_index_base<ctti_data> type_index_base<ctti_data>::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<T>();
}
template <>
template <class T>
type_index_base<ctti_data> type_index_base<ctti_data>::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<T>();
}
template <>
const char* type_index_base<ctti_data>::raw_name() const BOOST_NOEXCEPT {
return data_->typename_;
}
template <>
const char* type_index_base<ctti_data>::name() const BOOST_NOEXCEPT {
return data_->typename_;
}
template <>
std::string type_index_base<ctti_data>::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<ctti_data>::equal(const type_index_base<ctti_data>& rhs) const BOOST_NOEXCEPT {
return raw_name() == rhs.raw_name() || !std::strcmp(raw_name(), rhs.raw_name());
}
template <>
bool type_index_base<ctti_data>::before(const type_index_base<ctti_data>& 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<ctti_data>::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

View File

@@ -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 <boost/config.hpp>
#include <boost/static_assert.hpp>
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<T>::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 <class T>
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

View File

@@ -75,7 +75,7 @@ type_index_base<std::type_info> type_index_base<std::type_info>::construct() BOO
template <>
template <class T>
const type_index_base<std::type_info>& type_index_base<std::type_info>::construct_with_cvr() BOOST_NOEXCEPT {
type_index_base<std::type_info> type_index_base<std::type_info>::construct_with_cvr() BOOST_NOEXCEPT {
typedef typename boost::mpl::if_c<
boost::is_reference<T>::value
|| boost::is_const<T>::value
@@ -90,7 +90,7 @@ const type_index_base<std::type_info>& type_index_base<std::type_info>::construc
template <>
template <class T>
type_index_base<std::type_info>& type_index_base<std::type_info>::construct_runtime(T& rtti_val) BOOST_NOEXCEPT {
type_index_base<std::type_info> type_index_base<std::type_info>::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<std::type_info>::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
}

View File

@@ -34,6 +34,7 @@ nortti = <toolset>gcc:<cxxflags>-fno-rtti <toolset>clang:<cxxflags>-fno-rtti <to
test-suite type_index
:
[ run type_index_test.cpp $(tlib) ]
[ run type_index_test.cpp $(tlib) : : : <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) : : : <rtti>off ]