diff --git a/include/boost/smart_ptr/detail/local_counted_base.hpp b/include/boost/smart_ptr/detail/local_counted_base.hpp index ebaae19..df652b3 100644 --- a/include/boost/smart_ptr/detail/local_counted_base.hpp +++ b/include/boost/smart_ptr/detail/local_counted_base.hpp @@ -32,7 +32,6 @@ class local_counted_base { private: - local_counted_base( local_counted_base const & ); local_counted_base & operator= ( local_counted_base const & ); private: @@ -48,11 +47,19 @@ public: { } - virtual ~local_counted_base() /*BOOST_NOEXCEPT*/ + BOOST_CONSTEXPR local_counted_base( local_counted_base const & ) BOOST_SP_NOEXCEPT: local_use_count_( initial_ ) { } - void add_ref() + virtual ~local_counted_base() /*BOOST_SP_NOEXCEPT*/ + { + } + + virtual void destroy() BOOST_SP_NOEXCEPT = 0; + + virtual boost::shared_ptr get_shared_ptr() const BOOST_SP_NOEXCEPT = 0; + + void add_ref() BOOST_SP_NOEXCEPT { #if defined( __has_builtin ) # if __has_builtin( __builtin_assume ) @@ -65,13 +72,13 @@ public: local_use_count_ = static_cast( local_use_count_ + 1 ); } - void release() + void release() BOOST_SP_NOEXCEPT { local_use_count_ = static_cast( local_use_count_ - 1 ); if( local_use_count_ == 0 ) { - delete this; + destroy(); } } @@ -83,6 +90,10 @@ public: class local_counted_impl: public local_counted_base { +private: + + local_counted_impl( local_counted_impl const & ); + private: boost::shared_ptr pn_; @@ -100,6 +111,33 @@ public: } #endif + + virtual void destroy() BOOST_SP_NOEXCEPT + { + delete this; + } + + virtual boost::shared_ptr get_shared_ptr() const BOOST_SP_NOEXCEPT + { + return const_pointer_cast( pn_ ); + } +}; + +class local_counted_impl_em: public local_counted_base +{ +public: + + boost::shared_ptr pn_; + + virtual void destroy() BOOST_SP_NOEXCEPT + { + pn_.reset(); + } + + virtual boost::shared_ptr get_shared_ptr() const BOOST_SP_NOEXCEPT + { + return const_pointer_cast( pn_ ); + } }; } // namespace detail diff --git a/include/boost/smart_ptr/local_shared_ptr.hpp b/include/boost/smart_ptr/local_shared_ptr.hpp index 2b3795e..d0e1721 100644 --- a/include/boost/smart_ptr/local_shared_ptr.hpp +++ b/include/boost/smart_ptr/local_shared_ptr.hpp @@ -17,9 +17,121 @@ namespace boost { +template class local_shared_ptr; + namespace detail { +template class local_sp_deleter: public local_counted_impl_em +{ +private: + + D d_; + +public: + + local_sp_deleter(): d_() + { + } + + explicit local_sp_deleter( D const& d ) BOOST_SP_NOEXCEPT: d_( d ) + { + } + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + explicit local_sp_deleter( D&& d ) BOOST_SP_NOEXCEPT: d_( std::move(d) ) + { + } + +#endif + + template void operator()( Y* p ) const BOOST_SP_NOEXCEPT + { + d_( p ); + } + +#if !defined( BOOST_NO_CXX11_NULLPTR ) + + void operator()( boost::detail::sp_nullptr_t p ) const BOOST_SP_NOEXCEPT + { + d_( p ); + } + +#endif +}; + +template< class E, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E > * ppx, Y * p, boost::detail::local_counted_base * & pn ) +{ + boost::detail::sp_assert_convertible< Y, E >(); + + typedef boost::detail::local_sp_deleter< boost::checked_deleter > D; + + boost::shared_ptr p2( p, D() ); + + D * pd = static_cast< D * >( p2._internal_get_untyped_deleter() ); + + pd->pn_ = p2; + + pn = pd; +} + +template< class E, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E[] > * ppx, Y * p, boost::detail::local_counted_base * & pn ) +{ + boost::detail::sp_assert_convertible< Y[], E[] >(); + + typedef boost::detail::local_sp_deleter< boost::checked_array_deleter > D; + + boost::shared_ptr p2( p, D() ); + + D * pd = static_cast< D * >( p2._internal_get_untyped_deleter() ); + + pd->pn_ = p2; + + pn = pd; +} + +template< class E, std::size_t N, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E[N] > * ppx, Y * p, boost::detail::local_counted_base * & pn ) +{ + boost::detail::sp_assert_convertible< Y[N], E[N] >(); + + typedef boost::detail::local_sp_deleter< boost::checked_array_deleter > D; + + boost::shared_ptr p2( p, D() ); + + D * pd = static_cast< D * >( p2._internal_get_untyped_deleter() ); + + pd->pn_ = p2; + + pn = pd; +} + +template< class E, class P, class D > inline void lsp_deleter_construct( boost::local_shared_ptr< E > * ppx, P p, D const& d, boost::detail::local_counted_base * & pn ) +{ + typedef boost::detail::local_sp_deleter D2; + + boost::shared_ptr p2( p, D2( d ) ); + + D2 * pd = static_cast< D2 * >( p2._internal_get_untyped_deleter() ); + + pd->pn_ = p2; + + pn = pd; +} + +template< class E, class P, class D, class A > inline void lsp_allocator_construct( boost::local_shared_ptr< E > * ppx, P p, D const& d, A const& a, boost::detail::local_counted_base * & pn ) +{ + typedef boost::detail::local_sp_deleter D2; + + boost::shared_ptr p2( p, D2( d ), a ); + + D2 * pd = static_cast< D2 * >( p2._internal_get_untyped_deleter() ); + + pd->pn_ = p2; + + pn = pd; +} + } // namespace detail // @@ -73,35 +185,35 @@ public: #endif template - explicit local_shared_ptr( Y * p ): px( p ), - pn( new boost::detail::local_counted_impl( shared_ptr( p ) ) ) + explicit local_shared_ptr( Y * p ): px( p ), pn( 0 ) { + boost::detail::lsp_pointer_construct( this, p, pn ); } - template local_shared_ptr( Y * p, D d ): px( p ), - pn( new boost::detail::local_counted_impl( shared_ptr( p, d ) ) ) + template local_shared_ptr( Y * p, D d ): px( p ), pn( 0 ) { + boost::detail::lsp_deleter_construct( this, p, d, pn ); } #if !defined( BOOST_NO_CXX11_NULLPTR ) - template local_shared_ptr( boost::detail::sp_nullptr_t p, D d ): px( p ), - pn( new boost::detail::local_counted_impl( shared_ptr( p, d ) ) ) + template local_shared_ptr( boost::detail::sp_nullptr_t p, D d ): px( p ), pn( 0 ) { + boost::detail::lsp_deleter_construct( this, p, d, pn ); } #endif - template local_shared_ptr( Y * p, D d, A a ): px( p ), - pn( new boost::detail::local_counted_impl( shared_ptr( p, d, a ) ) ) + template local_shared_ptr( Y * p, D d, A a ): px( p ), pn( 0 ) { + boost::detail::lsp_allocator_construct( this, p, d, a, pn ); } #if !defined( BOOST_NO_CXX11_NULLPTR ) - template local_shared_ptr( boost::detail::sp_nullptr_t p, D d, A a ): px( p ), - pn( new boost::detail::local_counted_impl( shared_ptr( p, d, a ) ) ) + template local_shared_ptr( boost::detail::sp_nullptr_t p, D d, A a ): px( p ), pn( 0 ) { + boost::detail::lsp_allocator_construct( this, p, d, a, pn ); } #endif @@ -360,6 +472,44 @@ public: return pn? pn->local_use_count(): 0; } + // conversions to shared_ptr, weak_ptr + +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) && !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) + template::type> operator shared_ptr() const BOOST_SP_NOEXCEPT +#else + template operator shared_ptr() const BOOST_SP_NOEXCEPT +#endif + { + boost::detail::sp_assert_convertible(); + + if( pn ) + { + return static_pointer_cast( pn->get_shared_ptr() ); + } + else + { + return shared_ptr(); + } + } + +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) && !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) + template::type> operator weak_ptr() const BOOST_SP_NOEXCEPT +#else + template operator weak_ptr() const BOOST_SP_NOEXCEPT +#endif + { + boost::detail::sp_assert_convertible(); + + if( pn ) + { + return static_pointer_cast( pn->get_shared_ptr() ); + } + else + { + return weak_ptr(); + } + } + // swap void swap( local_shared_ptr & r ) BOOST_SP_NOEXCEPT @@ -410,6 +560,31 @@ template inline bool operator!=( boost::detail::sp_nullptr_t, local_sha #endif +template inline bool operator==( local_shared_ptr const & a, shared_ptr const & b ) BOOST_SP_NOEXCEPT +{ + return a.get() == b.get(); +} + +template inline bool operator!=( local_shared_ptr const & a, shared_ptr const & b ) BOOST_SP_NOEXCEPT +{ + return a.get() != b.get(); +} + +template inline bool operator==( shared_ptr const & a, local_shared_ptr const & b ) BOOST_SP_NOEXCEPT +{ + return a.get() == b.get(); +} + +template inline bool operator!=( shared_ptr const & a, local_shared_ptr const & b ) BOOST_SP_NOEXCEPT +{ + return a.get() != b.get(); +} + +template inline bool operator<(local_shared_ptr const & a, local_shared_ptr const & b) BOOST_SP_NOEXCEPT +{ + return a.owner_before( b ); +} + template inline void swap( local_shared_ptr & a, local_shared_ptr & b ) BOOST_SP_NOEXCEPT { a.swap( b ); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a0cf5d6..a6f6b0c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -214,5 +214,9 @@ import testing ; [ run atomic_sp_test.cpp ] [ run local_sp_test.cpp ] + [ run lsp_array_test.cpp ] + [ run lsp_array_n_test.cpp ] + [ run lsp_array_cv_test.cpp ] + [ run lsp_array_cast_test.cpp ] ; } diff --git a/test/local_sp_test.cpp b/test/local_sp_test.cpp index 69cbb30..b31d498 100644 --- a/test/local_sp_test.cpp +++ b/test/local_sp_test.cpp @@ -35,31 +35,29 @@ long X::instances = 0; class incomplete; -template static void test_empty( boost::local_shared_ptr const & p ) -{ - BOOST_TEST( p? false: true ); - BOOST_TEST( !p ); - BOOST_TEST( p.get() == 0 ); - BOOST_TEST( p.local_use_count() == 0 ); -} - // default constructor static void default_constructor() { { boost::local_shared_ptr p; - test_empty( p ); + + BOOST_TEST_EQ( p.get(), static_cast(0) ); + BOOST_TEST_EQ( p.local_use_count(), 0 ); } { boost::local_shared_ptr p; - test_empty( p ); + + BOOST_TEST_EQ( p.get(), static_cast(0) ); + BOOST_TEST_EQ( p.local_use_count(), 0 ); } { boost::local_shared_ptr p; - test_empty( p ); + + BOOST_TEST_EQ( p.get(), static_cast(0) ); + BOOST_TEST_EQ( p.local_use_count(), 0 ); } BOOST_TEST( X::instances == 0 ); @@ -69,7 +67,8 @@ static void default_constructor() BOOST_TEST( X::instances == 0 ); - test_empty( p ); + BOOST_TEST_EQ( p.get(), static_cast(0) ); + BOOST_TEST_EQ( p.local_use_count(), 0 ); } } @@ -81,17 +80,23 @@ static void nullptr_constructor() { boost::local_shared_ptr p( nullptr ); - test_empty( p ); + + BOOST_TEST_EQ( p.get(), static_cast(0) ); + BOOST_TEST_EQ( p.local_use_count(), 0 ); } { boost::local_shared_ptr p( nullptr ); - test_empty( p ); + + BOOST_TEST_EQ( p.get(), static_cast(0) ); + BOOST_TEST_EQ( p.local_use_count(), 0 ); } { boost::local_shared_ptr p( nullptr ); - test_empty( p ); + + BOOST_TEST_EQ( p.get(), static_cast(0) ); + BOOST_TEST_EQ( p.local_use_count(), 0 ); } BOOST_TEST( X::instances == 0 ); @@ -101,7 +106,9 @@ static void nullptr_constructor() BOOST_TEST( X::instances == 0 ); - test_empty( p ); + + BOOST_TEST_EQ( p.get(), static_cast(0) ); + BOOST_TEST_EQ( p.local_use_count(), 0 ); } #endif @@ -333,19 +340,29 @@ static void nullptr_allocator_constructor() template static void empty_copy_test() { boost::local_shared_ptr p1; - test_empty( p1 ); + + BOOST_TEST_EQ( p1.get(), static_cast(0) ); + BOOST_TEST_EQ( p1.local_use_count(), 0 ); boost::local_shared_ptr p2( p1 ); - test_empty( p2 ); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); boost::local_shared_ptr p3( p1 ); - test_empty( p3 ); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); boost::local_shared_ptr p4( p1 ); - test_empty( p4 ); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); boost::local_shared_ptr p5( p3 ); - test_empty( p5 ); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); } template static void test_nonempty_copy( boost::local_shared_ptr const & p1 ) @@ -417,16 +434,24 @@ static void copy_constructor() template static void empty_move_test() { boost::local_shared_ptr p2(( boost::local_shared_ptr() )); - test_empty( p2 ); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); boost::local_shared_ptr p3(( boost::local_shared_ptr() )); - test_empty( p3 ); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); boost::local_shared_ptr p4(( boost::local_shared_ptr() )); - test_empty( p4 ); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); boost::local_shared_ptr p5( std::move(p3) ); - test_empty( p5 ); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); } template static void test_nonempty_move( boost::local_shared_ptr && p1 ) @@ -632,16 +657,24 @@ template static void empty_shared_ptr_copy_test() boost::shared_ptr p1; boost::local_shared_ptr p2( p1 ); - test_empty( p2 ); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); boost::local_shared_ptr p3( p1 ); - test_empty( p3 ); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); boost::local_shared_ptr p4( p1 ); - test_empty( p4 ); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); boost::local_shared_ptr p5( p3 ); - test_empty( p5 ); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); } template static void test_nonempty_shared_ptr_copy( boost::shared_ptr const & p1 ) @@ -714,16 +747,24 @@ static void shared_ptr_copy_constructor() template static void empty_shared_ptr_move_test() { boost::local_shared_ptr p2(( boost::shared_ptr() )); - test_empty( p2 ); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); boost::local_shared_ptr p3(( boost::shared_ptr() )); - test_empty( p3 ); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); boost::local_shared_ptr p4(( boost::shared_ptr() )); - test_empty( p4 ); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); boost::local_shared_ptr p5( std::move(p3) ); - test_empty( p5 ); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); } template static void test_nonempty_shared_ptr_move( boost::shared_ptr && p1 ) @@ -908,53 +949,73 @@ static void unique_ptr_constructor() template static void empty_copy_assign_test() { boost::local_shared_ptr p1; - test_empty( p1 ); + + BOOST_TEST_EQ( p1.get(), static_cast(0) ); + BOOST_TEST_EQ( p1.local_use_count(), 0 ); boost::local_shared_ptr p2; p2 = p1; - test_empty( p2 ); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); boost::local_shared_ptr p3; p3 = p1; - test_empty( p3 ); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); boost::local_shared_ptr p4; p4 = p1; - test_empty( p4 ); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); boost::local_shared_ptr p5; p5 = p3; - test_empty( p5 ); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); } template static void empty_copy_assign_test_() { boost::local_shared_ptr p1; - test_empty( p1 ); + + BOOST_TEST_EQ( p1.get(), static_cast(0) ); + BOOST_TEST_EQ( p1.local_use_count(), 0 ); boost::local_shared_ptr p2( static_cast(0) ); p2 = p1; - test_empty( p2 ); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); boost::local_shared_ptr p3( static_cast(0) ); p3 = p1; - test_empty( p3 ); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); boost::local_shared_ptr p4( static_cast(0) ); p4 = p1; - test_empty( p4 ); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); boost::local_shared_ptr p5( static_cast(0) ); p5 = p3; - test_empty( p5 ); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); } template static void test_nonempty_copy_assign( boost::local_shared_ptr p2, boost::local_shared_ptr const & p1 ) @@ -1047,22 +1108,30 @@ template static void empty_move_assign_test() boost::local_shared_ptr p2; p2 = boost::local_shared_ptr(); - test_empty( p2 ); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); boost::local_shared_ptr p3; p3 = boost::local_shared_ptr(); - test_empty( p3 ); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); boost::local_shared_ptr p4; p4 = boost::local_shared_ptr(); - test_empty( p4 ); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); boost::local_shared_ptr p5; p5 = std::move( p3 ); - test_empty( p5 ); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); } template static void empty_move_assign_test_() @@ -1070,22 +1139,30 @@ template static void empty_move_assign_test_() boost::local_shared_ptr p2( static_cast(0) ); p2 = boost::local_shared_ptr(); - test_empty( p2 ); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); boost::local_shared_ptr p3( static_cast(0) ); p3 = boost::local_shared_ptr(); - test_empty( p3 ); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); boost::local_shared_ptr p4( static_cast(0) ); p4 = boost::local_shared_ptr(); - test_empty( p4 ); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); boost::local_shared_ptr p5( static_cast(0) ); p5 = std::move( p3 ); - test_empty( p5 ); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); } template static void test_nonempty_move_assign( boost::local_shared_ptr p2, boost::local_shared_ptr && p1 ) @@ -1236,6 +1313,372 @@ static void nullptr_assignment() #endif +// default_reset + +template static void test_default_reset( boost::local_shared_ptr p1 ) +{ + p1.reset(); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST( p1.local_use_count() == 0 ); +} + +template static void empty_default_reset_test() +{ + test_default_reset( boost::local_shared_ptr() ); + test_default_reset( boost::local_shared_ptr() ); + test_default_reset( boost::local_shared_ptr() ); + test_default_reset( boost::local_shared_ptr() ); +} + +template static void null_default_reset_test() +{ + test_default_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_default_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_default_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_default_reset( boost::local_shared_ptr( static_cast(0) ) ); +} + +template static void new_default_reset_test() +{ + test_default_reset( boost::local_shared_ptr( new T() ) ); + test_default_reset( boost::local_shared_ptr( new T const() ) ); + test_default_reset( boost::local_shared_ptr( new T volatile() ) ); + test_default_reset( boost::local_shared_ptr( new T const volatile() ) ); +} + +static void default_reset() +{ + empty_default_reset_test(); + empty_default_reset_test(); + empty_default_reset_test(); + empty_default_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + null_default_reset_test(); + null_default_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + new_default_reset_test(); + new_default_reset_test(); + + BOOST_TEST( X::instances == 0 ); +} + +// shared_ptr copy assignment + +template static void empty_shared_ptr_copy_assign_test() +{ + boost::shared_ptr sp1; + + BOOST_TEST_EQ( sp1.get(), static_cast(0) ); + BOOST_TEST_EQ( sp1.use_count(), 0 ); + + boost::local_shared_ptr p2; + + p2 = sp1; + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); + + boost::local_shared_ptr p3; + + p3 = sp1; + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); + + boost::local_shared_ptr p4; + + p4 = sp1; + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); + + boost::shared_ptr sp2( sp1 ); + boost::local_shared_ptr p5; + + p5 = sp2; + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); +} + +template static void empty_shared_ptr_copy_assign_test_() +{ + boost::shared_ptr sp1; + + BOOST_TEST_EQ( sp1.get(), static_cast(0) ); + BOOST_TEST_EQ( sp1.use_count(), 0 ); + + boost::local_shared_ptr p2( static_cast(0) ); + + p2 = sp1; + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); + + boost::local_shared_ptr p3( static_cast(0) ); + + p3 = sp1; + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); + + boost::local_shared_ptr p4( static_cast(0) ); + + p4 = sp1; + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); + + boost::shared_ptr sp2( sp1 ); + boost::local_shared_ptr p5( static_cast(0) ); + + p5 = sp2; + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); +} + +template static void test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr p2, boost::shared_ptr const & p1 ) +{ + long k = p1.use_count(); + + p2 = p1; + + BOOST_TEST( p2.get() == p1.get() ); + BOOST_TEST( p2.local_use_count() == 1 ); + BOOST_TEST( p1.use_count() == k + 1 ); + + p2.reset(); + + BOOST_TEST( p1.use_count() == k ); +} + +template static void null_shared_ptr_copy_assign_test() +{ + boost::shared_ptr p1( static_cast(0) ); + + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr( static_cast(0) ), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr( static_cast(0) ), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr( static_cast(0) ), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr( static_cast(0) ), p1 ); + + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); +} + +template static void new_shared_ptr_copy_assign_test() +{ + boost::shared_ptr p1( new T() ); + + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr( static_cast(0) ), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr( static_cast(0) ), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr( static_cast(0) ), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr( static_cast(0) ), p1 ); + + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr( new T() ), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr( new T const() ), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr( new T volatile() ), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr( new T const volatile() ), p1 ); + + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); + test_nonempty_shared_ptr_copy_assign( boost::local_shared_ptr(), p1 ); +} + +static void shared_ptr_copy_assignment() +{ + empty_shared_ptr_copy_assign_test(); + empty_shared_ptr_copy_assign_test(); + empty_shared_ptr_copy_assign_test_(); + empty_shared_ptr_copy_assign_test(); + empty_shared_ptr_copy_assign_test_(); + + BOOST_TEST( X::instances == 0 ); + + null_shared_ptr_copy_assign_test(); + null_shared_ptr_copy_assign_test(); + + BOOST_TEST( X::instances == 0 ); + + new_shared_ptr_copy_assign_test(); + new_shared_ptr_copy_assign_test(); + + BOOST_TEST( X::instances == 0 ); +} + +// shared_ptr_move assignment + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + +template static void empty_shared_ptr_move_assign_test() +{ + boost::local_shared_ptr p2; + + p2 = boost::shared_ptr(); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); + + boost::local_shared_ptr p3; + + p3 = boost::shared_ptr(); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); + + boost::local_shared_ptr p4; + + p4 = boost::shared_ptr(); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); + + boost::local_shared_ptr p5; + + p5 = boost::shared_ptr(); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); +} + +template static void empty_shared_ptr_move_assign_test_() +{ + boost::local_shared_ptr p2( static_cast(0) ); + + p2 = boost::shared_ptr(); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); + + boost::local_shared_ptr p3( static_cast(0) ); + + p3 = boost::shared_ptr(); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); + + boost::local_shared_ptr p4( static_cast(0) ); + + p4 = boost::shared_ptr(); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); + + boost::local_shared_ptr p5( static_cast(0) ); + + p5 = boost::shared_ptr(); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); +} + +template static void test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr p2, boost::shared_ptr && p1 ) +{ + U* q = p1.get(); + long k = p1.use_count(); + + p2 = std::move( p1 ); + + BOOST_TEST_EQ( p2.get(), q ); + BOOST_TEST_EQ( p2.local_use_count(), 1 ); + + BOOST_TEST( p1.get() == 0 ); + BOOST_TEST( p1.use_count() == 0 ); + + boost::shared_ptr p3( p2 ); + + BOOST_TEST_EQ( p3.get(), q ); + BOOST_TEST_EQ( p3.use_count(), k + 1 ); +} + +template static void null_shared_ptr_move_assign_test() +{ + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( static_cast(0) ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( static_cast(0) ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( static_cast(0) ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( static_cast(0) ) ); + + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr( static_cast(0) ), boost::shared_ptr( static_cast(0) ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr( static_cast(0) ), boost::shared_ptr( static_cast(0) ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr( static_cast(0) ), boost::shared_ptr( static_cast(0) ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr( static_cast(0) ), boost::shared_ptr( static_cast(0) ) ); + + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( static_cast(0) ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( static_cast(0) ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( static_cast(0) ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( static_cast(0) ) ); +} + +template static void new_shared_ptr_move_assign_test() +{ + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( new T() ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( new T() ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( new T() ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( new T() ) ); + + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr( static_cast(0) ), boost::shared_ptr( new T() ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr( static_cast(0) ), boost::shared_ptr( new T() ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr( static_cast(0) ), boost::shared_ptr( new T() ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr( static_cast(0) ), boost::shared_ptr( new T() ) ); + + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr( new T() ), boost::shared_ptr( new T() ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr( new T const() ), boost::shared_ptr( new T() ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr( new T volatile() ), boost::shared_ptr( new T() ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr( new T const volatile() ), boost::shared_ptr( new T() ) ); + + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( new T() ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( new T() ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( new T() ) ); + test_nonempty_shared_ptr_move_assign( boost::local_shared_ptr(), boost::shared_ptr( new T() ) ); +} + +static void shared_ptr_move_assignment() +{ + empty_shared_ptr_move_assign_test(); + empty_shared_ptr_move_assign_test(); + empty_shared_ptr_move_assign_test_(); + empty_shared_ptr_move_assign_test(); + empty_shared_ptr_move_assign_test_(); + + BOOST_TEST( X::instances == 0 ); + + null_shared_ptr_move_assign_test(); + null_shared_ptr_move_assign_test(); + + BOOST_TEST( X::instances == 0 ); + + new_shared_ptr_move_assign_test(); + new_shared_ptr_move_assign_test(); + + BOOST_TEST( X::instances == 0 ); +} + +#else + +static void shared_ptr_move_assignment() +{ +} + +#endif + // main int main() @@ -1257,10 +1700,11 @@ int main() copy_assignment(); move_assignment(); nullptr_assignment(); - // shared_ptr_copy_assignment(); - // shared_ptr_move_assignment(); + shared_ptr_copy_assignment(); + shared_ptr_move_assignment(); // unique_ptr_assignment(); + default_reset(); // pointer_reset(); // deleter_reset(); // allocator_reset(); diff --git a/test/lsp_array_cast_test.cpp b/test/lsp_array_cast_test.cpp new file mode 100644 index 0000000..183cddc --- /dev/null +++ b/test/lsp_array_cast_test.cpp @@ -0,0 +1,202 @@ +// +// lsp_array_cast_test.cpp +// +// Copyright 2012, 2017 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 + +struct X +{ +}; + +void static_cast_test() +{ + { + boost::local_shared_ptr pv; + + boost::local_shared_ptr pi = boost::static_pointer_cast( pv ); + BOOST_TEST( pi.get() == 0 ); + + boost::local_shared_ptr pi2 = boost::static_pointer_cast( pv ); + BOOST_TEST( pi2.get() == 0 ); + + boost::local_shared_ptr px = boost::static_pointer_cast( pv ); + BOOST_TEST( px.get() == 0 ); + + boost::local_shared_ptr px2 = boost::static_pointer_cast( pv ); + BOOST_TEST( px2.get() == 0 ); + } + + { + boost::local_shared_ptr pi( new int[2] ); + boost::local_shared_ptr pv( pi ); + + boost::local_shared_ptr pi2 = boost::static_pointer_cast( pv ); + BOOST_TEST(pi.get() == pi2.get()); + BOOST_TEST(!(pi < pi2 || pi2 < pi)); + + boost::local_shared_ptr pi3 = boost::static_pointer_cast( pv ); + BOOST_TEST(pi.get() == pi3.get()); + BOOST_TEST(!(pi < pi3 || pi3 < pi)); + + boost::local_shared_ptr pv2( pi3 ); + + boost::local_shared_ptr pi4 = boost::static_pointer_cast( pv2 ); + BOOST_TEST(pi.get() == pi4.get()); + BOOST_TEST(!(pi < pi4 || pi4 < pi)); + } + + { + boost::local_shared_ptr px( new X[4] ); + boost::local_shared_ptr pv( px ); + + boost::local_shared_ptr px2 = boost::static_pointer_cast( pv ); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + + boost::local_shared_ptr px3 = boost::static_pointer_cast( pv ); + BOOST_TEST(px.get() == px3.get()); + BOOST_TEST(!(px < px3 || px3 < px)); + + boost::local_shared_ptr pv2( px3 ); + + boost::local_shared_ptr px4 = boost::static_pointer_cast( pv2 ); + BOOST_TEST(px.get() == px4.get()); + BOOST_TEST(!(px < px4 || px4 < px)); + } +} + +void const_cast_test() +{ + { + boost::local_shared_ptr px; + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST( px2.get() == 0 ); + } + + { + boost::local_shared_ptr px; + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST( px2.get() == 0 ); + } + + { + boost::local_shared_ptr px; + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST( px2.get() == 0 ); + } + + { + boost::local_shared_ptr px; + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST( px2.get() == 0 ); + } + + { + boost::local_shared_ptr px( new int[3] ); + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + } + + { + boost::local_shared_ptr px( new int[3] ); + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + } + + { + boost::local_shared_ptr px( new X[4] ); + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + } + + { + boost::local_shared_ptr px( new X[4] ); + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + } +} + +void reinterpret_cast_test() +{ + { + boost::local_shared_ptr pi; + BOOST_TEST( pi.get() == 0 ); + + boost::local_shared_ptr pi2 = boost::reinterpret_pointer_cast( pi ); + BOOST_TEST( pi2.get() == 0 ); + + boost::local_shared_ptr pi3 = boost::reinterpret_pointer_cast( pi2 ); + BOOST_TEST( pi3.get() == 0 ); + } + + { + boost::local_shared_ptr px; + BOOST_TEST( px.get() == 0 ); + + boost::local_shared_ptr px2 = boost::reinterpret_pointer_cast( px ); + BOOST_TEST( px2.get() == 0 ); + + boost::local_shared_ptr px3 = boost::reinterpret_pointer_cast( px2 ); + BOOST_TEST( px3.get() == 0 ); + } + + { + boost::local_shared_ptr pi( new int[2] ); + + boost::local_shared_ptr pi2 = boost::reinterpret_pointer_cast( pi ); + BOOST_TEST(pi.get() == pi2.get()); + BOOST_TEST(!(pi < pi2 || pi2 < pi)); + + boost::local_shared_ptr pi3 = boost::reinterpret_pointer_cast( pi2 ); + BOOST_TEST(pi.get() == pi3.get()); + BOOST_TEST(!(pi < pi3 || pi3 < pi)); + + boost::local_shared_ptr pi4 = boost::reinterpret_pointer_cast( pi3 ); + BOOST_TEST(pi.get() == pi4.get()); + BOOST_TEST(!(pi < pi4 || pi4 < pi)); + } + + { + boost::local_shared_ptr px( new X[4] ); + + boost::local_shared_ptr px2 = boost::reinterpret_pointer_cast( px ); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + + boost::local_shared_ptr px3 = boost::reinterpret_pointer_cast( px2 ); + BOOST_TEST(px.get() == px3.get()); + BOOST_TEST(!(px < px3 || px3 < px)); + + boost::local_shared_ptr px4 = boost::reinterpret_pointer_cast( px3 ); + BOOST_TEST(px.get() == px4.get()); + BOOST_TEST(!(px < px4 || px4 < px)); + } +} + +int main() +{ + static_cast_test(); + const_cast_test(); + reinterpret_cast_test(); + + return boost::report_errors(); +} diff --git a/test/lsp_array_cv_test.cpp b/test/lsp_array_cv_test.cpp new file mode 100644 index 0000000..869d206 --- /dev/null +++ b/test/lsp_array_cv_test.cpp @@ -0,0 +1,60 @@ +// +// lsp_array_cv_test.cpp +// +// Copyright 2012, 2017 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 + +struct X +{ +}; + +class B +{ +}; + +class D: public B +{ +}; + +#define TEST_CONV( T, U ) \ + { \ + boost::local_shared_ptr< T > p1; \ + boost::local_shared_ptr< U > p2( p1 ); \ + p2 = p1; \ + boost::local_shared_ptr< U > p3 = boost::local_shared_ptr< T >(); \ + p3 = boost::local_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() +{ + TEST_CV_TRUE( X, X ) + TEST_CV_TRUE( X, void ) + TEST_CV_TRUE( D, B ) + + TEST_CV_TRUE( X[], X[] ) + TEST_CV_TRUE( X[3], X[3] ) + + TEST_CV_TRUE( X[3], X[] ) + + TEST_CV_TRUE( X[], void ) + TEST_CV_TRUE( X[3], void ) + + return 0; +} diff --git a/test/lsp_array_n_test.cpp b/test/lsp_array_n_test.cpp new file mode 100644 index 0000000..a31e264 --- /dev/null +++ b/test/lsp_array_n_test.cpp @@ -0,0 +1,248 @@ +// +// lsp_array_n_test.cpp +// +// Copyright 2012, 2017 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::local_shared_ptr px; + BOOST_TEST( !px ); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + + boost::local_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::local_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::local_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::local_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::local_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::local_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/lsp_array_test.cpp b/test/lsp_array_test.cpp new file mode 100644 index 0000000..77728ea --- /dev/null +++ b/test/lsp_array_test.cpp @@ -0,0 +1,311 @@ +// +// lsp_array_test.cpp +// +// Copyright 2012, 2017 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::local_shared_ptr px; + BOOST_TEST( !px ); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + + boost::local_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::local_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::local_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::local_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 ); + } + +#if !defined( BOOST_NO_CXX11_SMART_PTR ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + { + std::unique_ptr px( new X[ 4 ] ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 4 ); + + boost::local_shared_ptr px2( std::move( px ) ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 4 ); + BOOST_TEST( px.get() == 0 ); + + 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" ); + } + + px2.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + } + + { + std::unique_ptr px( new X[ 4 ] ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 4 ); + + boost::local_shared_ptr px2; + px2 = std::move( px ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 4 ); + BOOST_TEST( px.get() == 0 ); + + 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" ); + } + + px2.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + } + +#endif + + { + boost::local_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::local_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(); +}