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] 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