1//
2// Copyright (c) Antony Polukhin, 2013-2017.
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_STL_TYPE_INDEX_HPP
10#define BOOST_TYPE_INDEX_STL_TYPE_INDEX_HPP
11
12/// \file stl_type_index.hpp
13/// \brief Contains boost::typeindex::stl_type_index class.
14///
15/// boost::typeindex::stl_type_index class can be used as a drop-in replacement
16/// for std::type_index.
17///
18/// It is used in situations when RTTI is enabled or typeid() method is available.
19/// When typeid() is disabled or BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY macro
20/// is defined boost::typeindex::ctti is usually used instead of boost::typeindex::stl_type_index.
21
22#include <boost/type_index/type_index_facade.hpp>
23
24// MSVC is capable of calling typeid(T) even when RTTI is off
25#if defined(BOOST_NO_RTTI) && !defined(BOOST_MSVC)
26#error "File boost/type_index/stl_type_index.ipp is not usable when typeid() is not available."
27#endif
28
29#include <typeinfo>
30#include <cstring> // std::strcmp, std::strlen, std::strstr
31#include <stdexcept>
32#include <boost/static_assert.hpp>
33#include <boost/throw_exception.hpp>
34#include <boost/core/demangle.hpp>
35#include <boost/type_traits/is_const.hpp>
36#include <boost/type_traits/is_reference.hpp>
37#include <boost/type_traits/is_volatile.hpp>
38#include <boost/type_traits/remove_cv.hpp>
39#include <boost/type_traits/remove_reference.hpp>
40#include <boost/mpl/if.hpp>
41#include <boost/mpl/or.hpp>
42
43#if !((defined(_MSC_VER) && _MSC_VER > 1600) \
44 || (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ > 5 && defined(__GXX_EXPERIMENTAL_CXX0X__)) \
45 || (defined(__GNUC__) && __GNUC__ > 4 && __cplusplus >= 201103 ))
46# include <boost/functional/hash.hpp>
47#endif
48
49#if (defined(__EDG_VERSION__) && __EDG_VERSION__ < 245) \
50 || (defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 744)
51# include <boost/type_traits/is_signed.hpp>
52# include <boost/type_traits/make_signed.hpp>
53# include <boost/mpl/identity.hpp>
54#endif
55
56#ifdef BOOST_HAS_PRAGMA_ONCE
57# pragma once
58#endif
59
60namespace boost { namespace typeindex {
61
62/// \class stl_type_index
63/// This class is a wrapper around std::type_info, that workarounds issues and provides
64/// much more rich interface. \b For \b description \b of \b functions \b see type_index_facade.
65///
66/// This class requires typeid() to work. For cases when RTTI is disabled see ctti_type_index.
67class stl_type_index
68 : public type_index_facade<
69 stl_type_index,
70 #ifdef BOOST_NO_STD_TYPEINFO
71 type_info
72 #else
73 std::type_info
74 #endif
75 >
76{
77public:
78#ifdef BOOST_NO_STD_TYPEINFO
79 typedef type_info type_info_t;
80#else
81 typedef std::type_info type_info_t;
82#endif
83
84private:
85 const type_info_t* data_;
86
87public:
88 inline stl_type_index() BOOST_NOEXCEPT
89 : data_(&typeid(void))
90 {}
91
92 inline stl_type_index(const type_info_t& data) BOOST_NOEXCEPT
93 : data_(&data)
94 {}
95
96 inline const type_info_t& type_info() const BOOST_NOEXCEPT;
97
98 inline const char* raw_name() const BOOST_NOEXCEPT;
99 inline const char* name() const BOOST_NOEXCEPT;
100 inline std::string pretty_name() const;
101
102 inline std::size_t hash_code() const BOOST_NOEXCEPT;
103 inline bool equal(const stl_type_index& rhs) const BOOST_NOEXCEPT;
104 inline bool before(const stl_type_index& rhs) const BOOST_NOEXCEPT;
105
106 template <class T>
107 inline static stl_type_index type_id() BOOST_NOEXCEPT;
108
109 template <class T>
110 inline static stl_type_index type_id_with_cvr() BOOST_NOEXCEPT;
111
112 template <class T>
113 inline static stl_type_index type_id_runtime(const T& value) BOOST_NOEXCEPT;
114};
115
116inline const stl_type_index::type_info_t& stl_type_index::type_info() const BOOST_NOEXCEPT {
117 return *data_;
118}
119
120
121inline const char* stl_type_index::raw_name() const BOOST_NOEXCEPT {
122#ifdef _MSC_VER
123 return data_->raw_name();
124#else
125 return data_->name();
126#endif
127}
128
129inline const char* stl_type_index::name() const BOOST_NOEXCEPT {
130 return data_->name();
131}
132
133inline std::string stl_type_index::pretty_name() const {
134 static const char cvr_saver_name[] = "boost::typeindex::detail::cvr_saver<";
135 static BOOST_CONSTEXPR_OR_CONST std::string::size_type cvr_saver_name_len = sizeof(cvr_saver_name) - 1;
136
137 // In case of MSVC demangle() is a no-op, and name() already returns demangled name.
138 // In case of GCC and Clang (on non-Windows systems) name() returns mangled name and demangle() undecorates it.
139 const boost::core::scoped_demangled_name demangled_name(data_->name());
140
141 const char* begin = demangled_name.get();
142 if (!begin) {
143 boost::throw_exception(std::runtime_error("Type name demangling failed"));
144 }
145
146 const std::string::size_type len = std::strlen(begin);
147 const char* end = begin + len;
148
149 if (len > cvr_saver_name_len) {
150 const char* b = std::strstr(begin, cvr_saver_name);
151 if (b) {
152 b += cvr_saver_name_len;
153
154 // Trim leading spaces
155 while (*b == ' ') { // the string is zero terminated, we won't exceed the buffer size
156 ++ b;
157 }
158
159 // Skip the closing angle bracket
160 const char* e = end - 1;
161 while (e > b && *e != '>') {
162 -- e;
163 }
164
165 // Trim trailing spaces
166 while (e > b && *(e - 1) == ' ') {
167 -- e;
168 }
169
170 if (b < e) {
171 // Parsing seems to have succeeded, the type name is not empty
172 begin = b;
173 end = e;
174 }
175 }
176 }
177
178 return std::string(begin, end);
179}
180
181
182inline std::size_t stl_type_index::hash_code() const BOOST_NOEXCEPT {
183#if (defined(_MSC_VER) && _MSC_VER > 1600) \
184 || (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ > 5 && defined(__GXX_EXPERIMENTAL_CXX0X__)) \
185 || (defined(__GNUC__) && __GNUC__ > 4 && __cplusplus >= 201103)
186 return data_->hash_code();
187#else
188 return boost::hash_range(raw_name(), raw_name() + std::strlen(raw_name()));
189#endif
190}
191
192
193/// @cond
194
195// for this compiler at least, cross-shared-library type_info
196// comparisons don't work, so we are using typeid(x).name() instead.
197# if (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5))) \
198 || defined(_AIX) \
199 || (defined(__sgi) && defined(__host_mips)) \
200 || (defined(__hpux) && defined(__HP_aCC)) \
201 || (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC))
202# define BOOST_CLASSINFO_COMPARE_BY_NAMES
203# endif
204
205/// @endcond
206
207inline bool stl_type_index::equal(const stl_type_index& rhs) const BOOST_NOEXCEPT {
208#ifdef BOOST_CLASSINFO_COMPARE_BY_NAMES
209 return raw_name() == rhs.raw_name() || !std::strcmp(raw_name(), rhs.raw_name());
210#else
211 return !!(*data_ == *rhs.data_);
212#endif
213}
214
215inline bool stl_type_index::before(const stl_type_index& rhs) const BOOST_NOEXCEPT {
216#ifdef BOOST_CLASSINFO_COMPARE_BY_NAMES
217 return raw_name() != rhs.raw_name() && std::strcmp(raw_name(), rhs.raw_name()) < 0;
218#else
219 return !!data_->before(*rhs.data_);
220#endif
221}
222
223#ifdef BOOST_CLASSINFO_COMPARE_BY_NAMES
224#undef BOOST_CLASSINFO_COMPARE_BY_NAMES
225#endif
226
227
228
229template <class T>
230inline stl_type_index stl_type_index::type_id() BOOST_NOEXCEPT {
231 typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type no_ref_t;
232 typedef BOOST_DEDUCED_TYPENAME boost::remove_cv<no_ref_t>::type no_cvr_prefinal_t;
233
234 # if (defined(__EDG_VERSION__) && __EDG_VERSION__ < 245) \
235 || (defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 744)
236
237 // Old EDG-based compilers seem to mistakenly distinguish 'integral' from 'signed integral'
238 // in typeid() expressions. Full template specialization for 'integral' fixes that issue:
239 typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_<
240 boost::is_signed<no_cvr_prefinal_t>,
241 boost::make_signed<no_cvr_prefinal_t>,
242 boost::mpl::identity<no_cvr_prefinal_t>
243 >::type no_cvr_prefinal_lazy_t;
244
245 typedef BOOST_DEDUCED_TYPENAME no_cvr_prefinal_t::type no_cvr_t;
246 #else
247 typedef no_cvr_prefinal_t no_cvr_t;
248 #endif
249
250 return typeid(no_cvr_t);
251}
252
253namespace detail {
254 template <class T> class cvr_saver{};
255}
256
257template <class T>
258inline stl_type_index stl_type_index::type_id_with_cvr() BOOST_NOEXCEPT {
259 typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_<
260 boost::mpl::or_<boost::is_reference<T>, boost::is_const<T>, boost::is_volatile<T> >,
261 detail::cvr_saver<T>,
262 T
263 >::type type;
264
265 return typeid(type);
266}
267
268
269template <class T>
270inline stl_type_index stl_type_index::type_id_runtime(const T& value) BOOST_NOEXCEPT {
271#ifdef BOOST_NO_RTTI
272 return value.boost_type_index_type_id_runtime_();
273#else
274 return typeid(value);
275#endif
276}
277
278}} // namespace boost::typeindex
279
280#endif // BOOST_TYPE_INDEX_STL_TYPE_INDEX_HPP
281