pilfer.hpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/json
  8. //
  9. #ifndef BOOST_JSON_PILFER_HPP
  10. #define BOOST_JSON_PILFER_HPP
  11. #include <boost/core/detail/static_assert.hpp>
  12. #include <boost/json/detail/config.hpp>
  13. #include <type_traits>
  14. #include <utility>
  15. /*
  16. Implements "pilfering" from P0308R0
  17. @see
  18. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html
  19. */
  20. namespace boost {
  21. namespace json {
  22. /** Tag wrapper to specify pilfer-construction.
  23. This wrapper is used to specify a pilfer constructor
  24. overload.
  25. @par Example
  26. A pilfer constructor accepts a single argument
  27. of type @ref pilfered and throws nothing:
  28. @code
  29. struct T
  30. {
  31. T( pilfered<T> ) noexcept;
  32. };
  33. @endcode
  34. @note
  35. The constructor should not be marked explicit.
  36. @see @ref pilfer, @ref is_pilfer_constructible,
  37. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html">
  38. Valueless Variants Considered Harmful</a>
  39. */
  40. template<class T>
  41. class pilfered
  42. {
  43. T& t_;
  44. public:
  45. /** Constructor
  46. Construct the wrapper from `t`.
  47. @param t The pilferable object. Ownership
  48. is not transferred.
  49. */
  50. explicit
  51. constexpr
  52. pilfered(T&& t) noexcept
  53. : t_(t)
  54. {
  55. }
  56. /** Return a reference to the pilferable object.
  57. This returns a reference to the wrapped object.
  58. */
  59. constexpr T&
  60. get() const noexcept
  61. {
  62. return t_;
  63. }
  64. /** Return a pointer to the pilferable object.
  65. This returns a pointer to the wrapped object.
  66. */
  67. constexpr T*
  68. operator->() const noexcept
  69. {
  70. //return std::addressof(t_);
  71. return reinterpret_cast<T*>(
  72. const_cast<char *>(
  73. &reinterpret_cast<
  74. const volatile char &>(t_)));
  75. }
  76. };
  77. #ifndef BOOST_JSON_DOCS
  78. // VFALCO Renamed this to work around an msvc bug
  79. namespace detail_pilfer {
  80. template<class>
  81. struct not_pilfered
  82. {
  83. };
  84. } // detail_pilfer
  85. #endif
  86. /** Metafunction returning `true` if `T` is <em>PilferConstructible</em>
  87. If `T` can be pilfer constructed, this metafunction is
  88. equal to `std::true_type`. Otherwise it is equal to
  89. `std::false_type`.
  90. @see @ref pilfer, @ref pilfered,
  91. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html">
  92. Valueless Variants Considered Harmful</a>
  93. */
  94. template<class T>
  95. struct is_pilfer_constructible
  96. #ifndef BOOST_JSON_DOCS
  97. : std::integral_constant<bool,
  98. std::is_nothrow_move_constructible<T>::value ||
  99. (
  100. std::is_nothrow_constructible<
  101. T, pilfered<T> >::value &&
  102. ! std::is_nothrow_constructible<
  103. T, detail_pilfer::not_pilfered<T> >::value
  104. )>
  105. #endif
  106. {
  107. };
  108. /** Indicate that an object `t` may be pilfered from.
  109. A <em>pilfer</em> operation is the construction
  110. of a new object of type `T` from an existing
  111. object `t`. After the construction, the only
  112. valid operation on the pilfered-from object is
  113. destruction. This permits optimizations beyond
  114. those available for a move-construction, as the
  115. pilfered-from object is not required to be in
  116. a "usable" state.
  117. \n
  118. This is used similarly to `std::move`.
  119. @par Example
  120. A pilfer constructor accepts a single argument
  121. of type @ref pilfered and throws nothing:
  122. @code
  123. struct T
  124. {
  125. T( pilfered<T> ) noexcept;
  126. };
  127. @endcode
  128. Pilfer construction is performed using @ref pilfer :
  129. @code
  130. {
  131. T t1; // default construction
  132. T t2( pilfer( t1 ) ); // pilfer-construct from t1
  133. // At this point, t1 may only be destroyed
  134. }
  135. @endcode
  136. @see @ref pilfered, @ref is_pilfer_constructible,
  137. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html">
  138. Valueless Variants Considered Harmful</a>
  139. */
  140. template<class T>
  141. auto
  142. pilfer(T&& t) noexcept ->
  143. typename std::conditional<
  144. std::is_nothrow_constructible<
  145. typename std::remove_reference<T>::type,
  146. pilfered<typename
  147. std::remove_reference<T>::type> >::value &&
  148. ! std::is_nothrow_constructible<
  149. typename std::remove_reference<T>::type,
  150. detail_pilfer::not_pilfered<typename
  151. std::remove_reference<T>::type> >::value,
  152. pilfered<typename std::remove_reference<T>::type>,
  153. typename std::remove_reference<T>::type&&
  154. >::type
  155. {
  156. using U =
  157. typename std::remove_reference<T>::type;
  158. BOOST_CORE_STATIC_ASSERT( is_pilfer_constructible<U>::value );
  159. return typename std::conditional<
  160. std::is_nothrow_constructible<
  161. U, pilfered<U> >::value &&
  162. ! std::is_nothrow_constructible<
  163. U, detail_pilfer::not_pilfered<U> >::value,
  164. pilfered<U>, U&&
  165. >::type(std::move(t));
  166. }
  167. /*
  168. template<class T>
  169. void
  170. relocate(T* dest, T& src) noexcept
  171. {
  172. BOOST_CORE_STATIC_ASSERT( is_pilfer_constructible<T>::value );
  173. ::new(dest) T(pilfer(src));
  174. src.~T();
  175. }
  176. */
  177. } // json
  178. } // boost
  179. #endif