unique_any.hpp 11 KB

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