From 364ee17476d4f7138afda77c46b46182586dec29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Wed, 27 Aug 2014 23:21:36 +0200 Subject: [PATCH] Simplified and improved unique_ptr implementation: - No array specialization to avoid code duplication - Constructible and assignable from literal zero --- doc/Jamfile.v2 | 5 + include/boost/move/detail/meta_utils.hpp | 84 +-- include/boost/move/detail/workaround.hpp | 4 + include/boost/move/unique_ptr.hpp | 904 ++++++++--------------- test/unique_ptr.cpp | 144 +++- test/unique_ptr_default_deleter.cpp | 4 - test/unique_ptr_functions.cpp | 121 ++- 7 files changed, 571 insertions(+), 695 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 4218cc3..29d3661 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -24,7 +24,12 @@ doxygen autodoc "PREDEFINED=\"BOOST_MOVE_DOXYGEN_INVOKED\" \\ \"BOOST_MOVE_SEEDOC(T)=see_documentation\" \\ \"BOOST_RV_REF(T)=T&&\" \\ + \"BOOST_RV_REF_BEG=\" \\ + \"BOOST_RV_REF_END=&&\" \\ \"BOOST_FWD_REF(T)=T&&\" \\ + \"BOOST_MOVE_DOC0PTR(T)=std::nullptr_t\" \\ + \"BOOST_MOVE_DOC1ST(T1, T2)=T1\" \\ + \"BOOST_MOVE_DOCIGN(T1) \"\\ " ; diff --git a/include/boost/move/detail/meta_utils.hpp b/include/boost/move/detail/meta_utils.hpp index e246ae3..6cc1763 100644 --- a/include/boost/move/detail/meta_utils.hpp +++ b/include/boost/move/detail/meta_utils.hpp @@ -313,6 +313,15 @@ struct add_lvalue_reference typedef const volatile void type; }; +template +struct add_const_lvalue_reference +{ + typedef typename remove_reference::type t_unreferenced; + typedef typename add_const::type t_unreferenced_const; + typedef typename add_lvalue_reference + ::type type; +}; + ////////////////////////////////////// // is_same @@ -483,7 +492,8 @@ struct pointer_type_imp template struct pointer_type { - typedef typename pointer_type_imp::type>::type type; + typedef typename pointer_type_imp + ::type, typename remove_reference::type>::type type; }; ////////////////////////////////////// @@ -517,7 +527,7 @@ class is_convertible #endif ////////////////////////////////////// -// is_unary_or_binary_function +// is_unary_function ////////////////////////////////////// #if defined(BOOST_MSVC) || defined(__BORLANDC_) #define BOOST_MOVE_TT_DECL __cdecl @@ -530,120 +540,86 @@ class is_convertible #endif template -struct is_unary_or_binary_function_impl +struct is_unary_function_impl { static const bool value = false; }; -// avoid duplicate definitions of is_unary_or_binary_function_impl +// avoid duplicate definitions of is_unary_function_impl #ifndef BOOST_MOVE_TT_TEST_MSC_FUNC_SIGS template -struct is_unary_or_binary_function_impl +struct is_unary_function_impl { static const bool value = true; }; template -struct is_unary_or_binary_function_impl +struct is_unary_function_impl { static const bool value = true; }; #else // BOOST_MOVE_TT_TEST_MSC_FUNC_SIGS template -struct is_unary_or_binary_function_impl +struct is_unary_function_impl { static const bool value = true; }; #ifndef _MANAGED template -struct is_unary_or_binary_function_impl +struct is_unary_function_impl { static const bool value = true; }; #endif template -struct is_unary_or_binary_function_impl +struct is_unary_function_impl { static const bool value = true; }; template -struct is_unary_or_binary_function_impl +struct is_unary_function_impl { static const bool value = true; }; #endif -// avoid duplicate definitions of is_unary_or_binary_function_impl +// avoid duplicate definitions of is_unary_function_impl #ifndef BOOST_MOVE_TT_TEST_MSC_FUNC_SIGS template -struct is_unary_or_binary_function_impl +struct is_unary_function_impl { static const bool value = true; }; template -struct is_unary_or_binary_function_impl +struct is_unary_function_impl { static const bool value = true; }; #else // BOOST_MOVE_TT_TEST_MSC_FUNC_SIGS template -struct is_unary_or_binary_function_impl +struct is_unary_function_impl { static const bool value = true; }; #ifndef _MANAGED template -struct is_unary_or_binary_function_impl +struct is_unary_function_impl { static const bool value = true; }; #endif template -struct is_unary_or_binary_function_impl +struct is_unary_function_impl { static const bool value = true; }; template -struct is_unary_or_binary_function_impl +struct is_unary_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 +struct is_unary_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; }; +struct is_unary_function +{ static const bool value = is_unary_function_impl::value; }; } //namespace move_detail { } //namespace boost { diff --git a/include/boost/move/detail/workaround.hpp b/include/boost/move/detail/workaround.hpp index b46c808..181bc12 100644 --- a/include/boost/move/detail/workaround.hpp +++ b/include/boost/move/detail/workaround.hpp @@ -20,6 +20,10 @@ //Macros for documentation purposes. For code, expands to the argument #define BOOST_MOVE_IMPDEF(TYPE) TYPE #define BOOST_MOVE_SEEDOC(TYPE) TYPE +#define BOOST_MOVE_DOC0PTR(TYPE) TYPE +#define BOOST_MOVE_DOC1ST(TYPE1, TYPE2) TYPE2 +#define BOOST_MOVE_I , +#define BOOST_MOVE_DOCIGN(T1) T1 #include diff --git a/include/boost/move/unique_ptr.hpp b/include/boost/move/unique_ptr.hpp index 6a95155..f9b4128 100644 --- a/include/boost/move/unique_ptr.hpp +++ b/include/boost/move/unique_ptr.hpp @@ -44,29 +44,27 @@ namespace move_detail { template struct deleter_types { + typedef typename add_lvalue_reference::type del_ref; + typedef typename add_const_lvalue_reference::type del_cref; typedef typename if_c - < is_lvalue_reference::value - , D - , typename add_lvalue_reference::type>::type - >::type deleter_arg_type1; - + < is_lvalue_reference::value, D, del_cref >::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 > +//////////////////////////////////////////// +// unique_ptr_data +//////////////////////////////////////////// +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; + typedef typename deleter_types::del_ref del_ref; + typedef typename deleter_types::del_cref del_cref; unique_ptr_data() BOOST_NOEXCEPT : m_p(), d() @@ -89,18 +87,15 @@ struct unique_ptr_data : m_p(::boost::forward(p)), d(::boost::forward(d)) {} - deleter_lvalue_reference deleter() - { return d; } - - deleter_const_lvalue_reference deleter() const - { return d; } + del_ref deleter() { return d; } + del_cref deleter() const{ return d; } P m_p; + D d; private: + unique_ptr_data& operator=(const unique_ptr_data&); unique_ptr_data(const unique_ptr_data&); - unique_ptr_data &operator=(const unique_ptr_data&); - D d; }; template @@ -109,8 +104,8 @@ 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; + typedef typename deleter_types::del_ref del_ref; + typedef typename deleter_types::del_cref del_cref; unique_ptr_data() BOOST_NOEXCEPT : D(), m_p() @@ -133,35 +128,30 @@ struct unique_ptr_data : 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); } + del_ref deleter() { return static_cast(*this); } + del_cref deleter() const{ return static_cast(*this); } P m_p; + private: + unique_ptr_data& operator=(const unique_ptr_data&); unique_ptr_data(const unique_ptr_data&); - unique_ptr_data &operator=(const unique_ptr_data&); }; +//////////////////////////////////////////// +// is_unique_ptr_convertible +//////////////////////////////////////////// + //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; }; - + template static char test(int, typename X::element_type*); + template static int test(...); static const bool value = (1 == sizeof(test(0, 0))); - - typedef typename - if_c::type::element_type type; + typedef typename if_c::type::element_type type; }; template @@ -173,9 +163,7 @@ struct get_element_type template struct get_cvelement { - typedef typename remove_cv - ::type - >::type type; + typedef typename remove_cv::type>::type type; }; template @@ -183,46 +171,85 @@ 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 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_ptr_convertible + : is_same_cvelement_and_convertible {}; +template +struct is_unique_ptr_convertible + : is_convertible +{}; -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; -}; - +//////////////////////////////////////// +//// enable_def_del / enable_defdel_call +//////////////////////////////////////// template -struct enable_default_delete +struct enable_def_del : enable_if_c - < is_unique_acceptable < is_array::value - , is_array::value - , typename element_pointer::type - , typename element_pointer::type - >::value + < (is_array::value == is_array::value) && is_unique_ptr_convertible + ::value, typename remove_extent::type*, typename remove_extent::type*>::value , Type> {}; +template +struct enable_defdel_call + : public enable_def_del +{}; + +template +struct enable_defdel_call + : public enable_def_del +{}; + +//////////////////////////////////////// +//// enable_up_moveconv_assign +//////////////////////////////////////// + +template +struct enable_up_ptr + : enable_if_c< is_unique_ptr_convertible < is_array::value, FromPointer, ThisPointer>::value, Type> +{}; + +//////////////////////////////////////// +//// enable_up_moveconv_assign +//////////////////////////////////////// + +template +struct unique_moveconvert_assignable +{ + static const bool value = !is_array::value && is_unique_ptr_convertible + ::type, typename pointer_type::type>::value; +}; + +template +struct unique_moveconvert_assignable +{ + static const bool value = is_array::value && is_unique_ptr_convertible + ::type, typename pointer_type::type>::value; +}; + +template +struct enable_up_moveconv_assign + : enable_if_c::value, Type> +{}; + +//////////////////////////////////////// +//// enable_up_moveconv_constr +//////////////////////////////////////// + +template::value> +struct unique_deleter_is_initializable +{ + static const bool value = is_same::value; +}; + template class is_rvalue_convertible { @@ -245,12 +272,6 @@ class is_rvalue_convertible 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 { @@ -274,87 +295,33 @@ struct unique_deleter_is_initializable #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> +struct enable_up_moveconv_constr + : enable_if_c::value && + unique_deleter_is_initializable::value, Type> {}; -template -struct enable_unique_moveconvert_assignable - : enable_if_c - < unique_moveconvert_assignable::value, Type> -{}; +//////////////////////////////////////// +//// Some bool literal zero conversion utilities +//////////////////////////////////////// -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; -}; +struct bool_conversion {int for_bool; int for_arg(); }; +typedef int bool_conversion::* explicit_bool_arg; -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); } +#if !defined(BOOST_NO_CXX11_NULLPTR) +typedef std::nullptr_t nullptr_type; +#else +typedef int (bool_conversion::*nullptr_type)(); +#endif } //namespace move_detail { namespace movelib { +namespace bmd = boost::move_detail; + //!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 { @@ -375,138 +342,48 @@ struct default_delete default_delete(const default_delete&) BOOST_NOEXCEPT = default; default_delete &operator=(const default_delete&) BOOST_NOEXCEPT = default; #else - typedef T element_type; + typedef typename bmd::remove_extent::type 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*. + //! Remarks: This constructor shall not participate in overload resolution unless: + //! - If T is not an array type and U* is implicitly convertible to T*. + //! - If T is an array type and U* is a more CV qualified pointer to remove_extent::type. template default_delete(const default_delete& - #if !defined(BOOST_MOVE_DOXYGEN_INVOKED) - , typename ::boost::move_detail::enable_default_delete::type* = 0 - #endif + BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmd::enable_def_del::type* =0) ) 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 + //! Remarks: This constructor shall not participate in overload resolution unless: + //! - If T is not an array type and U* is implicitly convertible to T*. + //! - If T is an array type and U* is a more CV qualified pointer to remove_extent::type. template - #if defined(BOOST_MOVE_DOXYGEN_INVOKED) - default_delete & - #else - typename ::boost::move_detail::enable_default_delete::type - #endif + BOOST_MOVE_DOC1ST(default_delete&, + typename bmd::enable_def_del::type) operator=(const default_delete&) BOOST_NOEXCEPT { return *this; } - //! Effects: calls delete on ptr. + //! Effects: if T is not an array type, calls delete on static_cast(ptr), + //! otherwise calls delete[] on static_cast::type*>(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 + //! Remarks: If U is an incomplete type, the program is ill-formed. + //! This operator shall not participate in overload resolution unless: + //! - T is not an array type and U* is convertible to T*, OR + //! - T is an array type, and remove_cv::type is the same type as + //! remove_cv::type>::type and U* is convertible to remove_extent::type*. 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 + BOOST_MOVE_DOC1ST(void, typename bmd::enable_defdel_call::type) + operator()(U* ptr) const BOOST_NOEXCEPT { //U must be a complete type BOOST_STATIC_ASSERT(sizeof(U) > 0); - delete [] ptr; + element_type * const p = static_cast(ptr); + bmd::is_array::value ? delete [] p : delete p; } - #endif }; @@ -541,6 +418,11 @@ struct default_delete //! ownership of dynamically allocated memory to a function, and returning dynamically allocated memory from //! a function. //! +//! If T is an array type (e.g. unique_ptr) the interface is slightly altered: +//! - 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. +//! //! \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 @@ -559,15 +441,16 @@ class unique_ptr 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; + + typedef move_detail::pointer_type pointer_type_obtainer; + typedef bmd::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 bmd::integral_constant + >::value > is_default_deleter_t; + data_type m_data; #endif public: @@ -575,7 +458,9 @@ class unique_ptr //! 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; + //! If T is an array type, then element_type is equal to T. Otherwise, if T is a type + //! in the form U[], element_type is equal to U. + typedef typename BOOST_MOVE_SEEDOC(bmd::remove_extent::type) element_type; typedef D deleter_type; //! Requires: D shall satisfy the requirements of DefaultConstructible, and @@ -593,8 +478,19 @@ class unique_ptr { //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); + BOOST_STATIC_ASSERT(!bmd::is_pointer::value); + BOOST_STATIC_ASSERT(!bmd::is_reference::value); + } + + //! Effects: Same as unique_ptr() (default constructor). + //! + BOOST_CONSTEXPR unique_ptr(BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) 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(!bmd::is_pointer::value); + BOOST_STATIC_ASSERT(!bmd::is_reference::value); } //! Requires: D shall satisfy the requirements of DefaultConstructible, and @@ -606,14 +502,20 @@ class unique_ptr //! 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 + //! for the template argument D, the program is ill-formed. + //! This constructor shall not participate in overload resolution unless: + //! - If T is not an array type and Pointer is implicitly convertible to pointer. + //! - If T is an array type and Pointer is a more CV qualified pointer to element_type. + template + explicit unique_ptr(Pointer p + BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmd::enable_up_ptr::type* =0) + ) 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); + BOOST_STATIC_ASSERT(!bmd::is_pointer::value); + BOOST_STATIC_ASSERT(!bmd::is_reference::value); } //!The signature of this constructor depends upon whether D is a reference type. @@ -626,10 +528,21 @@ class unique_ptr //! //! 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 + //! + //! Remarks: This constructor shall not participate in overload resolution unless: + //! - If T is not an array type and Pointer is implicitly convertible to pointer. + //! - If T is an array type and Pointer is a more CV qualified pointer to element_type. + template + unique_ptr(Pointer p, BOOST_MOVE_SEEDOC(deleter_arg_type1) d1 + BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmd::enable_up_ptr::type* =0) + ) BOOST_NOEXCEPT : m_data(p, d1) {} + unique_ptr(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), BOOST_MOVE_SEEDOC(deleter_arg_type1) d1) BOOST_NOEXCEPT + : m_data(pointer(), 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). @@ -640,10 +553,21 @@ class unique_ptr //! //! 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 + //! + //! Remarks: This constructor shall not participate in overload resolution unless: + //! - If T is not an array type and Pointer is implicitly convertible to pointer. + //! - If T is an array type and Pointer is a more CV qualified pointer to element_type. + template + unique_ptr(Pointer p, BOOST_MOVE_SEEDOC(deleter_arg_type2) d2 + BOOST_MOVE_DOCIGN(BOOST_MOVE_I typename bmd::enable_up_ptr::type* =0) + ) BOOST_NOEXCEPT : m_data(p, ::boost::move(d2)) {} + unique_ptr(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), BOOST_MOVE_SEEDOC(deleter_arg_type2) d2) BOOST_NOEXCEPT + : m_data(pointer(), ::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. //! @@ -658,19 +582,6 @@ class unique_ptr : 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. @@ -688,9 +599,7 @@ class unique_ptr //! 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_MOVE_DOCIGN(BOOST_MOVE_I typename bmd::enable_up_moveconv_constr::type* =0) ) BOOST_NOEXCEPT : m_data(u.release(), ::boost::move_if_not_lvalue_reference(u.get_deleter())) {} @@ -702,7 +611,7 @@ class unique_ptr //! //! 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()); } + { if(m_data.m_p) m_data.deleter()(m_data.m_p); } //! 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 @@ -733,11 +642,8 @@ class unique_ptr //! //! Returns: *this. template - #if defined(BOOST_MOVE_DOXYGEN_INVOKED) - unique_ptr& - #else - typename ::boost::move_detail::enable_unique_moveconvert_assignable::type - #endif + BOOST_MOVE_DOC1ST(unique_ptr&, typename bmd::enable_up_moveconv_assign + ::type) operator=(BOOST_RV_REF_BEG unique_ptr BOOST_RV_REF_END u) BOOST_NOEXCEPT { this->reset(u.release()); @@ -745,50 +651,55 @@ class unique_ptr 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 + unique_ptr& operator=(BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) 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 + //! + //! Remarks::type) operator*() const - { return *get(); } + { + BOOST_STATIC_ASSERT((!bmd::is_array::value)); + return *get(); + } + + //! Requires: i < the number of elements in the array to which the stored pointer points. + //! + //! Returns: get()[i]. + //! + //! Remarks::type) + operator[](size_t i) const + { + BOOST_STATIC_ASSERT((bmd::is_array::value)); + const pointer p = this->get(); + BOOST_ASSERT(p); + return p[i]; + } //! Requires: get() != nullptr. //! //! Returns: get(). //! //! Note: use typically requires that T be a complete type. + //! + //! Remarks() const BOOST_NOEXCEPT - { return get(); } + { + BOOST_STATIC_ASSERT((!bmd::is_array::value)); + return get(); + } //! Returns: The stored pointer. //! @@ -797,22 +708,30 @@ class unique_ptr //! Returns: A reference to the stored deleter. //! - deleter_lvalue_reference get_deleter() BOOST_NOEXCEPT - { return m_data.deleter(); } + BOOST_MOVE_DOC1ST(D&, typename bmd::add_lvalue_reference::type) + get_deleter() BOOST_NOEXCEPT + { return m_data.deleter(); } //! Returns: A reference to the stored deleter. //! - deleter_const_lvalue_reference get_deleter() const BOOST_NOEXCEPT + BOOST_MOVE_DOC1ST(const D&, typename bmd::add_const_lvalue_reference::type) + get_deleter() const BOOST_NOEXCEPT { return m_data.deleter(); } #ifdef BOOST_MOVE_DOXYGEN_INVOKED //! Returns: Returns: get() != nullptr. //! - explicit operator bool() const BOOST_NOEXCEPT; + explicit operator bool #else - operator int nat::*() const BOOST_NOEXCEPT - { return m_data.m_p ? &nat::for_bool : (int nat::*)0; } + operator bmd::explicit_bool_arg #endif + ()const BOOST_NOEXCEPT + { + return m_data.m_p + ? &bmd::bool_conversion::for_bool + : bmd::explicit_bool_arg(0); + } + //! Postcondition: get() == nullptr. //! @@ -833,263 +752,45 @@ class unique_ptr //! //! 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 + //! + //! Remarks: This constructor shall not participate in overload resolution unless: + //! - If T is not an array type and Pointer is implicitly convertible to pointer. + //! - If T is an array type and Pointer is a more CV qualified pointer to element_type. + template + BOOST_MOVE_DOC1ST(void, typename bmd::enable_up_ptr::type) + reset(Pointer p) 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()); + if(tmp) m_data.deleter()(tmp); } + //! Requires: The expression get_deleter()(get()) shall be well formed, shall have well-defined behavior, + //! and shall not throw exceptions. + //! + //! Effects: assigns nullptr 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() BOOST_NOEXCEPT + { this->reset(pointer()); } + + //! Effects: Same as reset() + //! + void reset(BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) BOOST_NOEXCEPT + { this->reset(); } + //! 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; + using bmd::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). @@ -1110,32 +811,13 @@ 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 +//! Remarks: This comparison shall induce a +//! strict weak ordering betwen pointers. 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(); -} +{ return x.get() < y.get(); } //! Returns: !(y < x). //! @@ -1155,49 +837,45 @@ 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 +inline bool operator==(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) BOOST_NOEXCEPT { return !x; } //! Returns:!x. //! template -inline bool operator==(std::nullptr_t, const unique_ptr &x) BOOST_NOEXCEPT +inline bool operator==(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) BOOST_NOEXCEPT { return !x; } //! Returns: (bool)x. //! template -inline bool operator!=(const unique_ptr &x, std::nullptr_t) BOOST_NOEXCEPT +inline bool operator!=(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) BOOST_NOEXCEPT { return !!x; } //! Returns: (bool)x. //! template -inline bool operator!=(std::nullptr_t, const unique_ptr &x) BOOST_NOEXCEPT +inline bool operator!=(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), 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. +//! Requires: operator shall induce a strict weak ordering on unique_ptr::pointer values. //! -//! Returns: less::pointer>()(x.get(), nullptr). +//! Returns: Returns x.get() < pointer(). template -inline bool operator<(const unique_ptr &x, std::nullptr_t) +inline bool operator<(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) { 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. +//! Requires: operator shall induce a strict weak ordering on unique_ptr::pointer values. //! -//! Returns: The second function template returns less::pointer>()(nullptr, x.get()). +//! Returns: Returns pointer() < x.get(). template -inline bool operator<(std::nullptr_t, const unique_ptr &x) +inline bool operator<(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) { typedef typename unique_ptr::pointer pointer; return pointer() < x.get(); @@ -1206,7 +884,7 @@ inline bool operator<(std::nullptr_t, const unique_ptr &x) //! Returns: nullptr < x. //! template -inline bool operator>(const unique_ptr &x, std::nullptr_t) +inline bool operator>(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) { typedef typename unique_ptr::pointer pointer; return x.get() > pointer(); @@ -1215,7 +893,7 @@ inline bool operator>(const unique_ptr &x, std::nullptr_t) //! Returns: x < nullptr. //! template -inline bool operator>(std::nullptr_t, const unique_ptr &x) +inline bool operator>(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) { typedef typename unique_ptr::pointer pointer; return pointer() > x.get(); @@ -1224,28 +902,26 @@ inline bool operator>(std::nullptr_t, const unique_ptr &x) //! Returns: !(nullptr < x). //! template -inline bool operator<=(const unique_ptr &x, std::nullptr_t) -{ return !(nullptr < x); } +inline bool operator<=(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) +{ return !(bmd::nullptr_type() < x); } //! Returns: !(x < nullptr). //! template -inline bool operator<=(std::nullptr_t, const unique_ptr &x) -{ return !(x < nullptr); } +inline bool operator<=(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) +{ return !(x < bmd::nullptr_type()); } //! Returns: !(x < nullptr). //! template -inline bool operator>=(const unique_ptr &x, std::nullptr_t) -{ return !(x < nullptr); } +inline bool operator>=(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) +{ return !(x < bmd::nullptr_type()); } //! 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) +inline bool operator>=(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) +{ return !(bmd::nullptr_type() < x); } } //namespace movelib { } //namespace boost{ diff --git a/test/unique_ptr.cpp b/test/unique_ptr.cpp index c3b4811..e242406 100644 --- a/test/unique_ptr.cpp +++ b/test/unique_ptr.cpp @@ -10,8 +10,6 @@ // See http://www.boost.org/libs/move for documentation. // ////////////////////////////////////////////////////////////////////////////// -#include - #include #include #include @@ -511,17 +509,22 @@ void test() } //unique_ptr_asgn_move01 //////////////////////////////// -// unique_ptr_asgn_null +// unique_ptr_zero //////////////////////////////// -namespace unique_ptr_asgn_null { +namespace unique_ptr_zero { -// test assignment from null +// test initialization/assignment from zero void test() { //Single unique_ptr reset_counters(); { + bml::unique_ptr s2(0); + BOOST_TEST(A::count == 0); + } + BOOST_TEST(A::count == 0); + { bml::unique_ptr s2(new A); BOOST_TEST(A::count == 1); s2 = 0; @@ -532,6 +535,11 @@ void test() //Array unique_ptr { + bml::unique_ptr s2(0); + BOOST_TEST(A::count == 0); + } + BOOST_TEST(A::count == 0); + { bml::unique_ptr s2(new A[2]); BOOST_TEST(A::count == 2); s2 = 0; @@ -541,8 +549,7 @@ void test() BOOST_TEST(A::count == 0); } - -} //namespace unique_ptr_asgn_null { +} //namespace unique_ptr_zero { //////////////////////////////// @@ -1476,7 +1483,7 @@ void test() { //Single unique_ptr reset_counters(); - { + { //reset() bml::unique_ptr p(new A); BOOST_TEST(A::count == 1); A* i = p.get(); @@ -1486,7 +1493,7 @@ void test() BOOST_TEST(p.get() == 0); } BOOST_TEST(A::count == 0); - { + { //reset(p) bml::unique_ptr p(new A); BOOST_TEST(A::count == 1); A* i = p.get(); @@ -1495,9 +1502,19 @@ void test() BOOST_TEST(A::count == 1); } BOOST_TEST(A::count == 0); + { //reset(0) + bml::unique_ptr p(new A); + BOOST_TEST(A::count == 1); + A* i = p.get(); + (void)i; + p.reset(0); + BOOST_TEST(A::count == 0); + BOOST_TEST(p.get() == 0); + } + BOOST_TEST(A::count == 0); //Array unique_ptr reset_counters(); - { + { //reset() bml::unique_ptr p(new A[2]); BOOST_TEST(A::count == 2); A* i = p.get(); @@ -1507,7 +1524,7 @@ void test() BOOST_TEST(p.get() == 0); } BOOST_TEST(A::count == 0); - { + { //reset(p) bml::unique_ptr p(new A[2]); BOOST_TEST(A::count == 2); A* i = p.get(); @@ -1516,6 +1533,16 @@ void test() BOOST_TEST(A::count == 3); } BOOST_TEST(A::count == 0); + { //reset(0) + bml::unique_ptr p(new A[2]); + BOOST_TEST(A::count == 2); + A* i = p.get(); + (void)i; + p.reset(0); + BOOST_TEST(A::count == 0); + BOOST_TEST(p.get() == 0); + } + BOOST_TEST(A::count == 0); } } //namespace unique_ptr_modifiers_reset1{ @@ -1820,6 +1847,92 @@ void test() } //namespace unique_ptr_observers_op_index{ +//////////////////////////////// +// unique_ptr_nullptr +//////////////////////////////// + +namespace unique_ptr_nullptr{ + +void test() +{ + #if !defined(BOOST_NO_CXX11_NULLPTR) + //Single unique_ptr + reset_counters(); + { + bml::unique_ptr p(new A); + BOOST_TEST(A::count == 1); + A* i = p.get(); + (void)i; + p.reset(nullptr); + 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 = nullptr; + BOOST_TEST(A::count == 0); + BOOST_TEST(p.get() == 0); + } + BOOST_TEST(A::count == 0); + + { + bml::unique_ptr pi(nullptr); + BOOST_TEST(pi.get() == nullptr); + BOOST_TEST(pi.get() == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr pi(nullptr, bml::unique_ptr::deleter_type()); + BOOST_TEST(pi.get() == nullptr); + BOOST_TEST(pi.get() == 0); + } + 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(nullptr); + 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 = nullptr; + BOOST_TEST(A::count == 0); + BOOST_TEST(p.get() == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr pi(nullptr); + BOOST_TEST(pi.get() == nullptr); + BOOST_TEST(pi.get() == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr pi(nullptr, bml::unique_ptr::deleter_type()); + BOOST_TEST(pi.get() == nullptr); + BOOST_TEST(pi.get() == 0); + } + BOOST_TEST(A::count == 0); + + //Array element + #endif +} + +} //namespace unique_ptr_nullptr{ + //////////////////////////////// // main //////////////////////////////// @@ -1833,7 +1946,6 @@ int main() 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(); @@ -1873,8 +1985,13 @@ int main() unique_ptr_observers_op_arrow::test(); unique_ptr_observers_op_index::test(); + //nullptr + unique_ptr_zero::test(); + unique_ptr_nullptr::test(); + //Test results return boost::report_errors(); + } //Define the incomplete I type and out of line functions @@ -1902,6 +2019,3 @@ 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 index a3eff8f..94103f3 100644 --- a/test/unique_ptr_default_deleter.cpp +++ b/test/unique_ptr_default_deleter.cpp @@ -10,8 +10,6 @@ // See http://www.boost.org/libs/move for documentation. // ////////////////////////////////////////////////////////////////////////////// -#include - #include #include @@ -130,5 +128,3 @@ int main() //Test results return boost::report_errors(); } - -#include diff --git a/test/unique_ptr_functions.cpp b/test/unique_ptr_functions.cpp index dfc3f73..d730809 100644 --- a/test/unique_ptr_functions.cpp +++ b/test/unique_ptr_functions.cpp @@ -9,7 +9,6 @@ // See http://www.boost.org/libs/move for documentation. // ////////////////////////////////////////////////////////////////////////////// -#include #include #include @@ -135,30 +134,135 @@ void test() //Equal BOOST_TEST(rpl == rpl && rpl.get() == rpl.get()); - BOOST_TEST(!(rpl == rpg) && !(rpl.get() != rpg.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())); + BOOST_TEST(!(rpg < rpl) && !(rpg.get() < rpl.get())); //Greater BOOST_TEST(rpg > rpl && rpg.get() > rpl.get()); - BOOST_TEST(!(rpg > rpg) && !(rpg.get() > rpl.get())); + BOOST_TEST(!(rpg > rpg) && !(rpg.get() > rpg.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())); + 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(!(rpl >= rpg) && !(rpl.get() >= rpg.get())); } BOOST_TEST(A::count == 0); } } //namespace unique_compare{ + +//////////////////////////////// +// unique_compare_zero +//////////////////////////////// +namespace unique_compare_zero{ + +void test() +{ + //Single element deleter + reset_counters(); + { + bml::unique_ptr pa(bml::make_unique()); + bml::unique_ptr pb; + BOOST_TEST(A::count == 1); + + //Equal + BOOST_TEST(!(pa == 0)); + BOOST_TEST(!(0 == pa)); + BOOST_TEST((pb == 0)); + BOOST_TEST((0 == pb)); + //Unequal + BOOST_TEST((pa != 0)); + BOOST_TEST((0 != pa)); + BOOST_TEST(!(pb != 0)); + BOOST_TEST(!(0 != pb)); + //Less + BOOST_TEST((pa < 0) == (pa.get() < 0)); + BOOST_TEST((0 < pa) == (0 < pa.get())); + BOOST_TEST((pb < 0) == (pb.get() < 0)); + BOOST_TEST((0 < pb) == (0 < pb.get())); + //Greater + BOOST_TEST((pa > 0) == (pa.get() > 0)); + BOOST_TEST((0 > pa) == (0 > pa.get())); + BOOST_TEST((pb > 0) == (pb.get() > 0)); + BOOST_TEST((0 > pb) == (0 > pb.get())); + //Less or equal + BOOST_TEST((pa <= 0) == (pa.get() <= 0)); + BOOST_TEST((0 <= pa) == (0 <= pa.get())); + BOOST_TEST((pb <= 0) == (pb.get() <= 0)); + BOOST_TEST((0 <= pb) == (0 <= pb.get())); + //Greater or equal + BOOST_TEST((pa >= 0) == (pa.get() >= 0)); + BOOST_TEST((0 >= pa) == (0 >= pa.get())); + BOOST_TEST((pb >= 0) == (pb.get() >= 0)); + BOOST_TEST((0 >= pb) == (0 >= pb.get())); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_compare_zero{ + +//////////////////////////////// +// unique_compare_nullptr +//////////////////////////////// + +namespace unique_compare_nullptr{ + +void test() +{ + #if !defined(BOOST_NO_CXX11_NULLPTR) + //Single element deleter + reset_counters(); + { + bml::unique_ptr pa(bml::make_unique()); + bml::unique_ptr pb; + BOOST_TEST(A::count == 1); + + //Equal + BOOST_TEST(!(pa == nullptr)); + BOOST_TEST(!(nullptr == pa)); + BOOST_TEST((pb == nullptr)); + BOOST_TEST((nullptr == pb)); + //Unequal + BOOST_TEST((pa != nullptr)); + BOOST_TEST((nullptr != pa)); + BOOST_TEST(!(pb != nullptr)); + BOOST_TEST(!(nullptr != pb)); + //Less + BOOST_TEST((pa < nullptr) == (pa.get() < nullptr)); + BOOST_TEST((nullptr < pa) == (nullptr < pa.get())); + BOOST_TEST((pb < nullptr) == (pb.get() < nullptr)); + BOOST_TEST((nullptr < pb) == (nullptr < pb.get())); + //Greater + BOOST_TEST((pa > nullptr) == (pa.get() > nullptr)); + BOOST_TEST((nullptr > pa) == (nullptr > pa.get())); + BOOST_TEST((pb > nullptr) == (pb.get() > nullptr)); + BOOST_TEST((nullptr > pb) == (nullptr > pb.get())); + //Less or equal + BOOST_TEST((pa <= nullptr) == (pa.get() <= nullptr)); + BOOST_TEST((nullptr <= pa) == (nullptr <= pa.get())); + BOOST_TEST((pb <= nullptr) == (pb.get() <= nullptr)); + BOOST_TEST((nullptr <= pb) == (nullptr <= pb.get())); + //Greater or equal + BOOST_TEST((pa >= nullptr) == (pa.get() >= nullptr)); + BOOST_TEST((nullptr >= pa) == (nullptr >= pa.get())); + BOOST_TEST((pb >= nullptr) == (pb.get() >= nullptr)); + BOOST_TEST((nullptr >= pb) == (nullptr >= pb.get())); + } + BOOST_TEST(A::count == 0); + #endif //#if !defined(BOOST_NO_CXX11_NULLPTR) +} + +} //namespace unique_compare_nullptr{ + + //////////////////////////////// // main //////////////////////////////// @@ -166,9 +270,10 @@ int main() { make_unique_single::test(); make_unique_array::test(); + unique_compare::test(); + unique_compare_zero::test(); + unique_compare_nullptr::test(); //Test results return boost::report_errors(); } - -#include