From 69598a3d3ffe330bec11cb9174517f949d5e9059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 26 Apr 2015 23:29:27 +0200 Subject: [PATCH 1/2] - Reworked some traits to refactor code - is_trivially_copy_xxxxable updated to add is_pod - Updated is_pod adding scalar and void as some compilers' __is_pod intrinsic doesn't work with scalars - Added test for type_traits. Only a few tested, more to come. --- include/boost/move/detail/type_traits.hpp | 58 ++++++---- proj/vc7ide/Move.sln | 8 ++ proj/vc7ide/type_traits.vcproj | 135 ++++++++++++++++++++++ test/type_traits.cpp | 98 ++++++++++++++++ test/unique_ptr_types.cpp | 41 ++++--- 5 files changed, 299 insertions(+), 41 deletions(-) create mode 100644 proj/vc7ide/type_traits.vcproj create mode 100644 test/type_traits.cpp diff --git a/include/boost/move/detail/type_traits.hpp b/include/boost/move/detail/type_traits.hpp index ed02361..8e67755 100644 --- a/include/boost/move/detail/type_traits.hpp +++ b/include/boost/move/detail/type_traits.hpp @@ -219,7 +219,10 @@ #endif #ifdef BOOST_MOVE_IS_POD - #define BOOST_MOVE_IS_POD_IMPL(T) BOOST_MOVE_IS_POD(T) + //in some compilers the intrinsic is limited to class types so add scalar and void + #define BOOST_MOVE_IS_POD_IMPL(T) (::boost::move_detail::is_scalar::value ||\ + ::boost::move_detail::is_void::value ||\ + BOOST_MOVE_IS_POD(T)) #else #define BOOST_MOVE_IS_POD_IMPL(T) \ (::boost::move_detail::is_scalar::value || ::boost::move_detail::is_void::value) @@ -702,16 +705,31 @@ template struct is_empty { static const bool value = BOOST_MOVE_IS_EMPTY_IMPL(T); }; + +template +struct has_boost_move_no_copy_constructor_or_assign_type +{ + template + static yes_type test(typename U::boost_move_no_copy_constructor_or_assign*); + + template + static no_type test(...); + + static const bool value = sizeof(test(0)) == sizeof(yes_type); +}; + ////////////////////////////////////// // is_copy_constructible ////////////////////////////////////// +#if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) && !defined(BOOST_NO_CXX11_DECLTYPE) \ + && !defined(BOOST_INTEL_CXX_VERSION) && \ + !(defined(BOOST_MSVC) && _MSC_VER == 1800) +#define BOOST_MOVE_TT_CXX11_IS_COPY_CONSTRUCTIBLE +#endif + template struct is_copy_constructible { - typedef char yes_type; - struct no_type { char dummy[2]; }; - template static typename add_reference::type source(); - // Intel compiler has problems with SFINAE for copy constructors and deleted functions: // // error: function *function_name* cannot be referenced -- it is a deleted function @@ -719,8 +737,8 @@ struct is_copy_constructible // ^ // MSVC 12.0 (Visual 2013) has problems when the copy constructor has been deleted. See: // https://connect.microsoft.com/VisualStudio/feedback/details/800328/std-is-copy-constructible-is-broken - #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) && !defined(BOOST_INTEL_CXX_VERSION) &&\ - !(defined(BOOST_MSVC) && _MSC_VER == 1800) + #if defined(BOOST_MOVE_TT_CXX11_IS_COPY_CONSTRUCTIBLE) + template static typename add_reference::type source(); static no_type test(...); #ifdef BOOST_NO_CXX11_DECLTYPE template @@ -729,15 +747,13 @@ struct is_copy_constructible template static yes_type test(U&, decltype(U(source()))* = 0); #endif + static const bool value = sizeof(test(source())) == sizeof(yes_type); #else - template - static no_type test(U&, typename U::boost_move_no_copy_constructor_or_assign* = 0); - static yes_type test(...); + static const bool value = !has_boost_move_no_copy_constructor_or_assign_type::value; #endif - - static const bool value = sizeof(test(source())) == sizeof(yes_type); }; + ////////////////////////////////////// // is_copy_assignable ////////////////////////////////////// @@ -768,13 +784,7 @@ struct is_copy_assignable static const bool value = sizeof(test(0)) == sizeof(yes_type); #else - static typename add_reference::type produce(); - - template - static no_type test(T1&, typename T1::boost_move_no_copy_constructor_or_assign* = 0); - static yes_type test(...); - - static const bool value = sizeof(test(produce())) == sizeof(yes_type); + static const bool value = !has_boost_move_no_copy_constructor_or_assign_type::value; #endif }; @@ -800,8 +810,9 @@ struct is_trivially_copy_constructible { //In several compilers BOOST_MOVE_IS_TRIVIALLY_COPY_CONSTRUCTIBLE return true even with //deleted copy constructors so make sure the type is copy constructible. - static const bool value = ::boost::move_detail::is_copy_constructible::value && - BOOST_MOVE_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T); + static const bool value = ::boost::move_detail::is_pod::value || + ( ::boost::move_detail::is_copy_constructible::value && + BOOST_MOVE_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) ); }; ////////////////////////////////////// @@ -819,8 +830,9 @@ struct is_trivially_copy_assignable { //In several compilers BOOST_MOVE_IS_TRIVIALLY_COPY_CONSTRUCTIBLE return true even with //deleted copy constructors so make sure the type is copy constructible. - static const bool value = ::boost::move_detail::is_copy_assignable::value && - BOOST_MOVE_IS_TRIVIALLY_COPY_ASSIGNABLE(T); + static const bool value = ::boost::move_detail::is_pod::value || + ( ::boost::move_detail::is_copy_assignable::value && + BOOST_MOVE_IS_TRIVIALLY_COPY_ASSIGNABLE(T) ); }; ////////////////////////////////////// diff --git a/proj/vc7ide/Move.sln b/proj/vc7ide/Move.sln index 4b230a8..06e5cc9 100644 --- a/proj/vc7ide/Move.sln +++ b/proj/vc7ide/Move.sln @@ -107,6 +107,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adl_move_swap", "adl_move_s ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "type_traits", "type_traits.vcproj", "{D7C28A23-8621-FE05-BF87-3C7B6176BD02}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -223,6 +227,10 @@ Global {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 + {D7C28A23-8621-FE05-BF87-3C7B6176BD02}.Debug.ActiveCfg = Debug|Win32 + {D7C28A23-8621-FE05-BF87-3C7B6176BD02}.Debug.Build.0 = Debug|Win32 + {D7C28A23-8621-FE05-BF87-3C7B6176BD02}.Release.ActiveCfg = Release|Win32 + {D7C28A23-8621-FE05-BF87-3C7B6176BD02}.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/type_traits.vcproj b/proj/vc7ide/type_traits.vcproj new file mode 100644 index 0000000..daa696a --- /dev/null +++ b/proj/vc7ide/type_traits.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/type_traits.cpp b/test/type_traits.cpp new file mode 100644 index 0000000..3625777 --- /dev/null +++ b/test/type_traits.cpp @@ -0,0 +1,98 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. +// +// 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 + +// +// pod_struct +// +#if defined(BOOST_MOVE_IS_POD) +struct pod_struct +{ + int i; + float f; +}; +#endif + +// +// deleted_copy_and_assign_type +// +#if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) + +struct deleted_copy_and_assign_type +{ + deleted_copy_and_assign_type(const deleted_copy_and_assign_type&) = delete; + deleted_copy_and_assign_type & operator=(const deleted_copy_and_assign_type&) = delete; +}; + +#endif //defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) + +// +// boost_move_type +// +class boost_move_type +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(boost_move_type) + public: + boost_move_type(BOOST_RV_REF(boost_move_type)){} + boost_move_type & operator=(BOOST_RV_REF(boost_move_type)){ return *this; } +}; + +namespace is_pod_test +{ + +void test() +{ + BOOST_STATIC_ASSERT((boost::move_detail::is_pod::value)); + #if defined(BOOST_MOVE_IS_POD) + BOOST_STATIC_ASSERT((boost::move_detail::is_pod::value)); + #endif +} + +} //namespace is_pod_test + +namespace trivially_memcopyable_test { + +void test() +{ + #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) + BOOST_STATIC_ASSERT(!(boost::move_detail::is_trivially_copy_constructible::value)); + BOOST_STATIC_ASSERT(!(boost::move_detail::is_trivially_copy_assignable::value)); + #endif //#if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) + //boost_move_type + BOOST_STATIC_ASSERT(!(boost::move_detail::is_trivially_copy_constructible::value)); + BOOST_STATIC_ASSERT(!(boost::move_detail::is_trivially_copy_assignable::value)); + BOOST_STATIC_ASSERT(!(boost::move_detail::is_copy_constructible::value)); + BOOST_STATIC_ASSERT(!(boost::move_detail::is_copy_assignable::value)); + //POD + BOOST_STATIC_ASSERT((boost::move_detail::is_trivially_copy_constructible::value)); + BOOST_STATIC_ASSERT((boost::move_detail::is_trivially_copy_assignable::value)); + BOOST_STATIC_ASSERT((boost::move_detail::is_copy_constructible::value)); + BOOST_STATIC_ASSERT((boost::move_detail::is_copy_assignable::value)); + #if defined(BOOST_MOVE_IS_POD) + BOOST_STATIC_ASSERT((boost::move_detail::is_trivially_copy_constructible::value)); + BOOST_STATIC_ASSERT((boost::move_detail::is_trivially_copy_assignable::value)); + BOOST_STATIC_ASSERT((boost::move_detail::is_copy_constructible::value)); + BOOST_STATIC_ASSERT((boost::move_detail::is_copy_assignable::value)); + #endif +} + +} //namespace trivially_memcopyable_test { + +int main() +{ + trivially_memcopyable_test::test(); + is_pod_test::test(); + boost::report_errors(); +} diff --git a/test/unique_ptr_types.cpp b/test/unique_ptr_types.cpp index a88b46c..799b417 100644 --- a/test/unique_ptr_types.cpp +++ b/test/unique_ptr_types.cpp @@ -149,12 +149,30 @@ void test() } //namespace unique_ptr_element_type { //////////////////////////////// -// main +// unique_ptr_construct_assign_traits //////////////////////////////// -#if __cplusplus >= 201103L -#include -#endif +namespace unique_ptr_construct_assign_traits { + + void test() + { + typedef bml::unique_ptr unique_ptr_t; + //Even if BOOST_MOVE_TT_CXX11_IS_COPY_CONSTRUCTIBLE is not defined + //boost::unique_ptr shall work with boost::movelib traits + BOOST_STATIC_ASSERT(!(boost::move_detail::is_copy_constructible::value)); + //Even if BOOST_MOVE_TT_CXX11_IS_COPY_ASSIGNABLE is not defined + //boost::unique_ptr shall work with boost::movelib traits + BOOST_STATIC_ASSERT(!(boost::move_detail::is_copy_assignable::value)); + //Important traits for containers like boost::vector + BOOST_STATIC_ASSERT(!(boost::move_detail::is_trivially_copy_constructible::value)); + BOOST_STATIC_ASSERT(!(boost::move_detail::is_trivially_copy_assignable::value)); + } + +} //namespace unique_ptr_construct_assign_traits { + +//////////////////////////////// +// main +//////////////////////////////// int main() { @@ -162,23 +180,10 @@ int main() unique_ptr_pointer_type::test(); unique_ptr_deleter_type::test(); unique_ptr_element_type::test(); - - typedef bml::unique_ptr unique_ptr_t; - BOOST_STATIC_ASSERT(!(boost::move_detail::is_copy_constructible::value)); - BOOST_STATIC_ASSERT(!(boost::move_detail::is_copy_assignable::value)); - BOOST_STATIC_ASSERT(!(boost::move_detail::is_trivially_copy_constructible::value)); - BOOST_STATIC_ASSERT(!(boost::move_detail::is_trivially_copy_assignable::value)); - #if __cplusplus >= 201103L - typedef std::unique_ptr std_unique_ptr_t; - BOOST_STATIC_ASSERT(!(boost::move_detail::is_copy_constructible::value)); - BOOST_STATIC_ASSERT(!(boost::move_detail::is_copy_assignable::value)); - BOOST_STATIC_ASSERT(!(boost::move_detail::is_trivially_copy_constructible::value)); - BOOST_STATIC_ASSERT(!(boost::move_detail::is_trivially_copy_assignable::value)); - #endif + unique_ptr_construct_assign_traits::test(); //Test results return boost::report_errors(); - } #include "unique_ptr_test_utils_end.hpp" From 4a44ed3d26d299cab60950e90447648bdbf08e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 6 May 2015 12:32:11 +0200 Subject: [PATCH 2/2] Modify unique_ptr's constructor from convertible unique_ptr's to take the argument by value. This allows constructing unique_ptr from functions returning convertible unique_ptr's. See https://svn.boost.org/trac/boost/ticket/11259 for some details. --- include/boost/move/core.hpp | 21 ++++++ include/boost/move/unique_ptr.hpp | 18 ++++-- test/unique_ptr_ctordtor.cpp | 103 ++++++++++++++++++++++++++++++ test/unique_ptr_functions.cpp | 2 +- 4 files changed, 137 insertions(+), 7 deletions(-) diff --git a/include/boost/move/core.hpp b/include/boost/move/core.hpp index 8335982..771c780 100644 --- a/include/boost/move/core.hpp +++ b/include/boost/move/core.hpp @@ -153,6 +153,14 @@ >& \ // + #define BOOST_RV_REF_BEG_IF_CXX11 \ + \ + // + + #define BOOST_RV_REF_END_IF_CXX11 \ + \ + // + #define BOOST_FWD_REF(TYPE)\ const TYPE & \ // @@ -346,6 +354,19 @@ //!and ended with BOOST_RV_REF_END #define BOOST_RV_REF_END\ && \ + // + + //!This macro expands to BOOST_RV_REF_BEG if BOOST_NO_CXX11_RVALUE_REFERENCES + //!is not defined, empty otherwise + #define BOOST_RV_REF_BEG_IF_CXX11 \ + BOOST_RV_REF_BEG \ + // + + //!This macro expands to BOOST_RV_REF_END if BOOST_NO_CXX11_RVALUE_REFERENCES + //!is not defined, empty otherwise + #define BOOST_RV_REF_END_IF_CXX11 \ + BOOST_RV_REF_END \ + // //!This macro is used to achieve portable syntax in copy //!assignment for classes marked as BOOST_COPYABLE_AND_MOVABLE. diff --git a/include/boost/move/unique_ptr.hpp b/include/boost/move/unique_ptr.hpp index cbac2aa..f005f34 100644 --- a/include/boost/move/unique_ptr.hpp +++ b/include/boost/move/unique_ptr.hpp @@ -219,9 +219,14 @@ struct enable_up_ptr template struct unique_moveconvert_assignable { - static const bool value = (bmupmu::extent::value == bmupmu::extent::value) && is_unique_ptr_convertible - < bmupmu::is_array::value - , typename bmupmu::pointer_type::type, typename bmupmu::pointer_type::type>::value; + static const bool t_is_array = bmupmu::is_array::value; + static const bool value = + t_is_array == bmupmu::is_array::value && + bmupmu::extent::value == bmupmu::extent::value && + is_unique_ptr_convertible + < t_is_array + , typename bmupmu::pointer_type::type, typename bmupmu::pointer_type::type + >::value; }; template @@ -290,8 +295,9 @@ struct unique_deleter_is_initializable template struct enable_up_moveconv_constr - : bmupmu::enable_if_c::value && - unique_deleter_is_initializable::value, Type> + : bmupmu::enable_if_c + < unique_moveconvert_assignable::value && unique_deleter_is_initializable::value + , Type> {}; } //namespace move_upd { @@ -538,7 +544,7 @@ class unique_ptr //! Postconditions: get() yields the value u.get() yielded before the construction. get_deleter() //! returns a reference to the stored deleter that was constructed from u.get_deleter(). template - unique_ptr( BOOST_RV_REF_BEG unique_ptr BOOST_RV_REF_END u + unique_ptr( BOOST_RV_REF_BEG_IF_CXX11 unique_ptr BOOST_RV_REF_END_IF_CXX11 u BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmupd::enable_up_moveconv_constr::type* =0) ) BOOST_NOEXCEPT : m_data(u.release(), ::boost::move_if_not_lvalue_reference(u.get_deleter())) diff --git a/test/unique_ptr_ctordtor.cpp b/test/unique_ptr_ctordtor.cpp index 1225507..a583b92 100644 --- a/test/unique_ptr_ctordtor.cpp +++ b/test/unique_ptr_ctordtor.cpp @@ -681,6 +681,107 @@ void test() } //namespace unique_ptr_ctor_pointer_deleter_void{ +//////////////////////////////// +// return_unique_single_conversion +//////////////////////////////// + +namespace return_unique_single_conversion{ + +template +bml::unique_ptr make_unique_ptr_of_t() +{ + return bml::unique_ptr(new T); +} + +template +bml::unique_ptr return_const_unique_of_t() +{ + return bml::unique_ptr (make_unique_ptr_of_t()); +} + +void test() +{ + reset_counters(); + BOOST_TEST(A::count == 0); + { + bml::unique_ptr p(return_const_unique_of_t()); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr p(return_const_unique_of_t()); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + } + BOOST_TEST(A::count == 0); +} + +} //namespace return_unique_single_conversion{ + + +//////////////////////////////// +// return_unique_array_conversion +//////////////////////////////// + +namespace return_unique_array_conversion{ + +template +bml::unique_ptr return_unique_array_of_t(std::size_t n) +{ + return bml::unique_ptr(new T[n]); +} + +template +bml::unique_ptr return_const_array_of_t(std::size_t n) +{ + return bml::unique_ptr(return_unique_array_of_t(n)); +} + +template +bml::unique_ptr return_unique_array_of_t_2() +{ + return bml::unique_ptr(new T[2]); +} + +template +bml::unique_ptr return_const_array_of_t_2() +{ + return bml::unique_ptr(return_unique_array_of_t_2()); +} + +void test() +{ + reset_counters(); + BOOST_TEST(A::count == 0); + { + bml::unique_ptr p(return_unique_array_of_t(2)); + BOOST_TEST(A::count == 2); + BOOST_TEST(B::count == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr p(return_unique_array_of_t(2)); + BOOST_TEST(A::count == 2); + BOOST_TEST(B::count == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr p(return_const_array_of_t_2()); + BOOST_TEST(A::count == 2); + BOOST_TEST(B::count == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr p(return_const_array_of_t_2()); + BOOST_TEST(A::count == 2); + BOOST_TEST(B::count == 0); + } + BOOST_TEST(A::count == 0); +} + +} //namespace return_unique_array_conversion{ + //////////////////////////////// // main //////////////////////////////// @@ -699,6 +800,8 @@ int main() unique_ptr_ctor_pointer_deleter_dfctrdelconstref::test(); unique_ptr_ctor_pointer_deleter_convert::test(); unique_ptr_ctor_pointer_deleter_void::test(); + return_unique_single_conversion::test(); + return_unique_array_conversion::test(); //Test results return boost::report_errors(); diff --git a/test/unique_ptr_functions.cpp b/test/unique_ptr_functions.cpp index 33274d2..c68d085 100644 --- a/test/unique_ptr_functions.cpp +++ b/test/unique_ptr_functions.cpp @@ -134,7 +134,7 @@ void test() //////////////////////////////// -// make_unique_single +// make_unique_array //////////////////////////////// namespace make_unique_array{