unique_any.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Copyright Antony Polukhin, 2020-2025.
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. // See http://www.boost.org/libs/any for Documentation.
  7. #ifndef BOOST_ANYS_UNIQUE_ANY_HPP_INCLUDED
  8. #define BOOST_ANYS_UNIQUE_ANY_HPP_INCLUDED
  9. #include <boost/any/detail/config.hpp>
  10. #if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT)
  11. /// \file boost/any/unique_any.hpp
  12. /// \brief \copybrief boost::anys::unique_any
  13. #ifndef BOOST_ANY_INTERFACE_UNIT
  14. #include <boost/config.hpp>
  15. #ifdef BOOST_HAS_PRAGMA_ONCE
  16. # pragma once
  17. #endif
  18. #include <memory> // for std::unique_ptr
  19. #include <utility>
  20. #include <type_traits>
  21. #include <boost/throw_exception.hpp>
  22. #include <boost/type_index.hpp>
  23. #endif // #ifndef BOOST_ANY_INTERFACE_UNIT
  24. #include <boost/any/fwd.hpp>
  25. #include <boost/any/bad_any_cast.hpp>
  26. #include <boost/any/detail/placeholder.hpp>
  27. namespace boost { namespace anys {
  28. BOOST_ANY_BEGIN_MODULE_EXPORT
  29. /// Helper type for providing emplacement type to the constructor.
  30. template <class T>
  31. struct in_place_type_t
  32. {
  33. };
  34. #if !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES)
  35. template <class T>
  36. constexpr in_place_type_t<T> in_place_type{};
  37. #endif
  38. /// \brief A class whose instances can hold instances of any
  39. /// type (including non-copyable and non-movable types).
  40. class unique_any {
  41. public:
  42. /// \post this->has_value() is false.
  43. constexpr unique_any() noexcept = default;
  44. /// Move constructor that moves content of
  45. /// `other` into new instance and leaves `other` empty.
  46. ///
  47. /// \post other->has_value() is false.
  48. /// \throws Nothing.
  49. unique_any(unique_any&& other) noexcept = default;
  50. /// Forwards `value`, so
  51. /// that the content of the new instance has type `std::decay_t<T>`
  52. /// and value is the `value` before the forward.
  53. ///
  54. /// \throws std::bad_alloc or any exceptions arising from the move or
  55. /// copy constructor of the contained type.
  56. template<typename T>
  57. unique_any(T&& value, typename std::enable_if<!std::is_same<T&&, boost::any&&>::value>::type* = nullptr)
  58. : content(new holder< typename std::decay<T>::type >(std::forward<T>(value)))
  59. {
  60. static_assert(
  61. !boost::anys::detail::is_basic_any< typename std::decay<T>::type >::value,
  62. "boost::anys::unique_any could not be constructed from boost::anys::basic_any."
  63. );
  64. static_assert(
  65. !std::is_same<unique_any, typename std::decay<T>::type >::value,
  66. "boost::anys::unique_any could not be copied, only moved."
  67. );
  68. static_assert(
  69. !std::is_same<boost::any, typename std::decay<T>::type >::value,
  70. "boost::anys::unique_any could be constructed from an rvalue of boost::any, "
  71. "not a lvalue."
  72. );
  73. }
  74. /// Moves the content of `boost::any` into *this.
  75. ///
  76. /// \throws Nothing.
  77. /// \post `value.empty()` is true.
  78. template <class BoostAny>
  79. unique_any(BoostAny&& value, typename std::enable_if<std::is_same<BoostAny&&, boost::any&&>::value>::type* = nullptr) noexcept
  80. {
  81. content.reset(value.content);
  82. value.content = nullptr;
  83. }
  84. /// Inplace constructs `T` from forwarded `args...`,
  85. /// so that the content of `*this` is equivalent
  86. /// in type to `std::decay_t<T>`.
  87. ///
  88. /// \throws std::bad_alloc or any exceptions arising from the move or
  89. /// copy constructor of the contained type.
  90. template<class T, class... Args>
  91. explicit unique_any(in_place_type_t<T>, Args&&... args)
  92. : content(new holder<typename std::decay<T>::type>(std::forward<Args>(args)...))
  93. {
  94. }
  95. /// Inplace constructs `T` from `li` and forwarded `args...`,
  96. /// so that the initial content of `*this` is equivalent
  97. /// in type to `std::decay_t<T>`.
  98. ///
  99. /// \throws std::bad_alloc or any exceptions arising from the move or
  100. /// copy constructor of the contained type.
  101. template <class T, class U, class... Args>
  102. explicit unique_any(in_place_type_t<T>, std::initializer_list<U> il, Args&&... args)
  103. : content(new holder<typename std::decay<T>::type>(il, std::forward<Args>(args)...))
  104. {
  105. }
  106. /// Releases any and all resources used in management of instance.
  107. ///
  108. /// \throws Nothing.
  109. ~unique_any() noexcept = default;
  110. /// Moves content of `rhs` into
  111. /// current instance, discarding previous content, so that the
  112. /// new content is equivalent in both type and value to the
  113. /// content of <code>rhs</code> before move, or empty if `rhs.empty()`.
  114. ///
  115. /// \post `rhs->empty()` is true
  116. /// \throws Nothing.
  117. unique_any & operator=(unique_any&& rhs) noexcept = default;
  118. /// Forwards `rhs`,
  119. /// discarding previous content, so that the new content of is
  120. /// equivalent in both type and value to `rhs` before forward.
  121. ///
  122. /// \throws std::bad_alloc
  123. /// or any exceptions arising from the move or copy constructor of the
  124. /// contained type. Assignment satisfies the strong guarantee
  125. /// of exception safety.
  126. template <class T>
  127. unique_any & operator=(T&& rhs)
  128. {
  129. unique_any(std::forward<T>(rhs)).swap(*this);
  130. return *this;
  131. }
  132. /// Inplace constructs `T` from forwarded `args...`, discarding previous
  133. /// content, so that the content of `*this` is equivalent
  134. /// in type to `std::decay_t<T>`.
  135. ///
  136. /// \returns reference to the content of `*this`.
  137. /// \throws std::bad_alloc or any exceptions arising from the move or
  138. /// copy constructor of the contained type.
  139. template<class T, class... Args>
  140. typename std::decay<T>::type& emplace(Args&&... args) {
  141. auto* raw_ptr = new holder<typename std::decay<T>::type>(std::forward<Args>(args)...);
  142. content = std::unique_ptr<boost::anys::detail::placeholder>(raw_ptr);
  143. return raw_ptr->held;
  144. }
  145. /// Inplace constructs `T` from `li` and forwarded `args...`, discarding
  146. /// previous content, so that the content of `*this` is equivalent
  147. /// in type to `std::decay_t<T>`.
  148. ///
  149. /// \returns reference to the content of `*this`.
  150. /// \throws std::bad_alloc or any exceptions arising from the move or
  151. /// copy constructor of the contained type.
  152. template<class T, class U, class... Args>
  153. typename std::decay<T>::type& emplace(std::initializer_list<U> il, Args&&... args) {
  154. auto* raw_ptr = new holder<typename std::decay<T>::type>(il, std::forward<Args>(args)...);
  155. content = std::unique_ptr<boost::anys::detail::placeholder>(raw_ptr);
  156. return raw_ptr->held;
  157. }
  158. /// \post this->has_value() is false.
  159. void reset() noexcept
  160. {
  161. content.reset();
  162. }
  163. /// Exchange of the contents of `*this` and `rhs`.
  164. ///
  165. /// \returns `*this`
  166. /// \throws Nothing.
  167. void swap(unique_any& rhs) noexcept
  168. {
  169. content.swap(rhs.content);
  170. }
  171. /// \returns `true` if instance is not empty, otherwise `false`.
  172. /// \throws Nothing.
  173. bool has_value() const noexcept
  174. {
  175. return !!content;
  176. }
  177. /// \returns the `typeid` of the
  178. /// contained value if instance is non-empty, otherwise
  179. /// `typeid(void)`.
  180. ///
  181. /// Useful for querying against types known either at compile time or
  182. /// only at runtime.
  183. const boost::typeindex::type_info& type() const noexcept
  184. {
  185. return content ? content->type() : boost::typeindex::type_id<void>().type_info();
  186. }
  187. private: // types
  188. /// @cond
  189. template<typename T>
  190. class holder final: public boost::anys::detail::placeholder
  191. {
  192. public:
  193. template <class... Args>
  194. holder(Args&&... args)
  195. : held(std::forward<Args>(args)...)
  196. {
  197. }
  198. template <class U, class... Args>
  199. holder(std::initializer_list<U> il, Args&&... args)
  200. : held(il, std::forward<Args>(args)...)
  201. {
  202. }
  203. const boost::typeindex::type_info& type() const noexcept override
  204. {
  205. return boost::typeindex::type_id<T>().type_info();
  206. }
  207. public:
  208. T held;
  209. };
  210. private: // representation
  211. template<typename T>
  212. friend T * unsafe_any_cast(unique_any *) noexcept;
  213. std::unique_ptr<boost::anys::detail::placeholder> content;
  214. /// @endcond
  215. };
  216. /// Exchange of the contents of `lhs` and `rhs`.
  217. /// \throws Nothing.
  218. inline void swap(unique_any & lhs, unique_any & rhs) noexcept
  219. {
  220. lhs.swap(rhs);
  221. }
  222. /// @cond
  223. // Note: The "unsafe" versions of any_cast are not part of the
  224. // public interface and may be removed at any time. They are
  225. // required where we know what type is stored in the any and can't
  226. // use typeid() comparison, e.g., when our types may travel across
  227. // different shared libraries.
  228. template<typename T>
  229. inline T * unsafe_any_cast(unique_any * operand) noexcept
  230. {
  231. return std::addressof(
  232. static_cast<unique_any::holder<T>&>(*operand->content).held
  233. );
  234. }
  235. template<typename T>
  236. inline const T * unsafe_any_cast(const unique_any * operand) noexcept
  237. {
  238. return anys::unsafe_any_cast<T>(const_cast<unique_any *>(operand));
  239. }
  240. /// @endcond
  241. /// \returns Pointer to a `T` stored in `operand`, nullptr if
  242. /// `operand` does not contain specified `T`.
  243. template<typename T>
  244. T * any_cast(unique_any * operand) noexcept
  245. {
  246. return operand && operand->type() == boost::typeindex::type_id<T>()
  247. ? anys::unsafe_any_cast<typename std::remove_cv<T>::type>(operand)
  248. : nullptr;
  249. }
  250. /// \returns Const pointer to a `T` stored in `operand`, nullptr if
  251. /// `operand` does not contain specified `T`.
  252. template<typename T>
  253. inline const T * any_cast(const unique_any * operand) noexcept
  254. {
  255. return anys::any_cast<T>(const_cast<unique_any *>(operand));
  256. }
  257. /// \returns `T` stored in `operand`
  258. /// \throws boost::bad_any_cast if `operand` does not contain specified `T`.
  259. template<typename T>
  260. T any_cast(unique_any & operand)
  261. {
  262. using nonref = typename std::remove_reference<T>::type;
  263. nonref * result = anys::any_cast<nonref>(std::addressof(operand));
  264. if(!result)
  265. boost::throw_exception(bad_any_cast());
  266. // Attempt to avoid construction of a temporary object in cases when
  267. // `T` is not a reference. Example:
  268. // `static_cast<std::string>(*result);`
  269. // which is equal to `std::string(*result);`
  270. typedef typename std::conditional<
  271. std::is_reference<T>::value,
  272. T,
  273. T&
  274. >::type ref_type;
  275. #ifdef BOOST_MSVC
  276. # pragma warning(push)
  277. # pragma warning(disable: 4172) // "returning address of local variable or temporary" but *result is not local!
  278. #endif
  279. return static_cast<ref_type>(*result);
  280. #ifdef BOOST_MSVC
  281. # pragma warning(pop)
  282. #endif
  283. }
  284. /// \returns `T` stored in `operand`
  285. /// \throws boost::bad_any_cast if `operand` does not contain specified `T`.
  286. template<typename T>
  287. inline T any_cast(const unique_any & operand)
  288. {
  289. using nonref = typename std::remove_reference<T>::type;
  290. return anys::any_cast<const nonref &>(const_cast<unique_any &>(operand));
  291. }
  292. /// \returns `T` stored in `operand`
  293. /// \throws boost::bad_any_cast if `operand` does not contain specified `T`.
  294. template<typename T>
  295. inline T any_cast(unique_any&& operand)
  296. {
  297. static_assert(
  298. std::is_rvalue_reference<T&&>::value /*true if T is rvalue or just a value*/
  299. || std::is_const< typename std::remove_reference<T>::type >::value,
  300. "boost::any_cast shall not be used for getting nonconst references to temporary objects"
  301. );
  302. return std::move(anys::any_cast<T&>(operand));
  303. }
  304. BOOST_ANY_END_MODULE_EXPORT
  305. } // namespace anys
  306. BOOST_ANY_BEGIN_MODULE_EXPORT
  307. using boost::anys::any_cast;
  308. using boost::anys::unsafe_any_cast;
  309. BOOST_ANY_END_MODULE_EXPORT
  310. } // namespace boost
  311. #endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT)
  312. #endif // BOOST_ANYS_UNIQUE_ANY_HPP_INCLUDED