// // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/json // #ifndef BOOST_JSON_PILFER_HPP #define BOOST_JSON_PILFER_HPP #include <boost/json/detail/config.hpp> #include <type_traits> #include <utility> /* Implements "pilfering" from P0308R0 @see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html */ namespace boost { namespace json { /** Tag wrapper to specify pilfer-construction. This wrapper is used to specify a pilfer constructor overload. @par Example A pilfer constructor accepts a single argument of type @ref pilfered and throws nothing: @code struct T { T( pilfered<T> ) noexcept; }; @endcode @note The constructor should not be marked explicit. @see @ref pilfer, @ref is_pilfer_constructible, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html"> Valueless Variants Considered Harmful</a> */ template<class T> class pilfered { T& t_; public: /** Constructor Construct the wrapper from `t`. @param t The pilferable object. Ownership is not transferred. */ explicit constexpr pilfered(T&& t) noexcept : t_(t) { } /** Return a reference to the pilferable object. This returns a reference to the wrapped object. */ constexpr T& get() const noexcept { return t_; } /** Return a pointer to the pilferable object. This returns a pointer to the wrapped object. */ constexpr T* operator->() const noexcept { //return std::addressof(t_); return reinterpret_cast<T*>( const_cast<char *>( &reinterpret_cast< const volatile char &>(t_))); } }; #ifndef BOOST_JSON_DOCS // VFALCO Renamed this to work around an msvc bug namespace detail_pilfer { template<class> struct not_pilfered { }; } // detail_pilfer #endif /** Metafunction returning `true` if `T` is <em>PilferConstructible</em> If `T` can be pilfer constructed, this metafunction is equal to `std::true_type`. Otherwise it is equal to `std::false_type`. @see @ref pilfer, @ref pilfered, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html"> Valueless Variants Considered Harmful</a> */ template<class T> struct is_pilfer_constructible #ifndef BOOST_JSON_DOCS : std::integral_constant<bool, std::is_nothrow_move_constructible<T>::value || ( std::is_nothrow_constructible< T, pilfered<T> >::value && ! std::is_nothrow_constructible< T, detail_pilfer::not_pilfered<T> >::value )> #endif { }; /** Indicate that an object `t` may be pilfered from. A <em>pilfer</em> operation is the construction of a new object of type `T` from an existing object `t`. After the construction, the only valid operation on the pilfered-from object is destruction. This permits optimizations beyond those available for a move-construction, as the pilfered-from object is not required to be in a "usable" state. \n This is used similarly to `std::move`. @par Example A pilfer constructor accepts a single argument of type @ref pilfered and throws nothing: @code struct T { T( pilfered<T> ) noexcept; }; @endcode Pilfer construction is performed using @ref pilfer : @code { T t1; // default construction T t2( pilfer( t1 ) ); // pilfer-construct from t1 // At this point, t1 may only be destroyed } @endcode @see @ref pilfered, @ref is_pilfer_constructible, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html"> Valueless Variants Considered Harmful</a> */ template<class T> auto pilfer(T&& t) noexcept -> typename std::conditional< std::is_nothrow_constructible< typename std::remove_reference<T>::type, pilfered<typename std::remove_reference<T>::type> >::value && ! std::is_nothrow_constructible< typename std::remove_reference<T>::type, detail_pilfer::not_pilfered<typename std::remove_reference<T>::type> >::value, pilfered<typename std::remove_reference<T>::type>, typename std::remove_reference<T>::type&& >::type { using U = typename std::remove_reference<T>::type; static_assert( is_pilfer_constructible<U>::value, ""); return typename std::conditional< std::is_nothrow_constructible< U, pilfered<U> >::value && ! std::is_nothrow_constructible< U, detail_pilfer::not_pilfered<U> >::value, pilfered<U>, U&& >::type(std::move(t)); } /* template<class T> void relocate(T* dest, T& src) noexcept { static_assert( is_pilfer_constructible<T>::value, ""); ::new(dest) T(pilfer(src)); src.~T(); } */ } // json } // boost #endif