1 // 2 // Copyright (c) Antony Polukhin, 2012-2016. 3 // 4 // 5 // Distributed under the Boost Software License, Version 1.0. (See accompanying 6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 // 8 9 #ifndef BOOST_TYPE_INDEX_DETAIL_COMPILE_TIME_TYPE_INFO_HPP 10 #define BOOST_TYPE_INDEX_DETAIL_COMPILE_TIME_TYPE_INFO_HPP 11 12 /// \file compile_time_type_info.hpp 13 /// \brief Contains helper macros and implementation details of boost::typeindex::ctti_type_index. 14 /// Not intended for inclusion from user's code. 15 16 #include <boost/config.hpp> 17 #include <boost/static_assert.hpp> 18 #include <boost/mpl/bool.hpp> 19 20 #ifdef BOOST_HAS_PRAGMA_ONCE 21 # pragma once 22 #endif 23 24 /// @cond 25 #define BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(begin_skip, end_skip, runtime_skip, runtime_skip_until) \ 26 namespace boost { namespace typeindex { namespace detail { \ 27 BOOST_STATIC_CONSTEXPR std::size_t ctti_skip_size_at_begin = begin_skip; \ 28 BOOST_STATIC_CONSTEXPR std::size_t ctti_skip_size_at_end = end_skip; \ 29 BOOST_STATIC_CONSTEXPR bool ctti_skip_more_at_runtime = runtime_skip; \ 30 BOOST_STATIC_CONSTEXPR char ctti_skip_until_runtime[] = runtime_skip_until; \ 31 }}} /* namespace boost::typeindex::detail */ \ 32 /**/ 33 /// @endcond 34 35 36 #if defined(BOOST_TYPE_INDEX_DOXYGEN_INVOKED) 37 /* Nothing to document. All the macro docs are moved to <boost/type_index.hpp> */ 38 #elif defined(BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING) 39 # include <boost/preprocessor/facilities/expand.hpp> 40 BOOST_PP_EXPAND( BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING ) 41 #elif defined(_MSC_VER) && defined (BOOST_NO_CXX11_NOEXCEPT) 42 // sizeof("const char *__cdecl boost::detail::ctti<") - 1, sizeof(">::n(void)") - 1 43 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(40, 10, false, "") 44 #elif defined(_MSC_VER) && !defined (BOOST_NO_CXX11_NOEXCEPT) 45 // sizeof("const char *__cdecl boost::detail::ctti<") - 1, sizeof(">::n(void) noexcept") - 1 46 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(40, 19, false, "") 47 #elif defined(__clang__) && defined(__APPLE__) 48 // Someone made __clang_major__ equal to LLVM version rather than compiler version 49 // on APPLE platform. 50 // 51 // Using less efficient solution because there is no good way to detect real version of Clang. 52 // sizeof("static const char *boost::detail::ctti<") - 1, sizeof("]") - 1, true, "???????????>::n() [T = int" 53 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(39, 1, true, "T = ") 54 #elif defined(__clang__) && (__clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ == 0)) 55 // sizeof("static const char *boost::detail::ctti<") - 1, sizeof(">::n()") - 1 56 // note: checked on 3.0 57 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(39, 6, false, "") 58 #elif defined(__clang__) && (__clang_major__ >= 4 || (__clang_major__ == 3 && __clang_minor__ > 0)) 59 // sizeof("static const char *boost::detail::ctti<") - 1, sizeof("]") - 1, true, "int>::n() [T = int" 60 // note: checked on 3.1, 3.4 61 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(39, 1, true, "T = ") 62 #elif defined(__GNUC__) && (__GNUC__ < 7) && !defined(BOOST_NO_CXX14_CONSTEXPR) 63 // sizeof("static constexpr char boost::detail::ctti<T>::s() [with unsigned int I = 0u; T = ") - 1, sizeof("]") - 1 64 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(81, 1, false, "") 65 #elif defined(__GNUC__) && (__GNUC__ >= 7) && !defined(BOOST_NO_CXX14_CONSTEXPR) 66 // sizeof("static constexpr char boost::detail::ctti<T>::s() [with unsigned int I = 0; T = ") - 1, sizeof("]") - 1 67 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(80, 1, false, "") 68 #elif defined(__GNUC__) && defined(BOOST_NO_CXX14_CONSTEXPR) 69 // sizeof("static const char* boost::detail::ctti<T>::n() [with T = ") - 1, sizeof("]") - 1 70 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(57, 1, false, "") 71 #else 72 // Deafult code for other platforms... Just skip nothing! 73 BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(0, 0, false, "") 74 #endif 75 76 #undef BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS 77 78 namespace boost { namespace typeindex { namespace detail { 79 template <bool Condition> assert_compile_time_legths()80 BOOST_CXX14_CONSTEXPR inline void assert_compile_time_legths() BOOST_NOEXCEPT { 81 BOOST_STATIC_ASSERT_MSG( 82 Condition, 83 "TypeIndex library is misconfigured for your compiler. " 84 "Please define BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING to correct values. See section " 85 "'RTTI emulation limitations' of the documentation for more information." 86 ); 87 } 88 89 template <class T> failed_to_get_function_name()90 BOOST_CXX14_CONSTEXPR inline void failed_to_get_function_name() BOOST_NOEXCEPT { 91 BOOST_STATIC_ASSERT_MSG( 92 sizeof(T) && false, 93 "TypeIndex library could not detect your compiler. " 94 "Please make the BOOST_TYPE_INDEX_FUNCTION_SIGNATURE macro use " 95 "correct compiler macro for getting the whole function name. " 96 "Define BOOST_TYPE_INDEX_CTTI_USER_DEFINED_PARSING to correct value after that." 97 ); 98 } 99 100 template <unsigned int ArrayLength> skip_begining_runtime(const char * begin,boost::mpl::false_)101 BOOST_CXX14_CONSTEXPR inline const char* skip_begining_runtime(const char* begin, boost::mpl::false_) BOOST_NOEXCEPT { 102 return begin; 103 } 104 105 template<class ForwardIterator1, class ForwardIterator2> constexpr_search(ForwardIterator1 first1,ForwardIterator1 last1,ForwardIterator2 first2,ForwardIterator2 last2)106 BOOST_CXX14_CONSTEXPR inline ForwardIterator1 constexpr_search( 107 ForwardIterator1 first1, 108 ForwardIterator1 last1, 109 ForwardIterator2 first2, 110 ForwardIterator2 last2) BOOST_NOEXCEPT 111 { 112 if (first2 == last2) { 113 return first1; // specified in C++11 114 } 115 116 while (first1 != last1) { 117 ForwardIterator1 it1 = first1; 118 ForwardIterator2 it2 = first2; 119 120 while (*it1 == *it2) { 121 ++it1; 122 ++it2; 123 if (it2 == last2) return first1; 124 if (it1 == last1) return last1; 125 } 126 127 ++first1; 128 } 129 130 return last1; 131 } 132 constexpr_strcmp(const char * v1,const char * v2)133 BOOST_CXX14_CONSTEXPR inline int constexpr_strcmp(const char *v1, const char *v2) BOOST_NOEXCEPT { 134 while (*v1 != '\0' && *v1 == *v2) { 135 ++v1; 136 ++v2; 137 }; 138 139 return static_cast<int>(*v1) - *v2; 140 } 141 142 template <unsigned int ArrayLength> skip_begining_runtime(const char * begin,boost::mpl::true_)143 BOOST_CXX14_CONSTEXPR inline const char* skip_begining_runtime(const char* begin, boost::mpl::true_) BOOST_NOEXCEPT { 144 const char* const it = constexpr_search( 145 begin, begin + ArrayLength, 146 ctti_skip_until_runtime, ctti_skip_until_runtime + sizeof(ctti_skip_until_runtime) - 1 147 ); 148 return (it == begin + ArrayLength ? begin : it + sizeof(ctti_skip_until_runtime) - 1); 149 } 150 151 template <unsigned int ArrayLength> skip_begining(const char * begin)152 BOOST_CXX14_CONSTEXPR inline const char* skip_begining(const char* begin) BOOST_NOEXCEPT { 153 assert_compile_time_legths<(ArrayLength > ctti_skip_size_at_begin + ctti_skip_size_at_end)>(); 154 return skip_begining_runtime<ArrayLength - ctti_skip_size_at_begin>( 155 begin + ctti_skip_size_at_begin, 156 boost::mpl::bool_<ctti_skip_more_at_runtime>() 157 ); 158 } 159 160 #if !defined(__clang__) && defined(__GNUC__) && !defined(BOOST_NO_CXX14_CONSTEXPR) 161 template <unsigned int... I> 162 struct index_seq {}; 163 164 template <typename Left, typename Right> 165 struct make_index_sequence_join; 166 167 template <unsigned int... Left, unsigned int... Right> 168 struct make_index_sequence_join<index_seq<Left...>, index_seq<Right...> > { 169 typedef index_seq<Left..., Right...> type; 170 }; 171 172 template <unsigned int C, unsigned int D> 173 struct make_index_seq_impl { 174 typedef typename make_index_sequence_join< 175 typename make_index_seq_impl<C, D / 2>::type, 176 typename make_index_seq_impl<C + D / 2, (D + 1) / 2>::type 177 >::type type; 178 }; 179 180 template <unsigned int C> 181 struct make_index_seq_impl<C, 0> { 182 typedef index_seq<> type; 183 }; 184 185 template <unsigned int C> 186 struct make_index_seq_impl<C, 1> { 187 typedef index_seq<C> type; 188 }; 189 190 template <char... C> 191 struct cstring { 192 static constexpr unsigned int size_ = sizeof...(C); 193 static constexpr char data_[size_] = { C... }; 194 }; 195 196 template <char... C> 197 constexpr char cstring<C...>::data_[]; 198 #endif 199 200 }}} // namespace boost::typeindex::detail 201 202 namespace boost { namespace detail { 203 204 /// Noncopyable type_info that does not require RTTI. 205 /// CTTI == Compile Time Type Info. 206 /// This name must be as short as possible, to avoid code bloat 207 template <class T> 208 struct ctti { 209 210 #if !defined(__clang__) && defined(__GNUC__) && !defined(BOOST_NO_CXX14_CONSTEXPR) 211 //helper functions 212 template <unsigned int I> sboost::detail::ctti213 constexpr static char s() BOOST_NOEXCEPT { // step 214 constexpr unsigned int offset = 215 (I >= 10u ? 1u : 0u) 216 + (I >= 100u ? 1u : 0u) 217 + (I >= 1000u ? 1u : 0u) 218 + (I >= 10000u ? 1u : 0u) 219 + (I >= 100000u ? 1u : 0u) 220 + (I >= 1000000u ? 1u : 0u) 221 ; 222 223 #if defined(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE) 224 return BOOST_TYPE_INDEX_FUNCTION_SIGNATURE[I + offset]; 225 #elif defined(__FUNCSIG__) 226 return __FUNCSIG__[I + offset]; 227 #else 228 return __PRETTY_FUNCTION__[I + offset]; 229 #endif 230 } 231 232 template <unsigned int ...Indexes> implboost::detail::ctti233 constexpr static const char* impl(::boost::typeindex::detail::index_seq<Indexes...> ) BOOST_NOEXCEPT { 234 return ::boost::typeindex::detail::cstring<s<Indexes>()...>::data_; 235 } 236 237 template <unsigned int D = 0> // `D` means `Dummy` nboost::detail::ctti238 constexpr static const char* n() BOOST_NOEXCEPT { 239 #if defined(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE) 240 constexpr unsigned int size = sizeof(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE); 241 #elif defined(__FUNCSIG__) 242 constexpr unsigned int size = sizeof(__FUNCSIG__); 243 #elif defined(__PRETTY_FUNCTION__) \ 244 || defined(__GNUC__) \ 245 || (defined(__SUNPRO_CC) && (__SUNPRO_CC >= 0x5130)) \ 246 || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) \ 247 || (defined(__ICC) && (__ICC >= 600)) \ 248 || defined(__ghs__) \ 249 || defined(__DMC__) 250 constexpr unsigned int size = sizeof(__PRETTY_FUNCTION__); 251 #else 252 boost::typeindex::detail::failed_to_get_function_name(); 253 #endif 254 255 boost::typeindex::detail::assert_compile_time_legths< 256 (size > boost::typeindex::detail::ctti_skip_size_at_begin + boost::typeindex::detail::ctti_skip_size_at_end + sizeof("const *") - 1) 257 >(); 258 static_assert(!boost::typeindex::detail::ctti_skip_more_at_runtime, "Skipping for GCC in C++14 mode is unsupported"); 259 260 typedef typename boost::typeindex::detail::make_index_seq_impl< 261 boost::typeindex::detail::ctti_skip_size_at_begin, 262 size - sizeof("const *") + 1 - boost::typeindex::detail::ctti_skip_size_at_begin 263 >::type idx_seq; 264 return impl(idx_seq()); 265 } 266 #else 267 /// Returns raw name. Must be as short, as possible, to avoid code bloat 268 BOOST_CXX14_CONSTEXPR static const char* n() BOOST_NOEXCEPT { 269 #if defined(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE) 270 return boost::typeindex::detail::skip_begining< sizeof(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE) >(BOOST_TYPE_INDEX_FUNCTION_SIGNATURE); 271 #elif defined(__FUNCSIG__) 272 return boost::typeindex::detail::skip_begining< sizeof(__FUNCSIG__) >(__FUNCSIG__); 273 #elif defined(__PRETTY_FUNCTION__) \ 274 || defined(__GNUC__) \ 275 || (defined(__SUNPRO_CC) && (__SUNPRO_CC >= 0x5130)) \ 276 || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) \ 277 || (defined(__ICC) && (__ICC >= 600)) \ 278 || defined(__ghs__) \ 279 || defined(__DMC__) 280 return boost::typeindex::detail::skip_begining< sizeof(__PRETTY_FUNCTION__) >(__PRETTY_FUNCTION__); 281 #else 282 boost::typeindex::detail::failed_to_get_function_name(); 283 return ""; 284 #endif 285 } 286 #endif 287 }; 288 289 }} // namespace boost::detail 290 291 #endif // BOOST_TYPE_INDEX_DETAIL_COMPILE_TIME_TYPE_INFO_HPP 292