pilfer.hpp 5.2 KB

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