ctti_type_index.hpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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_CTTI_TYPE_INDEX_HPP
  9. #define BOOST_TYPE_INDEX_CTTI_TYPE_INDEX_HPP
  10. /// \file ctti_type_index.hpp
  11. /// \brief Contains boost::typeindex::ctti_type_index class that is constexpr if C++14 constexpr is supported by compiler.
  12. ///
  13. /// boost::typeindex::ctti_type_index class can be used as a drop-in replacement
  14. /// for std::type_index.
  15. ///
  16. /// It is used in situations when typeid() method is not available or
  17. /// BOOST_TYPE_INDEX_FORCE_NO_RTTI_COMPATIBILITY macro is defined.
  18. #include <boost/type_index/type_index_facade.hpp>
  19. #include <boost/type_index/detail/compile_time_type_info.hpp>
  20. #include <cstring>
  21. #include <boost/container_hash/hash.hpp>
  22. #include <boost/static_assert.hpp>
  23. #include <boost/type_traits/remove_cv.hpp>
  24. #include <boost/type_traits/remove_reference.hpp>
  25. #ifdef BOOST_HAS_PRAGMA_ONCE
  26. # pragma once
  27. #endif
  28. namespace boost { namespace typeindex {
  29. namespace detail {
  30. // That's the most trickiest part of the TypeIndex library:
  31. // 1) we do not want to give user ability to manually construct and compare `struct-that-represents-type`
  32. // 2) we need to distinguish between `struct-that-represents-type` and `const char*`
  33. // 3) we need a thread-safe way to have references to instances `struct-that-represents-type`
  34. // 4) we need a compile-time control to make sure that user does not copy or
  35. // default construct `struct-that-represents-type`
  36. //
  37. // Solution would be the following:
  38. /// \class ctti_data
  39. /// Standard-layout class with private constructors and assignment operators.
  40. ///
  41. /// You can not work with this class directly. The purpose of this class is to hold type info
  42. /// \b when \b RTTI \b is \b off and allow ctti_type_index construction from itself.
  43. ///
  44. /// \b Example:
  45. /// \code
  46. /// const detail::ctti_data& foo();
  47. /// ...
  48. /// type_index ti = type_index(foo());
  49. /// std::cout << ti.pretty_name();
  50. /// \endcode
  51. class ctti_data {
  52. #ifndef BOOST_NO_CXX11_DELETED_FUNCTIONS
  53. public:
  54. ctti_data() = delete;
  55. ctti_data(const ctti_data&) = delete;
  56. ctti_data& operator=(const ctti_data&) = delete;
  57. #else
  58. private:
  59. ctti_data();
  60. ctti_data(const ctti_data&);
  61. ctti_data& operator=(const ctti_data&);
  62. #endif
  63. };
  64. } // namespace detail
  65. /// Helper method for getting detail::ctti_data of a template parameter T.
  66. template <class T>
  67. inline const detail::ctti_data& ctti_construct() BOOST_NOEXCEPT {
  68. // Standard C++11, 5.2.10 Reinterpret cast:
  69. // An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue
  70. // v of type "pointer to T1" is converted to the type "pointer to cv T2", the result is static_cast<cv
  71. // T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment
  72. // requirements of T2 are no stricter than those of T1, or if either type is void. Converting a prvalue of type
  73. // "pointer to T1" to the type "pointer to T2" (where T1 and T2 are object types and where the alignment
  74. // requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer
  75. // value.
  76. //
  77. // Alignments are checked in `type_index_test_ctti_alignment.cpp` test.
  78. return *reinterpret_cast<const detail::ctti_data*>(boost::detail::ctti<T>::n());
  79. }
  80. /// \class ctti_type_index
  81. /// This class is a wrapper that pretends to work exactly like stl_type_index, but does
  82. /// not require RTTI support. \b For \b description \b of \b functions \b see type_index_facade.
  83. ///
  84. /// This class on C++14 compatible compilers has following functions marked as constexpr:
  85. /// * default constructor
  86. /// * copy constructors and assignemnt operations
  87. /// * class methods: name(), before(const ctti_type_index& rhs), equal(const ctti_type_index& rhs)
  88. /// * static methods type_id<T>(), type_id_with_cvr<T>()
  89. /// * comparison operators
  90. ///
  91. /// This class produces slightly longer type names, so consider using stl_type_index
  92. /// in situations when typeid() is working.
  93. class ctti_type_index: public type_index_facade<ctti_type_index, detail::ctti_data> {
  94. const char* data_;
  95. inline std::size_t get_raw_name_length() const BOOST_NOEXCEPT;
  96. BOOST_CXX14_CONSTEXPR inline explicit ctti_type_index(const char* data) BOOST_NOEXCEPT
  97. : data_(data)
  98. {}
  99. public:
  100. typedef detail::ctti_data type_info_t;
  101. BOOST_CXX14_CONSTEXPR inline ctti_type_index() BOOST_NOEXCEPT
  102. : data_(boost::detail::ctti<void>::n())
  103. {}
  104. inline ctti_type_index(const type_info_t& data) BOOST_NOEXCEPT
  105. : data_(reinterpret_cast<const char*>(&data))
  106. {}
  107. inline const type_info_t& type_info() const BOOST_NOEXCEPT;
  108. BOOST_CXX14_CONSTEXPR inline const char* raw_name() const BOOST_NOEXCEPT;
  109. BOOST_CXX14_CONSTEXPR inline const char* name() const BOOST_NOEXCEPT;
  110. inline std::string pretty_name() const;
  111. inline std::size_t hash_code() const BOOST_NOEXCEPT;
  112. BOOST_CXX14_CONSTEXPR inline bool equal(const ctti_type_index& rhs) const BOOST_NOEXCEPT;
  113. BOOST_CXX14_CONSTEXPR inline bool before(const ctti_type_index& rhs) const BOOST_NOEXCEPT;
  114. template <class T>
  115. BOOST_CXX14_CONSTEXPR inline static ctti_type_index type_id() BOOST_NOEXCEPT;
  116. template <class T>
  117. BOOST_CXX14_CONSTEXPR inline static ctti_type_index type_id_with_cvr() BOOST_NOEXCEPT;
  118. template <class T>
  119. inline static ctti_type_index type_id_runtime(const T& variable) BOOST_NOEXCEPT;
  120. };
  121. inline const ctti_type_index::type_info_t& ctti_type_index::type_info() const BOOST_NOEXCEPT {
  122. return *reinterpret_cast<const detail::ctti_data*>(data_);
  123. }
  124. BOOST_CXX14_CONSTEXPR inline bool ctti_type_index::equal(const ctti_type_index& rhs) const BOOST_NOEXCEPT {
  125. const char* const left = raw_name();
  126. const char* const right = rhs.raw_name();
  127. return /*left == right ||*/ !boost::typeindex::detail::constexpr_strcmp(left, right);
  128. }
  129. BOOST_CXX14_CONSTEXPR inline bool ctti_type_index::before(const ctti_type_index& rhs) const BOOST_NOEXCEPT {
  130. const char* const left = raw_name();
  131. const char* const right = rhs.raw_name();
  132. return /*left != right &&*/ boost::typeindex::detail::constexpr_strcmp(left, right) < 0;
  133. }
  134. template <class T>
  135. BOOST_CXX14_CONSTEXPR inline ctti_type_index ctti_type_index::type_id() BOOST_NOEXCEPT {
  136. typedef BOOST_DEDUCED_TYPENAME boost::remove_reference<T>::type no_ref_t;
  137. typedef BOOST_DEDUCED_TYPENAME boost::remove_cv<no_ref_t>::type no_cvr_t;
  138. return ctti_type_index(boost::detail::ctti<no_cvr_t>::n());
  139. }
  140. template <class T>
  141. BOOST_CXX14_CONSTEXPR inline ctti_type_index ctti_type_index::type_id_with_cvr() BOOST_NOEXCEPT {
  142. return ctti_type_index(boost::detail::ctti<T>::n());
  143. }
  144. template <class T>
  145. inline ctti_type_index ctti_type_index::type_id_runtime(const T& variable) BOOST_NOEXCEPT {
  146. return variable.boost_type_index_type_id_runtime_();
  147. }
  148. BOOST_CXX14_CONSTEXPR inline const char* ctti_type_index::raw_name() const BOOST_NOEXCEPT {
  149. return data_;
  150. }
  151. BOOST_CXX14_CONSTEXPR inline const char* ctti_type_index::name() const BOOST_NOEXCEPT {
  152. return data_;
  153. }
  154. inline std::size_t ctti_type_index::get_raw_name_length() const BOOST_NOEXCEPT {
  155. return std::strlen(raw_name() + detail::ctti_skip_size_at_end);
  156. }
  157. inline std::string ctti_type_index::pretty_name() const {
  158. std::size_t len = get_raw_name_length();
  159. while (raw_name()[len - 1] == ' ') --len; // MSVC sometimes adds whitespaces
  160. return std::string(raw_name(), len);
  161. }
  162. inline std::size_t ctti_type_index::hash_code() const BOOST_NOEXCEPT {
  163. return boost::hash_range(raw_name(), raw_name() + get_raw_name_length());
  164. }
  165. }} // namespace boost::typeindex
  166. #endif // BOOST_TYPE_INDEX_CTTI_TYPE_INDEX_HPP