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