]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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. | |
b32b8144 | 14 | /// Not intended for inclusion from user's code. |
7c673cae FG |
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 = ") | |
b32b8144 FG |
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 | |
7c673cae | 64 | BOOST_TYPE_INDEX_REGISTER_CTTI_PARSING_PARAMS(81, 1, false, "") |
b32b8144 FG |
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, "") | |
7c673cae FG |
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 | ||
b32b8144 | 78 | namespace boost { namespace typeindex { namespace detail { |
7c673cae FG |
79 | template <bool Condition> |
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> | |
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> | |
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> | |
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 | ||
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> | |
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> | |
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>( | |
b32b8144 | 155 | begin + ctti_skip_size_at_begin, |
7c673cae FG |
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 { | |
b32b8144 | 209 | |
7c673cae FG |
210 | #if !defined(__clang__) && defined(__GNUC__) && !defined(BOOST_NO_CXX14_CONSTEXPR) |
211 | //helper functions | |
212 | template <unsigned int I> | |
213 | 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> | |
233 | 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` | |
238 | 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 |