From aa7562c3e5c50bcb2270df4f11656b91c24a06cb Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 8 Nov 2012 18:07:49 +0000 Subject: [PATCH] Add support for shared_ptr. [SVN r81253] --- .../boost/smart_ptr/detail/sp_convertible.hpp | 5 + include/boost/smart_ptr/shared_ptr.hpp | 53 +++- test/Jamfile.v2 | 1 + test/sp_array_cv_test.cpp | 54 ++-- test/sp_array_n_test.cpp | 248 ++++++++++++++++++ test/sp_convertible_test.cpp | 2 +- 6 files changed, 341 insertions(+), 22 deletions(-) create mode 100644 test/sp_array_n_test.cpp diff --git a/include/boost/smart_ptr/detail/sp_convertible.hpp b/include/boost/smart_ptr/detail/sp_convertible.hpp index 4f47709..31b2627 100644 --- a/include/boost/smart_ptr/detail/sp_convertible.hpp +++ b/include/boost/smart_ptr/detail/sp_convertible.hpp @@ -58,6 +58,11 @@ template< class Y, class T > struct sp_convertible< Y[], T[] > enum _vt { value = sp_convertible< Y[1], T[1] >::value }; }; +template< class Y, std::size_t N, class T > struct sp_convertible< Y[N], T[] > +{ + enum _vt { value = sp_convertible< Y[1], T[1] >::value }; +}; + struct sp_empty { }; diff --git a/include/boost/smart_ptr/shared_ptr.hpp b/include/boost/smart_ptr/shared_ptr.hpp index 7ca3ba8..af1b13d 100644 --- a/include/boost/smart_ptr/shared_ptr.hpp +++ b/include/boost/smart_ptr/shared_ptr.hpp @@ -81,6 +81,11 @@ template< class T > struct sp_element< T[] > typedef T type; }; +template< class T, std::size_t N > struct sp_element< T[N] > +{ + typedef T type; +}; + #endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) // sp_dereference, return type of operator* @@ -121,6 +126,11 @@ template< class T > struct sp_dereference< T[] > typedef void type; }; +template< class T, std::size_t N > struct sp_dereference< T[N] > +{ + typedef void type; +}; + #endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) // sp_member_access, return type of operator-> @@ -137,6 +147,11 @@ template< class T > struct sp_member_access< T[] > typedef void type; }; +template< class T, std::size_t N > struct sp_member_access< T[N] > +{ + typedef void type; +}; + #endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) // sp_array_access, return type of operator[] @@ -153,6 +168,27 @@ template< class T > struct sp_array_access< T[] > typedef T & type; }; +template< class T, std::size_t N > struct sp_array_access< T[N] > +{ + typedef T & type; +}; + +#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +// sp_extent, for operator[] index check + +template< class T > struct sp_extent +{ + enum _vt { value = 0 }; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template< class T, std::size_t N > struct sp_extent< T[N] > +{ + enum _vt { value = N }; +}; + #endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) // enable_shared_from_this support @@ -207,8 +243,9 @@ template< class T, class R > struct sp_enable_if_auto_ptr< std::auto_ptr< T >, R template< class Y, class T > inline void sp_assert_convertible() { - T* p = static_cast< Y* >( 0 ); - (void)p; + // static_assert( sp_convertible< Y, T >::value ); + typedef char tmp[ sp_convertible< Y, T >::value? 1: -1 ]; + (void)sizeof( tmp ); } // pointer constructor helper @@ -224,7 +261,12 @@ template< class T, class Y > inline void sp_pointer_construct( boost::shared_ptr template< class T, class Y > inline void sp_pointer_construct( boost::shared_ptr< T[] > * /*ppx*/, Y * p, boost::detail::shared_count & pn ) { sp_assert_convertible< Y[], T[] >(); + boost::detail::shared_count( p, boost::checked_array_deleter< T >() ).swap( pn ); +} +template< class T, std::size_t N, class Y > inline void sp_pointer_construct( boost::shared_ptr< T[N] > * /*ppx*/, Y * p, boost::detail::shared_count & pn ) +{ + sp_assert_convertible< Y[N], T[N] >(); boost::detail::shared_count( p, boost::checked_array_deleter< T >() ).swap( pn ); } @@ -244,6 +286,11 @@ template< class T, class Y > inline void sp_deleter_construct( boost::shared_ptr sp_assert_convertible< Y[], T[] >(); } +template< class T, std::size_t N, class Y > inline void sp_deleter_construct( boost::shared_ptr< T[N] > * /*ppx*/, Y * /*p*/ ) +{ + sp_assert_convertible< Y[N], T[N] >(); +} + #endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) } // namespace detail @@ -547,7 +594,7 @@ public: typename boost::detail::sp_array_access< T >::type operator[] ( std::ptrdiff_t i ) const // never throws { BOOST_ASSERT( px != 0 ); - BOOST_ASSERT( i >= 0 ); + BOOST_ASSERT( i >= 0 && ( i < boost::detail::sp_extent< T >::value || boost::detail::sp_extent< T >::value == 0 ) ); return px[ i ]; } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ef64f89..f445193 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -73,6 +73,7 @@ import testing ; [ run sp_array_test.cpp ] [ compile sp_array_cv_test.cpp ] [ run sp_convertible_test.cpp ] + [ run sp_array_n_test.cpp ] [ compile-fail array_fail_spa_sp_c.cpp ] [ compile-fail array_fail_sp_spa_c.cpp ] diff --git a/test/sp_array_cv_test.cpp b/test/sp_array_cv_test.cpp index 2bdc9b6..8618fb0 100644 --- a/test/sp_array_cv_test.cpp +++ b/test/sp_array_cv_test.cpp @@ -14,29 +14,47 @@ struct X { }; +class B +{ +}; + +class D: public B +{ +}; + +#define TEST_CONV( T, U ) \ + { \ + boost::shared_ptr< T > p1; \ + boost::shared_ptr< U > p2( p1 ); \ + p2 = p1; \ + boost::shared_ptr< U > p3 = boost::shared_ptr< T >(); \ + p3 = boost::shared_ptr< T >(); \ + } + +#define TEST_CV_TRUE( T, U ) \ + TEST_CONV( T, U ) \ + TEST_CONV( T, const U ) \ + TEST_CONV( T, volatile U ) \ + TEST_CONV( T, const volatile U ) \ + TEST_CONV( const T, const U ) \ + TEST_CONV( const T, const volatile U ) \ + TEST_CONV( volatile T, volatile U ) \ + TEST_CONV( volatile T, const volatile U ) \ + TEST_CONV( const volatile T, const volatile U ) + int main() { - boost::shared_ptr< X[] > px; + TEST_CV_TRUE( X, X ) + TEST_CV_TRUE( X, void ) + TEST_CV_TRUE( D, B ) - boost::shared_ptr< X const[] > pcx( px ); - boost::shared_ptr< X volatile[] > pvx( px ); + TEST_CV_TRUE( X[], X[] ) + TEST_CV_TRUE( X[3], X[3] ) - boost::shared_ptr< X const volatile[] > pcvx( px ); - boost::shared_ptr< X const volatile[] > pcvx2( pcx ); - boost::shared_ptr< X const volatile[] > pcvx3( pvx ); + TEST_CV_TRUE( X[3], X[] ) - boost::shared_ptr< void > pv( px ); - - boost::shared_ptr< void const > pcv( px ); - boost::shared_ptr< void const > pcv2( pcx ); - - boost::shared_ptr< void volatile > pvv( px ); - boost::shared_ptr< void volatile > pvv2( pvx ); - - boost::shared_ptr< void const volatile > pcvv( px ); - boost::shared_ptr< void const volatile > pcvv2( pcx ); - boost::shared_ptr< void const volatile > pcvv3( pvx ); - boost::shared_ptr< void const volatile > pcvv4( pcvx ); + TEST_CV_TRUE( X[], void ) + TEST_CV_TRUE( X[3], void ) return 0; } diff --git a/test/sp_array_n_test.cpp b/test/sp_array_n_test.cpp new file mode 100644 index 0000000..ccbcc26 --- /dev/null +++ b/test/sp_array_n_test.cpp @@ -0,0 +1,248 @@ +// +// sp_array_n_test.cpp +// +// Copyright (c) 2012 Peter Dimov +// +// 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 +// + +#include +#include +#include +#include +#include +#include + +class X: public boost::enable_shared_from_this< X > +{ +public: + + static int allocations; + static int instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + + void* operator new[]( std::size_t n ) + { + ++allocations; + return ::operator new[]( n ); + } + + void operator delete[]( void* p ) + { + --allocations; + ::operator delete[]( p ); + } + +private: + + X( X const& ); + X& operator=( X const& ); +}; + +int X::allocations = 0; +int X::instances = 0; + +template< class T> class array_deleter +{ +public: + + static int calls; + + void operator()( T * p ) const + { + ++calls; + delete[] p; + } + +private: + + template< class Y > void operator()( Y * p ) const; +}; + +template< class T > int array_deleter< T >::calls = 0; + +int main() +{ + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr px; + BOOST_TEST( !px ); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + + boost::shared_ptr px2( new X[ 3 ] ); + BOOST_TEST( px2 ); + + try + { + px2[0].shared_from_this(); + BOOST_ERROR( "px2[0].shared_from_this() failed to throw" ); + } + catch( boost::bad_weak_ptr const& ) + { + } + catch( ... ) + { + BOOST_ERROR( "px2[0].shared_from_this() threw something else than bad_weak_ptr" ); + } + + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 3 ); + + { + X & rx = px2[ 0 ]; + BOOST_TEST( &rx == px2.get() ); + } + + boost::shared_ptr px3( px2 ); + BOOST_TEST( px3 == px2 ); + BOOST_TEST( !( px2 < px3 ) && !( px3 < px2 ) ); + + { + X const & rx = px3[ 1 ]; + BOOST_TEST( &rx == px3.get() + 1 ); + } + + px3.reset(); + px3 = px2; + BOOST_TEST( px3 == px2 ); + BOOST_TEST( !( px2 < px3 ) && !( px3 < px2 ) ); + + boost::shared_ptr px4( px2 ); + BOOST_TEST( px4 == px2 ); + BOOST_TEST( !( px2 < px4 ) && !( px4 < px2 ) ); + + { + X volatile & rx = px4[ 2 ]; + BOOST_TEST( &rx == px4.get() + 2 ); + } + + px4.reset(); + px4 = px2; + BOOST_TEST( px4 == px2 ); + BOOST_TEST( !( px2 < px4 ) && !( px4 < px2 ) ); + + boost::shared_ptr px5( px2 ); + BOOST_TEST( px5 == px2 ); + BOOST_TEST( !( px2 < px5 ) && !( px5 < px2 ) ); + + px5.reset(); + px5 = px2; + BOOST_TEST( px5 == px2 ); + BOOST_TEST( !( px2 < px5 ) && !( px5 < px2 ) ); + + boost::weak_ptr wp( px ); + BOOST_TEST( wp.lock() == px ); + + boost::weak_ptr wp2( px2 ); + BOOST_TEST( wp2.lock() == px2 ); + + wp2.reset(); + wp2 = px2; + BOOST_TEST( wp2.lock() == px2 ); + + boost::weak_ptr wp3( px2 ); + BOOST_TEST( wp3.lock() == px2 ); + + wp3.reset(); + wp3 = px2; + BOOST_TEST( wp3.lock() == px2 ); + + boost::weak_ptr wp4( px2 ); + BOOST_TEST( wp4.lock() == px2 ); + + wp4.reset(); + wp4 = px2; + BOOST_TEST( wp4.lock() == px2 ); + + boost::weak_ptr wp5( px2 ); + BOOST_TEST( wp5.lock() == px2 ); + + wp5.reset(); + wp5 = px2; + BOOST_TEST( wp5.lock() == px2 ); + + px2.reset(); + + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 3 ); + + px3.reset(); + px4.reset(); + px5.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + + BOOST_TEST( wp2.lock() == 0 ); + BOOST_TEST( wp3.lock() == 0 ); + BOOST_TEST( wp4.lock() == 0 ); + BOOST_TEST( wp5.lock() == 0 ); + } + + { + boost::shared_ptr px( new X[ 5 ], array_deleter< X >() ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 5 ); + + try + { + px[0].shared_from_this(); + BOOST_ERROR( "px[0].shared_from_this() failed to throw" ); + } + catch( boost::bad_weak_ptr const& ) + { + } + catch( ... ) + { + BOOST_ERROR( "px[0].shared_from_this() threw something else than bad_weak_ptr" ); + } + + px.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( array_deleter< X >::calls == 1 ); + } + + { + boost::shared_ptr px( new X[ 6 ], array_deleter< X >(), std::allocator< X >() ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 6 ); + + try + { + px[0].shared_from_this(); + BOOST_ERROR( "px[0].shared_from_this() failed to throw" ); + } + catch( boost::bad_weak_ptr const& ) + { + } + catch( ... ) + { + BOOST_ERROR( "px[0].shared_from_this() threw something else than bad_weak_ptr" ); + } + + px.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( array_deleter< X >::calls == 2 ); + } + + return boost::report_errors(); +} diff --git a/test/sp_convertible_test.cpp b/test/sp_convertible_test.cpp index 7a4a1cb..05b15c1 100644 --- a/test/sp_convertible_test.cpp +++ b/test/sp_convertible_test.cpp @@ -78,7 +78,7 @@ int main() TEST_CV_FALSE( X[3], X[4] ) TEST_CV_FALSE( D[3], B[3] ) - //TEST_CV_TRUE( X[3], X[] ) + TEST_CV_TRUE( X[3], X[] ) TEST_CV_FALSE( X[], X[3] ) TEST_CV_TRUE( X[], void )