From 86f1c4dc8785fc2266d7938a9f99011bae1a9b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 22 Aug 2014 18:29:28 +0200 Subject: [PATCH 1/6] Enable MSVC extensions. /Za is buggy and unrecommended. It breaks rvalue references in newer MSVC compilers. --- proj/vc7ide/construct_forward_test.vcproj | 2 +- proj/vc7ide/conversion_test.vcproj | 2 +- proj/vc7ide/doc_clone_ptr.vcproj | 2 +- proj/vc7ide/move_if_noexcept_test.vcproj | 2 +- proj/vc7ide/move_test.vcproj | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/proj/vc7ide/construct_forward_test.vcproj b/proj/vc7ide/construct_forward_test.vcproj index be11eec..0f44a59 100644 --- a/proj/vc7ide/construct_forward_test.vcproj +++ b/proj/vc7ide/construct_forward_test.vcproj @@ -24,7 +24,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="3" - DisableLanguageExtensions="TRUE" + DisableLanguageExtensions="FALSE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/conversion_test.vcproj b/proj/vc7ide/conversion_test.vcproj index 1321c21..215b0ea 100644 --- a/proj/vc7ide/conversion_test.vcproj +++ b/proj/vc7ide/conversion_test.vcproj @@ -24,7 +24,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="3" - DisableLanguageExtensions="TRUE" + DisableLanguageExtensions="FALSE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/doc_clone_ptr.vcproj b/proj/vc7ide/doc_clone_ptr.vcproj index e87a8b8..04ed12b 100644 --- a/proj/vc7ide/doc_clone_ptr.vcproj +++ b/proj/vc7ide/doc_clone_ptr.vcproj @@ -24,7 +24,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="3" - DisableLanguageExtensions="TRUE" + DisableLanguageExtensions="FALSE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/move_if_noexcept_test.vcproj b/proj/vc7ide/move_if_noexcept_test.vcproj index ac38316..4265c32 100644 --- a/proj/vc7ide/move_if_noexcept_test.vcproj +++ b/proj/vc7ide/move_if_noexcept_test.vcproj @@ -24,7 +24,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="3" - DisableLanguageExtensions="TRUE" + DisableLanguageExtensions="FALSE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" diff --git a/proj/vc7ide/move_test.vcproj b/proj/vc7ide/move_test.vcproj index a95ac52..4508392 100644 --- a/proj/vc7ide/move_test.vcproj +++ b/proj/vc7ide/move_test.vcproj @@ -24,7 +24,7 @@ MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="3" - DisableLanguageExtensions="TRUE" + DisableLanguageExtensions="FALSE" TreatWChar_tAsBuiltInType="TRUE" ForceConformanceInForLoopScope="TRUE" UsePrecompiledHeader="0" From cb06d1344839750842e3ead0fa6f7fdc58898e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 22 Aug 2014 18:34:19 +0200 Subject: [PATCH 2/6] Copyright updates. --- test/move.cpp | 1 + test/move_if_noexcept.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/test/move.cpp b/test/move.cpp index a01c230..3c98159 100644 --- a/test/move.cpp +++ b/test/move.cpp @@ -1,6 +1,7 @@ ////////////////////////////////////////////////////////////////////////////// // // (C) Copyright David Abrahams, Vicente Botet, Ion Gaztanaga 2009. +// (C) Copyright Ion Gaztanaga 2009-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) diff --git a/test/move_if_noexcept.cpp b/test/move_if_noexcept.cpp index 5f8124b..2c5afd3 100644 --- a/test/move_if_noexcept.cpp +++ b/test/move_if_noexcept.cpp @@ -1,6 +1,7 @@ ////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Antony Polukhin 2014. +// (C) Copyright Ion Gaztanaga 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) From e1da7c5ca1162841f643331af891a9a730eba118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 22 Aug 2014 18:34:34 +0200 Subject: [PATCH 3/6] Added class unique_ptr under boost::movelib namespace. This could be lifted to ::boost namespace if the community agrees. This unique_ptr implementation is based on C++14, including make_unique functions. Large parte of the testsuite is based on Howard Hinnant's unique_ptr emulation testsuite. --- doc/Jamfile.v2 | 6 +- doc/move.qbk | 1 + include/boost/move/detail/config_begin.hpp | 1 + include/boost/move/detail/meta_utils.hpp | 539 ++++- include/boost/move/detail/workaround.hpp | 26 + include/boost/move/make_unique.hpp | 148 ++ include/boost/move/unique_ptr.hpp | 1251 +++++++++++ include/boost/move/utility_core.hpp | 94 + proj/vc7ide/Move.sln | 26 + proj/vc7ide/unique_ptr_default_deleter.vcproj | 135 ++ proj/vc7ide/unique_ptr_functions.vcproj | 134 ++ proj/vc7ide/unique_ptr_test.vcproj | 135 ++ test/unique_ptr.cpp | 1907 +++++++++++++++++ test/unique_ptr_default_deleter.cpp | 134 ++ test/unique_ptr_functions.cpp | 174 ++ 15 files changed, 4657 insertions(+), 54 deletions(-) create mode 100644 include/boost/move/detail/workaround.hpp create mode 100644 include/boost/move/make_unique.hpp create mode 100644 include/boost/move/unique_ptr.hpp create mode 100644 proj/vc7ide/unique_ptr_default_deleter.vcproj create mode 100644 proj/vc7ide/unique_ptr_functions.vcproj create mode 100644 proj/vc7ide/unique_ptr_test.vcproj create mode 100644 test/unique_ptr.cpp create mode 100644 test/unique_ptr_default_deleter.cpp create mode 100644 test/unique_ptr_functions.cpp diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 6824339..4218cc3 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -21,7 +21,11 @@ doxygen autodoc EXTRACT_PRIVATE=NO ENABLE_PREPROCESSING=YES MACRO_EXPANSION=YES - "PREDEFINED=\"BOOST_MOVE_DOXYGEN_INVOKED\"" + "PREDEFINED=\"BOOST_MOVE_DOXYGEN_INVOKED\" \\ + \"BOOST_MOVE_SEEDOC(T)=see_documentation\" \\ + \"BOOST_RV_REF(T)=T&&\" \\ + \"BOOST_FWD_REF(T)=T&&\" \\ + " ; xml move : move.qbk ; diff --git a/doc/move.qbk b/doc/move.qbk index 824b725..d1a31bd 100644 --- a/doc/move.qbk +++ b/doc/move.qbk @@ -757,6 +757,7 @@ Many thanks to all boosters that have tested, reviewed and improved the library. [section:release_notes_boost_1_57_00 Boost 1.57 Release] +* Added `unique_ptr` utility. Thanks to Howard Hinnant for his excellent unique_ptr emulation code and testsuite. * Added `move_if_noexcept` utility. Thanks to Antony Polukhin for the implementation. * Fixed bugs: * [@https://svn.boost.org/trac/boost/ticket/9785 Trac #9785: ['"Compiler warning with intel icc in boost/move/core.hpp"]], diff --git a/include/boost/move/detail/config_begin.hpp b/include/boost/move/detail/config_begin.hpp index 837ee12..ae3a6ff 100644 --- a/include/boost/move/detail/config_begin.hpp +++ b/include/boost/move/detail/config_begin.hpp @@ -20,4 +20,5 @@ #endif #pragma warning (push) #pragma warning (disable : 4996) // "function": was declared deprecated + #pragma warning (disable : 4675) // "function": resolved overload was found by argument-dependent lookup #endif diff --git a/include/boost/move/detail/meta_utils.hpp b/include/boost/move/detail/meta_utils.hpp index 096705e..30fd58f 100644 --- a/include/boost/move/detail/meta_utils.hpp +++ b/include/boost/move/detail/meta_utils.hpp @@ -19,9 +19,32 @@ //Small meta-typetraits to support move namespace boost { + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES +//Forward declare boost::rv +template class rv; +#endif + namespace move_detail { -//if_ +////////////////////////////////////// +// empty +////////////////////////////////////// +struct empty{}; + +////////////////////////////////////// +// nat +////////////////////////////////////// +struct nat{}; + +////////////////////////////////////// +// natify +////////////////////////////////////// +template struct natify{}; + +////////////////////////////////////// +// if_c +////////////////////////////////////// template struct if_c { @@ -34,6 +57,9 @@ struct if_c typedef T2 type; }; +////////////////////////////////////// +// if_ +////////////////////////////////////// template struct if_ { @@ -41,22 +67,33 @@ struct if_ }; //enable_if_ -template +template struct enable_if_c { typedef T type; }; +////////////////////////////////////// +// enable_if_c +////////////////////////////////////// template struct enable_if_c {}; -template +////////////////////////////////////// +// enable_if +////////////////////////////////////// +template struct enable_if : public enable_if_c {}; -template +////////////////////////////////////// +// disable_if +////////////////////////////////////// +template struct disable_if : public enable_if_c {}; -//integral_constant +////////////////////////////////////// +// integral_constant +////////////////////////////////////// template struct integral_constant { @@ -65,62 +102,37 @@ struct integral_constant typedef integral_constant type; }; -//identity +typedef integral_constant true_type; +typedef integral_constant false_type; + +////////////////////////////////////// +// identity +////////////////////////////////////// template struct identity { typedef T type; }; -#if defined(_MSC_VER) && (_MSC_VER >= 1400) - -//use intrinsic since in MSVC -//overaligned types can't go through ellipsis -template -struct is_convertible -{ - static const bool value = __is_convertible_to(T, U); -}; - -#else - -template -class is_convertible -{ - typedef char true_t; - class false_t { char dummy[2]; }; - static false_t dispatch(...); - static true_t dispatch(U); - static T &trigger(); - public: - static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t); -}; - -#endif - -//and_ not_ +////////////////////////////////////// +// and_ +////////////////////////////////////// template > struct and_ : public integral_constant {}; +////////////////////////////////////// +// not_ +////////////////////////////////////// template struct not_ : public integral_constant {}; -//is_lvalue_reference -template -struct is_lvalue_reference - : public integral_constant -{}; - -template -struct is_lvalue_reference - : public integral_constant -{}; - -//remove_reference +////////////////////////////////////// +// remove_reference +////////////////////////////////////// template struct remove_reference { @@ -133,7 +145,6 @@ struct remove_reference typedef T type; }; - #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template @@ -142,9 +153,73 @@ struct remove_reference typedef T type; }; +#else + +template +struct remove_reference< rv > +{ + typedef T type; +}; + +template +struct remove_reference< rv &> +{ + typedef T type; +}; + +template +struct remove_reference< const rv &> +{ + typedef T type; +}; + + #endif -//add_const + +////////////////////////////////////// +// remove_const +////////////////////////////////////// +template< class T > +struct remove_const +{ + typedef T type; +}; + +template< class T > +struct remove_const +{ + typedef T type; +}; + +////////////////////////////////////// +// remove_volatile +////////////////////////////////////// +template< class T > +struct remove_volatile +{ + typedef T type; +}; + +template< class T > +struct remove_volatile +{ + typedef T type; +}; + +////////////////////////////////////// +// remove_cv +////////////////////////////////////// +template< class T > +struct remove_cv +{ + typedef typename remove_volatile + ::type>::type type; +}; + +////////////////////////////////////// +// add_const +////////////////////////////////////// template struct add_const { @@ -154,7 +229,7 @@ struct add_const template struct add_const { - typedef T& type; + typedef const T& type; }; #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES @@ -167,7 +242,171 @@ struct add_const #endif +////////////////////////////////////// +// remove_extent +////////////////////////////////////// +template +struct remove_extent +{ + typedef T type; +}; + +template +struct remove_extent +{ + typedef T type; +}; + +template +struct remove_extent +{ + typedef T type; +}; +////////////////////////////////////// +// element_pointer +////////////////////////////////////// +template +struct element_pointer +{ + typedef typename remove_extent::type element_type; + typedef element_type* type; +}; + +////////////////////////////////////// +// add_lvalue_reference +////////////////////////////////////// +template +struct add_lvalue_reference +{ + typedef T& type; +}; + +template +struct add_lvalue_reference +{ + typedef T& type; +}; + +template<> +struct add_lvalue_reference +{ + typedef void type; +}; + +template<> +struct add_lvalue_reference +{ + typedef const void type; +}; + +template<> +struct add_lvalue_reference +{ + typedef volatile void type; +}; + +template<> +struct add_lvalue_reference +{ + typedef const volatile void type; +}; + + +////////////////////////////////////// +// is_same +////////////////////////////////////// +template +struct is_same +{ + static const bool value = false; +}; + +template +struct is_same +{ + static const bool value = true; +}; + +////////////////////////////////////// +// is_pointer +////////////////////////////////////// +template< class T > +struct is_pointer +{ + static const bool value = false; +}; + +template< class T > +struct is_pointer +{ + static const bool value = true; +}; + +////////////////////////////////////// +// is_reference +////////////////////////////////////// +template< class T > +struct is_reference +{ + static const bool value = false; +}; + +template< class T > +struct is_reference +{ + static const bool value = true; +}; + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + +template< class T > +struct is_reference +{ + static const bool value = true; +}; + +#endif + +////////////////////////////////////// +// is_lvalue_reference +////////////////////////////////////// +template +struct is_lvalue_reference +{ + static const bool value = false; +}; + +template +struct is_lvalue_reference +{ + static const bool value = true; +}; + +////////////////////////////////////// +// is_array +////////////////////////////////////// +template +struct is_array +{ + static const bool value = false; +}; + +template +struct is_array +{ + static const bool value = true; +}; + +template +struct is_array +{ + static const bool value = true; +}; + +////////////////////////////////////// +// is_class_or_union +////////////////////////////////////// template struct is_class_or_union { @@ -179,10 +418,11 @@ struct is_class_or_union static const bool value = sizeof(is_class_or_union_tester(0)) == sizeof(char); }; -struct empty{}; - -//addressof -template struct addr_impl_ref +////////////////////////////////////// +// addressof +////////////////////////////////////// +template +struct addr_impl_ref { T & v_; inline addr_impl_ref( T & v ): v_( v ) {} @@ -192,7 +432,8 @@ template struct addr_impl_ref addr_impl_ref & operator=(const addr_impl_ref &); }; -template struct addressof_impl +template +struct addressof_impl { static inline T * f( T & v, long ) { @@ -211,6 +452,198 @@ inline T * addressof( T & v ) ( ::boost::move_detail::addr_impl_ref( v ), 0 ); } +////////////////////////////////////// +// has_pointer_type +////////////////////////////////////// +template +struct has_pointer_type +{ + struct two { char c[2]; }; + template static two test(...); + template static char test(typename U::pointer* = 0); + static const bool value = sizeof(test(0)) == 1; +}; + +////////////////////////////////////// +// pointer_type +////////////////////////////////////// +template ::value> +struct pointer_type_imp +{ + typedef typename D::pointer type; +}; + +template +struct pointer_type_imp +{ + typedef typename remove_extent::type* type; +}; + +template +struct pointer_type +{ + typedef typename pointer_type_imp::type>::type type; +}; + +////////////////////////////////////// +// is_convertible +////////////////////////////////////// +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + +//use intrinsic since in MSVC +//overaligned types can't go through ellipsis +template +struct is_convertible +{ + static const bool value = __is_convertible_to(T, U); +}; + +#else + +template +class is_convertible +{ + typedef typename add_lvalue_reference::type t_reference; + typedef char true_t; + class false_t { char dummy[2]; }; + static false_t dispatch(...); + static true_t dispatch(U); + static t_reference trigger(); + public: + static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t); +}; + +#endif + +////////////////////////////////////// +// is_unary_or_binary_function +////////////////////////////////////// +#if defined(BOOST_MSVC) || defined(__BORLANDC_) +#define BOOST_MOVE_TT_DECL __cdecl +#else +#define BOOST_MOVE_TT_DECL +#endif + +#if defined(_MSC_EXTENSIONS) && !defined(__BORLAND__) && !defined(_WIN64) && !defined(_M_ARM) && !defined(UNDER_CE) +#define BOOST_MOVE_TT_TEST_MSC_FUNC_SIGS +#endif + +template +struct is_unary_or_binary_function_impl +{ static const bool value = false; }; + +// avoid duplicate definitions of is_unary_or_binary_function_impl +#ifndef BOOST_MOVE_TT_TEST_MSC_FUNC_SIGS + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +#else // BOOST_MOVE_TT_TEST_MSC_FUNC_SIGS + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +#ifndef _MANAGED + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +#endif + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +#endif + +// avoid duplicate definitions of is_unary_or_binary_function_impl +#ifndef BOOST_MOVE_TT_TEST_MSC_FUNC_SIGS + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +#else // BOOST_MOVE_TT_TEST_MSC_FUNC_SIGS + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +#ifndef _MANAGED + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +#endif + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +#endif + +// avoid duplicate definitions of is_unary_or_binary_function_impl +#ifndef BOOST_MOVE_TT_TEST_MSC_FUNC_SIGS + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +#else // BOOST_MOVE_TT_TEST_MSC_FUNC_SIGS + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +#ifndef _MANAGED + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +#endif + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; + +template +struct is_unary_or_binary_function_impl +{ static const bool value = true; }; +#endif + +template +struct is_unary_or_binary_function_impl +{ static const bool value = false; }; + +template +struct is_unary_or_binary_function +{ static const bool value = is_unary_or_binary_function_impl::value; }; + } //namespace move_detail { } //namespace boost { diff --git a/include/boost/move/detail/workaround.hpp b/include/boost/move/detail/workaround.hpp new file mode 100644 index 0000000..b46c808 --- /dev/null +++ b/include/boost/move/detail/workaround.hpp @@ -0,0 +1,26 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_MOVE_DETAIL_WORKAROUND_HPP +#define BOOST_MOVE_DETAIL_WORKAROUND_HPP + +#include + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + #define BOOST_MOVE_PERFECT_FORWARDING +#endif + +//Macros for documentation purposes. For code, expands to the argument +#define BOOST_MOVE_IMPDEF(TYPE) TYPE +#define BOOST_MOVE_SEEDOC(TYPE) TYPE + +#include + +#endif //#ifndef BOOST_MOVE_DETAIL_WORKAROUND_HPP diff --git a/include/boost/move/make_unique.hpp b/include/boost/move/make_unique.hpp new file mode 100644 index 0000000..30aa8d8 --- /dev/null +++ b/include/boost/move/make_unique.hpp @@ -0,0 +1,148 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_MOVE_MAKE_UNIQUE_HPP_INCLUDED +#define BOOST_MOVE_MAKE_UNIQUE_HPP_INCLUDED + +#include +#include +#include +#include +#include + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#include +#include +#include +#endif + +//!\file +//! Defines "make_unique" functions, which are factories to create instances +//! of unique_ptr depending on the passed arguments. +//! +//! This header can be a bit heavyweight in C++03 compilers due to the use of the +//! preprocessor library, that's why it's a a separate header from unique_ptr.hpp + +namespace boost{ + +#if !defined(BOOST_MOVE_DOXYGEN_INVOKED) + +namespace move_detail { + +//Compile time switch between +//single element, unknown bound array +//and known bound array +template +struct unique_ptr_if +{ + typedef ::boost::movelib::unique_ptr t_is_not_array; +}; + +template +struct unique_ptr_if +{ + typedef ::boost::movelib::unique_ptr t_is_array_of_unknown_bound; +}; + +template +struct unique_ptr_if +{ + typedef void t_is_array_of_known_bound; +}; + +} //namespace move_detail { + +#endif //!defined(BOOST_MOVE_DOXYGEN_INVOKED) + +namespace movelib { + +#if defined(BOOST_MOVE_DOXYGEN_INVOKED) || !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +//! Remarks: This function shall not participate in overload resolution unless T is not an array. +//! +//! Returns: unique_ptr(new T(std::forward(args)...)). +template +inline + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + unique_ptr + #else + typename ::boost::move_detail::unique_ptr_if::t_is_not_array + #endif + make_unique(BOOST_FWD_REF(Args)... args) +{ return unique_ptr(new T(::boost::forward(args)...)); } + +#else + #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + #define BOOST_MOVE_PP_PARAM_LIST(z, n, data) \ + BOOST_PP_CAT(P, n) && BOOST_PP_CAT(p, n) \ + //! + #else + #define BOOST_MOVE_PP_PARAM_LIST(z, n, data) \ + const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n) \ + //! + #endif //#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + #define BOOST_MOVE_PP_PARAM_FORWARD(z, n, data) \ + ::boost::forward< BOOST_PP_CAT(P, n) >( BOOST_PP_CAT(p, n) ) \ + //! + + #define BOOST_MOVE_MAX_CONSTRUCTOR_PARAMETERS 10 + + #define BOOST_PP_LOCAL_MACRO(n) \ + template \ + typename ::boost::move_detail::unique_ptr_if::t_is_not_array \ + make_unique(BOOST_PP_ENUM(n, BOOST_MOVE_PP_PARAM_LIST, _)) \ + { return unique_ptr(new T(BOOST_PP_ENUM(n, BOOST_MOVE_PP_PARAM_FORWARD, _))); } \ + //! + + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_MOVE_MAX_CONSTRUCTOR_PARAMETERS) + #include BOOST_PP_LOCAL_ITERATE() + +#endif + + +//! Remarks: This function shall not participate in overload resolution unless T is an array of +//! unknown bound. +//! +//! Returns: unique_ptr(new remove_extent_t[n]()). +template +inline + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + unique_ptr + #else + typename ::boost::move_detail::unique_ptr_if::t_is_array_of_unknown_bound + #endif + make_unique(size_t n) +{ + typedef typename ::boost::move_detail::remove_extent::type U; + return unique_ptr(new U[n]()); +} + +#if defined(BOOST_MOVE_DOXYGEN_INVOKED) || !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) + +//! Remarks: This function shall not participate in overload resolution unless T is +//! an array of known bound. +template + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + unspecified + #else + typename ::boost::move_detail::unique_ptr_if::t_is_array_of_known_bound + #endif + make_unique(BOOST_FWD_REF(Args) ...) = delete; +#endif + +} //namespace movelib { + +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_MOVE_MAKE_UNIQUE_HPP_INCLUDED diff --git a/include/boost/move/unique_ptr.hpp b/include/boost/move/unique_ptr.hpp new file mode 100644 index 0000000..a6839ea --- /dev/null +++ b/include/boost/move/unique_ptr.hpp @@ -0,0 +1,1251 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_MOVE_UNIQUE_PTR_HPP_INCLUDED +#define BOOST_MOVE_UNIQUE_PTR_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include + +//!\file +//! Describes the smart pointer unique_ptr, a drop-in replacement for std::unique_ptr, +//! usable also from C++03 compilers. +//! +//! Main differences from std::unique_ptr to avoid heavy dependencies, +//! specially in C++03 compilers: +//! - operator < uses pointer operator < instead of std::less. +//! This avoids dependencies on std::common_type and std::less +//! (/ headers. In C++03 this avoid pulling Boost.Typeof and other +//! cascading dependencies. As in all Boost platforms operator < on raw pointers and +//! other smart pointers provides strict weak ordering in practice this should not be a problem for users. +//! - assignable from literal 0 for compilers without nullptr +//! - unique_ptr is constructible and assignable from unique_ptr if +//! cv-less T and cv-less U are the same type and T is more CV qualified than U. + +namespace boost{ + +namespace move_detail { + +template +struct deleter_types +{ + typedef typename if_c + < is_lvalue_reference::value + , D + , typename add_lvalue_reference::type>::type + >::type deleter_arg_type1; + + #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef typename remove_reference::type && deleter_arg_type2; + #else + typedef ::boost::rv &deleter_arg_type2; + #endif + typedef typename add_lvalue_reference::type deleter_lvalue_reference; + typedef typename add_lvalue_reference + ::type>::type deleter_const_lvalue_reference; +}; + +template ::value || is_reference::value > +struct unique_ptr_data +{ + typedef typename deleter_types::deleter_arg_type1 deleter_arg_type1; + typedef typename deleter_types::deleter_arg_type2 deleter_arg_type2; + typedef typename deleter_types::deleter_lvalue_reference deleter_lvalue_reference; + typedef typename deleter_types::deleter_const_lvalue_reference deleter_const_lvalue_reference; + + unique_ptr_data() BOOST_NOEXCEPT + : m_p(), d() + {} + + explicit unique_ptr_data(P p) BOOST_NOEXCEPT + : m_p(p), d() + {} + + unique_ptr_data(P p, deleter_arg_type1 d1) BOOST_NOEXCEPT + : m_p(p), d(d1) + {} + + unique_ptr_data(P p, deleter_arg_type2 d2) BOOST_NOEXCEPT + : m_p(p), d(::boost::move(d2)) + {} + + template + unique_ptr_data(P p, BOOST_FWD_REF(U) d) BOOST_NOEXCEPT + : m_p(::boost::forward(p)), d(::boost::forward(d)) + {} + + deleter_lvalue_reference deleter() + { return d; } + + deleter_const_lvalue_reference deleter() const + { return d; } + + P m_p; + + private: + unique_ptr_data(const unique_ptr_data&); + unique_ptr_data &operator=(const unique_ptr_data&); + D d; +}; + +template +struct unique_ptr_data + : private D +{ + typedef typename deleter_types::deleter_arg_type1 deleter_arg_type1; + typedef typename deleter_types::deleter_arg_type2 deleter_arg_type2; + typedef typename deleter_types::deleter_lvalue_reference deleter_lvalue_reference; + typedef typename deleter_types::deleter_const_lvalue_reference deleter_const_lvalue_reference; + + unique_ptr_data() BOOST_NOEXCEPT + : D(), m_p() + {} + + unique_ptr_data(P p) BOOST_NOEXCEPT + : D(), m_p(p) + {} + + unique_ptr_data(P p, deleter_arg_type1 d1) BOOST_NOEXCEPT + : D(d1), m_p(p) + {} + + unique_ptr_data(P p, deleter_arg_type2 d2) BOOST_NOEXCEPT + : D(::boost::move(d2)), m_p(p) + {} + + template + unique_ptr_data(P p, BOOST_FWD_REF(U) d) BOOST_NOEXCEPT + : D(::boost::forward(d)), m_p(p) + {} + + deleter_lvalue_reference deleter() + { return static_cast(*this); } + + deleter_const_lvalue_reference deleter() const + { return static_cast(*this); } + + P m_p; + private: + unique_ptr_data(const unique_ptr_data&); + unique_ptr_data &operator=(const unique_ptr_data&); +}; + +//Although non-standard, we avoid using pointer_traits +//to avoid heavy dependencies +template +struct get_element_type +{ + template + static char test(int, typename X::element_type*); + + template + static int test(...); + + struct DefaultWrap { typedef natify element_type; }; + + static const bool value = (1 == sizeof(test(0, 0))); + + typedef typename + if_c::type::element_type type; +}; + +template +struct get_element_type +{ + typedef T type; +}; + +template +struct get_cvelement +{ + typedef typename remove_cv + ::type + >::type type; +}; + +template +struct is_same_cvelement_and_convertible +{ + typedef typename remove_reference::type arg1; + typedef typename remove_reference::type arg2; + static const bool same_cvless = is_same::type + ,typename get_cvelement::type + >::value; + static const bool value = same_cvless && is_convertible::value; +}; + +template +struct enable_same_cvelement_and_convertible + : public enable_if_c + ::value, Type> +{}; + + +template +struct is_unique_acceptable +{ + static const bool value = OtherIsArray && + is_same_cvelement_and_convertible + ::value; +}; + +template +struct is_unique_acceptable +{ + static const bool value = !OtherIsArray && + is_convertible::value; +}; + + +template +struct enable_default_delete + : enable_if_c + < is_unique_acceptable < is_array::value + , is_array::value + , typename element_pointer::type + , typename element_pointer::type + >::value + , Type> +{}; + +template +class is_rvalue_convertible +{ + #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef typename remove_reference::type&& t_from; + #else + typedef typename if_c + < has_move_emulation_enabled::value && !is_reference::value + , boost::rv& + , typename add_lvalue_reference::type + >::type t_from; + #endif + + typedef char true_t; + class false_t { char dummy[2]; }; + static false_t dispatch(...); + static true_t dispatch(U); + static t_from trigger(); + public: + static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t); +}; + +template::value> +struct unique_deleter_is_initializable +{ + static const bool value = is_same::value; +}; + +template +struct unique_deleter_is_initializable +{ + #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + //Clang has some problems with is_rvalue_convertible with non-copyable types + //so use intrinsic if available + #if defined(BOOST_CLANG) + #if __has_feature(is_convertible_to) + static const bool value = __is_convertible_to(E, D); + #else + static const bool value = is_rvalue_convertible::value; + #endif + #else + static const bool value = is_rvalue_convertible::value; + #endif + + #else //!defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + //No hope for compilers with move emulation for now. In several compilers is_convertible + // leads to errors, so just move the Deleter and see if the conversion works + static const bool value = true; /*is_rvalue_convertible::value*/ + #endif +}; + +template +struct is_ptr_convertible +{ + typedef typename ::boost::move_detail::pointer_type::type from_ptr; + typedef typename ::boost::move_detail::pointer_type::type to_ptr; + static const bool value = is_convertible::value; +}; + +template +struct unique_moveconvert_assignable +{ + static const bool ptrconvert = is_ptr_convertible::value; + static const bool notarray = !is_array::value; + static const bool value = ptrconvert && notarray; +}; + +template +struct unique_moveconvert_constructible +{ + static const bool massignable = unique_moveconvert_assignable::value; + static const bool value = massignable && unique_deleter_is_initializable::value; +}; + +template +struct enable_unique_moveconvert_constructible + : enable_if_c + < unique_moveconvert_constructible::value, Type> +{}; + +template +struct enable_unique_moveconvert_assignable + : enable_if_c + < unique_moveconvert_assignable::value, Type> +{}; + +template +struct uniquearray_moveconvert_assignable +{ + typedef typename ::boost::move_detail::pointer_type::type from_ptr; + typedef typename ::boost::move_detail::pointer_type::type to_ptr; + static const bool ptrconvert = is_same_cvelement_and_convertible::value; + static const bool yesarray = is_array::value; + static const bool value = ptrconvert && yesarray; +}; + +template +struct uniquearray_moveconvert_constructible +{ + static const bool massignable = uniquearray_moveconvert_assignable::value; + static const bool value = massignable && unique_deleter_is_initializable::value; +}; + +template +struct enable_uniquearray_moveconvert_constructible + : enable_if_c + < uniquearray_moveconvert_constructible::value, Type> +{}; + +template +struct enable_uniquearray_moveconvert_assignable + : enable_if_c + < uniquearray_moveconvert_assignable::value, Type> +{}; + +template +void unique_ptr_call_deleter(Deleter &d, const Pointer &p, boost::move_detail::true_type) //default_deleter +{ d(p); } + +template +void unique_ptr_call_deleter(Deleter &d, const Pointer &p, boost::move_detail::false_type) +{ if(p) d(p); } + +} //namespace move_detail { + +namespace movelib { + +//!The class template default_delete serves as the default deleter +//!(destruction policy) for the class template unique_ptr. +//! +//!A specialization to delete array types is provided +//!with a slightly altered interface. +template +struct default_delete +{ + //! Default constructor. + //! + BOOST_CONSTEXPR default_delete() + //Avoid "defaulted on its first declaration must not have an exception-specification" error for GCC 4.6 + #if !defined(BOOST_GCC) || (BOOST_GCC < 40600 && BOOST_GCC >= 40700) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + BOOST_NOEXCEPT + #endif + #if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + = default; + #else + {}; + #endif + + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + default_delete(const default_delete&) BOOST_NOEXCEPT = default; + default_delete &operator=(const default_delete&) BOOST_NOEXCEPT = default; + #else + typedef T element_type; + #endif + + //! Effects: Constructs a default_delete object from another default_delete object. + //! + //! Remarks: This constructor shall not participate in overload resolution unless U* is + //! implicitly convertible to T*. + template + default_delete(const default_delete& + #if !defined(BOOST_MOVE_DOXYGEN_INVOKED) + , typename ::boost::move_detail::enable_default_delete::type* = 0 + #endif + ) BOOST_NOEXCEPT + {} + + //! Effects: Constructs a default_delete object from another default_delete object. + //! + //! Remarks: This constructor shall not participate in overload resolution unless U* is + //! implicitly convertible to T*. + //! + //! Note: Non-standard extension + template + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + default_delete & + #else + typename ::boost::move_detail::enable_default_delete::type + #endif + operator=(const default_delete&) BOOST_NOEXCEPT + { return *this; } + + //! Effects: calls delete on ptr. + //! + //! Remarks: If T is an incomplete type, the program is ill-formed. + void operator()(T* ptr) const + { + //T must be a complete type + BOOST_STATIC_ASSERT(sizeof(T) > 0); + delete ptr; + } +}; + +//!The specialization to delete array types (array_of_T = T[]) +//!with a slightly altered interface. +//! +//! \tparam array_of_T is an alias for types of form T[] +template +struct default_delete +#if defined(BOOST_MOVE_DOXYGEN_INVOKED) + +#else + +#endif +{ + //! Default constructor. + //! + BOOST_CONSTEXPR default_delete() + //Avoid "defaulted on its first declaration must not have an exception-specification" error for GCC 4.6 + #if !defined(BOOST_GCC) || (BOOST_GCC < 40600 && BOOST_GCC >= 40700) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + BOOST_NOEXCEPT + #endif + #if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + = default; + #else + {}; + #endif + + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + default_delete(const default_delete&) BOOST_NOEXCEPT = default; + default_delete &operator=(const default_delete&) BOOST_NOEXCEPT = default; + #else + typedef T element_type; + #endif + + //! Effects: Constructs a default_delete object from another default_delete object. + //! + //! Remarks: This constructor shall not participate in overload resolution unless U* is + //! a more CV cualified pointer to T. + //! + //! Note: Non-standard extension + template + default_delete(const default_delete& + #if !defined(BOOST_MOVE_DOXYGEN_INVOKED) + , typename ::boost::move_detail::enable_default_delete::type* = 0 + #endif + ) BOOST_NOEXCEPT + {} + + //! Effects: Constructs a default_delete object from another default_delete object. + //! + //! Remarks: This constructor shall not participate in overload resolution unless U* is + //! a more CV cualified pointer to T. + //! + //! Note: Non-standard extension + template + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + default_delete & + #else + typename ::boost::move_detail::enable_default_delete::type + #endif + operator=(const default_delete&) BOOST_NOEXCEPT + { return *this; } + + #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + //! Effects: calls delete[] on ptr. + //! + //! Remarks: If T is an incomplete type, the program is ill-formed. + void operator()(T* ptr) const + { + //T must be a complete type + BOOST_STATIC_ASSERT(sizeof(T) > 0); + delete [] ptr; + } + + //! Remarks: This deleter can't delete pointers convertible to T unless U* is + //! a more CV cualified pointer to T. + //! + //! Note: Non-standard extension + template + void operator()(U*) const = delete; + #else + template + void operator()(U* ptr + #if !defined(BOOST_MOVE_DOXYGEN_INVOKED) + , typename ::boost::move_detail::enable_default_delete::type * = 0 + #endif + ) const BOOST_NOEXCEPT + { + //U must be a complete type + BOOST_STATIC_ASSERT(sizeof(U) > 0); + delete [] ptr; + } + #endif +}; + + +//! A unique pointer is an object that owns another object and +//! manages that other object through a pointer. +//! +//! More precisely, a unique pointer is an object u that stores a pointer to a second object p and will dispose +//! of p when u is itself destroyed (e.g., when leaving block scope). In this context, u is said to own p. +//! +//! The mechanism by which u disposes of p is known as p's associated deleter, a function object whose correct +//! invocation results in p's appropriate disposition (typically its deletion). +//! +//! Let the notation u.p denote the pointer stored by u, and let u.d denote the associated deleter. Upon request, +//! u can reset (replace) u.p and u.d with another pointer and deleter, but must properly dispose of its owned +//! object via the associated deleter before such replacement is considered completed. +//! +//! Additionally, u can, upon request, transfer ownership to another unique pointer u2. Upon completion of +//! such a transfer, the following postconditions hold: +//! - u2.p is equal to the pre-transfer u.p, +//! - u.p is equal to nullptr, and +//! - if the pre-transfer u.d maintained state, such state has been transferred to u2.d. +//! +//! As in the case of a reset, u2 must properly dispose of its pre-transfer owned object via the pre-transfer +//! associated deleter before the ownership transfer is considered complete. +//! +//! Each object of a type U instantiated from the unique_ptr template specified in this subclause has the strict +//! ownership semantics, specified above, of a unique pointer. In partial satisfaction of these semantics, each +//! such U is MoveConstructible and MoveAssignable, but is not CopyConstructible nor CopyAssignable. +//! The template parameter T of unique_ptr may be an incomplete type. +//! +//! The uses of unique_ptr include providing exception safety for dynamically allocated memory, passing +//! ownership of dynamically allocated memory to a function, and returning dynamically allocated memory from +//! a function. +//! +//! \tparam T Provides the type of the stored pointer. +//! \tparam D The deleter type: +//! - The default type for the template parameter D is default_delete. A client-supplied template argument +//! D shall be a function object type, lvalue-reference to function, or lvalue-reference to function object type +//! for which, given a value d of type D and a value ptr of type unique_ptr::pointer, the expression +//! d(ptr) is valid and has the effect of disposing of the pointer as appropriate for that deleter. +//! - If the deleter's type D is not a reference type, D shall satisfy the requirements of Destructible. +//! - If the type remove_reference::type::pointer exists, it shall satisfy the requirements of NullablePointer. +template > +class unique_ptr +{ + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + public: + unique_ptr(const unique_ptr&) = delete; + unique_ptr& operator=(const unique_ptr&) = delete; + private: + #else + BOOST_MOVABLE_BUT_NOT_COPYABLE(unique_ptr) + typedef move_detail::pointer_type pointer_type_obtainer; + typedef ::boost::move_detail::unique_ptr_data + data_type; + typedef typename data_type::deleter_arg_type1 deleter_arg_type1; + typedef typename data_type::deleter_arg_type2 deleter_arg_type2; + typedef typename data_type::deleter_lvalue_reference deleter_lvalue_reference; + typedef typename data_type::deleter_const_lvalue_reference deleter_const_lvalue_reference; + struct nat {int for_bool;}; + typedef ::boost::move_detail::integral_constant >::value > is_default_deleter_t; + #endif + + public: + //! If the type remove_reference::type::pointer exists, then it shall be a + //! synonym for remove_reference::type::pointer. Otherwise it shall be a + //! synonym for T*. + typedef typename BOOST_MOVE_SEEDOC(pointer_type_obtainer::type) pointer; + typedef T element_type; + typedef D deleter_type; + + //! Requires: D shall satisfy the requirements of DefaultConstructible, and + //! that construction shall not throw an exception. + //! + //! Effects: Constructs a unique_ptr object that owns nothing, value-initializing the + //! stored pointer and the stored deleter. + //! + //! Postconditions: get() == nullptr. get_deleter() returns a reference to the stored deleter. + //! + //! Remarks: If this constructor is instantiated with a pointer type or reference type + //! for the template argument D, the program is ill-formed. + BOOST_CONSTEXPR unique_ptr() BOOST_NOEXCEPT + : m_data() + { + //If this constructor is instantiated with a pointer type or reference type + //for the template argument D, the program is ill-formed. + BOOST_STATIC_ASSERT(!::boost::move_detail::is_pointer::value); + BOOST_STATIC_ASSERT(!::boost::move_detail::is_reference::value); + } + + //! Requires: D shall satisfy the requirements of DefaultConstructible, and + //! that construction shall not throw an exception. + //! + //! Effects: Constructs a unique_ptr which owns p, initializing the stored pointer + //! with p and value initializing the stored deleter. + //! + //! Postconditions: get() == p. get_deleter() returns a reference to the stored deleter. + //! + //! Remarks: If this constructor is instantiated with a pointer type or reference type + //! for the template argument D, the program is ill-formed. + explicit unique_ptr(pointer p) BOOST_NOEXCEPT + : m_data(p) + { + //If this constructor is instantiated with a pointer type or reference type + //for the template argument D, the program is ill-formed. + BOOST_STATIC_ASSERT(!::boost::move_detail::is_pointer::value); + BOOST_STATIC_ASSERT(!::boost::move_detail::is_reference::value); + } + + //!The signature of this constructor depends upon whether D is a reference type. + //! - If D is non-reference type A, then the signature is unique_ptr(pointer p, const A& d). + //! - If D is an lvalue-reference type A&, then the signature is unique_ptr(pointer p, A& d). + //! - If D is an lvalue-reference type const A&, then the signature is unique_ptr(pointer p, const A& d). + //! + //! Effects: Constructs a unique_ptr object which owns p, initializing the stored pointer with p and + //! initializing the deleter as described above. + //! + //! Postconditions: get() == p.get_deleter() returns a reference to the stored deleter. If D is a + //! reference type then get_deleter() returns a reference to the lvalue d. + unique_ptr(pointer p, BOOST_MOVE_SEEDOC(deleter_arg_type1) d1) BOOST_NOEXCEPT + : m_data(p, d1) + {} + + //! The signature of this constructor depends upon whether D is a reference type. + //! - If D is non-reference type A, then the signature is unique_ptr(pointer p, A&& d). + //! - If D is an lvalue-reference type A&, then the signature is unique_ptr(pointer p, A&& d). + //! - If D is an lvalue-reference type const A&, then the signature is unique_ptr(pointer p, const A&& d). + //! + //! Effects: Constructs a unique_ptr object which owns p, initializing the stored pointer with p and + //! initializing the deleter as described above. + //! + //! Postconditions: get() == p.get_deleter() returns a reference to the stored deleter. If D is a + //! reference type then get_deleter() returns a reference to the lvalue d. + unique_ptr(pointer p, BOOST_MOVE_SEEDOC(deleter_arg_type2) d2) BOOST_NOEXCEPT + : m_data(p, ::boost::move(d2)) + {} + + //! Requires: If D is not a reference type, D shall satisfy the requirements of MoveConstructible. + //! Construction of the deleter from an rvalue of type D shall not throw an exception. + //! + //! Effects: Constructs a unique_ptr by transferring ownership from u to *this. If D is a reference type, + //! this deleter is copy constructed from u's deleter; otherwise, this deleter is move constructed from u's + //! deleter. + //! + //! 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(). If D is a + //! reference type then get_deleter() and u.get_deleter() both reference the same lvalue deleter. + unique_ptr(BOOST_RV_REF(unique_ptr) u) BOOST_NOEXCEPT + : m_data(u.release(), ::boost::move_if_not_lvalue_reference(u.get_deleter())) + {} + + #if !defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + //! Effects: Same as unique_ptr() (default constructor). + //! + BOOST_CONSTEXPR unique_ptr(std::nullptr_t) BOOST_NOEXCEPT + : m_data() + { + //If this constructor is instantiated with a pointer type or reference type + //for the template argument D, the program is ill-formed. + BOOST_STATIC_ASSERT(!::boost::move_detail::is_pointer::value); + BOOST_STATIC_ASSERT(!::boost::move_detail::is_reference::value); + } + #endif + + //! Requires: If E is not a reference type, construction of the deleter from an rvalue of type E shall be + //! well formed and shall not throw an exception. Otherwise, E is a reference type and construction of the + //! deleter from an lvalue of type E shall be well formed and shall not throw an exception. + //! + //! Remarks: This constructor shall not participate in overload resolution unless: + //! - unique_ptr::pointer is implicitly convertible to pointer, + //! - U is not an array type, and + //! - either D is a reference type and E is the same type as D, or D is not a reference type and E is + //! implicitly convertible to D. + //! + //! Effects: Constructs a unique_ptr by transferring ownership from u to *this. If E is a reference type, + //! this deleter is copy constructed from u's deleter; otherwise, this deleter is move constructed from u's deleter. + //! + //! 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 + #if !defined(BOOST_MOVE_DOXYGEN_INVOKED) + , typename ::boost::move_detail::enable_unique_moveconvert_constructible::type * = 0 + #endif + ) BOOST_NOEXCEPT + : m_data(u.release(), ::boost::move_if_not_lvalue_reference(u.get_deleter())) + {} + + //! Requires: The expression get_deleter()(get()) shall be well formed, shall have well-defined behavior, + //! and shall not throw exceptions. + //! + //! Effects: If get() == nullpt1r there are no effects. Otherwise get_deleter()(get()). + //! + //! Note: The use of default_delete requires T to be a complete type + ~unique_ptr() + { unique_ptr_call_deleter(m_data.deleter(), m_data.m_p, is_default_deleter_t()); } + + //! Requires: If D is not a reference type, D shall satisfy the requirements of MoveAssignable + //! and assignment of the deleter from an rvalue of type D shall not throw an exception. Otherwise, D + //! is a reference type; remove_reference::type shall satisfy the CopyAssignable requirements and + //! assignment of the deleter from an lvalue of type D shall not throw an exception. + //! + //! Effects: Transfers ownership from u to *this as if by calling reset(u.release()) followed + //! by get_deleter() = std::forward(u.get_deleter()). + //! + //! Returns: *this. + unique_ptr& operator=(BOOST_RV_REF(unique_ptr) u) BOOST_NOEXCEPT + { + this->reset(u.release()); + m_data.deleter() = ::boost::move_if_not_lvalue_reference(u.get_deleter()); + return *this; + } + + //! Requires: If E is not a reference type, assignment of the deleter from an rvalue of type E shall be + //! well-formed and shall not throw an exception. Otherwise, E is a reference type and assignment of the + //! deleter from an lvalue of type E shall be well-formed and shall not throw an exception. + //! + //! Remarks: This operator shall not participate in overload resolution unless: + //! - unique_ptr::pointer is implicitly convertible to pointer and + //! - U is not an array type. + //! + //! Effects: Transfers ownership from u to *this as if by calling reset(u.release()) followed by + //! get_deleter() = std::forward(u.get_deleter()). + //! + //! Returns: *this. + template + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + unique_ptr& + #else + typename ::boost::move_detail::enable_unique_moveconvert_assignable::type + #endif + operator=(BOOST_RV_REF_BEG unique_ptr BOOST_RV_REF_END u) BOOST_NOEXCEPT + { + this->reset(u.release()); + m_data.deleter() = ::boost::move_if_not_lvalue_reference(u.get_deleter()); + return *this; + } + + #if !defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + //! Effects: reset(). + //! + //! Postcondition: get() == nullptr + //! + //! Returns: *this. + unique_ptr& operator=(std::nullptr_t) BOOST_NOEXCEPT + { + this->reset(); + return *this; + } + #else + //! Effects: reset(). + //! + //! Postcondition: get() == nullptr + //! + //! + //! Note: Non-standard extension to use 0 as nullptr + unique_ptr& operator=(int nat::*) BOOST_NOEXCEPT + { + this->reset(); + return *this; + } + #endif + + + //! Requires: get() != nullptr. + //! + //! Returns: *get(). + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + add_lvalue_reference_t + #else + typename ::boost::move_detail::add_lvalue_reference::type + #endif + operator*() const + { return *get(); } + + //! Requires: get() != nullptr. + //! + //! Returns: get(). + //! + //! Note: use typically requires that T be a complete type. + pointer operator->() const BOOST_NOEXCEPT + { return get(); } + + //! Returns: The stored pointer. + //! + pointer get() const BOOST_NOEXCEPT + { return m_data.m_p; } + + //! Returns: A reference to the stored deleter. + //! + deleter_lvalue_reference get_deleter() BOOST_NOEXCEPT + { return m_data.deleter(); } + + //! Returns: A reference to the stored deleter. + //! + deleter_const_lvalue_reference get_deleter() const BOOST_NOEXCEPT + { return m_data.deleter(); } + + #ifdef BOOST_MOVE_DOXYGEN_INVOKED + //! Returns: Returns: get() != nullptr. + //! + explicit operator bool() const BOOST_NOEXCEPT; + #else + operator int nat::*() const BOOST_NOEXCEPT + { return m_data.m_p ? &nat::for_bool : (int nat::*)0; } + #endif + + //! Postcondition: get() == nullptr. + //! + //! Returns: The value get() had at the start of the call to release. + pointer release() BOOST_NOEXCEPT + { + const pointer tmp = m_data.m_p; + m_data.m_p = pointer(); + return tmp; + } + + //! Requires: The expression get_deleter()(get()) shall be well formed, shall have well-defined behavior, + //! and shall not throw exceptions. + //! + //! Effects: assigns p to the stored pointer, and then if the old value of the stored pointer, old_p, was not + //! equal to nullptr, calls get_deleter()(old_p). Note: The order of these operations is significant + //! because the call to get_deleter() may destroy *this. + //! + //! Postconditions: get() == p. Note: The postcondition does not hold if the call to get_deleter() + //! destroys *this since this->get() is no longer a valid expression. + void reset(pointer p = pointer()) BOOST_NOEXCEPT + { + pointer tmp = m_data.m_p; + m_data.m_p = p; + unique_ptr_call_deleter(m_data.deleter(), tmp, is_default_deleter_t()); + } + + //! Requires: get_deleter() shall be swappable and shall not throw an exception under swap. + //! + //! 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()); + } + + #if !defined(BOOST_MOVE_DOXYGEN_INVOKED) + data_type m_data; + #endif +}; + +//!A specialization for array types (array_of_T = T[]) is provided with a slightly altered interface. +//! - Conversions between different types of unique_ptr or to or from the non-array forms of +//! unique_ptr produce an ill-formed program. +//! - Pointers to types derived from T are rejected by the constructors, and by reset. +//! - The observers operator* and operator-> are not provided. +//! - The indexing observer operator[] is provided. +//! - The default deleter will call delete[]. +//! +//! Descriptions are provided below only for member functions that have behavior different from the primary template. +//! +//! \tparam array_of_T is an alias for types of form T[]. The template argument T shall be a complete type. +template +class unique_ptr +#if defined(BOOST_MOVE_DOXYGEN_INVOKED) +< array_of_T +#else +< T[] +#endif +, D> +{ + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + public: + unique_ptr(const unique_ptr&) = delete; + unique_ptr& operator=(const unique_ptr&) = delete; + private: + #else + BOOST_MOVABLE_BUT_NOT_COPYABLE(unique_ptr) + typedef ::boost::move_detail::pointer_type pointer_type_obtainer; + typedef ::boost::move_detail::unique_ptr_data + data_type; + typedef typename data_type::deleter_arg_type1 deleter_arg_type1; + typedef typename data_type::deleter_arg_type2 deleter_arg_type2; + typedef typename data_type::deleter_lvalue_reference deleter_lvalue_reference; + typedef typename data_type::deleter_const_lvalue_reference deleter_const_lvalue_reference; + struct nat {int for_bool;}; + typedef ::boost::move_detail::integral_constant >::value > is_default_deleter_t; + #endif + + public: + typedef typename BOOST_MOVE_SEEDOC(pointer_type_obtainer::type) pointer; + typedef T element_type; + typedef D deleter_type; + + BOOST_CONSTEXPR unique_ptr() BOOST_NOEXCEPT + : m_data() + { + //If this constructor is instantiated with a pointer type or reference type + //for the template argument D, the program is ill-formed. + BOOST_STATIC_ASSERT(!::boost::move_detail::is_pointer::value); + BOOST_STATIC_ASSERT(!::boost::move_detail::is_reference::value); + } + + //! This constructor behave the same as in the primary template except that it does + //! not accept pointer types which are convertible to pointer. + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + unique_ptr(pointer p); + #else + template + explicit unique_ptr(P p + ,typename ::boost::move_detail::enable_same_cvelement_and_convertible::type* = 0 + ) BOOST_NOEXCEPT + : m_data(p) + { + BOOST_STATIC_ASSERT(!::boost::move_detail::is_pointer::value); + BOOST_STATIC_ASSERT(!::boost::move_detail::is_reference::value); + } + #endif + + //! This constructor behave the same as in the primary template except that it does + //! not accept pointer types which are convertible to pointer. + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + unique_ptr(pointer p, BOOST_MOVE_SEEDOC(deleter_arg_type1) d1); + #else + template + unique_ptr(P p, BOOST_MOVE_SEEDOC(deleter_arg_type1) d1 + ,typename ::boost::move_detail::enable_same_cvelement_and_convertible::type* = 0 + ) BOOST_NOEXCEPT + : m_data(p, d1) + {} + #endif + + //! This assignement behave the same as in the primary template except that it does + //! only accept pointer types which are equal or less cv qualified than pointer + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + unique_ptr(pointer p, BOOST_MOVE_SEEDOC(deleter_arg_type2) d2); + #else + template + unique_ptr(P p, BOOST_MOVE_SEEDOC(deleter_arg_type2) d2 + ,typename ::boost::move_detail::enable_same_cvelement_and_convertible::type* = 0 + ) BOOST_NOEXCEPT + : m_data(p, ::boost::move(d2)) + {} + #endif + + unique_ptr(BOOST_RV_REF(unique_ptr) u) BOOST_NOEXCEPT + : m_data(u.release(), ::boost::move_if_not_lvalue_reference(u.get_deleter())) + {} + + //! This assignement behave the same as in the primary template except that it does + //! only accept pointer types which are equal or less cv qualified than pointer. + //! + //! Note: Non-standard extension + template + unique_ptr( BOOST_RV_REF_BEG unique_ptr BOOST_RV_REF_END u + #if !defined(BOOST_MOVE_DOXYGEN_INVOKED) + , typename ::boost::move_detail::enable_uniquearray_moveconvert_constructible::type * = 0 + #endif + ) BOOST_NOEXCEPT + : m_data(u.release(), ::boost::move_if_not_lvalue_reference(u.get_deleter())) + {} + + #if !defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + BOOST_CONSTEXPR unique_ptr(std::nullptr_t) BOOST_NOEXCEPT + : m_data() + { + //If this constructor is instantiated with a pointer type or reference type + //for the template argument D, the program is ill-formed. + BOOST_STATIC_ASSERT(!::boost::move_detail::is_pointer::value); + BOOST_STATIC_ASSERT(!::boost::move_detail::is_reference::value); + } + #endif + + ~unique_ptr() + { + unique_ptr_call_deleter(m_data.deleter(), m_data.m_p, is_default_deleter_t()); + } + + unique_ptr& operator=(BOOST_RV_REF(unique_ptr) u) BOOST_NOEXCEPT + { + this->reset(u.release()); + m_data.deleter() = ::boost::move_if_not_lvalue_reference(u.get_deleter()); + return *this; + } + + //! This assignement behave the same as in the primary template except that it does + //! only accept pointer types which are equal or less cv qualified than pointer + //! + //! Note: Non-standard extension + template + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + unique_ptr& + #else + typename ::boost::move_detail::enable_uniquearray_moveconvert_assignable::type + #endif + operator=(BOOST_RV_REF_BEG unique_ptr BOOST_RV_REF_END u) BOOST_NOEXCEPT + { + this->reset(u.release()); + m_data.deleter() = ::boost::move_if_not_lvalue_reference(u.get_deleter()); + return *this; + } + + #if !defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + unique_ptr& operator=(std::nullptr_t) BOOST_NOEXCEPT + { + this->reset(); + return *this; + } + #else + unique_ptr& operator=(int nat::*) BOOST_NOEXCEPT + { + this->reset(); + return *this; + } + #endif + + //! Requires: i < the number of elements in the array to which the stored pointer points. + //! Returns: get()[i]. + T& operator[](size_t i) const + { + const pointer p = this->get(); + BOOST_ASSERT(p); + return p[i]; + } + + pointer get() const BOOST_NOEXCEPT + { return m_data.m_p; } + + deleter_lvalue_reference get_deleter() BOOST_NOEXCEPT + { return m_data.deleter(); } + + deleter_const_lvalue_reference get_deleter() const BOOST_NOEXCEPT + { return m_data.deleter(); } + + #ifdef BOOST_MOVE_DOXYGEN_INVOKED + explicit operator bool() const BOOST_NOEXCEPT; + #else + operator int nat::*() const BOOST_NOEXCEPT + { return m_data.m_p ? &nat::for_bool : (int nat::*)0; } + #endif + + pointer release() BOOST_NOEXCEPT + { + const pointer tmp = m_data.m_p; + m_data.m_p = pointer(); + return tmp; + } + + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + void reset(pointer p = pointer()); + #else + template + void reset(P p + ,typename ::boost::move_detail::enable_same_cvelement_and_convertible::type* = 0 + ) BOOST_NOEXCEPT + { + pointer tmp = m_data.m_p; + m_data.m_p = p; + unique_ptr_call_deleter(m_data.deleter(), tmp, is_default_deleter_t()); + } + + void reset() BOOST_NOEXCEPT + { + pointer tmp = m_data.m_p; + m_data.m_p = pointer(); + unique_ptr_call_deleter(m_data.deleter(), tmp, is_default_deleter_t()); + } + #endif + + #if !defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + void reset(std::nullptr_t) BOOST_NOEXCEPT + { this->reset(); } + #endif + + 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()); + } + + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + template void reset(U) = delete; + #else + data_type m_data; + #endif +}; + +//! Effects: Calls x.swap(y). +//! +template +inline void swap(unique_ptr &x, unique_ptr &y) BOOST_NOEXCEPT +{ x.swap(y); } + +//! Returns: x.get() == y.get(). +//! +template +inline bool operator==(const unique_ptr &x, const unique_ptr &y) +{ return x.get() == y.get(); } + +//! Returns: x.get() != y.get(). +//! +template +inline bool operator!=(const unique_ptr &x, const unique_ptr &y) +{ return x.get() != y.get(); } + +#if 0 +//! Requires: Let CT be common_type::pointer, unique_ptr::pointer>:: +//! type. Then the specialization less shall be a function object type that induces a +//! strict weak ordering on the pointer values. +//! +//! Returns: less()(x.get(), y.get()). +//! +//! Remarks: If unique_ptr::pointer is not implicitly convertible to CT or +//! unique_ptr::pointer is not implicitly convertible to CT, the program is ill-formed. +#else +//! Returns: x.get() < y.get(). +//! +//! Remarks: This comparison shall induces a +//! strict weak ordering on the pointer values. +#endif +template +inline bool operator<(const unique_ptr &x, const unique_ptr &y) +{ + #if 0 + typedef typename common_type + < typename unique_ptr::pointer + , typename unique_ptr::pointer>::type CT; + return std::less()(x.get(), y.get());*/ + #endif + return x.get() < y.get(); +} + +//! Returns: !(y < x). +//! +template +inline bool operator<=(const unique_ptr &x, const unique_ptr &y) +{ return !(y < x); } + +//! Returns: y < x. +//! +template +inline bool operator>(const unique_ptr &x, const unique_ptr &y) +{ return y < x; } + +//! Returns:!(x < y). +//! +template +inline bool operator>=(const unique_ptr &x, const unique_ptr &y) +{ return !(x < y); } + +#if !defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + +//! Returns:!x. +//! +template +inline bool operator==(const unique_ptr &x, std::nullptr_t) BOOST_NOEXCEPT +{ return !x; } + +//! Returns:!x. +//! +template +inline bool operator==(std::nullptr_t, const unique_ptr &x) BOOST_NOEXCEPT +{ return !x; } + +//! Returns: (bool)x. +//! +template +inline bool operator!=(const unique_ptr &x, std::nullptr_t) BOOST_NOEXCEPT +{ return !!x; } + +//! Returns: (bool)x. +//! +template +inline bool operator!=(std::nullptr_t, const unique_ptr &x) BOOST_NOEXCEPT +{ return !!x; } + +//! Requires: The specialization less::pointer> shall be a function object type +//! that induces a strict weak ordering on the pointer values. +//! +//! Returns: less::pointer>()(x.get(), nullptr). +template +inline bool operator<(const unique_ptr &x, std::nullptr_t) +{ + typedef typename unique_ptr::pointer pointer; + return x.get() < pointer(); +} + +//! Requires: The specialization less::pointer> shall be a function object type +//! that induces a strict weak ordering on the pointer values. +//! +//! Returns: The second function template returns less::pointer>()(nullptr, x.get()). +template +inline bool operator<(std::nullptr_t, const unique_ptr &x) +{ + typedef typename unique_ptr::pointer pointer; + return pointer() < x.get(); +} + +//! Returns: nullptr < x. +//! +template +inline bool operator>(const unique_ptr &x, std::nullptr_t) +{ + typedef typename unique_ptr::pointer pointer; + return x.get() > pointer(); +} + +//! Returns: x < nullptr. +//! +template +inline bool operator>(std::nullptr_t, const unique_ptr &x) +{ + typedef typename unique_ptr::pointer pointer; + return pointer() > x.get(); +} + +//! Returns: !(nullptr < x). +//! +template +inline bool operator<=(const unique_ptr &x, std::nullptr_t) +{ return !(nullptr < x); } + +//! Returns: !(x < nullptr). +//! +template +inline bool operator<=(std::nullptr_t, const unique_ptr &x) +{ return !(x < nullptr); } + +//! Returns: !(x < nullptr). +//! +template +inline bool operator>=(const unique_ptr &x, std::nullptr_t) +{ return !(x < nullptr); } + +//! Returns: !(nullptr < x). +//! +template +inline bool operator>=(std::nullptr_t, const unique_ptr &x) +{ return !(nullptr < x); } + +#endif // #if !defined(BOOST_NO_CXX11_NULLPTR) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + +} //namespace movelib { +} //namespace boost{ + +#include + +#endif //#ifndef BOOST_MOVE_UNIQUE_PTR_HPP_INCLUDED diff --git a/include/boost/move/utility_core.hpp b/include/boost/move/utility_core.hpp index 236f9a9..1786b1e 100644 --- a/include/boost/move/utility_core.hpp +++ b/include/boost/move/utility_core.hpp @@ -84,6 +84,48 @@ return x; } + ////////////////////////////////////////////////////////////////////////////// + // + // move_if_not_lvalue_reference() + // + ////////////////////////////////////////////////////////////////////////////// + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && + ::boost::move_detail::is_rv::value + , T &>::type + move_if_not_lvalue_reference(const typename ::boost::move_detail::identity::type &x) BOOST_NOEXCEPT + { + return const_cast(x); + } + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && + !::boost::move_detail::is_rv::value && + (::boost::move_detail::is_lvalue_reference::value || + !has_move_emulation_enabled::value) + , typename ::boost::move_detail::add_lvalue_reference::type + >::type + move_if_not_lvalue_reference(typename ::boost::move_detail::remove_reference::type &x) BOOST_NOEXCEPT + { + return x; + } + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && + !::boost::move_detail::is_rv::value && + (!::boost::move_detail::is_lvalue_reference::value && + has_move_emulation_enabled::value) + , rv& + >::type + move_if_not_lvalue_reference(typename ::boost::move_detail::remove_reference::type &x) BOOST_NOEXCEPT + { + return move(x); + } + } //namespace boost #else //#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) @@ -186,12 +228,64 @@ #endif //BOOST_MOVE_DOXYGEN_INVOKED + ////////////////////////////////////////////////////////////////////////////// + // + // move_if_not_lvalue_reference + // + ////////////////////////////////////////////////////////////////////////////// + + + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + template output_reference move_if_not_lvalue_reference(input_reference) noexcept; + #elif defined(BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES) + + //Old move approach, lvalues could bind to rvalue references + + template + inline T&& move_if_not_lvalue_reference(typename ::boost::move_detail::identity::type&& t) BOOST_NOEXCEPT + { return t; } + + #else //Old move + + template + inline T&& move_if_not_lvalue_reference(typename ::boost::move_detail::remove_reference::type& t) BOOST_NOEXCEPT + { return static_cast(t); } + + template + inline T&& move_if_not_lvalue_reference(typename ::boost::move_detail::remove_reference::type&& t) BOOST_NOEXCEPT + { + //"boost::forward error: 'T' is a lvalue reference, can't forward as rvalue."; + BOOST_STATIC_ASSERT(!boost::move_detail::is_lvalue_reference::value); + return static_cast(t); + } + + #endif //BOOST_MOVE_DOXYGEN_INVOKED + } //namespace boost { #endif //#if defined(BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE) #endif //BOOST_NO_CXX11_RVALUE_REFERENCES +#if !defined(BOOST_MOVE_DOXYGEN_INVOKED) + +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); +} + +} //namespace move_detail{ +} //namespace boost{ + +#endif //#if !defined(BOOST_MOVE_DOXYGEN_INVOKED) + + #include #endif //#ifndef BOOST_MOVE_MOVE_UTILITY_CORE_HPP diff --git a/proj/vc7ide/Move.sln b/proj/vc7ide/Move.sln index cdb3f54..0ab9b29 100644 --- a/proj/vc7ide/Move.sln +++ b/proj/vc7ide/Move.sln @@ -67,6 +67,18 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "move_if_noexcept_test", "mo ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unique_ptr_default_deleter_test", "unique_ptr_default_deleter.vcproj", "{C57C25A3-4620-FE08-F8B7-AB673D762B60}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unique_ptr_test", "unique_ptr_test.vcproj", "{C57C28A3-4FE0-6208-BF87-A2B61D3A7671}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unique_ptr_functions_test", "unique_ptr_functions.vcproj", "{C57C25A3-4620-FE08-F8B7-AB673D762B60}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -143,6 +155,18 @@ Global {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 + {C57C25A3-4620-FE08-F8B7-AB673D762B60}.Debug.ActiveCfg = Debug|Win32 + {C57C25A3-4620-FE08-F8B7-AB673D762B60}.Debug.Build.0 = Debug|Win32 + {C57C25A3-4620-FE08-F8B7-AB673D762B60}.Release.ActiveCfg = Release|Win32 + {C57C25A3-4620-FE08-F8B7-AB673D762B60}.Release.Build.0 = Release|Win32 + {C57C28A3-4FE0-6208-BF87-A2B61D3A7671}.Debug.ActiveCfg = Debug|Win32 + {C57C28A3-4FE0-6208-BF87-A2B61D3A7671}.Debug.Build.0 = Debug|Win32 + {C57C28A3-4FE0-6208-BF87-A2B61D3A7671}.Release.ActiveCfg = Release|Win32 + {C57C28A3-4FE0-6208-BF87-A2B61D3A7671}.Release.Build.0 = Release|Win32 + {C57C25A3-4620-FE08-F8B7-AB673D762B60}.Debug.ActiveCfg = Debug|Win32 + {C57C25A3-4620-FE08-F8B7-AB673D762B60}.Debug.Build.0 = Debug|Win32 + {C57C25A3-4620-FE08-F8B7-AB673D762B60}.Release.ActiveCfg = Release|Win32 + {C57C25A3-4620-FE08-F8B7-AB673D762B60}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionItems) = postSolution ..\..\..\..\boost\move\algorithm.hpp = ..\..\..\..\boost\move\algorithm.hpp @@ -151,11 +175,13 @@ Global ..\..\..\..\boost\move\core.hpp = ..\..\..\..\boost\move\core.hpp ..\..\..\..\boost\move\iterator.hpp = ..\..\..\..\boost\move\iterator.hpp ..\..\doc\Jamfile.v2 = ..\..\doc\Jamfile.v2 + ..\..\..\..\boost\move\make_unique.hpp = ..\..\..\..\boost\move\make_unique.hpp ..\..\..\..\boost\move\detail\meta_utils.hpp = ..\..\..\..\boost\move\detail\meta_utils.hpp ..\..\..\..\boost\move\move.hpp = ..\..\..\..\boost\move\move.hpp ..\..\doc\move.qbk = ..\..\doc\move.qbk ..\..\..\..\boost\move\detail\move_helpers.hpp = ..\..\..\..\boost\move\detail\move_helpers.hpp ..\..\..\..\boost\move\traits.hpp = ..\..\..\..\boost\move\traits.hpp + ..\..\..\..\boost\move\unique_ptr.hpp = ..\..\..\..\boost\move\unique_ptr.hpp ..\..\..\..\boost\move\utility.hpp = ..\..\..\..\boost\move\utility.hpp ..\..\..\..\boost\move\utility_core.hpp = ..\..\..\..\boost\move\utility_core.hpp EndGlobalSection diff --git a/proj/vc7ide/unique_ptr_default_deleter.vcproj b/proj/vc7ide/unique_ptr_default_deleter.vcproj new file mode 100644 index 0000000..23ac752 --- /dev/null +++ b/proj/vc7ide/unique_ptr_default_deleter.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/unique_ptr_functions.vcproj b/proj/vc7ide/unique_ptr_functions.vcproj new file mode 100644 index 0000000..4917faa --- /dev/null +++ b/proj/vc7ide/unique_ptr_functions.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj/vc7ide/unique_ptr_test.vcproj b/proj/vc7ide/unique_ptr_test.vcproj new file mode 100644 index 0000000..31aca33 --- /dev/null +++ b/proj/vc7ide/unique_ptr_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/unique_ptr.cpp b/test/unique_ptr.cpp new file mode 100644 index 0000000..c3b4811 --- /dev/null +++ b/test/unique_ptr.cpp @@ -0,0 +1,1907 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Howard Hinnant 2009 +// (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 +#include + +////////////////////////////////////////////// +// +// The initial implementation of these tests +// was written by Howard Hinnant. +// +// These test were later refactored grouping +// and porting them to Boost.Move. +// +// Many thanks to Howard for releasing his C++03 +// unique_ptr implementation with such detailed +// test cases. +// +////////////////////////////////////////////// + +namespace bml = ::boost::movelib; + +//A deleter that can only default constructed +template +class def_constr_deleter +{ + int state_; + def_constr_deleter(const def_constr_deleter&); + def_constr_deleter& operator=(const def_constr_deleter&); + + public: + typedef typename ::boost::move_detail::remove_extent::type element_type; + static const bool is_array = ::boost::move_detail::is_array::value; + + def_constr_deleter() : state_(5) {} + + explicit def_constr_deleter(int s) : state_(s) {} + + int state() const {return state_;} + + void set_state(int s) {state_ = s;} + + void operator()(element_type* p) const + { is_array ? delete []p : delete p; } + + void operator()(element_type* p) + { ++state_; is_array ? delete []p : delete p; } +}; + +template +struct enable_if_conversion_acceptable + : ::boost::move_detail::enable_if_c + < OtherIsArray && ::boost::move_detail::is_same_cvelement_and_convertible::value + , Type + > +{}; + +template +struct enable_if_conversion_acceptable + : ::boost::move_detail::enable_if_c + < !OtherIsArray && ::boost::move_detail::is_convertible::value + , Type + > +{}; + +//A deleter that can be copy constructed +template +class copy_constr_deleter +{ + int state_; + + public: + typedef typename ::boost::move_detail::remove_extent::type element_type; + static const bool is_array = ::boost::move_detail::is_array::value; + + copy_constr_deleter() : state_(5) {} + + template + copy_constr_deleter(const copy_constr_deleter& + , typename enable_if_conversion_acceptable + < copy_constr_deleter::is_array + , is_array + , typename copy_constr_deleter::element_type + , element_type + >::type* = 0) + { state_ = 5; } + + explicit copy_constr_deleter(int s) : state_(s) {} + + template + typename enable_if_conversion_acceptable + < copy_constr_deleter::is_array + , is_array + , typename copy_constr_deleter::element_type + , element_type + , copy_constr_deleter& + >::type + operator=(const copy_constr_deleter &d) + { + state_ = d.state(); + return *this; + } + + int state() const {return state_;} + + void set_state(int s) {state_ = s;} + + void operator()(element_type* p) const + { is_array ? delete []p : delete p; } + + void operator()(element_type* p) + { ++state_; is_array ? delete []p : delete p; } +}; + +//A deleter that can be only move constructed +template +class move_constr_deleter +{ + int state_; + + BOOST_MOVABLE_BUT_NOT_COPYABLE(move_constr_deleter) + + public: + typedef typename ::boost::move_detail::remove_extent::type element_type; + static const bool is_array = ::boost::move_detail::is_array::value; + + move_constr_deleter() : state_(5) {} + + move_constr_deleter(BOOST_RV_REF(move_constr_deleter) r) + : state_(r.state_) + { r.state_ = 0; } + + explicit move_constr_deleter(int s) : state_(s) {} + + template + move_constr_deleter(BOOST_RV_REF(move_constr_deleter) d + , typename enable_if_conversion_acceptable + < move_constr_deleter::is_array + , is_array + , typename move_constr_deleter::element_type + , element_type + >::type* = 0) + : state_(d.state()) + { d.set_state(0); } + + move_constr_deleter& operator=(BOOST_RV_REF(move_constr_deleter) r) + { + state_ = r.state_; + r.state_ = 0; + return *this; + } + + template + typename enable_if_conversion_acceptable + < move_constr_deleter::is_array + , is_array + , typename move_constr_deleter::element_type + , element_type + , move_constr_deleter& + >::type + operator=(BOOST_RV_REF(move_constr_deleter) d) + { + state_ = d.state(); + d.set_state(0); + return *this; + } + + int state() const {return state_;} + + void set_state(int s) {state_ = s;} + + void operator()(element_type* p) const + { is_array ? delete []p : delete p; } + + void operator()(element_type* p) + { ++state_; is_array ? delete []p : delete p; } + + friend bool operator==(const move_constr_deleter& x, const move_constr_deleter& y) + {return x.state_ == y.state_;} +}; + +//A base class containing state with a static instance counter +struct A +{ + int state_; + static int count; + + A() : state_(999) {++count;} + explicit A(int i) : state_(i) {++count;} + A(const A& a) : state_(a.state_) {++count;} + A& operator=(const A& a) { state_ = a.state_; return *this; } + void set(int i) {state_ = i;} + virtual ~A() {--count;} + friend bool operator==(const A& x, const A& y) { return x.state_ == y.state_; } +}; + +int A::count = 0; + +//A class derived from A with a static instance counter +struct B + : public A +{ + static int count; + B() {++count;} + B(const B&) {++count;} + virtual ~B() {--count;} +}; + +int B::count = 0; + +void reset_counters(); + +BOOST_STATIC_ASSERT((::boost::move_detail::is_convertible::value)); + +//Incomplete Type +struct I; +void check(int i); +I* get(); +I* get_array(int i); + +template > +struct J +{ + typedef bml::unique_ptr unique_ptr_type; + typedef typename unique_ptr_type::element_type element_type; + bml::unique_ptr a_; + J() {} + explicit J(element_type*a) : a_(a) {} + ~J(); + + element_type* get() const {return a_.get();} + D& get_deleter() {return a_.get_deleter();} +}; + +//////////////////////////////// +// pointer_type +//////////////////////////////// +namespace pointer_type { + +struct Deleter +{ + struct pointer {}; +}; + +// Test unique_ptr::pointer type +void test() +{ + //Single unique_ptr + { + typedef bml::unique_ptr P; + BOOST_STATIC_ASSERT((boost::move_detail::is_same::value)); + } + { + typedef bml::unique_ptr P; + BOOST_STATIC_ASSERT((boost::move_detail::is_same::value)); + } + //Array unique_ptr + { + typedef bml::unique_ptr P; + BOOST_STATIC_ASSERT((boost::move_detail::is_same::value)); + } + { + typedef bml::unique_ptr P; + BOOST_STATIC_ASSERT((boost::move_detail::is_same::value)); + } +} + +} //namespace pointer_type { + +//////////////////////////////// +// unique_ptr_asgn_move_convert01 +//////////////////////////////// +namespace unique_ptr_asgn_move_convert01 { + +void test() +{ + //Single unique_ptr + reset_counters(); + { + bml::unique_ptr s(new B); + A* p = s.get(); + bml::unique_ptr s2(new A); + BOOST_TEST(A::count == 2); + s2 = boost::move(s); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + + reset_counters(); + //Array unique_ptr, only from the same CV qualified pointers + { + bml::unique_ptr s(new A[2]); + A* p = s.get(); + bml::unique_ptr s2(new const A[2]); + BOOST_TEST(A::count == 4); + s2 = boost::move(s); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 2); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_asgn_move_convert01{ + + +//////////////////////////////// +// unique_ptr_asgn_move_convert02 +//////////////////////////////// + +namespace unique_ptr_asgn_move_convert02{ + +void test() +{ + //Single unique_ptr + reset_counters(); + { + bml::unique_ptr > s(new B); + A* p = s.get(); + bml::unique_ptr > s2(new A); + BOOST_TEST(A::count == 2); + s2 = (boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + BOOST_TEST(s2.get_deleter().state() == 5); + BOOST_TEST(s.get_deleter().state() == 0); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + + //Array unique_ptr, only from the same CV qualified pointers + reset_counters(); + { + bml::unique_ptr > s(new A[2]); + A* p = s.get(); + bml::unique_ptr > s2(new const A[2]); + BOOST_TEST(A::count == 4); + s2 = (boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 2); + BOOST_TEST(s2.get_deleter().state() == 5); + BOOST_TEST(s.get_deleter().state() == 0); + } + BOOST_TEST(A::count == 0); +} + + + +} //namespace unique_ptr_asgn_move_convert02{ + +//////////////////////////////// +// unique_ptr_asgn_move_convert03 +//////////////////////////////// + +namespace unique_ptr_asgn_move_convert03{ + +// test converting move assignment with reference deleters + +void test() +{ + //Single unique_ptr + reset_counters(); + { + copy_constr_deleter db(5); + bml::unique_ptr&> s(new B, db); + A* p = s.get(); + copy_constr_deleter da(6); + bml::unique_ptr&> s2(new A, da); + s2 = boost::move(s); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + BOOST_TEST(s2.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + + //Array unique_ptr, only from the same CV qualified pointers + reset_counters(); + { + copy_constr_deleter db(5); + bml::unique_ptr&> s(new A[2], db); + A* p = s.get(); + copy_constr_deleter da(6); + bml::unique_ptr&> s2(new const A[2], da); + BOOST_TEST(A::count == 4); + s2 = boost::move(s); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 2); + BOOST_TEST(s2.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); +} + +} //namespace unique_ptr_asgn_move_convert03{ + +//////////////////////////////// +// unique_ptr_asgn_move01 +//////////////////////////////// +namespace unique_ptr_asgn_move01 { + +void test() +{ + //Single unique_ptr + reset_counters(); + { + bml::unique_ptr s1(new A); + A* p = s1.get(); + bml::unique_ptr s2(new A); + BOOST_TEST(A::count == 2); + s2 = boost::move(s1); + BOOST_TEST(A::count == 1); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s1.get() == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr > s1(new A); + A* p = s1.get(); + bml::unique_ptr > s2(new A); + BOOST_TEST(A::count == 2); + s2 = boost::move(s1); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s1.get() == 0); + BOOST_TEST(A::count == 1); + BOOST_TEST(s2.get_deleter().state() == 5); + BOOST_TEST(s1.get_deleter().state() == 0); + } + BOOST_TEST(A::count == 0); + { + copy_constr_deleter d1(5); + bml::unique_ptr&> s1(new A, d1); + A* p = s1.get(); + copy_constr_deleter d2(6); + bml::unique_ptr&> s2(new A, d2); + s2 = boost::move(s1); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s1.get() == 0); + BOOST_TEST(A::count == 1); + BOOST_TEST(d1.state() == 5); + BOOST_TEST(d2.state() == 5); + } + BOOST_TEST(A::count == 0); + + //Array unique_ptr + reset_counters(); + { + bml::unique_ptr s1(new A[2]); + A* p = s1.get(); + bml::unique_ptr s2(new A[2]); + BOOST_TEST(A::count == 4); + s2 = boost::move(s1); + BOOST_TEST(A::count == 2); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s1.get() == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr > s1(new A[2]); + A* p = s1.get(); + bml::unique_ptr > s2(new A[2]); + BOOST_TEST(A::count == 4); + s2 = boost::move(s1); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s1.get() == 0); + BOOST_TEST(A::count == 2); + BOOST_TEST(s2.get_deleter().state() == 5); + BOOST_TEST(s1.get_deleter().state() == 0); + } + BOOST_TEST(A::count == 0); + { + copy_constr_deleter d1(5); + bml::unique_ptr&> s1(new A[2], d1); + A* p = s1.get(); + copy_constr_deleter d2(6); + bml::unique_ptr&> s2(new A[2], d2); + BOOST_TEST(A::count == 4); + s2 = boost::move(s1); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s1.get() == 0); + BOOST_TEST(A::count == 2); + BOOST_TEST(d1.state() == 5); + BOOST_TEST(d2.state() == 5); + } + BOOST_TEST(A::count == 0); +} + +} //unique_ptr_asgn_move01 + +//////////////////////////////// +// unique_ptr_asgn_null +//////////////////////////////// +namespace unique_ptr_asgn_null { + +// test assignment from null + +void test() +{ + //Single unique_ptr + reset_counters(); + { + bml::unique_ptr s2(new A); + BOOST_TEST(A::count == 1); + s2 = 0; + BOOST_TEST(A::count == 0); + BOOST_TEST(s2.get() == 0); + } + BOOST_TEST(A::count == 0); + + //Array unique_ptr + { + bml::unique_ptr s2(new A[2]); + BOOST_TEST(A::count == 2); + s2 = 0; + BOOST_TEST(A::count == 0); + BOOST_TEST(s2.get() == 0); + } + BOOST_TEST(A::count == 0); +} + + +} //namespace unique_ptr_asgn_null { + + +//////////////////////////////// +// unique_ptr_ctor_default01 +//////////////////////////////// + +namespace unique_ptr_ctor_default01{ + +// default unique_ptr ctor should only require default deleter ctor + +void test() +{ + //Single unique_ptr + { + bml::unique_ptr p; + BOOST_TEST(p.get() == 0); + } + { + bml::unique_ptr > p; + BOOST_TEST(p.get() == 0); + BOOST_TEST(p.get_deleter().state() == 5); + } + //Array unique_ptr + { + bml::unique_ptr p; + BOOST_TEST(p.get() == 0); + } + { + bml::unique_ptr > p; + BOOST_TEST(p.get() == 0); + BOOST_TEST(p.get_deleter().state() == 5); + } +} + +} //namespace unique_ptr_ctor_default01{ + +//////////////////////////////// +// unique_ptr_ctor_default02 +//////////////////////////////// + +namespace unique_ptr_ctor_default02{ + +// default unique_ptr ctor shouldn't require complete type + +void test() +{ + //Single unique_ptr + reset_counters(); + { + J s; + BOOST_TEST(s.get() == 0); + } + check(0); + { + J > s; + BOOST_TEST(s.get() == 0); + BOOST_TEST(s.get_deleter().state() == 5); + } + check(0); + //Array unique_ptr + reset_counters(); + { + J s; + BOOST_TEST(s.get() == 0); + } + check(0); + { + J > s; + BOOST_TEST(s.get() == 0); + BOOST_TEST(s.get_deleter().state() == 5); + } + check(0); +} + +} //namespace unique_ptr_ctor_default02{ + +//////////////////////////////// +// unique_ptr_ctor_move_convert01 +//////////////////////////////// + +namespace unique_ptr_ctor_move_convert01{ + +// test converting move ctor. Should only require a MoveConstructible deleter, or if +// deleter is a reference, not even that. +// Explicit version + +void test() +{ + //Single unique_ptr + reset_counters(); + { + bml::unique_ptr s(new B); + A* p = s.get(); + bml::unique_ptr s2(boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + //Array unique_ptr, only from the same CV qualified pointers + reset_counters(); + { + bml::unique_ptr s(new A[2]); + A* p = s.get(); + bml::unique_ptr s2(boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 2); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_move_convert01{ + +//////////////////////////////// +// unique_ptr_ctor_move_convert02 +//////////////////////////////// + +namespace unique_ptr_ctor_move_convert02{ + +// test converting move ctor. Should only require a MoveConstructible deleter, or if +// deleter is a reference, not even that. +// Explicit version + +void test() +{ + //Single unique_ptr + reset_counters(); + BOOST_STATIC_ASSERT((boost::move_detail::is_convertible::value)); + { + bml::unique_ptr > s(new B); + A* p = s.get(); + bml::unique_ptr > s2(boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + BOOST_TEST(s2.get_deleter().state() == 5); + BOOST_TEST(s.get_deleter().state() == 0); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + //Array unique_ptr, only from the same CV qualified pointers + reset_counters(); + { + bml::unique_ptr > s(new const A[2]); + const A* p = s.get(); + bml::unique_ptr > s2(boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 2); + BOOST_TEST(s2.get_deleter().state() == 5); + BOOST_TEST(s.get_deleter().state() == 0); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); +} + + +} //namespace unique_ptr_ctor_move_convert02{ + +//////////////////////////////// +// unique_ptr_ctor_move_convert03 +//////////////////////////////// + +namespace unique_ptr_ctor_move_convert03{ + +// test converting move ctor. Should only require a MoveConstructible deleter, or if +// deleter is a reference, not even that. +// Explicit version + +void test() +{ + //Single unique_ptr + reset_counters(); + { + def_constr_deleter d; + bml::unique_ptr&> s(new B, d); + A* p = s.get(); + bml::unique_ptr&> s2(boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + d.set_state(6); + BOOST_TEST(s2.get_deleter().state() == d.state()); + BOOST_TEST(s.get_deleter().state() == d.state()); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + //Array unique_ptr, only from the same CV qualified pointers + reset_counters(); + { + def_constr_deleter d; + bml::unique_ptr&> s(new A[2], d); + A* p = s.get(); + bml::unique_ptr&> s2(boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 2); + d.set_state(6); + BOOST_TEST(s2.get_deleter().state() == d.state()); + BOOST_TEST(s.get_deleter().state() == d.state()); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_move_convert03{ + +//////////////////////////////// +// unique_ptr_ctor_move_convert04 +//////////////////////////////// + +namespace unique_ptr_ctor_move_convert04{ + +// test converting move ctor. Should only require a MoveConstructible deleter, or if +// deleter is a reference, not even that. +// implicit version + +void test() +{ + //Single unique_ptr + reset_counters(); + { + bml::unique_ptr s(new B); + A* p = s.get(); + bml::unique_ptr s2(boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + //Array unique_ptr, only from the same CV qualified pointers + reset_counters(); + { + bml::unique_ptr s(new A[2]); + A* p = s.get(); + bml::unique_ptr s2(boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 2); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_move_convert04{ + + + +//////////////////////////////// +// unique_ptr_ctor_move_convert05 +//////////////////////////////// + +namespace unique_ptr_ctor_move_convert05{ + +// test converting move ctor. Should only require a MoveConstructible deleter, or if +// deleter is a reference, not even that. +// Implicit version + +void test() +{ + //Single unique_ptr + reset_counters(); + { + bml::unique_ptr > s(new B); + A* p = s.get(); + bml::unique_ptr > s2(boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + BOOST_TEST(s2.get_deleter().state() == 5); + BOOST_TEST(s.get_deleter().state() == 0); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + //Array unique_ptr, only from the same CV qualified pointers + reset_counters(); + { + bml::unique_ptr > s(new const A[2]); + const A* p = s.get(); + bml::unique_ptr > s2(boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 2); + BOOST_TEST(s2.get_deleter().state() == 5); + BOOST_TEST(s.get_deleter().state() == 0); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_move_convert05{ + +//////////////////////////////// +// unique_ptr_ctor_move_convert06 +//////////////////////////////// + +namespace unique_ptr_ctor_move_convert06{ + +// test converting move ctor. Should only require a MoveConstructible deleter, or if +// deleter is a reference, not even that. +// Implicit version + +void test() +{ + //Single unique_ptr + reset_counters(); + { + def_constr_deleter d; + bml::unique_ptr&> s(new B, d); + A* p = s.get(); + bml::unique_ptr&> s2(boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + d.set_state(6); + BOOST_TEST(s2.get_deleter().state() == d.state()); + BOOST_TEST(s.get_deleter().state() == d.state()); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + //Array unique_ptr, only from the same CV qualified pointers + reset_counters(); + { + def_constr_deleter d; + bml::unique_ptr&> s(new volatile A[2], d); + volatile A* p = s.get(); + bml::unique_ptr&> s2(boost::move(s)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 2); + d.set_state(6); + BOOST_TEST(s2.get_deleter().state() == d.state()); + BOOST_TEST(s.get_deleter().state() == d.state()); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_move_convert06{ + +//////////////////////////////// +// unique_ptr_ctor_move01 +//////////////////////////////// + +namespace unique_ptr_ctor_move01{ + +// test converting move ctor. Should only require a MoveConstructible deleter, or if +// deleter is a reference, not even that. +// Implicit version + +void test() +{ + //Single unique_ptr + reset_counters(); + { + bml::unique_ptr s(new A); + A* p = s.get(); + bml::unique_ptr s2 = boost::move(s); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 1); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr > s(new A); + A* p = s.get(); + bml::unique_ptr > s2 = boost::move(s); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 1); + BOOST_TEST(s2.get_deleter().state() == 5); + BOOST_TEST(s.get_deleter().state() == 0); + } + BOOST_TEST(A::count == 0); + { + def_constr_deleter d; + bml::unique_ptr&> s(new A, d); + A* p = s.get(); + bml::unique_ptr&> s2 = boost::move(s); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 1); + d.set_state(6); + BOOST_TEST(s2.get_deleter().state() == d.state()); + BOOST_TEST(s.get_deleter().state() == d.state()); + } + BOOST_TEST(A::count == 0); + //Array unique_ptr + reset_counters(); + { + bml::unique_ptr s(new A[2]); + A* p = s.get(); + bml::unique_ptr s2 = boost::move(s); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 2); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr > s(new A[2]); + A* p = s.get(); + bml::unique_ptr > s2 = boost::move(s); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 2); + BOOST_TEST(s2.get_deleter().state() == 5); + BOOST_TEST(s.get_deleter().state() == 0); + } + BOOST_TEST(A::count == 0); + { + def_constr_deleter d; + bml::unique_ptr&> s(new A[2], d); + A* p = s.get(); + bml::unique_ptr&> s2 = boost::move(s); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s.get() == 0); + BOOST_TEST(A::count == 2); + d.set_state(6); + BOOST_TEST(s2.get_deleter().state() == d.state()); + BOOST_TEST(s.get_deleter().state() == d.state()); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_move01{ + +//////////////////////////////// +// unique_ptr_ctor_move02 +//////////////////////////////// + +namespace unique_ptr_ctor_move02{ + +// test move ctor. Should only require a MoveConstructible deleter, or if +// deleter is a reference, not even that. + +bml::unique_ptr source1() +{ return bml::unique_ptr(new A); } + +bml::unique_ptr source1_array() +{ return bml::unique_ptr (new A[2]); } + +void sink1(bml::unique_ptr) +{} + +void sink1_array(bml::unique_ptr) +{} + +bml::unique_ptr > source2() +{ return bml::unique_ptr > (new A); } + +bml::unique_ptr > source2_array() +{ return bml::unique_ptr >(new A[2]); } + +void sink2(bml::unique_ptr >) +{} + +void sink2_array(bml::unique_ptr >) +{} + +bml::unique_ptr&> source3() +{ + static def_constr_deleter d; + return bml::unique_ptr&>(new A, d); +} + +bml::unique_ptr&> source3_array() +{ + static def_constr_deleter d; + return bml::unique_ptr&>(new A[2], d); +} + +void sink3(bml::unique_ptr&> ) +{} + +void sink3_array(bml::unique_ptr&> ) +{} + +void test() +{ + //Single unique_ptr + reset_counters(); + sink1(source1()); + sink2(source2()); + sink3(source3()); + BOOST_TEST(A::count == 0); + //Array unique_ptr + reset_counters(); + sink1_array(source1_array()); + sink2_array(source2_array()); + sink3_array(source3_array()); + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_move02{ + +//////////////////////////////// +// unique_ptr_ctor_pointer_deleter01 +//////////////////////////////// + +namespace unique_ptr_ctor_pointer_deleter01{ + +// test move ctor. Should only require a MoveConstructible deleter, or if +// deleter is a reference, not even that. + +// unique_ptr(pointer, deleter()) only requires MoveConstructible deleter + +void test() +{ + //Single unique_ptr + reset_counters(); + { + A* p = new A; + BOOST_TEST(A::count == 1); + move_constr_deleter d; + bml::unique_ptr > s(p, ::boost::move(d)); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); + //Array unique_ptr + reset_counters(); + { + A* p = new A[2]; + BOOST_TEST(A::count == 2); + move_constr_deleter d; + bml::unique_ptr > s(p, ::boost::move(d)); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_pointer_deleter01{ + +//////////////////////////////// +// unique_ptr_ctor_pointer_deleter02 +//////////////////////////////// + +namespace unique_ptr_ctor_pointer_deleter02{ + +// unique_ptr(pointer, d) requires CopyConstructible deleter + +void test() +{ + //Single unique_ptr + reset_counters(); + { + A* p = new A; + BOOST_TEST(A::count == 1); + copy_constr_deleter d; + bml::unique_ptr > s(p, d); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + d.set_state(6); + BOOST_TEST(s.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); + //Array unique_ptr + reset_counters(); + { + A* p = new A[2]; + BOOST_TEST(A::count == 2); + copy_constr_deleter d; + bml::unique_ptr > s(p, d); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + d.set_state(6); + BOOST_TEST(s.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_pointer_deleter02{ + +//////////////////////////////// +// unique_ptr_ctor_pointer_deleter03 +//////////////////////////////// + +namespace unique_ptr_ctor_pointer_deleter03{ + +// unique_ptr(pointer, d) does not requires CopyConstructible deleter + +void test() +{ + //Single unique_ptr + reset_counters(); + { + A* p = new A; + BOOST_TEST(A::count == 1); + def_constr_deleter d; + bml::unique_ptr&> s(p, d); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + d.set_state(6); + BOOST_TEST(s.get_deleter().state() == 6); + } + BOOST_TEST(A::count == 0); + //Array unique_ptr + reset_counters(); + { + A* p = new A[2]; + BOOST_TEST(A::count == 2); + def_constr_deleter d; + bml::unique_ptr&> s(p, d); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + d.set_state(6); + BOOST_TEST(s.get_deleter().state() == 6); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_pointer_deleter03{ + +//////////////////////////////// +// unique_ptr_ctor_pointer_deleter04 +//////////////////////////////// + +namespace unique_ptr_ctor_pointer_deleter04{ + +// unique_ptr(pointer, d) does not requires CopyConstructible deleter + +void test() +{ + //Single unique_ptr + reset_counters(); + { + A* p = new A; + BOOST_TEST(A::count == 1); + def_constr_deleter d; + bml::unique_ptr&> s(p, d); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); + //Array unique_ptr + reset_counters(); + { + A* p = new A[2]; + BOOST_TEST(A::count == 2); + def_constr_deleter d; + bml::unique_ptr&> s(p, d); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_pointer_deleter04{ + +//////////////////////////////// +// unique_ptr_ctor_pointer_deleter05 +//////////////////////////////// + +namespace unique_ptr_ctor_pointer_deleter05{ + +// unique_ptr(pointer, deleter) should work with derived pointers +// or same (cv aside) types for array unique_ptrs + +void test() +{ + //Single unique_ptr + reset_counters(); + { + B* p = new B; + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + bml::unique_ptr > s(p, copy_constr_deleter()); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + //Array unique_ptr + reset_counters(); + { + A* p = new A[2]; + BOOST_TEST(A::count == 2); + bml::unique_ptr > s(p, copy_constr_deleter()); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); +} + +} //namespace unique_ptr_ctor_pointer_deleter05{ + +//////////////////////////////// +// unique_ptr_ctor_pointer_deleter06 +//////////////////////////////// + +namespace unique_ptr_ctor_pointer_deleter06{ + +// unique_ptr(pointer, deleter) should work with function pointers +// unique_ptr should work + +bool my_free_called = false; + +void my_free(void*) +{ + my_free_called = true; +} + +void test() +{ + { + int i = 0; + bml::unique_ptr s(&i, my_free); + BOOST_TEST(s.get() == &i); + BOOST_TEST(s.get_deleter() == my_free); + BOOST_TEST(!my_free_called); + } + BOOST_TEST(my_free_called); +} + +} //namespace unique_ptr_ctor_pointer_deleter06{ + +//////////////////////////////// +// unique_ptr_ctor_pointer01 +//////////////////////////////// + +namespace unique_ptr_ctor_pointer01{ + +// unique_ptr(pointer) ctor should only require default deleter ctor + +void test() +{ + //Single unique_ptr + reset_counters(); + { + A* p = new A; + BOOST_TEST(A::count == 1); + bml::unique_ptr s(p); + BOOST_TEST(s.get() == p); + } + BOOST_TEST(A::count == 0); + { + A* p = new A; + BOOST_TEST(A::count == 1); + bml::unique_ptr > s(p); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); + //Array unique_ptr + reset_counters(); + { + A* p = new A[2]; + BOOST_TEST(A::count == 2); + bml::unique_ptr s(p); + BOOST_TEST(s.get() == p); + } + BOOST_TEST(A::count == 0); + { + A* p = new A[2]; + BOOST_TEST(A::count == 2); + bml::unique_ptr > s(p); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_pointer01{ + +//////////////////////////////// +// unique_ptr_ctor_pointer02 +//////////////////////////////// + +namespace unique_ptr_ctor_pointer02{ + +// unique_ptr(pointer) ctor shouldn't require complete type + +void test() +{ + //Single unique_ptr + reset_counters(); + { + I* p = get(); + check(1); + J s(p); + BOOST_TEST(s.get() == p); + } + check(0); + { + I* p = get(); + check(1); + J > s(p); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + } + check(0); + //Array unique_ptr + reset_counters(); + { + I* p = get_array(2); + check(2); + J s(p); + BOOST_TEST(s.get() == p); + } + check(0); + { + I* p = get_array(2); + check(2); + J > s(p); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + } + check(0); +} + +} //namespace unique_ptr_ctor_pointer02{ + +//////////////////////////////// +// unique_ptr_ctor_pointer03 +//////////////////////////////// + +namespace unique_ptr_ctor_pointer03{ + +// unique_ptr(pointer) ctor should work with derived pointers +// or same types (cv aside) for unique_ptr + +void test() +{ + //Single unique_ptr + reset_counters(); + { + B* p = new B; + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + bml::unique_ptr s(p); + BOOST_TEST(s.get() == p); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + { + B* p = new B; + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + bml::unique_ptr > s(p); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + //Array unique_ptr + reset_counters(); + { + A* p = new A[2]; + BOOST_TEST(A::count == 2); + bml::unique_ptr s(p); + BOOST_TEST(s.get() == p); + } + BOOST_TEST(A::count == 0); + { + const A* p = new const A[2]; + BOOST_TEST(A::count == 2); + bml::unique_ptr > s(p); + BOOST_TEST(s.get() == p); + BOOST_TEST(s.get_deleter().state() == 5); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_ctor_pointer03{ + +//////////////////////////////// +// unique_ptr_dtor_null +//////////////////////////////// + +namespace unique_ptr_dtor_null{ + +// The deleter is not called if get() == 0 + +void test() +{ + //Single unique_ptr + def_constr_deleter d; + BOOST_TEST(d.state() == 5); + { + bml::unique_ptr&> p(0, d); + BOOST_TEST(p.get() == 0); + BOOST_TEST(&p.get_deleter() == &d); + } + BOOST_TEST(d.state() == 5); +} + +} //namespace unique_ptr_dtor_null{ + +//////////////////////////////// +// unique_ptr_modifiers_release +//////////////////////////////// + +namespace unique_ptr_modifiers_release{ + +void test() +{ + //Single unique_ptr + { + bml::unique_ptr p(new int(3)); + int* i = p.get(); + int* j = p.release(); + BOOST_TEST(p.get() == 0); + BOOST_TEST(i == j); + } + //Array unique_ptr + { + bml::unique_ptr p(new int[2]); + int* i = p.get(); + int* j = p.release(); + BOOST_TEST(p.get() == 0); + BOOST_TEST(i == j); + } +} + +} //namespace unique_ptr_modifiers_release{ + +//////////////////////////////// +// unique_ptr_modifiers_reset1 +//////////////////////////////// + +namespace unique_ptr_modifiers_reset1{ + +void test() +{ + //Single unique_ptr + reset_counters(); + { + bml::unique_ptr p(new A); + BOOST_TEST(A::count == 1); + A* i = p.get(); + (void)i; + p.reset(); + BOOST_TEST(A::count == 0); + BOOST_TEST(p.get() == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr p(new A); + BOOST_TEST(A::count == 1); + A* i = p.get(); + (void)i; + p.reset(new A); + BOOST_TEST(A::count == 1); + } + BOOST_TEST(A::count == 0); + //Array unique_ptr + reset_counters(); + { + bml::unique_ptr p(new A[2]); + BOOST_TEST(A::count == 2); + A* i = p.get(); + (void)i; + p.reset(); + BOOST_TEST(A::count == 0); + BOOST_TEST(p.get() == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr p(new A[2]); + BOOST_TEST(A::count == 2); + A* i = p.get(); + (void)i; + p.reset(new A[3]); + BOOST_TEST(A::count == 3); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_modifiers_reset1{ + +//////////////////////////////// +// unique_ptr_modifiers_reset2 +//////////////////////////////// + +namespace unique_ptr_modifiers_reset2{ + +void test() +{ + //Single unique_ptr + reset_counters(); + { + bml::unique_ptr p(new A); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 0); + A* i = p.get(); + (void)i; + p.reset(new B); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + { + bml::unique_ptr p(new B); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + A* i = p.get(); + (void)i; + p.reset(new B); + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + } + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + //Array unique_ptr + reset_counters(); + { + bml::unique_ptr p(new const A[2]); + BOOST_TEST(A::count == 2); + const volatile A* i = p.get(); + (void)i; + p.reset(new volatile A[3]); + BOOST_TEST(A::count == 3); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr p(new A[2]); + BOOST_TEST(A::count == 2); + const A* i = p.get(); + (void)i; + p.reset(new const A[3]); + BOOST_TEST(A::count == 3); + } + BOOST_TEST(A::count == 0); +} + +} //unique_ptr_modifiers_reset2 + + +//////////////////////////////// +// unique_ptr_modifiers +//////////////////////////////// + +namespace unique_ptr_modifiers_swap{ + +// test swap + +void test() +{ + //Single unique_ptr + reset_counters(); + { + A* p1 = new A(1); + move_constr_deleter d1(1); + bml::unique_ptr > s1(p1, ::boost::move(d1)); + A* p2 = new A(2); + move_constr_deleter d2(2); + bml::unique_ptr > s2(p2, ::boost::move(d2)); + BOOST_TEST(s1.get() == p1); + BOOST_TEST(*s1 == A(1)); + BOOST_TEST(s1.get_deleter().state() == 1); + BOOST_TEST(s2.get() == p2); + BOOST_TEST(*s2 == A(2)); + BOOST_TEST(s2.get_deleter().state() == 2); + swap(s1, s2); + BOOST_TEST(s1.get() == p2); + BOOST_TEST(*s1 == A(2)); + BOOST_TEST(s1.get_deleter().state() == 2); + BOOST_TEST(s2.get() == p1); + BOOST_TEST(*s2 == A(1)); + BOOST_TEST(s2.get_deleter().state() == 1); + } + //Array unique_ptr + reset_counters(); + { + A* p1 = new A[2]; + p1[0].set(1); + p1[1].set(2); + move_constr_deleter d1(1); + bml::unique_ptr > s1(p1, ::boost::move(d1)); + A* p2 = new A[2]; + p2[0].set(3); + p2[1].set(4); + move_constr_deleter d2(2); + bml::unique_ptr > s2(p2, ::boost::move(d2)); + BOOST_TEST(s1.get() == p1); + BOOST_TEST(s1[0] == A(1)); + BOOST_TEST(s1[1] == A(2)); + BOOST_TEST(s1.get_deleter().state() == 1); + BOOST_TEST(s2.get() == p2); + BOOST_TEST(s2[0] == A(3)); + BOOST_TEST(s2[1] == A(4)); + BOOST_TEST(s2.get_deleter().state() == 2); + swap(s1, s2); + BOOST_TEST(s1.get() == p2); + BOOST_TEST(s1[0] == A(3)); + BOOST_TEST(s1[1] == A(4)); + BOOST_TEST(s1.get_deleter().state() == 2); + BOOST_TEST(s2.get() == p1); + BOOST_TEST(s2[0] == A(1)); + BOOST_TEST(s2[1] == A(2)); + BOOST_TEST(s2.get_deleter().state() == 1); + } +} + +} //namespace unique_ptr_modifiers_swap{ + +//////////////////////////////// +// unique_ptr_observers_dereference +//////////////////////////////// + +namespace unique_ptr_observers_dereference{ + +void test() +{ + //Single unique_ptr + { + bml::unique_ptr p(new int(3)); + BOOST_TEST(*p == 3); + } + //Array unique_ptr + { + int *pi = new int[2]; + pi[0] = 3; + pi[1] = 4; + bml::unique_ptr p(pi); + BOOST_TEST(p[0] == 3); + BOOST_TEST(p[1] == 4); + } +} + +} //namespace unique_ptr_observers_dereference{ + +//////////////////////////////// +// unique_ptr_observers_dereference +//////////////////////////////// + +namespace unique_ptr_observers_explicit_bool{ + +void test() +{ + //Single unique_ptr + { + bml::unique_ptr p(new int(3)); + if (p) + ; + else + BOOST_TEST(false); + if (!p) + BOOST_TEST(false); + } + { + bml::unique_ptr p; + if (!p) + ; + else + BOOST_TEST(false); + if (p) + BOOST_TEST(false); + } + //Array unique_ptr + { + bml::unique_ptr p(new int[2]); + if (p) + ; + else + BOOST_TEST(false); + if (!p) + BOOST_TEST(false); + } + { + bml::unique_ptr p; + if (!p) + ; + else + BOOST_TEST(false); + if (p) + BOOST_TEST(false); + } +} + +} //namespace unique_ptr_observers_explicit_bool{ + +//////////////////////////////// +// unique_ptr_observers_get +//////////////////////////////// + +namespace unique_ptr_observers_get{ + +void test() +{ + //Single unique_ptr + { + int* p = new int; + bml::unique_ptr s(p); + BOOST_TEST(s.get() == p); + } + //Array unique_ptr + { + int* p = new int[2]; + bml::unique_ptr s(p); + BOOST_TEST(s.get() == p); + } +} + +} //namespace unique_ptr_observers_get{ + +//////////////////////////////// +// unique_ptr_observers_get_deleter +//////////////////////////////// + +namespace unique_ptr_observers_get_deleter{ + +struct Deleter +{ + void operator()(void*) {} + + int test() {return 5;} + int test() const {return 6;} +}; + +void test() +{ + //Single unique_ptr + { + bml::unique_ptr p; + BOOST_TEST(p.get_deleter().test() == 5); + } + { + const bml::unique_ptr p; + BOOST_TEST(p.get_deleter().test() == 6); + } + //Array unique_ptr + { + bml::unique_ptr p; + BOOST_TEST(p.get_deleter().test() == 5); + } + { + const bml::unique_ptr p; + BOOST_TEST(p.get_deleter().test() == 6); + } +} + +} //namespace unique_ptr_observers_get_deleter{ + +//////////////////////////////// +// unique_ptr_observers_op_arrow +//////////////////////////////// + +namespace unique_ptr_observers_op_arrow{ + +void test() +{ + //Single unique_ptr + { + bml::unique_ptr p(new A); + BOOST_TEST(p->state_ == 999); + } +} + +} //namespace unique_ptr_observers_op_arrow{ + + +namespace unique_ptr_observers_op_index{ + +void test() +{ + //Single unique_ptr + { + A *pa = new A[2]; + //pa[0] is left default constructed + pa[1].set(888); + bml::unique_ptr p(pa); + BOOST_TEST(p[0].state_ == 999); + BOOST_TEST(p[1].state_ == 888); + } +} + +} //namespace unique_ptr_observers_op_index{ + +//////////////////////////////// +// main +//////////////////////////////// +int main() +{ + //General + pointer_type::test(); + + //Assignment + unique_ptr_asgn_move_convert01::test(); + unique_ptr_asgn_move_convert02::test(); + unique_ptr_asgn_move_convert03::test(); + unique_ptr_asgn_move01::test(); + unique_ptr_asgn_null::test(); + + //Constructor + unique_ptr_ctor_default01::test(); + unique_ptr_ctor_default02::test(); + unique_ptr_ctor_move_convert01::test(); + unique_ptr_ctor_move_convert02::test(); + unique_ptr_ctor_move_convert03::test(); + unique_ptr_ctor_move_convert04::test(); + unique_ptr_ctor_move_convert05::test(); + unique_ptr_ctor_move_convert06::test(); + unique_ptr_ctor_move01::test(); + unique_ptr_ctor_move02::test(); + unique_ptr_ctor_pointer_deleter01::test(); + unique_ptr_ctor_pointer_deleter02::test(); + unique_ptr_ctor_pointer_deleter03::test(); + unique_ptr_ctor_pointer_deleter04::test(); + unique_ptr_ctor_pointer_deleter05::test(); + unique_ptr_ctor_pointer_deleter06::test(); + unique_ptr_ctor_pointer01::test(); + unique_ptr_ctor_pointer02::test(); + unique_ptr_ctor_pointer03::test(); + + //Destructor + unique_ptr_dtor_null::test(); + + //Modifiers + unique_ptr_modifiers_release::test(); + unique_ptr_modifiers_reset1::test(); + unique_ptr_modifiers_reset2::test(); + unique_ptr_modifiers_swap::test(); + + //Observers + unique_ptr_observers_dereference::test(); + unique_ptr_observers_explicit_bool::test(); + unique_ptr_observers_get::test(); + unique_ptr_observers_get_deleter::test(); + unique_ptr_observers_op_arrow::test(); + unique_ptr_observers_op_index::test(); + + //Test results + return boost::report_errors(); +} + +//Define the incomplete I type and out of line functions + +struct I +{ + static int count; + I() {++count;} + I(const A&) {++count;} + ~I() {--count;} +}; + +int I::count = 0; + +I* get() {return new I;} +I* get_array(int i) {return new I[i];} + +void check(int i) +{ + BOOST_TEST(I::count == i); +} + +template +J::~J() {} + +void reset_counters() +{ A::count = 0; B::count = 0; I::count = 0; } + + +#include diff --git a/test/unique_ptr_default_deleter.cpp b/test/unique_ptr_default_deleter.cpp new file mode 100644 index 0000000..a3eff8f --- /dev/null +++ b/test/unique_ptr_default_deleter.cpp @@ -0,0 +1,134 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Howard Hinnant 2009 +// (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 + +////////////////////////////////////////////// +// +// The initial implementation of these tests +// was written by Howard Hinnant. +// +// These test were later refactored grouping +// and porting them to Boost.Move. +// +// Many thanks to Howard for releasing his C++03 +// unique_ptr implementation with such detailed +// test cases. +// +////////////////////////////////////////////// + +//////////////////////////////// +// unique_ptr_dltr_dflt_convert_ctor +//////////////////////////////// + +namespace bml = ::boost::movelib; + +struct A +{ + static int count; + A() {++count;} + A(const A&) {++count;} + virtual ~A() {--count;} +}; + +int A::count = 0; + +struct B + : public A +{ + static int count; + B() {++count;} + B(const B&) {++count;} + virtual ~B() {--count;} +}; + +int B::count = 0; + +void reset_counters() +{ A::count = B::count = 0; } + +namespace unique_ptr_dltr_dflt_convert_ctor{ + +void test() +{ + //Single element deleter + { + reset_counters(); + bml::default_delete d2; + bml::default_delete d1 = d2; + A* p = new B; + BOOST_TEST(A::count == 1); + BOOST_TEST(B::count == 1); + d1(p); + BOOST_TEST(A::count == 0); + BOOST_TEST(B::count == 0); + } + //Array element deleter + { + reset_counters(); + bml::default_delete d2; + bml::default_delete d1 = d2; + const A* p = new const A[2]; + BOOST_TEST(A::count == 2); + d1(p); + BOOST_TEST(A::count == 0); + } +} + +} //namespace unique_ptr_dltr_dflt_convert_ctor{ + +//////////////////////////////// +// unique_ptr_dltr_dflt_default +//////////////////////////////// + +namespace unique_ptr_dltr_dflt_default{ + +void test() +{ + { + //Single element deleter + reset_counters(); + bml::default_delete d; + A* p = new A; + BOOST_TEST(A::count == 1); + d(p); + BOOST_TEST(A::count == 0); + } + { + //Array element deleter + reset_counters(); + bml::default_delete d; + A* p = new A[2]; + BOOST_TEST(A::count == 2); + d(p); + BOOST_TEST(A::count == 0); + } +} + +} //namespace unique_ptr_dltr_dflt_default{ + +//////////////////////////////// +// main +//////////////////////////////// +int main() +{ + unique_ptr_dltr_dflt_convert_ctor::test(); + unique_ptr_dltr_dflt_default::test(); + + //Test results + return boost::report_errors(); +} + +#include diff --git a/test/unique_ptr_functions.cpp b/test/unique_ptr_functions.cpp new file mode 100644 index 0000000..dfc3f73 --- /dev/null +++ b/test/unique_ptr_functions.cpp @@ -0,0 +1,174 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 + +struct A +{ + int a, b, c; + static int count; + A() : a (999), b(1000), c(1001) {++count;} + A(int a) : a (a), b(1000), c(1001) {++count;} + A(int a, int b) : a (a), b(b), c(1001) {++count;} + A(int a, int b, int c) : a (a), b(b), c(c) {++count;} + A(const A&) {++count;} + virtual ~A() {--count;} +}; + +int A::count = 0; + +struct B + : public A +{ + static int count; + B() {++count;} + B(const B&) {++count;} + virtual ~B() {--count;} +}; + +int B::count = 0; + +void reset_counters() +{ A::count = B::count = 0; } + +namespace bml = ::boost::movelib; + +//////////////////////////////// +// make_unique_single +//////////////////////////////// + +namespace make_unique_single{ + +void test() +{ + //Single element deleter + reset_counters(); + { + bml::unique_ptr p(bml::make_unique()); + BOOST_TEST(A::count == 1); + BOOST_TEST(p->a == 999); + BOOST_TEST(p->b == 1000); + BOOST_TEST(p->c == 1001); + } + { + bml::unique_ptr p(bml::make_unique(0)); + BOOST_TEST(A::count == 1); + BOOST_TEST(p->a == 0); + BOOST_TEST(p->b == 1000); + BOOST_TEST(p->c == 1001); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr p(bml::make_unique(0, 1)); + BOOST_TEST(A::count == 1); + BOOST_TEST(p->a == 0); + BOOST_TEST(p->b == 1); + BOOST_TEST(p->c == 1001); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr p(bml::make_unique(0, 1, 2)); + BOOST_TEST(A::count == 1); + BOOST_TEST(p->a == 0); + BOOST_TEST(p->b == 1); + BOOST_TEST(p->c == 2); + } + BOOST_TEST(A::count == 0); +} + +} //namespace make_unique_single{ + +//////////////////////////////// +// make_unique_single +//////////////////////////////// + +namespace make_unique_array{ + +void test() +{ + //Single element deleter + reset_counters(); + { + bml::unique_ptr p(bml::make_unique(10)); + BOOST_TEST(A::count == 10); + for(int i = 0; i != 10; ++i){ + BOOST_TEST(p[i].a == 999); + BOOST_TEST(p[i].b == 1000); + BOOST_TEST(p[i].c == 1001); + } + } + BOOST_TEST(A::count == 0); +} + +} //namespace make_unique_array{ + +//////////////////////////////// +// unique_compare +//////////////////////////////// + +namespace unique_compare{ + +void test() +{ + //Single element deleter + reset_counters(); + { + bml::unique_ptr pa(bml::make_unique()); + bml::unique_ptr pb(bml::make_unique()); + BOOST_TEST(A::count == 2); + + //Take references to less and greater + bml::unique_ptr &rpl = pa < pb ? pa : pb; + bml::unique_ptr &rpg = pa < pb ? pb : pa; + + //Now test operations with .get() + + //Equal + BOOST_TEST(rpl == rpl && rpl.get() == rpl.get()); + BOOST_TEST(!(rpl == rpg) && !(rpl.get() != rpg.get())); + //Unequal + BOOST_TEST(rpl != rpg && rpl.get() != rpg.get()); + BOOST_TEST(!(rpl != rpl) && !(rpl.get() != rpl.get())); + //Less + BOOST_TEST(rpl < rpg && rpl.get() < rpg.get()); + BOOST_TEST(!(rpl < rpg) && !(rpl.get() < rpg.get())); + //Greater + BOOST_TEST(rpg > rpl && rpg.get() > rpl.get()); + BOOST_TEST(!(rpg > rpg) && !(rpg.get() > rpl.get())); + //Less or equal + BOOST_TEST(rpl <= rpg && rpl.get() <= rpg.get()); + BOOST_TEST(rpl <= rpl && rpl.get() <= rpl.get()); + BOOST_TEST(!(rpg <= rpl) && !(rpg.get() < rpl.get())); + //Greater or equal + BOOST_TEST(rpg >= rpl && rpg.get() >= rpl.get()); + BOOST_TEST(rpg >= rpg && rpg.get() >= rpg.get()); + BOOST_TEST(!(rpl >= rpg) && !(rpl.get() < rpg.get())); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_compare{ + +//////////////////////////////// +// main +//////////////////////////////// +int main() +{ + make_unique_single::test(); + make_unique_array::test(); + + //Test results + return boost::report_errors(); +} + +#include From a9bc0876cd28a9c445e36f6c62a2af6b03ccb710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 23 Aug 2014 00:32:30 +0200 Subject: [PATCH 4/6] Added missing cstddef for std::nullptr_t --- include/boost/move/unique_ptr.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/move/unique_ptr.hpp b/include/boost/move/unique_ptr.hpp index a6839ea..6a95155 100644 --- a/include/boost/move/unique_ptr.hpp +++ b/include/boost/move/unique_ptr.hpp @@ -18,6 +18,10 @@ #include #include +#if !defined(BOOST_NO_CXX11_NULLPTR) +#include //For std::nullptr_t +#endif + //!\file //! Describes the smart pointer unique_ptr, a drop-in replacement for std::unique_ptr, //! usable also from C++03 compilers. From 7797b52f61104eab3390beb7bdaf505976440b18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 24 Aug 2014 21:17:26 +0200 Subject: [PATCH 5/6] Added missing cstddef includes and corrected the use of plain "size_t" --- include/boost/move/detail/meta_utils.hpp | 1 + include/boost/move/make_unique.hpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/boost/move/detail/meta_utils.hpp b/include/boost/move/detail/meta_utils.hpp index 30fd58f..e246ae3 100644 --- a/include/boost/move/detail/meta_utils.hpp +++ b/include/boost/move/detail/meta_utils.hpp @@ -15,6 +15,7 @@ #define BOOST_MOVE_DETAIL_META_UTILS_HPP #include +#include //for std::size_t //Small meta-typetraits to support move diff --git a/include/boost/move/make_unique.hpp b/include/boost/move/make_unique.hpp index 30aa8d8..825a66a 100644 --- a/include/boost/move/make_unique.hpp +++ b/include/boost/move/make_unique.hpp @@ -15,6 +15,7 @@ #include #include #include +#include //for std::size_t #include #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -52,7 +53,7 @@ struct unique_ptr_if typedef ::boost::movelib::unique_ptr t_is_array_of_unknown_bound; }; -template +template struct unique_ptr_if { typedef void t_is_array_of_known_bound; @@ -120,7 +121,7 @@ inline #else typename ::boost::move_detail::unique_ptr_if::t_is_array_of_unknown_bound #endif - make_unique(size_t n) + make_unique(std::size_t n) { typedef typename ::boost::move_detail::remove_extent::type U; return unique_ptr(new U[n]()); From e3959c982c371fd58701b2a593dbaa561a035cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 24 Aug 2014 21:17:43 +0200 Subject: [PATCH 6/6] Corrected typos in documentation --- doc/move.qbk | 12 ++++++------ include/boost/move/core.hpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/move.qbk b/doc/move.qbk index d1a31bd..1df3e5d 100644 --- a/doc/move.qbk +++ b/doc/move.qbk @@ -153,13 +153,13 @@ some good introduction and tutorials on rvalue references in these papers: * [@http://www.artima.com/cppsource/rvalue.html ['A Brief Introduction to Rvalue References]] * [@http://blogs.msdn.com/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx ['Rvalue References: C++0x Features in VC10, Part 2]] -When the source of the copy is known to be an `rvalue` (e.g.: a temporary object), one can avoid the +When the source of the copy is known to be a `rvalue` (e.g.: a temporary object), one can avoid the potentially expensive `clone()` operation by pilfering source's pointer (no one will notice!). The move constructor above does exactly that, leaving the rvalue in a default constructed state. The move assignment operator simply does the same freeing old resources. -Now when code tries to copy an rvalue `clone_ptr`, or if that code explicitly gives permission to -consider the source of the copy an rvalue (using `boost::move`), the operation will execute much faster. +Now when code tries to copy a rvalue `clone_ptr`, or if that code explicitly gives permission to +consider the source of the copy a rvalue (using `boost::move`), the operation will execute much faster. [move_clone_ptr] @@ -236,7 +236,7 @@ increased. Movable but non-copyable types can be returned by value from factory data_file = create_file(/* ... */); // No copies! In the above example, the underlying file handle is passed from object to object, as long -as the source `file_descriptor` is an rvalue. At all times, there is still only one underlying file +as the source `file_descriptor` is a rvalue. At all times, there is still only one underlying file handle, and only one `file_descriptor` owns it at a time. To write a movable but not copyable type in portable syntax, you need to follow these simple steps: @@ -427,7 +427,7 @@ both C++03 and C++11 compilers. [classref boost::move_iterator move_iterator] is an iterator adaptor with the same behavior as the underlying iterator except that its dereference operator implicitly converts the value returned by the -underlying iterator's dereference operator to an rvalue reference: `boost::move(*underlying_iterator)` +underlying iterator's dereference operator to a rvalue reference: `boost::move(*underlying_iterator)` It is a read-once iterator, but can have up to random access traversal characteristics. `move_iterator` is very useful because some generic algorithms and container insertion functions @@ -455,7 +455,7 @@ provided with this library. With regular iterator classes, while (first != last) *result++ = *first++; causes a range [first,last) to be copied into a range starting with result. The same code with -result being an move insert iterator will move insert corresponding elements into the container. +result being a move insert iterator will move insert corresponding elements into the container. This device allows all of the copying algorithms in the library to work in the move insert mode instead of the regular overwrite mode. This library offers 3 move insert iterators and their helper functions: diff --git a/include/boost/move/core.hpp b/include/boost/move/core.hpp index dada893..40a257f 100644 --- a/include/boost/move/core.hpp +++ b/include/boost/move/core.hpp @@ -380,8 +380,8 @@ #if !defined(BOOST_MOVE_MSVC_AUTO_MOVE_RETURN_BUG) || defined(BOOST_MOVE_DOXYGEN_INVOKED) //!This macro is used to achieve portable move return semantics. - //!The Standard allows implicit move returns when the object to be returned - //!is designated by an lvalue and: + //!The C++11 Standard allows implicit move returns when the object to be returned + //!is designated by a lvalue and: //! - The criteria for elision of a copy operation are met OR //! - The criteria would be met save for the fact that the source object is a function parameter //!