From 8e3466ece5e2d787e2ee0b9f9780c2521b66f4f5 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Tue, 29 Mar 2016 21:21:04 +0300 Subject: [PATCH] Log(N) complexity and templates depth in make_index_seq_impl, avoid usage of slow sizeof...(I), workaround GCC ICE in constexpr tests --- .travis.yml | 4 +- include/boost/type_index/ctti_type_index.hpp | 8 +- .../detail/compile_time_type_info.hpp | 139 ++++++++---------- test/type_index_constexpr_test.cpp | 31 ++-- 4 files changed, 80 insertions(+), 102 deletions(-) diff --git a/.travis.yml b/.travis.yml index 95195d3..63cf3a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,8 +41,8 @@ env: - CXX_FLAGS="--coverage -DBOOST_TRAVISCI_BUILD -std=c++98" LINK_FLAGS=--coverage TOOLSET=gcc - CXX_FLAGS="--coverage -DBOOST_TRAVISCI_BUILD -std=c++11" LINK_FLAGS=--coverage TOOLSET=gcc-5 - CXX_FLAGS="--coverage -DBOOST_TRAVISCI_BUILD -std=c++1y" LINK_FLAGS=--coverage TOOLSET=gcc-5 - - CXX_FLAGS="--coverage -DBOOST_TRAVISCI_BUILD -std=c++11 -stdlib=libc++" LINK_FLAGS="--coverage -stdlib=libc++" TOOLSET=clang - - CXX_FLAGS="--coverage -DBOOST_TRAVISCI_BUILD -std=c++1y -stdlib=libc++" LINK_FLAGS="--coverage -stdlib=libc++" TOOLSET=clang + #- CXX_FLAGS="--coverage -DBOOST_TRAVISCI_BUILD -std=c++11 -stdlib=libc++" LINK_FLAGS="--coverage -stdlib=libc++" TOOLSET=clang + #- CXX_FLAGS="--coverage -DBOOST_TRAVISCI_BUILD -std=c++1y -stdlib=libc++" LINK_FLAGS="--coverage -stdlib=libc++" TOOLSET=clang ############################################################################################################### # From this point and below code is same for all the Boost libs diff --git a/include/boost/type_index/ctti_type_index.hpp b/include/boost/type_index/ctti_type_index.hpp index 16f8eb5..611ad92 100644 --- a/include/boost/type_index/ctti_type_index.hpp +++ b/include/boost/type_index/ctti_type_index.hpp @@ -10,9 +10,9 @@ #define BOOST_TYPE_INDEX_CTTI_TYPE_INDEX_HPP /// \file ctti_type_index.hpp -/// \brief Contains boost::typeindex::ctti_type_index class. +/// \brief Contains boost::typeindex::ctti_type_index class that is constexpr if C++14 constexpr is supported by compiler. /// -/// boost::typeindex::ctti_type_index class can be used as a drop-in replacement +/// boost::typeindex::ctti_type_index class can be used as a drop-in replacement /// for std::type_index. /// /// It is used in situations when typeid() method is not available or @@ -89,7 +89,7 @@ inline const detail::ctti_data& ctti_construct() BOOST_NOEXCEPT { } /// \class ctti_type_index -/// This class is a wrapper that pretends to work exactly like stl_type_index, but does +/// This class is a wrapper that pretends to work exactly like stl_type_index, but does /// not require RTTI support. \b For \b description \b of \b functions \b see type_index_facade. /// /// This class on C++14 compatible compilers has following functions marked as constexpr: @@ -99,7 +99,7 @@ inline const detail::ctti_data& ctti_construct() BOOST_NOEXCEPT { /// * static methods type_id(), type_id_with_cvr() /// * comparison operators /// -/// This class produces slightly longer type names, so consider using stl_type_index +/// This class produces slightly longer type names, so consider using stl_type_index /// in situations when typeid() is working. class ctti_type_index: public type_index_facade { const char* data_; diff --git a/include/boost/type_index/detail/compile_time_type_info.hpp b/include/boost/type_index/detail/compile_time_type_info.hpp index 6e95827..4288bd6 100644 --- a/include/boost/type_index/detail/compile_time_type_info.hpp +++ b/include/boost/type_index/detail/compile_time_type_info.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) Antony Polukhin, 2012-2015. +// Copyright (c) Antony Polukhin, 2012-2016. // // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -22,13 +22,13 @@ #endif /// @cond -#define BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(begin_skip, end_skip, runtime_skip, runtime_skip_until) \ - namespace boost { namespace typeindex { namespace detail { \ - BOOST_STATIC_CONSTEXPR std::size_t ctti_skip_size_at_begin = begin_skip; \ - BOOST_STATIC_CONSTEXPR std::size_t ctti_skip_size_at_end = end_skip; \ - BOOST_STATIC_CONSTEXPR bool ctti_skip_more_at_runtime = runtime_skip; \ - BOOST_STATIC_CONSTEXPR char ctti_skip_until_runtime[] = runtime_skip_until; \ - }}} /* namespace boost::typeindex::detail */ \ +#define BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(begin_skip, end_skip, runtime_skip, runtime_skip_until) \ + namespace boost { namespace typeindex { namespace detail { \ + BOOST_STATIC_CONSTEXPR std::size_t ctti_skip_size_at_begin = begin_skip; \ + BOOST_STATIC_CONSTEXPR std::size_t ctti_skip_size_at_end = end_skip; \ + BOOST_STATIC_CONSTEXPR bool ctti_skip_more_at_runtime = runtime_skip; \ + BOOST_STATIC_CONSTEXPR char ctti_skip_until_runtime[] = runtime_skip_until; \ + }}} /* namespace boost::typeindex::detail */ \ /**/ /// @endcond @@ -36,19 +36,14 @@ #if defined(BOOST_TYPE_INDEX_DOXYGEN_INVOKED) /* Nothing to document. All the macro docs are moved to */ #elif defined(BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING) - # include BOOST_PP_EXPAND( BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING ) - -#elif defined(_MSC_VER) - -#if defined (BOOST_NO_CXX11_NOEXCEPT) +#elif defined(_MSC_VER) && defined (BOOST_NO_CXX11_NOEXCEPT) // sizeof("const char *__cdecl boost::detail::ctti<") - 1, sizeof(">::n(void)") - 1 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(40, 10, false, "") -#else +#elif defined(_MSC_VER) && !defined (BOOST_NO_CXX11_NOEXCEPT) // sizeof("const char *__cdecl boost::detail::ctti<") - 1, sizeof(">::n(void) noexcept") - 1 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(40, 19, false, "") -#endif #elif defined(__clang__) && defined(__APPLE__) // Someone made __clang_major__ equal to LLVM version rather than compiler version // on APPLE platform. @@ -64,16 +59,12 @@ // sizeof("static const char *boost::detail::ctti<") - 1, sizeof("]") - 1, true, "int>::n() [T = int" // note: checked on 3.1, 3.4 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(39, 1, true, "T = ") -#elif defined(__GNUC__) - -#ifndef BOOST_NO_CXX14_CONSTEXPR - // sizeof("static contexpr char boost::detail::ctti::s() [with long unsigned int Index = 0ul; T = ") - 1, sizeof("]") - 1 - BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(91, 1, false, "") -#else +#elif defined(__GNUC__) && !defined(BOOST_NO_CXX14_CONSTEXPR) + // sizeof("static contexpr char boost::detail::ctti::s() [with long unsigned int I = 0ul; T = ") - 1, sizeof("]") - 1 + BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(87, 1, false, "") +#elif defined(__GNUC__) && defined(BOOST_NO_CXX14_CONSTEXPR) // sizeof("static const char* boost::detail::ctti::n() [with T = ") - 1, sizeof("]") - 1 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(57, 1, false, "") -#endif - #else // Deafult code for other platforms... Just skip nothing! BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(0, 0, false, "") @@ -162,59 +153,45 @@ namespace boost { namespace typeindex { namespace detail { boost::mpl::bool_() ); } - -#if !defined(__clang__) && defined(__GNUC__) && !defined(BOOST_NO_CXX14_CONSTEXPR) - - template - struct switch_{ - typedef typename TDefault::type type; - }; - -#define DEFINE_SWITCH(Index) \ - template \ - struct switch_{ typedef typename T##Index::type type; }; \ - /**/ - - DEFINE_SWITCH(0) DEFINE_SWITCH(1) DEFINE_SWITCH(2) DEFINE_SWITCH(3) DEFINE_SWITCH(4) - DEFINE_SWITCH(5) DEFINE_SWITCH(6) DEFINE_SWITCH(7) DEFINE_SWITCH(8) -#undef DEFINE_SWITCH +#if !defined(__clang__) && defined(__GNUC__) && !defined(BOOST_NO_CXX14_CONSTEXPR) template struct index_seq {}; - template> - struct make_index_seq; - - template - struct make_index_seq > { - typedef typename switch_< - S - C - 1, - make_index_seq >, - make_index_seq >, - make_index_seq >, - make_index_seq >, - make_index_seq >, - make_index_seq >, - make_index_seq >, - make_index_seq >, - make_index_seq >, - make_index_seq > + template + struct make_index_sequence_join; + + template + struct make_index_sequence_join, index_seq > { + typedef index_seq type; + }; + + template + struct make_index_seq_impl { + typedef typename make_index_sequence_join< + typename make_index_seq_impl::type, + typename make_index_seq_impl::type >::type type; }; - template - struct make_index_seq > { - typedef index_seq type; + template + struct make_index_seq_impl { + typedef index_seq<> type; + }; + + template + struct make_index_seq_impl { + typedef index_seq type; }; template struct cstring { - static constexpr std::size_t size_ = sizeof...(C) + 1; - static constexpr char data_[size_] = { C..., '\0' }; + static constexpr std::size_t size_ = sizeof...(C); + static constexpr char data_[size_] = { C... }; }; template - constexpr char cstring::data_[]; + constexpr char cstring::data_[]; #endif }}} // namespace boost::typeindex::detail @@ -229,33 +206,33 @@ struct ctti { #if !defined(__clang__) && defined(__GNUC__) && !defined(BOOST_NO_CXX14_CONSTEXPR) //helper functions - template - constexpr static char s() { // step + template + constexpr static char s() BOOST_NOEXCEPT { // step constexpr std::size_t offset = - (Index >= 10u ? 1u : 0u) - + (Index >= 100u ? 1u : 0u) - + (Index >= 1000u ? 1u : 0u) - + (Index >= 10000u ? 1u : 0u) - + (Index >= 100000u ? 1u : 0u) - + (Index >= 1000000u ? 1u : 0u) + (I >= 10u ? 1u : 0u) + + (I >= 100u ? 1u : 0u) + + (I >= 1000u ? 1u : 0u) + + (I >= 10000u ? 1u : 0u) + + (I >= 100000u ? 1u : 0u) + + (I >= 1000000u ? 1u : 0u) ; #if defined(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE) - return BOOST_TYPE_INDEX_FUNCTION_SIGNATURE[Index + offset]; + return BOOST_TYPE_INDEX_FUNCTION_SIGNATURE[I + offset]; #elif defined(__FUNCSIG__) - return __FUNCSIG__[Index + offset]; + return __FUNCSIG__[I + offset]; #else - return __PRETTY_FUNCTION__[Index + offset]; + return __PRETTY_FUNCTION__[I + offset]; #endif } - + template - constexpr static const char* impl(::boost::typeindex::detail::index_seq ) { + constexpr static const char* impl(::boost::typeindex::detail::index_seq ) BOOST_NOEXCEPT { return ::boost::typeindex::detail::cstring()...>::data_; } - - template - constexpr static const char* n() { + + template // `D` means `Dummy` + constexpr static const char* n() BOOST_NOEXCEPT { #if defined(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE) constexpr std::size_t size = sizeof(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE); #elif defined(__FUNCSIG__) @@ -277,9 +254,9 @@ struct ctti { >(); static_assert(!boost::typeindex::detail::ctti_skip_more_at_runtime, "Skipping for GCC in C++14 mode is unsupported"); - typedef typename boost::typeindex::detail::make_index_seq< - size - sizeof("const *") + 1, - boost::typeindex::detail::ctti_skip_size_at_begin + typedef typename boost::typeindex::detail::make_index_seq_impl< + boost::typeindex::detail::ctti_skip_size_at_begin, + size - sizeof("const *") + 1 - boost::typeindex::detail::ctti_skip_size_at_begin >::type idx_seq; return impl(idx_seq()); } diff --git a/test/type_index_constexpr_test.cpp b/test/type_index_constexpr_test.cpp index 59176cf..dddd50b 100644 --- a/test/type_index_constexpr_test.cpp +++ b/test/type_index_constexpr_test.cpp @@ -74,16 +74,20 @@ void search_same() { ); } -/* -#ifndef BOOST_NO_CXX14_CONSTEXPR +template +BOOST_CXX14_CONSTEXPR bool in_namespace(const char (&ns)[N]) BOOST_NOEXCEPT { + BOOST_CXX14_CONSTEXPR const char* name = boost::typeindex::ctti_type_index::type_id().raw_name(); + for (std::size_t i = 0; i < N - 1; ++i) + if (name[i] != ns[i]) + return false; + + return true; +} + template -struct is_boost_namespace { - static constexpr char cb[5] = {'b', 'o', 'o', 's', 't'}; - static constexpr boost::typeindex::ctti_type_index type = boost::typeindex::ctti_type_index::type_id(); - static constexpr bool value = (boost::typeindex::detail::constexpr_search(type.name(), type.name() + 5, cb, cb + 5) != cb + 5); -}; -#endif -*/ +BOOST_CXX14_CONSTEXPR bool is_boost_namespace() BOOST_NOEXCEPT { + return in_namespace("boost::"); +} void constexpr_test() { using namespace boost::typeindex; @@ -127,15 +131,12 @@ void constexpr_test() { BOOST_CXX14_CONSTEXPR const char* short_name = t_short0.name(); BOOST_TEST(*short_name != '\0'); -/* -#ifndef BOOST_NO_CXX14_CONSTEXPR - constexpr bool in_namespace = is_boost_namespace::value; + + BOOST_CXX14_CONSTEXPR bool in_namespace = is_boost_namespace(); BOOST_TEST(in_namespace); - constexpr bool not_in_namespace = !is_boost_namespace::value; + BOOST_CXX14_CONSTEXPR bool not_in_namespace = !is_boost_namespace(); BOOST_TEST(not_in_namespace); -#endif -*/ }