any.hpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2015-present
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. #ifndef RANGES_V3_UTILITY_ANY_HPP
  14. #define RANGES_V3_UTILITY_ANY_HPP
  15. #include <memory>
  16. #include <type_traits>
  17. #include <typeinfo>
  18. #include <meta/meta.hpp>
  19. #include <concepts/concepts.hpp>
  20. #include <range/v3/range_fwd.hpp>
  21. #include <range/v3/utility/swap.hpp>
  22. #include <range/v3/detail/prologue.hpp>
  23. RANGES_DIAGNOSTIC_PUSH
  24. RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
  25. namespace ranges
  26. {
  27. struct bad_any_cast : std::bad_cast
  28. {
  29. virtual const char * what() const noexcept override
  30. {
  31. return "bad any_cast";
  32. }
  33. };
  34. struct RANGES_DEPRECATED(
  35. "ranges::any will be going away in the not-too-distant future. "
  36. "We suggest you use std::any or boost::any instead (or simply steal "
  37. "this header and maintain it yourself).") any;
  38. template<typename T>
  39. meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any &);
  40. template<typename T>
  41. meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any const &);
  42. template<typename T>
  43. meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any &&);
  44. template<typename T>
  45. T * any_cast(any *) noexcept;
  46. template<typename T>
  47. T const * any_cast(any const *) noexcept;
  48. struct any
  49. {
  50. private:
  51. template<typename T>
  52. friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(any &);
  53. template<typename T>
  54. friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(
  55. any const &);
  56. template<typename T>
  57. friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(
  58. any &&);
  59. template<typename T>
  60. friend T * any_cast(any *) noexcept;
  61. template<typename T>
  62. friend T const * any_cast(any const *) noexcept;
  63. struct interface
  64. {
  65. virtual ~interface()
  66. {}
  67. virtual interface * clone() const = 0;
  68. virtual std::type_info const & type() const noexcept = 0;
  69. };
  70. template<typename T>
  71. struct impl final : interface
  72. {
  73. private:
  74. T obj;
  75. public:
  76. impl() = default;
  77. impl(T o)
  78. : obj(std::move(o))
  79. {}
  80. T & get()
  81. {
  82. return obj;
  83. }
  84. T const & get() const
  85. {
  86. return obj;
  87. }
  88. impl * clone() const override
  89. {
  90. return new impl{obj};
  91. }
  92. std::type_info const & type() const noexcept override
  93. {
  94. return typeid(T);
  95. }
  96. };
  97. std::unique_ptr<interface> ptr_;
  98. public:
  99. any() noexcept = default;
  100. template(typename TRef, typename T = detail::decay_t<TRef>)(
  101. requires copyable<T> AND (!same_as<T, any>)) //
  102. any(TRef && t)
  103. : ptr_(new impl<T>(static_cast<TRef &&>(t)))
  104. {}
  105. any(any &&) noexcept = default;
  106. any(any const & that)
  107. : ptr_{that.ptr_ ? that.ptr_->clone() : nullptr}
  108. {}
  109. any & operator=(any &&) noexcept = default;
  110. any & operator=(any const & that)
  111. {
  112. ptr_.reset(that.ptr_ ? that.ptr_->clone() : nullptr);
  113. return *this;
  114. }
  115. template(typename TRef, typename T = detail::decay_t<TRef>)(
  116. requires copyable<T> AND (!same_as<T, any>)) //
  117. any & operator=(TRef && t)
  118. {
  119. any{static_cast<TRef &&>(t)}.swap(*this);
  120. return *this;
  121. }
  122. void clear() noexcept
  123. {
  124. ptr_.reset();
  125. }
  126. bool empty() const noexcept
  127. {
  128. return !ptr_;
  129. }
  130. std::type_info const & type() const noexcept
  131. {
  132. return ptr_ ? ptr_->type() : typeid(void);
  133. }
  134. void swap(any & that) noexcept
  135. {
  136. ptr_.swap(that.ptr_);
  137. }
  138. #if !RANGES_BROKEN_CPO_LOOKUP
  139. friend void swap(any & x, any & y) noexcept
  140. {
  141. x.swap(y);
  142. }
  143. #endif
  144. };
  145. #if RANGES_BROKEN_CPO_LOOKUP
  146. namespace _any_
  147. {
  148. inline void swap(any & x, any & y) noexcept
  149. {
  150. x.swap(y);
  151. }
  152. } // namespace _any_
  153. #endif
  154. /// \throw bad_any_cast
  155. template<typename T>
  156. meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any & x)
  157. {
  158. if(x.type() != typeid(detail::decay_t<T>))
  159. throw bad_any_cast{};
  160. return static_cast<any::impl<detail::decay_t<T>> *>(x.ptr_.get())->get();
  161. }
  162. /// \overload
  163. template<typename T>
  164. meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any const & x)
  165. {
  166. if(x.type() != typeid(detail::decay_t<T>))
  167. throw bad_any_cast{};
  168. return static_cast<any::impl<detail::decay_t<T>> const *>(x.ptr_.get())->get();
  169. }
  170. /// \overload
  171. template<typename T>
  172. meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any && x)
  173. {
  174. if(x.type() != typeid(detail::decay_t<T>))
  175. throw bad_any_cast{};
  176. return static_cast<any::impl<detail::decay_t<T>> *>(x.ptr_.get())->get();
  177. }
  178. /// \overload
  179. template<typename T>
  180. T * any_cast(any * p) noexcept
  181. {
  182. if(p && p->ptr_)
  183. if(any::impl<T> * q = dynamic_cast<any::impl<T> *>(p->ptr_.get()))
  184. return &q->get();
  185. return nullptr;
  186. }
  187. /// \overload
  188. template<typename T>
  189. T const * any_cast(any const * p) noexcept
  190. {
  191. if(p && p->ptr_)
  192. if(any::impl<T> const * q = dynamic_cast<any::impl<T> const *>(p->ptr_.get()))
  193. return &q->get();
  194. return nullptr;
  195. }
  196. } // namespace ranges
  197. RANGES_DIAGNOSTIC_POP
  198. #include <range/v3/detail/epilogue.hpp>
  199. #endif