From 587ef8e9889d4f597890bc78a8debe889b0dd0d3 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Mon, 14 Apr 2014 23:44:34 +0200 Subject: [PATCH] Added 'raw' move semantics; no unit-tests --- include/boost/optional/optional.hpp | 137 ++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 9 deletions(-) diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 603facd..4ae36f0 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -131,6 +131,9 @@ struct types_when_isnt_ref { typedef T const& reference_const_type ; typedef T & reference_type ; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef T && rval_reference_type ; +#endif typedef T const* pointer_const_type ; typedef T * pointer_type ; typedef T const& argument_type ; @@ -140,11 +143,14 @@ struct types_when_is_ref { typedef BOOST_DEDUCED_TYPENAME remove_reference::type raw_type ; - typedef raw_type& reference_const_type ; - typedef raw_type& reference_type ; - typedef raw_type* pointer_const_type ; - typedef raw_type* pointer_type ; - typedef raw_type& argument_type ; + typedef raw_type& reference_const_type ; + typedef raw_type& reference_type ; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef raw_type&& rval_reference_type ; +#endif + typedef raw_type* pointer_const_type ; + typedef raw_type* pointer_type ; + typedef raw_type& argument_type ; } ; struct optional_tag {} ; @@ -184,6 +190,9 @@ class optional_base : public optional_tag typedef BOOST_DEDUCED_TYPENAME types::reference_type reference_type ; typedef BOOST_DEDUCED_TYPENAME types::reference_const_type reference_const_type ; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef BOOST_DEDUCED_TYPENAME types::rval_reference_type rval_reference_type ; +#endif typedef BOOST_DEDUCED_TYPENAME types::pointer_type pointer_type ; typedef BOOST_DEDUCED_TYPENAME types::pointer_const_type pointer_const_type ; typedef BOOST_DEDUCED_TYPENAME types::argument_type argument_type ; @@ -209,6 +218,17 @@ class optional_base : public optional_tag construct(val); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // move-construct an optional initialized from an rvalue-ref to 'val'. + // Can throw if T::T(T&&) does + optional_base ( rval_reference_type val ) + : + m_initialized(false) + { + construct( static_cast(val) ); + } +#endif + // Creates an optional initialized with 'val' IFF cond is true, otherwise creates an uninitialzed optional. // Can throw if T::T(T const&) does optional_base ( bool cond, argument_type val ) @@ -229,6 +249,17 @@ class optional_base : public optional_tag construct(rhs.get_impl()); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Creates a deep move of another optional + // Can throw if T::T(T&&) does + optional_base ( optional_base&& rhs ) + : + m_initialized(false) + { + if ( rhs.is_initialized() ) + construct( static_cast(rhs.get_impl()) ); + } +#endif // This is used for both converting and in-place constructions. // Derived classes use the 'tag' to select the appropriate @@ -279,6 +310,26 @@ class optional_base : public optional_tag } } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // move-assigns from another _convertible_ optional (deep-moves from the rhs value) + template + void assign ( optional&& rhs ) + { + typedef BOOST_DEDUCED_TYPENAME optional::rval_reference_type ref_type; + if (is_initialized()) + { + if ( rhs.is_initialized() ) + assign_value(static_cast(rhs.get()), is_reference_predicate() ); + else destroy(); + } + else + { + if ( rhs.is_initialized() ) + construct(static_cast(rhs.get())); + } + } +#endif + // Assigns from a T (deep-copies the rhs value) void assign ( argument_type val ) { @@ -286,6 +337,16 @@ class optional_base : public optional_tag assign_value(val, is_reference_predicate() ); else construct(val); } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Assigns from a T (deep-moves the rhs value) + void assign ( rval_reference_type val ) + { + if (is_initialized()) + assign_value( static_cast(val), is_reference_predicate() ); + else construct( static_cast(val) ); + } +#endif // Assigns from "none", destroying the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) @@ -325,6 +386,14 @@ class optional_base : public optional_tag new (m_storage.address()) internal_type(val) ; m_initialized = true ; } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + void construct ( rval_reference_type val ) + { + new (m_storage.address()) internal_type( static_cast(val) ) ; + m_initialized = true ; + } +#endif #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT // Constructs in-place using the given factory @@ -411,6 +480,10 @@ class optional_base : public optional_tag void assign_value ( argument_type val, is_not_reference_tag ) { get_impl() = val; } void assign_value ( argument_type val, is_reference_tag ) { construct(val); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + void assign_value ( rval_reference_type val, is_not_reference_tag ) { get_impl() = static_cast(val); } + void assign_value ( rval_reference_type val, is_reference_tag ) { construct( static_cast(val) ); } +#endif void destroy() { @@ -488,22 +561,34 @@ class optional : public optional_detail::optional_base typedef BOOST_DEDUCED_TYPENAME base::value_type value_type ; typedef BOOST_DEDUCED_TYPENAME base::reference_type reference_type ; typedef BOOST_DEDUCED_TYPENAME base::reference_const_type reference_const_type ; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef BOOST_DEDUCED_TYPENAME base::rval_reference_type rval_reference_type ; +#endif typedef BOOST_DEDUCED_TYPENAME base::pointer_type pointer_type ; typedef BOOST_DEDUCED_TYPENAME base::pointer_const_type pointer_const_type ; typedef BOOST_DEDUCED_TYPENAME base::argument_type argument_type ; // Creates an optional uninitialized. // No-throw - optional() : base() {} + optional() BOOST_NOEXCEPT : base() {} // Creates an optional uninitialized. // No-throw - optional( none_t none_ ) : base(none_) {} + optional( none_t none_ ) BOOST_NOEXCEPT : base(none_) {} // Creates an optional initialized with 'val'. // Can throw if T::T(T const&) does optional ( argument_type val ) : base(val) {} +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Creates an optional initialized with 'move(val)'. + // Can throw if T::T(T &&) does + optional ( rval_reference_type val ) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(static_cast(val)))) + : + base( static_cast(val) ) + {} +#endif + // Creates an optional initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional. // Can throw if T::T(T const&) does optional ( bool cond, argument_type val ) : base(cond,val) {} @@ -521,6 +606,20 @@ class optional : public optional_detail::optional_base if ( rhs.is_initialized() ) this->construct(rhs.get()); } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Creates a deep move of another convertible optional + // Requires a valid conversion from U to T. + // Can throw if T::T(U&&) does + template + explicit optional ( optional && rhs ) + : + base() + { + if ( rhs.is_initialized() ) + this->construct( static_cast::rval_reference_type>(rhs.get()) ); + } +#endif #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT // Creates an optional with an expression which can be either @@ -573,6 +672,16 @@ class optional : public optional_detail::optional_base return *this ; } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Assigns from another optional (deep-moves the rhs value) + optional& operator= ( optional && rhs ) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(static_cast(*rhs))) && BOOST_NOEXCEPT_EXPR(*rhs = static_cast(*rhs))) + { + this->assign( static_cast(rhs) ) ; + return *this ; + } +#endif + // Assigns from a T (deep-copies the rhs value) // Basic Guarantee: If T::( T const& ) throws, this is left UNINITIALIZED optional& operator= ( argument_type val ) @@ -581,6 +690,15 @@ class optional : public optional_detail::optional_base return *this ; } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Assigns from a T (deep-moves the rhs value) + optional& operator= ( rval_reference_type val ) + { + this->assign( static_cast(val) ) ; + return *this ; + } +#endif + // Assigns from a "none" // Which destroys the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) @@ -591,10 +709,10 @@ class optional : public optional_detail::optional_base } void swap( optional & arg ) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(static_cast(*arg))) && BOOST_NOEXCEPT_EXPR(*arg = static_cast(*arg))) { // allow for Koenig lookup - using boost::swap; - swap(*this, arg); + boost::swap(*this, arg); } @@ -961,6 +1079,7 @@ template struct optional_swap_should_use_default_constructor : has_nothrow_default_constructor {} ; template inline void swap ( optional& x, optional& y ) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(static_cast(*x))) && BOOST_NOEXCEPT_EXPR(*y = static_cast(*x))) { optional_detail::swap_selector::value>::optional_swap(x, y); }