compile_time_type_info.hpp 14 KB

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