You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

231 lines
6.0KB

  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. RANGES_DIAGNOSTIC_PUSH
  23. RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
  24. namespace ranges
  25. {
  26. struct bad_any_cast : std::bad_cast
  27. {
  28. virtual const char * what() const noexcept override
  29. {
  30. return "bad any_cast";
  31. }
  32. };
  33. struct RANGES_DEPRECATED(
  34. "ranges::any will be going away in the not-too-distant future. "
  35. "We suggest you use std::any or boost::any instead (or simply steal "
  36. "this header and maintain it yourself).") any;
  37. template<typename T>
  38. meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any &);
  39. template<typename T>
  40. meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any const &);
  41. template<typename T>
  42. meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any &&);
  43. template<typename T>
  44. T * any_cast(any *) noexcept;
  45. template<typename T>
  46. T const * any_cast(any const *) noexcept;
  47. struct any
  48. {
  49. private:
  50. template<typename T>
  51. friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(any &);
  52. template<typename T>
  53. friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(
  54. any const &);
  55. template<typename T>
  56. friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(
  57. any &&);
  58. template<typename T>
  59. friend T * any_cast(any *) noexcept;
  60. template<typename T>
  61. friend T const * any_cast(any const *) noexcept;
  62. struct interface
  63. {
  64. virtual ~interface()
  65. {}
  66. virtual interface * clone() const = 0;
  67. virtual std::type_info const & type() const noexcept = 0;
  68. };
  69. template<typename T>
  70. struct impl final : interface
  71. {
  72. private:
  73. T obj;
  74. public:
  75. impl() = default;
  76. impl(T o)
  77. : obj(std::move(o))
  78. {}
  79. T & get()
  80. {
  81. return obj;
  82. }
  83. T const & get() const
  84. {
  85. return obj;
  86. }
  87. impl * clone() const override
  88. {
  89. return new impl{obj};
  90. }
  91. std::type_info const & type() const noexcept override
  92. {
  93. return typeid(T);
  94. }
  95. };
  96. std::unique_ptr<interface> ptr_;
  97. public:
  98. any() noexcept = default;
  99. template<typename TRef, typename T = detail::decay_t<TRef>>
  100. CPP_ctor(any)(TRef && t)( //
  101. requires copyable<T> && (!same_as<T, any>))
  102. : ptr_(new impl<T>(static_cast<TRef &&>(t)))
  103. {}
  104. any(any &&) noexcept = default;
  105. any(any const & that)
  106. : ptr_{that.ptr_ ? that.ptr_->clone() : nullptr}
  107. {}
  108. any & operator=(any &&) noexcept = default;
  109. any & operator=(any const & that)
  110. {
  111. ptr_.reset(that.ptr_ ? that.ptr_->clone() : nullptr);
  112. return *this;
  113. }
  114. template<typename TRef, typename T = detail::decay_t<TRef>>
  115. auto operator=(TRef && t) -> CPP_ret(any &)( //
  116. requires copyable<T> && (!same_as<T, any>))
  117. {
  118. any{static_cast<TRef &&>(t)}.swap(*this);
  119. return *this;
  120. }
  121. void clear() noexcept
  122. {
  123. ptr_.reset();
  124. }
  125. bool empty() const noexcept
  126. {
  127. return !ptr_;
  128. }
  129. std::type_info const & type() const noexcept
  130. {
  131. return ptr_ ? ptr_->type() : typeid(void);
  132. }
  133. void swap(any & that) noexcept
  134. {
  135. ptr_.swap(that.ptr_);
  136. }
  137. #if !RANGES_BROKEN_CPO_LOOKUP
  138. friend void swap(any & x, any & y) noexcept
  139. {
  140. x.swap(y);
  141. }
  142. #endif
  143. };
  144. #if RANGES_BROKEN_CPO_LOOKUP
  145. namespace _any_
  146. {
  147. inline void swap(any & x, any & y) noexcept
  148. {
  149. x.swap(y);
  150. }
  151. } // namespace _any_
  152. #endif
  153. /// \throw bad_any_cast
  154. template<typename T>
  155. meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any & x)
  156. {
  157. if(x.type() != typeid(detail::decay_t<T>))
  158. throw bad_any_cast{};
  159. return static_cast<any::impl<detail::decay_t<T>> *>(x.ptr_.get())->get();
  160. }
  161. /// \overload
  162. template<typename T>
  163. meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any const & x)
  164. {
  165. if(x.type() != typeid(detail::decay_t<T>))
  166. throw bad_any_cast{};
  167. return static_cast<any::impl<detail::decay_t<T>> const *>(x.ptr_.get())->get();
  168. }
  169. /// \overload
  170. template<typename T>
  171. meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any && x)
  172. {
  173. if(x.type() != typeid(detail::decay_t<T>))
  174. throw bad_any_cast{};
  175. return static_cast<any::impl<detail::decay_t<T>> *>(x.ptr_.get())->get();
  176. }
  177. /// \overload
  178. template<typename T>
  179. T * any_cast(any * p) noexcept
  180. {
  181. if(p && p->ptr_)
  182. if(any::impl<T> * q = dynamic_cast<any::impl<T> *>(p->ptr_.get()))
  183. return &q->get();
  184. return nullptr;
  185. }
  186. /// \overload
  187. template<typename T>
  188. T const * any_cast(any const * p) noexcept
  189. {
  190. if(p && p->ptr_)
  191. if(any::impl<T> const * q = dynamic_cast<any::impl<T> const *>(p->ptr_.get()))
  192. return &q->get();
  193. return nullptr;
  194. }
  195. } // namespace ranges
  196. RANGES_DIAGNOSTIC_POP
  197. #endif