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