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