From 8355309c5fafd4909edc904359deeec1e7f10efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 1 Nov 2014 19:28:24 +0100 Subject: [PATCH 1/5] Added #pragma once --- include/boost/move/algorithm.hpp | 4 ++++ include/boost/move/core.hpp | 4 ++++ include/boost/move/default_delete.hpp | 4 ++++ include/boost/move/detail/meta_utils.hpp | 4 ++++ include/boost/move/detail/move_helpers.hpp | 4 ++++ include/boost/move/detail/unique_ptr_meta_utils.hpp | 4 ++++ include/boost/move/detail/workaround.hpp | 4 ++++ include/boost/move/iterator.hpp | 4 ++++ include/boost/move/make_unique.hpp | 4 ++++ include/boost/move/move.hpp | 4 ++++ include/boost/move/traits.hpp | 4 ++++ include/boost/move/unique_ptr.hpp | 4 ++++ include/boost/move/utility.hpp | 4 ++++ include/boost/move/utility_core.hpp | 4 ++++ 14 files changed, 56 insertions(+) diff --git a/include/boost/move/algorithm.hpp b/include/boost/move/algorithm.hpp index f5f4b81..bb628c6 100644 --- a/include/boost/move/algorithm.hpp +++ b/include/boost/move/algorithm.hpp @@ -14,6 +14,10 @@ #ifndef BOOST_MOVE_ALGORITHM_HPP #define BOOST_MOVE_ALGORITHM_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include diff --git a/include/boost/move/core.hpp b/include/boost/move/core.hpp index 4728a71..ccdcc52 100644 --- a/include/boost/move/core.hpp +++ b/include/boost/move/core.hpp @@ -16,6 +16,10 @@ #ifndef BOOST_MOVE_CORE_HPP #define BOOST_MOVE_CORE_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include //boost_move_no_copy_constructor_or_assign typedef diff --git a/include/boost/move/default_delete.hpp b/include/boost/move/default_delete.hpp index d8494e8..a367674 100644 --- a/include/boost/move/default_delete.hpp +++ b/include/boost/move/default_delete.hpp @@ -11,6 +11,10 @@ #ifndef BOOST_MOVE_DEFAULT_DELETE_HPP_INCLUDED #define BOOST_MOVE_DEFAULT_DELETE_HPP_INCLUDED +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include diff --git a/include/boost/move/detail/meta_utils.hpp b/include/boost/move/detail/meta_utils.hpp index 0df0086..a23c8dc 100644 --- a/include/boost/move/detail/meta_utils.hpp +++ b/include/boost/move/detail/meta_utils.hpp @@ -14,6 +14,10 @@ #ifndef BOOST_MOVE_DETAIL_META_UTILS_HPP #define BOOST_MOVE_DETAIL_META_UTILS_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include //for std::size_t diff --git a/include/boost/move/detail/move_helpers.hpp b/include/boost/move/detail/move_helpers.hpp index 78d98ea..a97bea6 100644 --- a/include/boost/move/detail/move_helpers.hpp +++ b/include/boost/move/detail/move_helpers.hpp @@ -12,6 +12,10 @@ #ifndef BOOST_MOVE_MOVE_HELPERS_HPP #define BOOST_MOVE_MOVE_HELPERS_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include diff --git a/include/boost/move/detail/unique_ptr_meta_utils.hpp b/include/boost/move/detail/unique_ptr_meta_utils.hpp index 42fd272..50c6e01 100644 --- a/include/boost/move/detail/unique_ptr_meta_utils.hpp +++ b/include/boost/move/detail/unique_ptr_meta_utils.hpp @@ -14,6 +14,10 @@ #ifndef BOOST_MOVE_UNIQUE_PTR_DETAIL_META_UTILS_HPP #define BOOST_MOVE_UNIQUE_PTR_DETAIL_META_UTILS_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include //for std::size_t //Small meta-typetraits to support move diff --git a/include/boost/move/detail/workaround.hpp b/include/boost/move/detail/workaround.hpp index 1bf879c..3906f32 100644 --- a/include/boost/move/detail/workaround.hpp +++ b/include/boost/move/detail/workaround.hpp @@ -11,6 +11,10 @@ #ifndef BOOST_MOVE_DETAIL_WORKAROUND_HPP #define BOOST_MOVE_DETAIL_WORKAROUND_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_MOVE_PERFECT_FORWARDING #endif diff --git a/include/boost/move/iterator.hpp b/include/boost/move/iterator.hpp index dda6f83..eaf83ef 100644 --- a/include/boost/move/iterator.hpp +++ b/include/boost/move/iterator.hpp @@ -14,6 +14,10 @@ #ifndef BOOST_MOVE_ITERATOR_HPP #define BOOST_MOVE_ITERATOR_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include //std::iterator diff --git a/include/boost/move/make_unique.hpp b/include/boost/move/make_unique.hpp index 59cfafa..fb57850 100644 --- a/include/boost/move/make_unique.hpp +++ b/include/boost/move/make_unique.hpp @@ -11,6 +11,10 @@ #ifndef BOOST_MOVE_MAKE_UNIQUE_HPP_INCLUDED #define BOOST_MOVE_MAKE_UNIQUE_HPP_INCLUDED +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include diff --git a/include/boost/move/move.hpp b/include/boost/move/move.hpp index 5a22d31..be3fffc 100644 --- a/include/boost/move/move.hpp +++ b/include/boost/move/move.hpp @@ -17,6 +17,10 @@ #ifndef BOOST_MOVE_MOVE_HPP #define BOOST_MOVE_MOVE_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include diff --git a/include/boost/move/traits.hpp b/include/boost/move/traits.hpp index c4b3afe..4e29006 100644 --- a/include/boost/move/traits.hpp +++ b/include/boost/move/traits.hpp @@ -14,6 +14,10 @@ #ifndef BOOST_MOVE_MOVE_TRAITS_HPP #define BOOST_MOVE_MOVE_TRAITS_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include diff --git a/include/boost/move/unique_ptr.hpp b/include/boost/move/unique_ptr.hpp index df10fb3..231735b 100644 --- a/include/boost/move/unique_ptr.hpp +++ b/include/boost/move/unique_ptr.hpp @@ -11,6 +11,10 @@ #ifndef BOOST_MOVE_UNIQUE_PTR_HPP_INCLUDED #define BOOST_MOVE_UNIQUE_PTR_HPP_INCLUDED +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include diff --git a/include/boost/move/utility.hpp b/include/boost/move/utility.hpp index a1ddd26..955734c 100644 --- a/include/boost/move/utility.hpp +++ b/include/boost/move/utility.hpp @@ -16,6 +16,10 @@ #ifndef BOOST_MOVE_MOVE_UTILITY_HPP #define BOOST_MOVE_MOVE_UTILITY_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include diff --git a/include/boost/move/utility_core.hpp b/include/boost/move/utility_core.hpp index ae17fd3..30ab539 100644 --- a/include/boost/move/utility_core.hpp +++ b/include/boost/move/utility_core.hpp @@ -17,6 +17,10 @@ #ifndef BOOST_MOVE_MOVE_UTILITY_CORE_HPP #define BOOST_MOVE_MOVE_UTILITY_CORE_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include From ad50fba54fd2278762045ab3b03c32c0df8ac231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 1 Nov 2014 19:32:36 +0100 Subject: [PATCH 2/5] Added BOOST_MOVE_BASE utility --- doc/move.qbk | 29 +++++++++++++++++++++-------- example/doc_clone_ptr.cpp | 8 ++++---- include/boost/move/core.hpp | 16 +++++++++++++++- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/doc/move.qbk b/doc/move.qbk index dbd7d11..0d47f52 100644 --- a/doc/move.qbk +++ b/doc/move.qbk @@ -532,19 +532,26 @@ care to achieve portable and efficient code when using the library with C++03 co [section:emulation_limitations_base Initializing base classes] When initializing base classes in move constructors, users must -cast the reference to a base class reference before moving it. Example: +cast the reference to a base class reference before moving it or just +use `BOOST_MOVE_BASE`. Example: [c++] - //Portable and efficient Derived(BOOST_RV_REF(Derived) x) // Move ctor - : Base(boost::move(static_cast(x))), - mem_(boost::move(x.mem_)) { } + : Base(boost::move(static_cast(x))) + //... +or + +[c++] + + Derived(BOOST_RV_REF(Derived) x) // Move ctor + : Base(BOOST_MOVE_BASE(Base, x)) + //... If casting is not performed the emulation will not move construct -the base class, because no conversion is available from `BOOST_RV_REF(Derived)` -to `BOOST_RV_REF(Base)`. Without the cast we might obtain a compilation +the base class, because no conversion is available from `BOOST_RV_REF(Derived)` to +`BOOST_RV_REF(Base)`. Without the cast or `BOOST_MOVE_BASE` we might obtain a compilation error (for non-copyable types) or a less-efficient move constructor (for copyable types): [c++] @@ -552,8 +559,8 @@ error (for non-copyable types) or a less-efficient move constructor (for copyabl //If Derived is copyable, then Base is copy-constructed. //If not, a compilation error is issued Derived(BOOST_RV_REF(Derived) x) // Move ctor - : Base(boost::move(x)), - mem_(boost::move(x.mem_)) { } + : Base(boost::move(x)) + //... [endsect] @@ -755,6 +762,12 @@ Many thanks to all boosters that have tested, reviewed and improved the library. [section:release_notes Release Notes] +[section:release_notes_boost_1_58_00 Boost 1.58 Release] + +* Added `BOOST_MOVE_BASE` utility. + +[endsect] + [section:release_notes_boost_1_57_00 Boost 1.57 Release] * Added `unique_ptr` smart pointer. Thanks to Howard Hinnant for his excellent unique_ptr emulation code and testsuite. diff --git a/example/doc_clone_ptr.cpp b/example/doc_clone_ptr.cpp index 8842e38..e0fa73c 100644 --- a/example/doc_clone_ptr.cpp +++ b/example/doc_clone_ptr.cpp @@ -64,19 +64,19 @@ class Derived : public Base // Compiler-generated copy constructor... Derived(BOOST_RV_REF(Derived) x) // Move ctor - : Base(boost::move(static_cast(x))), + : Base(BOOST_MOVE_BASE(Base, x)), mem_(boost::move(x.mem_)) { } Derived& operator=(BOOST_RV_REF(Derived) x) // Move assign { - Base::operator=(boost::move(static_cast(x))); - mem_ = boost::move(x.mem_); + Base::operator=(BOOST_MOVE_BASE(Base, x)); + mem_ = boost::move(x.mem_); return *this; } Derived& operator=(BOOST_COPY_ASSIGN_REF(Derived) x) // Copy assign { - Base::operator=(static_cast(x)); + Base::operator=(x); mem_ = x.mem_; return *this; } diff --git a/include/boost/move/core.hpp b/include/boost/move/core.hpp index ccdcc52..113a95d 100644 --- a/include/boost/move/core.hpp +++ b/include/boost/move/core.hpp @@ -198,6 +198,10 @@ boost::move_detail::move_return< RET_TYPE >(REF) // + #define BOOST_MOVE_BASE(BASE_TYPE, ARG) \ + ::boost::move((BASE_TYPE&)(ARG)) + // + ////////////////////////////////////////////////////////////////////////////// // // BOOST_MOVABLE_BUT_NOT_COPYABLE @@ -373,7 +377,6 @@ const TYPE & \ // - #endif //#if !defined(BOOST_MOVE_DOXYGEN_INVOKED) #if !defined(BOOST_MOVE_MSVC_AUTO_MOVE_RETURN_BUG) || defined(BOOST_MOVE_DOXYGEN_INVOKED) @@ -436,6 +439,17 @@ #endif //!defined(BOOST_MOVE_MSVC_AUTO_MOVE_RETURN_BUG) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + //!This macro is used to achieve portable optimal move constructors. + //! + //!When implementing the move constructor, in C++03 compilers the moved-from argument must be + //!cast to the base type before calling `::boost::move()` due to rvalue reference limitations. + //! + //!In C++11 compilers the cast from a rvalue reference of a derived type to a rvalue reference of + //!a base type is implicit. + #define BOOST_MOVE_BASE(BASE_TYPE, ARG) \ + ::boost::move((BASE_TYPE&)(ARG)) + // + namespace boost { namespace move_detail { From cbda10ecdde552655a664cdbbd9af9e7ea55b1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 26 Nov 2014 19:27:40 +0100 Subject: [PATCH 3/5] Added adl_move_swap utility --- include/boost/move/adl_move_swap.hpp | 89 ++++++++++++++++++++++++++++ include/boost/move/unique_ptr.hpp | 6 +- include/boost/move/utility_core.hpp | 8 --- proj/vc7ide/Move.sln | 1 + test/unique_ptr_modifiers.cpp | 3 +- 5 files changed, 95 insertions(+), 12 deletions(-) create mode 100644 include/boost/move/adl_move_swap.hpp diff --git a/include/boost/move/adl_move_swap.hpp b/include/boost/move/adl_move_swap.hpp new file mode 100644 index 0000000..c2c92dc --- /dev/null +++ b/include/boost/move/adl_move_swap.hpp @@ -0,0 +1,89 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright 2007, 2008 Steven Watanabe, Joseph Gauterin, Niels Dekker +// (C) Copyright Ion Gaztanaga 2005-2013. 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) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_MOVE_ADL_MOVE_SWAP_HPP +#define BOOST_MOVE_ADL_MOVE_SWAP_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +//Based on Boost.Core's swap. +//Many thanks to Steven Watanabe, Joseph Gauterin and Niels Dekker. + +#include +#include //for std::size_t + +//Try to avoid including , as it's quite big +#if defined(_MSC_VER) && defined(BOOST_DINKUMWARE_STDLIB) + #include //Dinkum libraries define std::swap in utility which is lighter than algorithm +#elif defined(BOOST_GNU_STDLIB) + #if (__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) + #include //algobase is lighter than + #elif ((__GNUC__ == 4) && (__GNUC_MINOR__ == 3)) + //In GCC 4.3 a tiny stl_move.h was created with swap and move utilities + #include //algobase is much lighter than + #else + //In GCC 4.4 stl_move.h was renamed to move.h + #include //algobase is much lighter than + #endif +#elif defined(_LIBCPP_VERSION) + #include //The initial import of libc++ defines std::swap and still there +#else //Fallback + #include +#endif + +#include //for boost::move + +namespace boost_move_adl_swap{ + +template +void swap_proxy(T& left, T& right, typename boost::move_detail::enable_if_c::value>::type* = 0) +{ + //use std::swap if argument dependent lookup fails + //Use using directive ("using namespace xxx;") instead as some older compilers + //don't do ADL with using declarations ("using ns::func;"). + using namespace std; + swap(left, right); +} + +template +void swap_proxy(T& left, T& right, typename boost::move_detail::enable_if_c::value>::type* = 0) +{ + T tmp(::boost::move(left)); + left = ::boost::move(right); + right = ::boost::move(tmp); +} + +template +void swap_proxy(T (& left)[N], T (& right)[N]) +{ + for (std::size_t i = 0; i < N; ++i){ + ::boost_move_adl_swap::swap_proxy(left[i], right[i]); + } +} + +} //namespace boost_move_adl_swap { + +namespace boost{ + +// adl_move_swap has two template arguments, instead of one, to +// avoid ambiguity when swapping objects of a Boost type that does +// not have its own boost::swap overload. +template +void adl_move_swap(T& left, T& right) +{ + ::boost_move_adl_swap::swap_proxy(left, right); +} + +} //namespace boost{ + +#endif //#ifndef BOOST_MOVE_ADL_MOVE_SWAP_HPP diff --git a/include/boost/move/unique_ptr.hpp b/include/boost/move/unique_ptr.hpp index 231735b..48fa275 100644 --- a/include/boost/move/unique_ptr.hpp +++ b/include/boost/move/unique_ptr.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -727,9 +728,8 @@ class unique_ptr //! Effects: Invokes swap on the stored pointers and on the stored deleters of *this and u. void swap(unique_ptr& u) BOOST_NOEXCEPT { - using ::boost::move_detail::swap; - swap(m_data.m_p, u.m_data.m_p); - swap(m_data.deleter(), u.m_data.deleter()); + ::boost::adl_move_swap(m_data.m_p, u.m_data.m_p); + ::boost::adl_move_swap(m_data.deleter(), u.m_data.deleter()); } }; diff --git a/include/boost/move/utility_core.hpp b/include/boost/move/utility_core.hpp index 30ab539..8d09e2a 100644 --- a/include/boost/move/utility_core.hpp +++ b/include/boost/move/utility_core.hpp @@ -277,14 +277,6 @@ namespace boost{ namespace move_detail{ -template -void swap(T &a, T &b) -{ - T c((::boost::move(a))); - a = ::boost::move(b); - b = ::boost::move(c); -} - template typename boost::move_detail::add_rvalue_reference::type declval(); diff --git a/proj/vc7ide/Move.sln b/proj/vc7ide/Move.sln index c12681b..bb3bfb9 100644 --- a/proj/vc7ide/Move.sln +++ b/proj/vc7ide/Move.sln @@ -217,6 +217,7 @@ Global {C57C28A3-4FE0-6208-BF87-B2B61D3A7675}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionItems) = postSolution + ..\..\..\..\boost\move\adl_move_swap.hpp = ..\..\..\..\boost\move\adl_move_swap.hpp ..\..\..\..\boost\move\algorithm.hpp = ..\..\..\..\boost\move\algorithm.hpp ..\..\..\..\boost\move\detail\config_begin.hpp = ..\..\..\..\boost\move\detail\config_begin.hpp ..\..\..\..\boost\move\detail\config_end.hpp = ..\..\..\..\boost\move\detail\config_end.hpp diff --git a/test/unique_ptr_modifiers.cpp b/test/unique_ptr_modifiers.cpp index b67d4f5..3de952d 100644 --- a/test/unique_ptr_modifiers.cpp +++ b/test/unique_ptr_modifiers.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include ////////////////////////////////////////////// @@ -284,7 +285,7 @@ void test() BOOST_TEST(s2.get() == p2); BOOST_TEST(*s2 == A(2)); BOOST_TEST(s2.get_deleter().state() == 2); - swap(s1, s2); + boost::adl_move_swap(s1, s2); BOOST_TEST(s1.get() == p2); BOOST_TEST(*s1 == A(2)); BOOST_TEST(s1.get_deleter().state() == 2); From 910165c230ad31a43f5402c3544a5679faf61df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 28 Nov 2014 15:39:49 +0100 Subject: [PATCH 4/5] Added test for adl_move_swap.cpp For move-emulation enabled types, if present, member swap is used, instead of the move-based swap. --- doc/move.qbk | 3 +- include/boost/move/adl_move_swap.hpp | 162 ++++++++++++++-- proj/vc7ide/Move.sln | 8 + proj/vc7ide/adl_move_swap.vcproj | 134 ++++++++++++++ test/adl_move_swap.cpp | 268 +++++++++++++++++++++++++++ 5 files changed, 561 insertions(+), 14 deletions(-) create mode 100644 proj/vc7ide/adl_move_swap.vcproj create mode 100644 test/adl_move_swap.cpp diff --git a/doc/move.qbk b/doc/move.qbk index 0d47f52..372b374 100644 --- a/doc/move.qbk +++ b/doc/move.qbk @@ -764,7 +764,8 @@ Many thanks to all boosters that have tested, reviewed and improved the library. [section:release_notes_boost_1_58_00 Boost 1.58 Release] -* Added `BOOST_MOVE_BASE` utility. +* Added [macroref BOOST_MOVE_BASE BOOST_MOVE_BASE] utility. +* Added [funcref boost::adl_move_swap adl_move_swap] utility. [endsect] diff --git a/include/boost/move/adl_move_swap.hpp b/include/boost/move/adl_move_swap.hpp index c2c92dc..a84b883 100644 --- a/include/boost/move/adl_move_swap.hpp +++ b/include/boost/move/adl_move_swap.hpp @@ -43,45 +43,181 @@ #include //for boost::move +#if !defined(BOOST_MOVE_DOXYGEN_INVOKED) + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +namespace boost_move_member_swap { + +struct dont_care +{ + dont_care(...); +}; + +struct private_type +{ + static private_type p; + private_type const &operator,(int) const; +}; + +typedef char yes_type; +struct no_type{ char dummy[2]; }; + +template +no_type is_private_type(T const &); + +yes_type is_private_type(private_type const &); + +template +class has_member_function_named_swap +{ + struct BaseMixin + { + void swap(); + }; + + struct Base : public Type, public BaseMixin { Base(); }; + template class Helper{}; + + template + static no_type deduce(U*, Helper* = 0); + static yes_type deduce(...); + + public: + static const bool value = sizeof(yes_type) == sizeof(deduce((Base*)(0))); +}; + +template +struct has_member_swap_impl +{ + static const bool value = false; +}; + +template +struct has_member_swap_impl +{ + struct FunWrap : Fun + { + FunWrap(); + + using Fun::swap; + private_type swap(dont_care) const; + }; + + static Fun &declval_fun(); + static FunWrap declval_wrap(); + + static bool const value = + sizeof(no_type) == sizeof(is_private_type( (declval_wrap().swap(declval_fun()), 0)) ); +}; + +template +struct has_member_swap : public has_member_swap_impl + ::value> +{}; + +} //namespace boost_move_member_swap + namespace boost_move_adl_swap{ +template +struct and_op_impl +{ static const bool value = false; }; + +template +struct and_op_impl +{ static const bool value = P2::value; }; + +template +struct and_op + : and_op_impl +{}; + +////// + +template +struct and_op_not_impl +{ static const bool value = false; }; + +template +struct and_op_not_impl +{ static const bool value = !P2::value; }; + +template +struct and_op_not + : and_op_not_impl +{}; + template -void swap_proxy(T& left, T& right, typename boost::move_detail::enable_if_c::value>::type* = 0) +void swap_proxy(T& x, T& y, typename boost::move_detail::enable_if_c::value>::type* = 0) { //use std::swap if argument dependent lookup fails //Use using directive ("using namespace xxx;") instead as some older compilers //don't do ADL with using declarations ("using ns::func;"). using namespace std; - swap(left, right); + swap(x, y); } template -void swap_proxy(T& left, T& right, typename boost::move_detail::enable_if_c::value>::type* = 0) +void swap_proxy(T& x, T& y + , typename boost::move_detail::enable_if< and_op_not_impl + , boost_move_member_swap::has_member_swap > + >::type* = 0) +{ T t(::boost::move(x)); x = ::boost::move(y); y = ::boost::move(t); } + +template +void swap_proxy(T& x, T& y + , typename boost::move_detail::enable_if< and_op_impl< boost::move_detail::has_move_emulation_enabled_impl + , boost_move_member_swap::has_member_swap > + >::type* = 0) +{ x.swap(y); } + +} //namespace boost_move_adl_swap{ + +#else + +namespace boost_move_adl_swap{ + +template +void swap_proxy(T& x, T& y) { - T tmp(::boost::move(left)); - left = ::boost::move(right); - right = ::boost::move(tmp); + using std::swap; + swap(x, y); } +} //namespace boost_move_adl_swap{ + +#endif //#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +namespace boost_move_adl_swap{ + template -void swap_proxy(T (& left)[N], T (& right)[N]) +void swap_proxy(T (& x)[N], T (& y)[N]) { for (std::size_t i = 0; i < N; ++i){ - ::boost_move_adl_swap::swap_proxy(left[i], right[i]); + ::boost_move_adl_swap::swap_proxy(x[i], y[i]); } } } //namespace boost_move_adl_swap { +#endif //!defined(BOOST_MOVE_DOXYGEN_INVOKED) + namespace boost{ -// adl_move_swap has two template arguments, instead of one, to -// avoid ambiguity when swapping objects of a Boost type that does -// not have its own boost::swap overload. +//! Exchanges the values of a and b, using Argument Dependent Lookup (ADL) to select a +//! specialized swap function if available. If no specialized swap function is available, +//! std::swap is used. +//! +//! Exception: If T uses Boost.Move's move emulation and the compiler has +//! no rvalue references then: +//! +//! - If T has a T::swap(T&) member, that member is called. +//! - Otherwise a move-based swap is called, equivalent to: +//! T t(::boost::move(x)); x = ::boost::move(y); y = ::boost::move(t);. template -void adl_move_swap(T& left, T& right) +void adl_move_swap(T& x, T& y) { - ::boost_move_adl_swap::swap_proxy(left, right); + ::boost_move_adl_swap::swap_proxy(x, y); } } //namespace boost{ diff --git a/proj/vc7ide/Move.sln b/proj/vc7ide/Move.sln index bb3bfb9..8429ad4 100644 --- a/proj/vc7ide/Move.sln +++ b/proj/vc7ide/Move.sln @@ -103,6 +103,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unique_ptr_types_test", "un ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adl_move_swap", "adl_move_swap.vcproj", "{CD2617A8-79EB-6172-2CE4-26617AA3AC93}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -215,6 +219,10 @@ Global {C57C28A3-4FE0-6208-BF87-B2B61D3A7675}.Debug.Build.0 = Debug|Win32 {C57C28A3-4FE0-6208-BF87-B2B61D3A7675}.Release.ActiveCfg = Release|Win32 {C57C28A3-4FE0-6208-BF87-B2B61D3A7675}.Release.Build.0 = Release|Win32 + {CD2617A8-79EB-6172-2CE4-26617AA3AC93}.Debug.ActiveCfg = Debug|Win32 + {CD2617A8-79EB-6172-2CE4-26617AA3AC93}.Debug.Build.0 = Debug|Win32 + {CD2617A8-79EB-6172-2CE4-26617AA3AC93}.Release.ActiveCfg = Release|Win32 + {CD2617A8-79EB-6172-2CE4-26617AA3AC93}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionItems) = postSolution ..\..\..\..\boost\move\adl_move_swap.hpp = ..\..\..\..\boost\move\adl_move_swap.hpp diff --git a/proj/vc7ide/adl_move_swap.vcproj b/proj/vc7ide/adl_move_swap.vcproj new file mode 100644 index 0000000..4c57491 --- /dev/null +++ b/proj/vc7ide/adl_move_swap.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/adl_move_swap.cpp b/test/adl_move_swap.cpp new file mode 100644 index 0000000..863e893 --- /dev/null +++ b/test/adl_move_swap.cpp @@ -0,0 +1,268 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2014. +// 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) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +class swap_stats +{ + public: + static void reset_stats() + { + member_swap_calls = 0; + friend_swap_calls = 0; + move_cnstor_calls = 0; + move_assign_calls = 0; + copy_cnstor_calls = 0; + copy_assign_calls = 0; + } + + static unsigned int member_swap_calls; + static unsigned int friend_swap_calls; + static unsigned int move_cnstor_calls; + static unsigned int move_assign_calls; + static unsigned int copy_cnstor_calls; + static unsigned int copy_assign_calls; +}; + +unsigned int swap_stats::member_swap_calls = 0; +unsigned int swap_stats::friend_swap_calls = 0; +unsigned int swap_stats::move_cnstor_calls = 0; +unsigned int swap_stats::move_assign_calls = 0; +unsigned int swap_stats::copy_cnstor_calls = 0; +unsigned int swap_stats::copy_assign_calls = 0; + +class movable : public swap_stats +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(movable) + public: + movable() {} + movable(BOOST_RV_REF(movable)) { ++move_cnstor_calls; } + movable & operator=(BOOST_RV_REF(movable)){ ++move_assign_calls; return *this; } + friend void swap(movable &, movable &) { ++friend_swap_calls; } +}; + +class movable_swap_member : public swap_stats +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(movable_swap_member) + public: + movable_swap_member() {} + movable_swap_member(BOOST_RV_REF(movable_swap_member)) { ++move_cnstor_calls; } + movable_swap_member & operator=(BOOST_RV_REF(movable_swap_member)){ ++move_assign_calls; return *this; } + void swap(movable_swap_member &) { ++member_swap_calls; } + friend void swap(movable_swap_member &, movable_swap_member &) { ++friend_swap_calls; } +}; + +class copyable : public swap_stats +{ + public: + copyable() {} + copyable(const copyable &) { ++copy_cnstor_calls; } + copyable & operator=(const copyable&) { ++copy_assign_calls; return *this; } + void swap(copyable &) { ++member_swap_calls; } + friend void swap(copyable &, copyable &) { ++friend_swap_calls; } +}; + +class no_swap : public swap_stats +{ + private: unsigned m_state; + public: + explicit no_swap(unsigned i): m_state(i){} + no_swap(const no_swap &x) { m_state = x.m_state; ++copy_cnstor_calls; } + no_swap & operator=(const no_swap& x) { m_state = x.m_state; ++copy_assign_calls; return *this; } + void swap(no_swap &) { ++member_swap_calls; } + friend bool operator==(const no_swap &x, const no_swap &y) { return x.m_state == y.m_state; } + friend bool operator!=(const no_swap &x, const no_swap &y) { return !(x==y); } +}; + + +int main() +{ + { //movable + movable x, y; + swap_stats::reset_stats(); + ::boost::adl_move_swap(x, y); + #if defined(BOOST_NO_RVALUE_REFERENCES) + //In non rvalue reference compilers, + //movable classes with no swap() member uses + //boost::move() to implement swap. + BOOST_TEST(swap_stats::friend_swap_calls == 0); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::move_cnstor_calls == 1); + BOOST_TEST(swap_stats::move_assign_calls == 2); + BOOST_TEST(swap_stats::copy_cnstor_calls == 0); + BOOST_TEST(swap_stats::copy_assign_calls == 0); + #else + //In compilers with rvalue references, this should call friend swap via ADL + BOOST_TEST(swap_stats::friend_swap_calls == 1); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::move_cnstor_calls == 0); + BOOST_TEST(swap_stats::move_assign_calls == 0); + BOOST_TEST(swap_stats::copy_cnstor_calls == 0); + BOOST_TEST(swap_stats::copy_assign_calls == 0); + #endif + } + { //movable_swap_member + movable_swap_member x, y; + swap_stats::reset_stats(); + ::boost::adl_move_swap(x, y); + #if defined(BOOST_NO_RVALUE_REFERENCES) + //In non rvalue reference compilers, + //movable classes with no swap() member uses + //boost::move() to implement swap. + BOOST_TEST(swap_stats::friend_swap_calls == 0); + BOOST_TEST(swap_stats::member_swap_calls == 1); + BOOST_TEST(swap_stats::move_cnstor_calls == 0); + BOOST_TEST(swap_stats::move_assign_calls == 0); + BOOST_TEST(swap_stats::copy_cnstor_calls == 0); + BOOST_TEST(swap_stats::copy_assign_calls == 0); + #else + //In compilers with rvalue references, this should call friend swap via ADL + BOOST_TEST(swap_stats::friend_swap_calls == 1); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::move_cnstor_calls == 0); + BOOST_TEST(swap_stats::move_assign_calls == 0); + BOOST_TEST(swap_stats::copy_cnstor_calls == 0); + BOOST_TEST(swap_stats::copy_assign_calls == 0); + #endif + } + { //copyable + copyable x, y; + swap_stats::reset_stats(); + ::boost::adl_move_swap(x, y); + //This should call friend swap via ADL + BOOST_TEST(swap_stats::friend_swap_calls == 1); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::move_cnstor_calls == 0); + BOOST_TEST(swap_stats::move_assign_calls == 0); + BOOST_TEST(swap_stats::copy_cnstor_calls == 0); + BOOST_TEST(swap_stats::copy_assign_calls == 0); + } + { //no_swap + no_swap x(1), y(2), x_back(x), y_back(y); + swap_stats::reset_stats(); + ::boost::adl_move_swap(x, y); + //This should call std::swap which uses copies + BOOST_TEST(swap_stats::friend_swap_calls == 0); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::move_cnstor_calls == 0); + BOOST_TEST(swap_stats::move_assign_calls == 0); + BOOST_TEST(swap_stats::copy_cnstor_calls == 1); + BOOST_TEST(swap_stats::copy_assign_calls == 2); + BOOST_TEST(x == y_back); + BOOST_TEST(y == x_back); + BOOST_TEST(x != y); + } + return ::boost::report_errors(); +} +#include + +/* +#include + +namespace boost_move_member_swap { + +struct dont_care +{ + dont_care(...); +}; + +struct private_type +{ + static private_type p; + private_type const &operator,(int) const; +}; + +typedef char yes_type; +struct no_type{ char dummy[2]; }; + +template +no_type is_private_type(T const &); + +yes_type is_private_type(private_type const &); + +template +class has_member_function_named_swap +{ + struct BaseMixin + { + void swap(); + }; + + struct Base : public Type, public BaseMixin { Base(); }; + template class Helper{}; + + template + static no_type deduce(U*, Helper* = 0); + static yes_type deduce(...); + + public: + static const bool value = sizeof(yes_type) == sizeof(deduce((Base*)(0))); +}; + +template +struct has_member_swap_impl +{ + static const bool value = false; +}; + +template +struct has_member_swap_impl +{ + struct FunWrap : Fun + { + FunWrap(); + + using Fun::swap; + private_type swap(dont_care) const; + }; + + static Fun &declval_fun(); + static FunWrap declval_wrap(); + + static bool const value = + sizeof(no_type) == sizeof(is_private_type( (declval_wrap().swap(declval_fun()), 0)) ); +}; + +template +struct has_member_swap : public has_member_swap_impl + ::value> +{}; + +} //namespace boost_move_member_swap + +class noswap +{ + public: + void swap(); +}; + +class noneswap +{ +}; + +class yesswap +{ + public: + void swap(yesswap&); +}; + +int main() +{ + BOOST_TEST(!boost_move_member_swap::has_member_swap::value); + BOOST_TEST(boost_move_member_swap::has_member_swap::value); + BOOST_TEST(!boost_move_member_swap::has_member_swap::value); + return boost::report_errors(); +} +*/ \ No newline at end of file From 85b41c26d42cadb81cc71bd80736924f4916e060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 29 Nov 2014 18:45:13 +0100 Subject: [PATCH 5/5] Limit libstdc++ only to GCC as clang/icc gnuc versions don't match well with libstdc++ installations --- include/boost/move/adl_move_swap.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/move/adl_move_swap.hpp b/include/boost/move/adl_move_swap.hpp index a84b883..a3373a1 100644 --- a/include/boost/move/adl_move_swap.hpp +++ b/include/boost/move/adl_move_swap.hpp @@ -25,15 +25,15 @@ //Try to avoid including , as it's quite big #if defined(_MSC_VER) && defined(BOOST_DINKUMWARE_STDLIB) #include //Dinkum libraries define std::swap in utility which is lighter than algorithm -#elif defined(BOOST_GNU_STDLIB) +#elif defined(BOOST_GCC) && defined(BOOST_GNU_STDLIB) #if (__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) #include //algobase is lighter than #elif ((__GNUC__ == 4) && (__GNUC_MINOR__ == 3)) //In GCC 4.3 a tiny stl_move.h was created with swap and move utilities - #include //algobase is much lighter than + #include #else //In GCC 4.4 stl_move.h was renamed to move.h - #include //algobase is much lighter than + #include #endif #elif defined(_LIBCPP_VERSION) #include //The initial import of libc++ defines std::swap and still there