stl_type_index.hpp 8.8 KB

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