From 3daeab38fad9bdf9a5de33b16643a885a540229b Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 6 Feb 2014 16:00:27 +0400 Subject: [PATCH] Started the work on new interface --- include/boost/type_index.hpp | 57 ++- include/boost/type_index/stl_type_index.ipp | 223 +++++++++++ include/boost/type_index/type_index_base.hpp | 125 +++++++ include/boost/type_index/type_info.hpp | 373 ------------------- test/Jamfile.v2 | 62 +-- test/template_index_test.cpp | 2 +- test/template_index_tests.ipp | 191 ---------- test/type_index_test.cpp | 196 +++++++++- todos.txt | 72 ++++ 9 files changed, 698 insertions(+), 603 deletions(-) create mode 100644 include/boost/type_index/stl_type_index.ipp create mode 100644 include/boost/type_index/type_index_base.hpp delete mode 100644 include/boost/type_index/type_info.hpp create mode 100644 todos.txt diff --git a/include/boost/type_index.hpp b/include/boost/type_index.hpp index b415a45..905be16 100644 --- a/include/boost/type_index.hpp +++ b/include/boost/type_index.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) Antony Polukhin, 2012-2013. +// 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) @@ -25,10 +25,57 @@ # pragma once #endif -#include -#include -#include -#include +#if (!defined(BOOST_NO_RTTI) && !defined(BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY)) || defined(BOOST_MSVC) +# include +#else + +#endif + +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 + +#endif + +typedef type_index::type_info_t type_info; + +// TODO: +// inline bool is_equal(const type_info&, const type_info&) BOOST_NOEXCEPT; +// inline bool is_before(const type_info&, const type_info&) BOOST_NOEXCEPT; + + +/// Function to get boost::type_index for a type T. +/// Strips const, volatile and & modifiers from T. +template +inline type_index type_id() BOOST_NOEXCEPT { + return type_index::construct(); +} + +/// Function for constructing boost::type_index instance for type T. +/// Does not strip const, volatile, & and && modifiers from T. +/// If T has no const, volatile, & and && modifiers, then returns exactly +/// the same result as in case of calling `type_id()`. +template +inline type_index type_id_with_cvr() BOOST_NOEXCEPT { + return type_index::construct_with_cvr(); +} + +/// Function that works exactly like C++ typeid(rtti_val) call, but returns boost::type_index. +template +inline type_index type_id_runtime(T& runtime_val) BOOST_NOEXCEPT { + return type_index::construct_runtime(runtime_val); +} + +/// Function that works exactly like C++ typeid(rtti_val) call, but returns boost::type_info. +template +inline type_index type_id_runtime(T* runtime_val) { + return type_index::construct_runtime(runtime_val); +} + +}} // namespace boost::typeind + #endif // BOOST_TYPE_INDEX_HPP diff --git a/include/boost/type_index/stl_type_index.ipp b/include/boost/type_index/stl_type_index.ipp new file mode 100644 index 0000000..7b0c495 --- /dev/null +++ b/include/boost/type_index/stl_type_index.ipp @@ -0,0 +1,223 @@ +// +// 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_STL_TYPE_INDEX_IPP +#define BOOST_TYPE_INDEX_STL_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 + + +// MSVC is capable of calling typeid(T) even when RTTI is off +#if defined(BOOST_NO_RTTI) && !defined(BOOST_MSVC) +#error "File boost/type_index/stl_type_index.ipp is not usable when typeid() is not available." +#endif + +#include + +#ifdef __GNUC__ +#include +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +namespace boost { namespace typeind { namespace detail { + +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; + + # if (defined(__EDG_VERSION__) && __EDG_VERSION__ < 245) \ + || (defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 744) + BOOST_STATIC_ASSERT_MSG( !boost::is_arithmetic::type::value + , "Your EDG-based compiler seems to mistakenly distinguish 'int' from 'signed int', in typeid() expressions."); + #endif + + return typeid(no_cvr_t); +} + + +template <> +template +const 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 + || boost::is_volatile::value, + detail::cvr_saver, + T + >::type type; + + return typeid(type); +} + + +template <> +template +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"); +#endif + + return typeid(rtti_val); +} + + +template <> +template +type_index_base type_index_base::construct_runtime(T* rtti_val) { +#ifdef BOOST_NO_RTTI + BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, + "type_id_runtime(T*) and type_index::construct_runtime(T*) require RTTI"); +#endif + return typeid(rtti_val); +} + + +template <> +const char* type_index_base::raw_name() const BOOST_NOEXCEPT { +#ifdef _MSC_VER + return data_->raw_name(); +#else + return data_->name(); +#endif +} + + +template <> +const char* type_index_base::name() const BOOST_NOEXCEPT { + return data_->name(); +} + +template <> +std::string type_index_base::pretty_name() const { +#if defined(_MSC_VER) + std::string ret = data_->name(); +#else + std::string ret; + int status = 0; + char* demang = abi::__cxa_demangle(raw_name(), NULL, 0, &status); + BOOST_ASSERT(!status); + + BOOST_TRY { + ret = demang; // may throw out of memory exception + } BOOST_CATCH (...) { + free(demang); + BOOST_RETHROW; + } BOOST_CATCH_END + + free(demang); +#endif + + std::string::size_type pos = ret.find("boost::typeind::detail::cvr_saver<"); + if (pos == std::string::npos) { + return ret; + } + + pos += sizeof("boost::typeind::detail::cvr_saver<") - 1; + while (ret[pos] == ' ') { + ++ pos; + } + + std::string::size_type end = ret.rfind(">"); + BOOST_ASSERT(end != std::string::npos); + while (ret[end - 1] == ' ') { + -- end; + } + + return ret.substr(pos, end - pos); +} + + +/// @cond + +// for this compiler at least, cross-shared-library type_info +// comparisons don't work, so we are using typeid(x).name() instead. +# if (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5))) \ + || defined(_AIX) \ + || (defined(__sgi) && defined(__host_mips)) \ + || (defined(__hpux) && defined(__HP_aCC)) \ + || (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) +# define BOOST_CLASSINFO_COMPARE_BY_NAMES +# endif + +/// @endcond + + +template <> +bool type_index_base::equal(const type_index_base& rhs) const BOOST_NOEXCEPT { +#ifdef BOOST_CLASSINFO_COMPARE_BY_NAMES + return raw_name() == rhs.raw_name() || !std::strcmp(raw_name(), rhs.raw_name()); +#else + return *data_ == *rhs.data_; +#endif +} + + +template <> +bool type_index_base::before(const type_index_base& rhs) const BOOST_NOEXCEPT { +#ifdef BOOST_CLASSINFO_COMPARE_BY_NAMES + return raw_name() != rhs.raw_name() && std::strcmp(raw_name(), rhs.raw_name()) < 0; +#else + return !!data_->before(*rhs.data_); +#endif +} + + +#ifdef BOOST_CLASSINFO_COMPARE_BY_NAMES +#undef BOOST_CLASSINFO_COMPARE_BY_NAMES +#endif + + +template <> +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())); +#endif +} + + +}}} // namespace boost::typeind::detail + + +#endif // BOOST_TYPE_INDEX_STL_TYPE_INDEX_IPP + diff --git a/include/boost/type_index/type_index_base.hpp b/include/boost/type_index/type_index_base.hpp new file mode 100644 index 0000000..2e40862 --- /dev/null +++ b/include/boost/type_index/type_index_base.hpp @@ -0,0 +1,125 @@ +// +// 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_TYPE_INDEX_BASE_HPP +#define BOOST_TYPE_INDEX_TYPE_INDEX_BASE_HPP + +// MS compatible compilers support #pragma once +#if defined(_MSC_VER) +# pragma once +#endif + +#include +#include + +#if !defined(BOOST_NO_IOSTREAM) +#if !defined(BOOST_NO_IOSFWD) +#include // for std::basic_ostream +#else +#include +#endif +#endif + +namespace boost { namespace typeind { namespace detail { + +template class cvr_saver{}; + +template +class type_index_base { + const TypeInfo* data_; + +public: + typedef TypeInfo type_info_t; + typedef type_index_base this_type; + + type_index_base(const TypeInfo& info) BOOST_NOEXCEPT + : data_(&info) + {} + + const type_info_t& type_info() const BOOST_NOEXCEPT { + return *data_; + } + + // All of the following methods must be explicitly specialized for each type_index_base. + const char* raw_name() const BOOST_NOEXCEPT; + const char* name() const BOOST_NOEXCEPT; + std::string pretty_name() const; + std::size_t hash_code() const BOOST_NOEXCEPT; + bool equal(const this_type& rhs) const BOOST_NOEXCEPT; + bool before(const this_type& rhs) const BOOST_NOEXCEPT; + + template + static this_type construct() BOOST_NOEXCEPT; + template + static this_type construct_with_cvr() BOOST_NOEXCEPT; + template + static this_type construct_runtime(T&) BOOST_NOEXCEPT; + template + static this_type construct_runtime(T* rtti_val); +}; + + +template +inline bool operator == (const type_index_base& lhs, const type_index_base& rhs) BOOST_NOEXCEPT { + return lhs.equal(rhs); +} + +template +inline bool operator < (const type_index_base& lhs, const type_index_base& rhs) BOOST_NOEXCEPT { + return lhs.before(rhs); +} + + + +template +inline bool operator > (const type_index_base& lhs, const type_index_base& rhs) BOOST_NOEXCEPT { + return rhs < lhs; +} + +template +inline bool operator <= (const type_index_base& lhs, const type_index_base& rhs) BOOST_NOEXCEPT { + return !(lhs > rhs); +} + +template +inline bool operator >= (const type_index_base& lhs, const type_index_base& rhs) BOOST_NOEXCEPT { + return !(lhs < rhs); +} + +template +inline bool operator != (const type_index_base& lhs, const type_index_base& rhs) BOOST_NOEXCEPT { + return !(lhs == rhs); +} + + +#ifndef BOOST_NO_IOSTREAM +#ifdef BOOST_NO_TEMPLATED_IOSTREAMS +/// Ostream operator that will output demangled name +template +inline std::ostream& operator<<(std::ostream& ostr, const type_index_base& ind) { + ostr << ind.pretty_name(); + return ostr; +} +#else +/// Ostream operator that will output demangled name +template +inline std::basic_ostream& operator<<( + std::basic_ostream& ostr, + const type_index_base& ind) +{ + ostr << ind.pretty_name(); + return ostr; +} +#endif // BOOST_NO_TEMPLATED_IOSTREAMS +#endif // BOOST_NO_IOSTREAM + + +}}} // namespace boost::typeind::detail + +#endif // BOOST_TYPE_INDEX_TYPE_INDEX_BASE_HPP + diff --git a/include/boost/type_index/type_info.hpp b/include/boost/type_index/type_info.hpp deleted file mode 100644 index 5ac7ca4..0000000 --- a/include/boost/type_index/type_info.hpp +++ /dev/null @@ -1,373 +0,0 @@ -// -// Copyright (c) Antony Polukhin, 2012-2013. -// -// -// 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_TYPE_INFO_HPP -#define BOOST_TYPE_INDEX_TYPE_INFO_HPP - -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) -# pragma once -#endif - -/// \file type_info.hpp -/// \brief Contains implementation of boost::type_info class. -/// -/// boost::type_info class can be used as a drop-in replacement for std::type_info, but unlike std::type_info -/// this class has a name_demangled() function for getting human-readable type names. -/// -/// boost::type_info class is used in situations when RTTI is enabled. -/// When RTTI 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 - - -// MSVC is capable of calling typeid(T) even when RTTI is off -#if (!defined(BOOST_NO_RTTI) && !defined(BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY)) || defined(BOOST_MSVC) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef __GNUC__ -#include -#endif - -namespace boost { - -/// @cond - -// for this compiler at least, cross-shared-library type_info -// comparisons don't work, so we are using typeid(x).name() instead. -# if (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5))) \ - || defined(_AIX) \ - || (defined(__sgi) && defined(__host_mips)) \ - || (defined(__hpux) && defined(__HP_aCC)) \ - || (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) -# define BOOST_CLASSINFO_COMPARE_BY_NAMES -# endif - -/// @endcond - -namespace detail { -#ifdef BOOST_NO_STD_TYPEINFO - typedef type_info stl_type_info; -#else - typedef std::type_info stl_type_info; -#endif - - template class cvr_saver{}; -} - -/// boost::type_info is a class that can be used as a drop-in replacement for std::type_info. -/// -/// boost::type_info class is used in situations when RTTI is enabled. -/// When RTTI is disabled or BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY macro is defined boost::template_info -/// is used instead of it. -/// -/// Unlike std::type_info this class: -/// * has a name_demangled() function for getting human-readable type names -/// * name() function always noexcept and returns simple mangled name as character a character array -/// * contains workarounds for some compiler issues -/// -/// boost::type_info is not copyable and is not default constructible. Use boost::type_id* functions -/// to get const references to instances of boost::type_info objects. -class type_info: public detail::stl_type_info { -#ifndef BOOST_NO_DELETED_FUNCTIONS - type_info() = delete; - type_info(const type_info&) = delete; -#else - type_info(); - type_info(const type_info&); -#endif -public: - typedef detail::stl_type_info stl_type_info; - - /// Factory method for constructing boost::type_info instance for type T. - /// Strips const, volatile and & modifiers from T. - /// - /// Works exactly like boost::type_id(). - template - static const boost::type_info& 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; - - # if (defined(__EDG_VERSION__) && __EDG_VERSION__ < 245) \ - || (defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 744) - BOOST_STATIC_ASSERT_MSG( !boost::is_arithmetic::type::value - , "Your EDG-based compiler seems to mistakenly distinguish 'int' from 'signed int', in typeid() expressions."); - #endif - - return static_cast(typeid(no_cvr_t)); - } - - /// Factory method for constructing boost::type_info instance for type T. - /// Does not strip const, volatile, & and && modifiers from T. - /// If T has no const, volatile, & and && modifiers, then returns exactly - /// the same result as in case of calling `construct()`. - /// - /// Works exactly like boost::type_id_with_cvr(). - template - static const boost::type_info& construct_with_cvr() BOOST_NOEXCEPT { - typedef typename boost::mpl::if_c< - boost::is_reference::value - || boost::is_const::value - || boost::is_volatile::value, - detail::cvr_saver, - T - >::type type; - - return static_cast(typeid(type)); - } - - /// Factory function, that works exactly like C++ typeid(rtti_val) call, but returns boost::type_info. - /// This method available only with RTTI enabled. - /// - /// Same as boost::type_id_rtti_only(). - template - static const type_info& construct_rtti_only(T& rtti_val) BOOST_NOEXCEPT { -#ifdef BOOST_NO_RTTI - BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, - "boost::type_id_rtti_only(T&) and boost::type_info::construct_rtti_only(T&) require RTTI"); -#endif - return static_cast(typeid(rtti_val)); - } - - /// Factory function, that works exactly like C++ typeid(rtti_val) call, but returns boost::type_info. - /// This method available only with RTTI enabled. - /// - /// Same as boost::type_id_rtti_only(). - template - static const type_info& construct_rtti_only(T* rtti_val) { -#ifdef BOOST_NO_RTTI - BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, - "boost::type_id_rtti_only(T*) and boost::type_info::construct_rtti_only(T*) require RTTI"); -#endif - return static_cast(typeid(rtti_val)); - } - - /// Returns mangled type name. - const char* name() const BOOST_NOEXCEPT { - #ifdef _MSC_VER - return stl_type_info::raw_name(); - #else - return stl_type_info::name(); - #endif - } - - /// Returns user-friendly name - std::string name_demangled() const { - #if defined(_MSC_VER) - std::string ret = stl_type_info::name(); - #else - std::string ret; - int status = 0; - char* demang = abi::__cxa_demangle(name(), NULL, 0, &status); - BOOST_ASSERT(!status); - - BOOST_TRY { - ret = demang; // may throw out of memory exception - } BOOST_CATCH (...) { - free(demang); - BOOST_RETHROW; - } BOOST_CATCH_END - - free(demang); - #endif - std::string::size_type pos = ret.find("boost::detail::cvr_saver<"); - if (pos == std::string::npos) { - return ret; - } - - pos += sizeof("boost::detail::cvr_saver<") - 1; - while (ret[pos] == ' ') { - ++ pos; - } - std::string::size_type end = ret.rfind(">"); - BOOST_ASSERT(end != std::string::npos); - while (ret[end - 1] == ' ') { - -- end; - } - - return ret.substr(pos, end - pos); - } - - bool operator == (type_info const& rhs) const BOOST_NOEXCEPT { - #ifdef BOOST_CLASSINFO_COMPARE_BY_NAMES - return name() == rhs.name() || !std::strcmp(name(), rhs.name()); - #else - return static_cast(*this) == static_cast(rhs); - #endif - } - - bool operator != (type_info const& rhs) const BOOST_NOEXCEPT { - return !(*this == rhs); - } - - bool operator == (stl_type_info const& rhs) const BOOST_NOEXCEPT { - return *this == static_cast(rhs); - } - - bool operator != (stl_type_info const& rhs) const BOOST_NOEXCEPT { - return !(*this == rhs); - } - - /// Returns true if the type precedes the type of rhs in the collation order. - /// The collation order is just an internal order. - /// Works exactly like operator < - bool before(type_info const& rhs) const BOOST_NOEXCEPT { - #ifdef BOOST_CLASSINFO_COMPARE_BY_NAMES - return name() != rhs.name() && std::strcmp(name(), rhs.name()) < 0; - #else - return !!stl_type_info::before(rhs); - #endif - } - - /// Returns true if the type precedes the type of rhs in the collation order. - /// The collation order is just an internal order. - /// Works exactly like operator < - bool before(stl_type_info const& rhs) const BOOST_NOEXCEPT { - return before(static_cast(rhs)); - } - - /// Function for getting hash value - std::size_t hash_code() const BOOST_NOEXCEPT { -#if _MSC_VER > 1600 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5 && defined(__GXX_EXPERIMENTAL_CXX0X__)) - return stl_type_info::hash_code(); -#else - return boost::hash_range(name(), name() + std::strlen(name())); -#endif - } -}; - -#ifdef BOOST_CLASSINFO_COMPARE_BY_NAMES -#undef BOOST_CLASSINFO_COMPARE_BY_NAMES -#endif - -/// Function to get boost::type_info for a type T. -/// Strips const, volatile and & modifiers from T. -template -inline const type_info& type_id() BOOST_NOEXCEPT { - return type_info::construct(); -} - -/// Function for constructing boost::type_info instance for type T. -/// Does not strip const, volatile, & and && modifiers from T. -/// If T has no const, volatile, & and && modifiers, then returns exactly -/// the same result as in case of calling `type_id()`. -template -inline const type_info& type_id_with_cvr() BOOST_NOEXCEPT { - return type_info::construct_with_cvr(); -} - -/// Function that works exactly like C++ typeid(rtti_val) call, but returns boost::type_info. -/// This method available only with RTTI enabled. Without RTTI support it won't compile, -/// producing a compile-time error with message: "boost::type_id_rtti_only(T&) requires RTTI" -template -inline const type_info& type_id_rtti_only(T& rtti_val) BOOST_NOEXCEPT { -#ifdef BOOST_NO_RTTI - BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, "boost::type_id_rtti_only(T&) requires RTTI"); -#endif - return static_cast(typeid(rtti_val)); -} - -/// Function that works exactly like C++ typeid(rtti_val) call, but returns boost::type_info. -/// This method available only with RTTI enabled. Without RTTI support it won't compile, -/// producing a compile-time error with message: "boost::type_id_rtti_only(T*) requires RTTI" -template -inline const type_info& type_id_rtti_only(T* rtti_val) { -#ifdef BOOST_NO_RTTI - BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, "boost::type_id_rtti_only(T*) requires RTTI"); -#endif - return static_cast(typeid(rtti_val)); -} - -/* *************** type_info free functions ******************* */ - -#ifndef BOOST_TYPE_INDEX_DOXYGEN_INVOKED - -inline bool operator == (detail::stl_type_info const& lhs, type_info const& rhs) BOOST_NOEXCEPT { - return rhs == static_cast(lhs); -} - -inline bool operator != (detail::stl_type_info const& lhs, type_info const& rhs) BOOST_NOEXCEPT { - return !(lhs == rhs); -} - -#else // BOOST_TYPE_INDEX_DOXYGEN_INVOKED - -inline bool operator == (std::type_info const& lhs, type_info const& rhs) BOOST_NOEXCEPT; -inline bool operator != (std::type_info const& lhs, type_info const& rhs) BOOST_NOEXCEPT; - -#endif // BOOST_TYPE_INDEX_DOXYGEN_INVOKED - -/// hash_value function overload for boost::type_info. -inline std::size_t hash_value(type_info const& v) BOOST_NOEXCEPT { - return v.hash_code(); -} - -} // namespace boost - -#else // !defined(BOOST_NO_RTTI) && !defined(BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY) -# include -# include - -namespace boost { - -typedef template_info type_info; - -template -inline const type_info& type_id() BOOST_NOEXCEPT { - return template_info::construct(); -} - -template -inline const type_info& type_id_with_cvr() BOOST_NOEXCEPT { - return template_info::construct_with_cvr(); -} - -template -inline const type_info& type_id_rtti_only(T& rtti_val) BOOST_NOEXCEPT { - BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, "boost::type_id_rtti_only(T&) requires RTTI"); - return template_info::construct_with_cvr(); -} - -template -inline const type_info& type_id_rtti_only(T* rtti_val) { - BOOST_STATIC_ASSERT_MSG(sizeof(T) && false, "boost::type_id_rtti_only(T*) requires RTTI"); - return template_info::construct_with_cvr(); -} - -} // namespace boost - -#endif // (!defined(BOOST_NO_RTTI) && !defined(BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY)) || defined (BOOST_MSVC) - -#if defined(BOOST_TYPE_INDEX_DOXYGEN_INVOKED) -/// \def BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY -/// Define the BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY macro if you are mixing objects -/// compiled with different RTTI flags. This will force the usage of boost::template_index -/// class instead of boost::type_index. -#define BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY -#endif // BOOST_TYPE_INDEX_DOXYGEN_INVOKED - -#endif // BOOST_TYPE_INDEX_TYPE_INFO_HPP - diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 6865544..5e634d9 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -18,45 +18,45 @@ compat = BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY ; nortti = gcc:-fno-rtti clang:-fno-rtti msvc:/GR- ; -# Making libraries that CANNOT work between rtti-on/rtti-off modules -obj test_lib_nortti-obj : test_lib.cpp : shared off ; -obj test_lib_rtti-obj : test_lib.cpp : shared ; -lib test_lib_rtti : test_lib_rtti-obj : shared ; -lib test_lib_nortti : test_lib_nortti-obj : shared off ; +## Making libraries that CANNOT work between rtti-on/rtti-off modules +#obj test_lib_nortti-obj : test_lib.cpp : shared off ; +#obj test_lib_rtti-obj : test_lib.cpp : shared ; +#lib test_lib_rtti : test_lib_rtti-obj : shared ; +#lib test_lib_nortti : test_lib_nortti-obj : shared off ; -# Making libraries that can work between rtti-on/rtti-off modules -obj test_lib_nortti_compat-obj : test_lib.cpp : shared $(nortti) $(compat) ; -obj test_lib_rtti_compat-obj : test_lib.cpp : shared $(nortti) $(compat) ; -lib test_lib_nortti_compat : test_lib_nortti_compat-obj : shared $(nortti) $(compat) ; -lib test_lib_rtti_compat : test_lib_rtti_compat-obj : shared $(nortti) $(compat) ; +## Making libraries that can work between rtti-on/rtti-off modules +#obj test_lib_nortti_compat-obj : test_lib.cpp : shared $(nortti) $(compat) ; +#obj test_lib_rtti_compat-obj : test_lib.cpp : shared $(nortti) $(compat) ; +#lib test_lib_nortti_compat : test_lib_nortti_compat-obj : shared $(nortti) $(compat) ; +#lib test_lib_rtti_compat : test_lib_rtti_compat-obj : shared $(nortti) $(compat) ; test-suite type_index : [ run type_index_test.cpp $(tlib) ] - [ run template_index_test.cpp $(tlib) ] - [ run testing_both.cpp $(tlib) ] - [ run testing_both_no_rtti.cpp $(tlib) : : : off ] - [ run testing_crossmodule.cpp test_lib_rtti $(tlib) ] - [ run testing_crossmodule.cpp test_lib_nortti $(tlib) : : : off : testing_crossmodule_no_rtti ] +# [ run template_index_test.cpp $(tlib) ] +# [ run testing_both.cpp $(tlib) ] +# [ run testing_both_no_rtti.cpp $(tlib) : : : off ] +# [ run testing_crossmodule.cpp test_lib_rtti $(tlib) ] +# [ run testing_crossmodule.cpp test_lib_nortti $(tlib) : : : off : testing_crossmodule_no_rtti ] - # Mixing RTTI on and off - [ link-fail testing_crossmodule.cpp $(tlib) test_lib_rtti : $(nortti) : link_fail_nortti_rtti ] - # MSVC sometimes overrides the /GR-, that's why the following tests is disabled - #[ link-fail testing_crossmodule.cpp $(tlib) test_lib_nortti : : link_fail_rtti_nortti ] - [ run testing_crossmodule.cpp $(tlib) test_lib_rtti_compat : : : $(nortti) $(compat) : testing_crossmodule_nortti_rtti_compat ] - [ run testing_crossmodule.cpp $(tlib) test_lib_nortti_compat : : : $(compat) : testing_crossmodule_rtti_nortti_compat ] - - # Examples that must work even with RTTI disabled - [ run ../examples/registry.cpp : : : off : registry_no_rtti ] - [ run ../examples/exact_types_match.cpp : : : off : exact_types_match_no_rtti ] - [ run ../examples/demangled_names.cpp : : : off : demangled_names_no_rtti ] - [ compile-fail ../examples/inheritance.cpp : off : failing_inheritance_example ] +# # Mixing RTTI on and off +# [ link-fail testing_crossmodule.cpp $(tlib) test_lib_rtti : $(nortti) : link_fail_nortti_rtti ] +# # MSVC sometimes overrides the /GR-, that's why the following tests is disabled +# #[ link-fail testing_crossmodule.cpp $(tlib) test_lib_nortti : : link_fail_rtti_nortti ] +# [ run testing_crossmodule.cpp $(tlib) test_lib_rtti_compat : : : $(nortti) $(compat) : testing_crossmodule_nortti_rtti_compat ] +# [ run testing_crossmodule.cpp $(tlib) test_lib_nortti_compat : : : $(compat) : testing_crossmodule_rtti_nortti_compat ] +# +# # Examples that must work even with RTTI disabled +# [ run ../examples/registry.cpp : : : off : registry_no_rtti ] +# [ run ../examples/exact_types_match.cpp : : : off : exact_types_match_no_rtti ] +# [ run ../examples/demangled_names.cpp : : : off : demangled_names_no_rtti ] +# [ compile-fail ../examples/inheritance.cpp : off : failing_inheritance_example ] ; # Assuring that examples compile and run. Adding sources from `examples` directory to the `type_index` test suite. -for local p in [ glob ../examples/*.cpp ] -{ - type_index += [ run $(p) ] ; -} +#for local p in [ glob ../examples/*.cpp ] +#{ +# type_index += [ run $(p) ] ; +#} diff --git a/test/template_index_test.cpp b/test/template_index_test.cpp index 056ed8a..41ea92c 100644 --- a/test/template_index_test.cpp +++ b/test/template_index_test.cpp @@ -8,7 +8,7 @@ #define BOOST_TEST_MODULE template_index_test_module #include -#include +#include namespace my_namespace1 { class my_class{}; diff --git a/test/template_index_tests.ipp b/test/template_index_tests.ipp index 4a1d1c8..c13a48a 100644 --- a/test/template_index_tests.ipp +++ b/test/template_index_tests.ipp @@ -5,195 +5,4 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include -#include -BOOST_AUTO_TEST_CASE(names_matches_template_id) -{ - using namespace boost; - BOOST_CHECK_EQUAL(template_id().name_demangled(), "int"); - BOOST_CHECK_EQUAL(template_id().name_demangled(), "double"); - - BOOST_CHECK_EQUAL(template_id().name(), template_id().name()); - BOOST_CHECK_NE(template_id().name(), template_id().name()); - BOOST_CHECK_NE(template_id().name(), template_id().name()); - BOOST_CHECK_EQUAL(template_id().name(), template_id().name()); -} - -BOOST_AUTO_TEST_CASE(comparators_template_id) -{ - using namespace boost; - template_index t_int = template_id(); - template_index t_double = template_id(); - - BOOST_CHECK_EQUAL(t_int, t_int); - BOOST_CHECK_LE(t_int, t_int); - BOOST_CHECK_GE(t_int, t_int); - BOOST_CHECK_NE(t_int, t_double); - - BOOST_CHECK_LE(t_double, t_double); - BOOST_CHECK_GE(t_double, t_double); - BOOST_CHECK_NE(t_double, t_int); - - BOOST_CHECK(t_double < t_int || t_int < t_double); - BOOST_CHECK(t_double > t_int || t_int > t_double); -} - -BOOST_AUTO_TEST_CASE(hash_code_template_id) -{ - using namespace boost; - std::size_t t_int1 = template_id().hash_code(); - std::size_t t_double1 = template_id().hash_code(); - - std::size_t t_int2 = template_id().hash_code(); - std::size_t t_double2 = template_id().hash_code(); - - BOOST_CHECK_EQUAL(t_int1, t_int2); - BOOST_CHECK_NE(t_int1, t_double2); - BOOST_CHECK_LE(t_double1, t_double2); -} - -template -static void test_with_modofiers() { - using namespace boost; - - template_index t1 = template_id_with_cvr(); - template_index t2 = template_id_with_cvr(); - - BOOST_CHECK_NE(t2, t1); - BOOST_CHECK(t1 < t2 || t2 < t1); - BOOST_CHECK(t1 > t2 || t2 > t1); - - BOOST_CHECK_EQUAL(t1, template_id_with_cvr()); - BOOST_CHECK_EQUAL(t2, template_id_with_cvr()); - - BOOST_CHECK_EQUAL(t1.hash_code(), template_id_with_cvr().hash_code()); - BOOST_CHECK_EQUAL(t2.hash_code(), template_id_with_cvr().hash_code()); - - BOOST_CHECK_NE(t1.hash_code(), template_id_with_cvr().hash_code()); - BOOST_CHECK_NE(t2.hash_code(), template_id_with_cvr().hash_code()); -} - -BOOST_AUTO_TEST_CASE(template_id_storing_modifiers) -{ - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); - test_with_modofiers(); -#endif -} - -template -static void test_storing_nonstoring_modifiers_templ() { - using namespace boost; - - template_index t1 = template_id_with_cvr(); - template_index t2 = template_id(); - - BOOST_CHECK_EQUAL(t2, t1); - BOOST_CHECK_EQUAL(t1, t2); - BOOST_CHECK(t1 <= t2); - BOOST_CHECK(t1 >= t2); - BOOST_CHECK(t2 <= t1); - BOOST_CHECK(t2 >= t1); - - BOOST_CHECK_EQUAL(t2.name_demangled(), t1.name_demangled()); -} - -BOOST_AUTO_TEST_CASE(template_id_storing_modifiers_vs_nonstoring) -{ - test_storing_nonstoring_modifiers_templ(); - test_storing_nonstoring_modifiers_templ(); - test_storing_nonstoring_modifiers_templ(); - - boost::template_index t1 = boost::template_id_with_cvr(); - boost::template_index t2 = boost::template_id(); - BOOST_CHECK_NE(t2, t1); - BOOST_CHECK(t1.name_demangled() == "const int" || t1.name_demangled() == "int const"); -} - -BOOST_AUTO_TEST_CASE(template_index_stream_operator_via_lexical_cast_testing) -{ - using namespace boost; - - std::string s_int2 = lexical_cast(template_id()); - BOOST_CHECK_EQUAL(s_int2, "int"); - - std::string s_double2 = lexical_cast(template_id()); - BOOST_CHECK_EQUAL(s_double2, "double"); -} - -BOOST_AUTO_TEST_CASE(template_index_stripping_cvr_test) -{ - using namespace boost; - - BOOST_CHECK_EQUAL(template_id(), template_id()); - BOOST_CHECK_EQUAL(template_id(), template_id()); - BOOST_CHECK_EQUAL(template_id(), template_id()); - - BOOST_CHECK_EQUAL(template_id(), template_id()); - BOOST_CHECK_EQUAL(template_id(), template_id()); - BOOST_CHECK_EQUAL(template_id(), template_id()); - - - BOOST_CHECK_EQUAL(template_id(), template_id()); - BOOST_CHECK_EQUAL(template_id(), template_id()); - BOOST_CHECK_EQUAL(template_id(), template_id()); - - BOOST_CHECK_EQUAL(template_id(), template_id()); - BOOST_CHECK_EQUAL(template_id(), template_id()); - BOOST_CHECK_EQUAL(template_id(), template_id()); -} - - -BOOST_AUTO_TEST_CASE(template_index_user_defined_class_test) -{ - using namespace boost; - - BOOST_CHECK_EQUAL(template_id(), template_id()); - BOOST_CHECK_EQUAL(template_id(), template_id()); - - BOOST_CHECK_NE(template_id(), template_id()); - BOOST_CHECK_NE( - template_id().name_demangled().find("my_namespace1::my_class"), - std::string::npos); -} diff --git a/test/type_index_test.cpp b/test/type_index_test.cpp index 0d242d0..cd641e3 100644 --- a/test/type_index_test.cpp +++ b/test/type_index_test.cpp @@ -8,7 +8,10 @@ #define BOOST_TEST_MODULE type_index_test_module #include -#include +#include + +#include +#include namespace my_namespace1 { class my_class{}; @@ -19,4 +22,193 @@ namespace my_namespace2 { class my_class{}; } -#include "type_index_tests.ipp" + +BOOST_AUTO_TEST_CASE(names_matches_type_id) +{ + using namespace boost::typeind; + BOOST_CHECK_EQUAL(type_id().pretty_name(), "int"); + BOOST_CHECK_EQUAL(type_id().pretty_name(), "double"); + + BOOST_CHECK_EQUAL(type_id().name(), type_id().name()); + BOOST_CHECK_NE(type_id().name(), type_id().name()); + BOOST_CHECK_NE(type_id().name(), type_id().name()); + BOOST_CHECK_EQUAL(type_id().name(), type_id().name()); +} + +BOOST_AUTO_TEST_CASE(comparators_type_id) +{ + using namespace boost::typeind; + type_index t_int = type_id(); + type_index t_double = type_id(); + + BOOST_CHECK_EQUAL(t_int, t_int); + BOOST_CHECK_LE(t_int, t_int); + BOOST_CHECK_GE(t_int, t_int); + BOOST_CHECK_NE(t_int, t_double); + + BOOST_CHECK_LE(t_double, t_double); + BOOST_CHECK_GE(t_double, t_double); + BOOST_CHECK_NE(t_double, t_int); + + BOOST_CHECK(t_double < t_int || t_int < t_double); + BOOST_CHECK(t_double > t_int || t_int > t_double); +} + +BOOST_AUTO_TEST_CASE(hash_code_type_id) +{ + using namespace boost::typeind; + std::size_t t_int1 = type_id().hash_code(); + std::size_t t_double1 = type_id().hash_code(); + + std::size_t t_int2 = type_id().hash_code(); + std::size_t t_double2 = type_id().hash_code(); + + BOOST_CHECK_EQUAL(t_int1, t_int2); + BOOST_CHECK_NE(t_int1, t_double2); + BOOST_CHECK_LE(t_double1, t_double2); +} + +template +static void test_with_modofiers() { + using namespace boost::typeind; + + type_index t1 = type_id_with_cvr(); + type_index t2 = type_id_with_cvr(); + + BOOST_CHECK_NE(t2, t1); + BOOST_CHECK(t1 < t2 || t2 < t1); + BOOST_CHECK(t1 > t2 || t2 > t1); + + BOOST_CHECK_EQUAL(t1, type_id_with_cvr()); + BOOST_CHECK_EQUAL(t2, type_id_with_cvr()); + + BOOST_CHECK_EQUAL(t1.hash_code(), type_id_with_cvr().hash_code()); + BOOST_CHECK_EQUAL(t2.hash_code(), type_id_with_cvr().hash_code()); + + BOOST_CHECK_NE(t1.hash_code(), type_id_with_cvr().hash_code()); + BOOST_CHECK_NE(t2.hash_code(), type_id_with_cvr().hash_code()); +} + +BOOST_AUTO_TEST_CASE(type_id_storing_modifiers) +{ + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); + test_with_modofiers(); +#endif +} + +template +static void test_storing_nonstoring_modifiers_templ() { + using namespace boost::typeind; + + type_index t1 = type_id_with_cvr(); + type_index t2 = type_id(); + + BOOST_CHECK_EQUAL(t2, t1); + BOOST_CHECK_EQUAL(t1, t2); + BOOST_CHECK(t1 <= t2); + BOOST_CHECK(t1 >= t2); + BOOST_CHECK(t2 <= t1); + BOOST_CHECK(t2 >= t1); + + BOOST_CHECK_EQUAL(t2.pretty_name(), t1.pretty_name()); +} + +BOOST_AUTO_TEST_CASE(type_id_storing_modifiers_vs_nonstoring) +{ + test_storing_nonstoring_modifiers_templ(); + test_storing_nonstoring_modifiers_templ(); + test_storing_nonstoring_modifiers_templ(); + + boost::typeind::type_index t1 = boost::typeind::type_id_with_cvr(); + boost::typeind::type_index t2 = boost::typeind::type_id(); + BOOST_CHECK_NE(t2, t1); + BOOST_CHECK(t1.pretty_name() == "const int" || t1.pretty_name() == "int const"); +} + +BOOST_AUTO_TEST_CASE(type_index_stream_operator_via_lexical_cast_testing) +{ + using namespace boost::typeind; + + std::string s_int2 = boost::lexical_cast(type_id()); + BOOST_CHECK_EQUAL(s_int2, "int"); + + std::string s_double2 = boost::lexical_cast(type_id()); + BOOST_CHECK_EQUAL(s_double2, "double"); +} + +BOOST_AUTO_TEST_CASE(type_index_stripping_cvr_test) +{ + using namespace boost::typeind; + + BOOST_CHECK_EQUAL(type_id(), type_id()); + BOOST_CHECK_EQUAL(type_id(), type_id()); + BOOST_CHECK_EQUAL(type_id(), type_id()); + + BOOST_CHECK_EQUAL(type_id(), type_id()); + BOOST_CHECK_EQUAL(type_id(), type_id()); + BOOST_CHECK_EQUAL(type_id(), type_id()); + + + BOOST_CHECK_EQUAL(type_id(), type_id()); + BOOST_CHECK_EQUAL(type_id(), type_id()); + BOOST_CHECK_EQUAL(type_id(), type_id()); + + BOOST_CHECK_EQUAL(type_id(), type_id()); + BOOST_CHECK_EQUAL(type_id(), type_id()); + BOOST_CHECK_EQUAL(type_id(), type_id()); +} + + +BOOST_AUTO_TEST_CASE(type_index_user_defined_class_test) +{ + using namespace boost::typeind; + + BOOST_CHECK_EQUAL(type_id(), type_id()); + BOOST_CHECK_EQUAL(type_id(), type_id()); + + BOOST_CHECK_NE(type_id(), type_id()); + BOOST_CHECK_NE( + type_id().pretty_name().find("my_namespace1::my_class"), + std::string::npos); +} diff --git a/todos.txt b/todos.txt new file mode 100644 index 0000000..89184bb --- /dev/null +++ b/todos.txt @@ -0,0 +1,72 @@ +Sketch of TypeIndex v3 library interface: + +// boost/type_index/type_index_base.hpp +namespace boost{ namespace typeind { + +namespce detail { + +template +class type_index_base + const TypeInfo* data_; + +public: +type_index_base(const TypeInfo&); + +const char* raw_name() const noexcept; +const char* name() const noexcept; +const char* pretty_name() const; +std::size_t hash_value() const noexcept; +const TypeInfo& type_info() const noexcept; + +// comparison operators +}; + +}}} // namespace boost::typeind::detail + + +// boost/type_index.hpp +/// Contians core functionality for everyday use +namespace boost{ namespace typeind { + +// MSVC is capable of calling typeid(T) even when RTTI is off +#if (!defined(BOOST_NO_RTTI) && !defined(BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY)) || defined(BOOST_MSVC) +typedef std::type_info type_info; // RTTI on/off dependent +typedef type_index_base type_index; +#else +#else +#endif + +inline bool is_equal(const type_info&, const type_info&) noexcept; + +template +type_index type_id() noexcept; + +template +type_index type_id_with_cvr() noexcept; + +template +type_index type_id_runtime(const T&) noexcept; + +template +type_index type_id_runtime(const T*) noexcept; + +/* macro that must be put inside class to allow `type_id_runtime` calls with RTTI disabled */ +/// Empty if RTTI is on +#define BOOST_TYPE_INDEX_REGISTER_CLASS + +}} // namespace boost::typeind + +// boost/type_index/ctti.hpp +/// Contians minimal functionality required by boost/type_index.hpp with RTTI off +namespace boost { namespace detail { + template + struct ctti { + /// Returns raw name. Must be as short, as possible, to avoid code bloat + static const char* n() noexcept; + }; +} // namespace detail + +namespace typeind { + // Will be used instead of std::type_info when RTTI is off + class ctti_data; // POD. Interface is close to std::type_info +}}