diff --git a/include/boost/detail/shared_count.hpp b/include/boost/detail/shared_count.hpp index 085b12f..1eae671 100644 --- a/include/boost/detail/shared_count.hpp +++ b/include/boost/detail/shared_count.hpp @@ -46,6 +46,8 @@ int const weak_count_id = 0x298C38A4; #endif +struct sp_nothrow_tag {}; + class weak_count; class shared_count @@ -216,6 +218,7 @@ public: } explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0 + shared_count( weak_count const & r, sp_nothrow_tag ); // constructs an empty *this when r.use_count() == 0 shared_count & operator= (shared_count const & r) // nothrow { @@ -248,6 +251,11 @@ public: return use_count() == 1; } + bool empty() const // nothrow + { + return pi_ == 0; + } + friend inline bool operator==(shared_count const & a, shared_count const & b) { return a.pi_ == b.pi_; @@ -364,6 +372,17 @@ inline shared_count::shared_count( weak_count const & r ): pi_( r.pi_ ) } } +inline shared_count::shared_count( weak_count const & r, sp_nothrow_tag ): pi_( r.pi_ ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif +{ + if( pi_ != 0 && !pi_->add_ref_lock() ) + { + pi_ = 0; + } +} + } // namespace detail } // namespace boost diff --git a/include/boost/detail/sp_counted_base.hpp b/include/boost/detail/sp_counted_base.hpp index f2e59b9..312893d 100644 --- a/include/boost/detail/sp_counted_base.hpp +++ b/include/boost/detail/sp_counted_base.hpp @@ -23,6 +23,10 @@ # include +#elif defined( BOOST_SP_USE_SPINLOCK ) + +# include + #elif defined( BOOST_SP_USE_PTHREADS ) # include diff --git a/include/boost/detail/sp_counted_base_spin.hpp b/include/boost/detail/sp_counted_base_spin.hpp new file mode 100644 index 0000000..610a468 --- /dev/null +++ b/include/boost/detail/sp_counted_base_spin.hpp @@ -0,0 +1,131 @@ +#ifndef BOOST_DETAIL_SP_COUNTED_BASE_SPIN_HPP_INCLUDED +#define BOOST_DETAIL_SP_COUNTED_BASE_SPIN_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/sp_counted_base_spin.hpp - spinlock pool atomic emulation +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2008 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 + +namespace boost +{ + +namespace detail +{ + +inline int atomic_exchange_and_add( int * pw, int dv ) +{ + spinlock_pool<1>::scoped_lock lock( pw ); + + int r = *pw; + *pw += dv; + return r; +} + +inline void atomic_increment( int * pw ) +{ + spinlock_pool<1>::scoped_lock lock( pw ); + ++*pw; +} + +inline int atomic_conditional_increment( int * pw ) +{ + spinlock_pool<1>::scoped_lock lock( pw ); + + int rv = *pw; + if( rv != 0 ) ++*pw; + return rv; +} + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + int use_count_; // #shared + int weak_count_; // #weak + (#shared != 0) + +public: + + sp_counted_base(): use_count_( 1 ), weak_count_( 1 ) + { + } + + virtual ~sp_counted_base() // nothrow + { + } + + // dispose() is called when use_count_ drops to zero, to release + // the resources managed by *this. + + virtual void dispose() = 0; // nothrow + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + + void add_ref_copy() + { + atomic_increment( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + return atomic_conditional_increment( &use_count_ ) != 0; + } + + void release() // nothrow + { + if( atomic_exchange_and_add( &use_count_, -1 ) == 1 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_exchange_and_add( &weak_count_, -1 ) == 1 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + spinlock_pool<1>::scoped_lock lock( &use_count_ ); + return use_count_; + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_SP_COUNTED_BASE_SPIN_HPP_INCLUDED diff --git a/include/boost/detail/spinlock.hpp b/include/boost/detail/spinlock.hpp new file mode 100644 index 0000000..e273647 --- /dev/null +++ b/include/boost/detail/spinlock.hpp @@ -0,0 +1,47 @@ +#ifndef BOOST_DETAIL_SPINLOCK_HPP_INCLUDED +#define BOOST_DETAIL_SPINLOCK_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/spinlock.hpp +// +// Copyright (c) 2008 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) +// +// struct spinlock +// { +// void lock(); +// bool try_lock(); +// void unlock(); +// +// class scoped_lock; +// }; +// +// #define BOOST_DETAIL_SPINLOCK_INIT +// + +#include + +#if defined(__GNUC__) && defined( __arm__ ) +# include +#elif defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) +# include +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# include +#elif defined(BOOST_HAS_PTHREADS) +# include +#elif !defined(BOOST_HAS_THREADS) +# include +#else +# error Unrecognized threading platform +#endif + +#endif // #ifndef BOOST_DETAIL_SPINLOCK_HPP_INCLUDED diff --git a/include/boost/detail/spinlock_gcc_arm.hpp b/include/boost/detail/spinlock_gcc_arm.hpp new file mode 100644 index 0000000..c21163b --- /dev/null +++ b/include/boost/detail/spinlock_gcc_arm.hpp @@ -0,0 +1,85 @@ +#ifndef BOOST_DETAIL_SPINLOCK_GCC_ARM_HPP_INCLUDED +#define BOOST_DETAIL_SPINLOCK_GCC_ARM_HPP_INCLUDED + +// +// Copyright (c) 2008 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 + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + int v_; + +public: + + bool try_lock() + { + int r; + + __asm__ __volatile__( + "swp %0, %1, [%2]": + "=&r"( r ): // outputs + "r"( 1 ), "r"( &v_ ): // inputs + "memory", "cc" ); + + return r == 0; + } + + void lock() + { + for( unsigned k = 0; !try_lock(); ++k ) + { + boost::detail::yield( k ); + } + } + + void unlock() + { + __asm__ __volatile__( "" ::: "memory" ); + *const_cast< int volatile* >( &v_ ) = 0; + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT {0} + +#endif // #ifndef BOOST_DETAIL_SPINLOCK_GCC_ARM_HPP_INCLUDED diff --git a/include/boost/detail/spinlock_nt.hpp b/include/boost/detail/spinlock_nt.hpp new file mode 100644 index 0000000..f03ba08 --- /dev/null +++ b/include/boost/detail/spinlock_nt.hpp @@ -0,0 +1,89 @@ +#ifndef BOOST_DETAIL_SPINLOCK_NT_HPP_INCLUDED +#define BOOST_DETAIL_SPINLOCK_NT_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// Copyright (c) 2008 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 + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + bool locked_; + +public: + + inline bool try_lock() + { + if( locked_ ) + { + return false; + } + else + { + locked_ = true; + return true; + } + } + + inline void lock() + { + BOOST_ASSERT( !locked_ ); + locked_ = true; + } + + inline void unlock() + { + BOOST_ASSERT( locked_ ); + locked_ = false; + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT { false } + +#endif // #ifndef BOOST_DETAIL_SPINLOCK_NT_HPP_INCLUDED diff --git a/include/boost/detail/spinlock_pool.hpp b/include/boost/detail/spinlock_pool.hpp new file mode 100644 index 0000000..92d26cb --- /dev/null +++ b/include/boost/detail/spinlock_pool.hpp @@ -0,0 +1,85 @@ +#ifndef BOOST_DETAIL_SPINLOCK_POOL_HPP_INCLUDED +#define BOOST_DETAIL_SPINLOCK_POOL_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/spinlock_pool.hpp +// +// Copyright (c) 2008 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) +// +// spinlock_pool<0> is reserved for atomic<>, when/if it arrives +// spinlock_pool<1> is reserved for shared_ptr reference counts +// spinlock_pool<2> is reserved for shared_ptr atomic access +// + +#include + +namespace boost +{ + +namespace detail +{ + +template< int I > class spinlock_pool +{ +private: + + static spinlock pool_[ 41 ]; + +public: + + static spinlock & spinlock_for( void const * pv ) + { + size_t i = reinterpret_cast< size_t >( pv ) % 41; + return pool_[ i ]; + } + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( void const * pv ): sp_( spinlock_for( pv ) ) + { + sp_.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +template< int I > spinlock spinlock_pool< I >::pool_[ 41 ] = +{ + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, + BOOST_DETAIL_SPINLOCK_INIT +}; + +} // namespace detail +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_SPINLOCK_POOL_HPP_INCLUDED diff --git a/include/boost/detail/spinlock_pt.hpp b/include/boost/detail/spinlock_pt.hpp new file mode 100644 index 0000000..dfb2d6f --- /dev/null +++ b/include/boost/detail/spinlock_pt.hpp @@ -0,0 +1,79 @@ +#ifndef BOOST_DETAIL_SPINLOCK_PT_HPP_INCLUDED +#define BOOST_DETAIL_SPINLOCK_PT_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// Copyright (c) 2008 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 + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + pthread_mutex_t v_; + +public: + + bool try_lock() + { + return pthread_mutex_trylock( &v_ ) == 0; + } + + void lock() + { + pthread_mutex_lock( &v_ ); + } + + void unlock() + { + pthread_mutex_unlock( &v_ ); + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT { PTHREAD_MUTEX_INITIALIZER } + +#endif // #ifndef BOOST_DETAIL_SPINLOCK_PT_HPP_INCLUDED diff --git a/include/boost/detail/spinlock_sync.hpp b/include/boost/detail/spinlock_sync.hpp new file mode 100644 index 0000000..d602365 --- /dev/null +++ b/include/boost/detail/spinlock_sync.hpp @@ -0,0 +1,83 @@ +#ifndef BOOST_DETAIL_SPINLOCK_SYNC_HPP_INCLUDED +#define BOOST_DETAIL_SPINLOCK_SYNC_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// Copyright (c) 2008 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 + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + int v_; + +public: + + bool try_lock() + { + int r = __sync_lock_test_and_set( &v_, 1 ); + return r == 0; + } + + void lock() + { + for( unsigned k = 0; !try_lock(); ++k ) + { + boost::detail::yield( k ); + } + } + + void unlock() + { + __sync_lock_release( &v_ ); + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT {0} + +#endif // #ifndef BOOST_DETAIL_SPINLOCK_SYNC_HPP_INCLUDED diff --git a/include/boost/detail/spinlock_w32.hpp b/include/boost/detail/spinlock_w32.hpp new file mode 100644 index 0000000..76cfe8f --- /dev/null +++ b/include/boost/detail/spinlock_w32.hpp @@ -0,0 +1,113 @@ +#ifndef BOOST_DETAIL_SPINLOCK_W32_HPP_INCLUDED +#define BOOST_DETAIL_SPINLOCK_W32_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// Copyright (c) 2008 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 + +// BOOST_COMPILER_FENCE + +#if defined(__INTEL_COMPILER) + +#define BOOST_COMPILER_FENCE __memory_barrier(); + +#elif defined( _MSC_VER ) && _MSC_VER >= 1310 + +extern "C" void _ReadWriteBarrier(); +#pragma intrinsic( _ReadWriteBarrier ) + +#define BOOST_COMPILER_FENCE _ReadWriteBarrier(); + +#elif defined(__GNUC__) + +#define BOOST_COMPILER_FENCE __asm__ __volatile__( "" ::: "memory" ); + +#else + +#define BOOST_COMPILER_FENCE + +#endif + +// + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + long v_; + +public: + + bool try_lock() + { + long r = BOOST_INTERLOCKED_EXCHANGE( &v_, 1 ); + + BOOST_COMPILER_FENCE + + return r == 0; + } + + void lock() + { + for( unsigned k = 0; !try_lock(); ++k ) + { + boost::detail::yield( k ); + } + } + + void unlock() + { + BOOST_COMPILER_FENCE + *const_cast< long volatile* >( &v_ ) = 0; + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT {0} + +#endif // #ifndef BOOST_DETAIL_SPINLOCK_W32_HPP_INCLUDED diff --git a/include/boost/detail/yield_k.hpp b/include/boost/detail/yield_k.hpp new file mode 100644 index 0000000..d856d57 --- /dev/null +++ b/include/boost/detail/yield_k.hpp @@ -0,0 +1,145 @@ +#ifndef BOOST_DETAIL_YIELD_K_HPP_INCLUDED +#define BOOST_DETAIL_YIELD_K_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/yield_k.hpp +// +// Copyright (c) 2008 Peter Dimov +// +// void yield( unsigned k ); +// +// Typical use: +// +// for( unsigned k = 0; !try_lock(); ++k ) yield( k ); +// +// 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 + +// BOOST_SMT_PAUSE + +#if defined(_MSC_VER) && _MSC_VER >= 1310 && ( defined(_M_IX86) || defined(_M_X64) ) + +extern "C" void _mm_pause(); +#pragma intrinsic( _mm_pause ) + +#define BOOST_SMT_PAUSE _mm_pause(); + +#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) + +#define BOOST_SMT_PAUSE __asm__ __volatile__( "rep; nop" ::: "memory" ); + +#endif + +// + +#if defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ ) || defined( __CYGWIN__ ) + +#if defined( BOOST_USE_WINDOWS_H ) +# include +#endif + +namespace boost +{ + +namespace detail +{ + +#if !defined( BOOST_USE_WINDOWS_H ) + extern "C" void __stdcall Sleep( unsigned ms ); +#endif + +inline void yield( unsigned k ) +{ + if( k < 4 ) + { + } +#if defined( BOOST_SMT_PAUSE ) + else if( k < 16 ) + { + BOOST_SMT_PAUSE + } +#endif + else if( k < 32 ) + { + Sleep( 0 ); + } + else + { + Sleep( 1 ); + } +} + +} // namespace detail + +} // namespace boost + +#elif defined( BOOST_HAS_PTHREADS ) + +#include +#include + +namespace boost +{ + +namespace detail +{ + +inline void yield( unsigned k ) +{ + if( k < 4 ) + { + } +#if defined( BOOST_SMT_PAUSE ) + else if( k < 16 ) + { + BOOST_SMT_PAUSE + } +#endif + else if( k < 32 || k & 1 ) + { + sched_yield(); + } + else + { + struct timespec rqtp = { 0 }; + + rqtp.tv_sec = 0; + rqtp.tv_nsec = 1000; + + nanosleep( &rqtp, 0 ); + } +} + +} // namespace detail + +} // namespace boost + +#else + +namespace boost +{ + +namespace detail +{ + +inline void yield( unsigned ) +{ +} + +} // namespace detail + +} // namespace boost + +#endif + +#endif // #ifndef BOOST_DETAIL_YIELD_K_HPP_INCLUDED diff --git a/include/boost/scoped_array.hpp b/include/boost/scoped_array.hpp index 667dfff..fcb80f6 100644 --- a/include/boost/scoped_array.hpp +++ b/include/boost/scoped_array.hpp @@ -46,6 +46,9 @@ private: typedef scoped_array this_type; + void operator==( scoped_array const& ) const; + void operator!=( scoped_array const& ) const; + public: typedef T element_type; diff --git a/include/boost/scoped_ptr.hpp b/include/boost/scoped_ptr.hpp index 651deed..279cec3 100644 --- a/include/boost/scoped_ptr.hpp +++ b/include/boost/scoped_ptr.hpp @@ -47,6 +47,9 @@ private: typedef scoped_ptr this_type; + void operator==( scoped_ptr const& ) const; + void operator!=( scoped_ptr const& ) const; + public: typedef T element_type; diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index 5e1abd8..6f4d49a 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -31,7 +31,14 @@ #include // for std::swap #include // for std::less #include // for std::bad_cast + +#if !defined(BOOST_NO_IOSTREAM) +#if !defined(BOOST_NO_IOSFWD) #include // for std::basic_ostream +#else +#include +#endif +#endif #ifdef BOOST_MSVC // moved here to work around VC++ compiler crash # pragma warning(push) @@ -207,6 +214,15 @@ public: px = r.px; } + template + shared_ptr( weak_ptr const & r, boost::detail::sp_nothrow_tag ): px( 0 ), pn( r.pn, boost::detail::sp_nothrow_tag() ) // never throws + { + if( !pn.empty() ) + { + px = r.px; + } + } + template shared_ptr(shared_ptr const & r): px(r.px), pn(r.pn) // never throws { @@ -555,6 +571,8 @@ template inline T * get_pointer(shared_ptr const & p) // operator<< +#if !defined(BOOST_NO_IOSTREAM) + #if defined(__GNUC__) && (__GNUC__ < 3) template std::ostream & operator<< (std::ostream & os, shared_ptr const & p) @@ -584,6 +602,8 @@ template std::basic_ostream & operator<< (std:: #endif // __GNUC__ < 3 +#endif // !defined(BOOST_NO_IOSTREAM) + // get_deleter #if ( defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3) ) || \ diff --git a/include/boost/weak_ptr.hpp b/include/boost/weak_ptr.hpp index ae606f2..4335738 100644 --- a/include/boost/weak_ptr.hpp +++ b/include/boost/weak_ptr.hpp @@ -93,31 +93,7 @@ public: shared_ptr lock() const // never throws { -#if defined(BOOST_HAS_THREADS) - - // optimization: avoid throw overhead - if(expired()) - { - return shared_ptr(); - } - - try - { - return shared_ptr(*this); - } - catch(bad_weak_ptr const &) - { - // Q: how can we get here? - // A: another thread may have invalidated r after the use_count test above. - return shared_ptr(); - } - -#else - - // optimization: avoid try/catch overhead when single threaded - return expired()? shared_ptr(): shared_ptr(*this); - -#endif + return shared_ptr( *this, boost::detail::sp_nothrow_tag() ); } long use_count() const // never throws diff --git a/shared_ptr.htm b/shared_ptr.htm index e108278..5b4444f 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -373,8 +373,8 @@ q = p;
long use_count() const; // never throws

Returns: the number of shared_ptr objects, *this included, - that share ownership with *this, or an unspecified nonnegative - value when *this is empty.

+ that share ownership with *this, or 0 when *this + is empty.

Throws: nothing.

Notes: use_count() is not necessarily efficient. Use only for debugging and testing purposes, not for production code.

@@ -522,6 +522,7 @@ q = p;

Returns: If *this owns a deleter d of type (cv-unqualified) D, returns &d; otherwise returns 0.

+

Throws: nothing.

Example

See shared_ptr_example.cpp for a @@ -709,8 +710,8 @@ int * p = a.release();

$Date$

Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. - Copyright 2002-2005 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.

+ Copyright 2002-2005 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.

diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e6b49d7..7abcb6e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -33,5 +33,14 @@ import testing ; [ run shared_ptr_move_test.cpp ] [ compile-fail shared_ptr_pv_fail.cpp ] [ run sp_unary_addr_test.cpp ] + [ compile-fail scoped_ptr_eq_fail.cpp ] + [ compile-fail scoped_array_eq_fail.cpp ] + [ run esft_regtest.cpp ] + [ run yield_k_test.cpp ] + [ run yield_k_test.cpp : : : multi : yield_k_test.mt ] + [ run spinlock_test.cpp ] + [ run spinlock_try_test.cpp ] + [ run spinlock_try_test.cpp : : : multi : spinlock_try_test.mt ] + [ run spinlock_pool_test.cpp ] ; } diff --git a/test/esft_regtest.cpp b/test/esft_regtest.cpp new file mode 100644 index 0000000..0e3036c --- /dev/null +++ b/test/esft_regtest.cpp @@ -0,0 +1,136 @@ +// +// esft_regtest.cpp +// +// A regression test for enable_shared_from_this +// +// Copyright (c) 2008 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 + +class X: public boost::enable_shared_from_this< X > +{ +private: + + int destroyed_; + int deleted_; + int expected_; + +private: + + X( X const& ); + X& operator=( X const& ); + +public: + + static int instances; + +public: + + explicit X( int expected ): destroyed_( 0 ), deleted_( 0 ), expected_( expected ) + { + ++instances; + } + + ~X() + { + BOOST_TEST( deleted_ == expected_ ); + BOOST_TEST( destroyed_ == 0 ); + ++destroyed_; + --instances; + } + + typedef void (*deleter_type)( X* ); + + static void deleter( X * px ) + { + ++px->deleted_; + } + + static void deleter2( X * px ) + { + ++px->deleted_; + delete px; + } +}; + +int X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + X x( 0 ); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + std::auto_ptr px( new X( 0 ) ); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr px( new X( 0 ) ); + BOOST_TEST( X::instances == 1 ); + + boost::weak_ptr wp( px ); + BOOST_TEST( !wp.expired() ); + + px.reset(); + + BOOST_TEST( wp.expired() ); + } + + BOOST_TEST( X::instances == 0 ); + + { + X x( 1 ); + boost::shared_ptr px( &x, X::deleter ); + BOOST_TEST( X::instances == 1 ); + + X::deleter_type * pd = boost::get_deleter( px ); + BOOST_TEST( pd != 0 && *pd == X::deleter ); + + boost::weak_ptr wp( px ); + BOOST_TEST( !wp.expired() ); + + px.reset(); + + BOOST_TEST( wp.expired() ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr px( new X( 1 ), X::deleter2 ); + BOOST_TEST( X::instances == 1 ); + + X::deleter_type * pd = boost::get_deleter( px ); + BOOST_TEST( pd != 0 && *pd == X::deleter2 ); + + boost::weak_ptr wp( px ); + BOOST_TEST( !wp.expired() ); + + px.reset(); + + BOOST_TEST( wp.expired() ); + } + + BOOST_TEST( X::instances == 0 ); + + return boost::report_errors(); +} diff --git a/test/scoped_array_eq_fail.cpp b/test/scoped_array_eq_fail.cpp new file mode 100644 index 0000000..6c7f214 --- /dev/null +++ b/test/scoped_array_eq_fail.cpp @@ -0,0 +1,27 @@ +#include + +#if defined(BOOST_MSVC) +#pragma warning(disable: 4786) // identifier truncated in debug info +#pragma warning(disable: 4710) // function not inlined +#pragma warning(disable: 4711) // function selected for automatic inline expansion +#pragma warning(disable: 4514) // unreferenced inline removed +#endif + +// +// scoped_array_eq_fail.cpp - a negative test for "p == q" +// +// Copyright (c) 2008 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 + +int main() +{ + boost::scoped_array p, q; + p == q; // must fail + return 0; +} diff --git a/test/scoped_ptr_eq_fail.cpp b/test/scoped_ptr_eq_fail.cpp new file mode 100644 index 0000000..0d6ade4 --- /dev/null +++ b/test/scoped_ptr_eq_fail.cpp @@ -0,0 +1,27 @@ +#include + +#if defined(BOOST_MSVC) +#pragma warning(disable: 4786) // identifier truncated in debug info +#pragma warning(disable: 4710) // function not inlined +#pragma warning(disable: 4711) // function selected for automatic inline expansion +#pragma warning(disable: 4514) // unreferenced inline removed +#endif + +// +// scoped_ptr_eq_fail.cpp - a negative test for "p == q" +// +// Copyright (c) 2008 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 + +int main() +{ + boost::scoped_ptr p, q; + p == q; // must fail + return 0; +} diff --git a/test/shared_from_this_test.cpp b/test/shared_from_this_test.cpp index 5107cb1..61515bd 100644 --- a/test/shared_from_this_test.cpp +++ b/test/shared_from_this_test.cpp @@ -133,7 +133,8 @@ void test3() try { boost::shared_ptr r = v2.shared_from_this(); - BOOST_ERROR("v2.shared_from_this() failed to throw"); + BOOST_TEST( p < r || r < p ); + BOOST_TEST( r.get() == &v2 ); } catch(boost::bad_weak_ptr const &) { diff --git a/test/shared_ptr_test.cpp b/test/shared_ptr_test.cpp index 2f852ea..f697192 100644 --- a/test/shared_ptr_test.cpp +++ b/test/shared_ptr_test.cpp @@ -62,6 +62,7 @@ void default_constructor() BOOST_TEST(pi? false: true); BOOST_TEST(!pi); BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 0); } { @@ -69,6 +70,7 @@ void default_constructor() BOOST_TEST(pv? false: true); BOOST_TEST(!pv); BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 0); } { @@ -76,6 +78,7 @@ void default_constructor() BOOST_TEST(px? false: true); BOOST_TEST(!px); BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 0); } } @@ -1565,6 +1568,7 @@ void plain_reset() BOOST_TEST(pi? false: true); BOOST_TEST(!pi); BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 0); } { @@ -1573,6 +1577,7 @@ void plain_reset() BOOST_TEST(pi? false: true); BOOST_TEST(!pi); BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 0); } { @@ -1581,6 +1586,7 @@ void plain_reset() BOOST_TEST(pi? false: true); BOOST_TEST(!pi); BOOST_TEST(pi.get() == 0); + BOOST_TEST(pi.use_count() == 0); } { @@ -1589,6 +1595,7 @@ void plain_reset() BOOST_TEST(px? false: true); BOOST_TEST(!px); BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 0); } { @@ -1597,6 +1604,7 @@ void plain_reset() BOOST_TEST(px? false: true); BOOST_TEST(!px); BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 0); } { @@ -1605,6 +1613,7 @@ void plain_reset() BOOST_TEST(px? false: true); BOOST_TEST(!px); BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 0); } { @@ -1615,6 +1624,7 @@ void plain_reset() BOOST_TEST(px? false: true); BOOST_TEST(!px); BOOST_TEST(px.get() == 0); + BOOST_TEST(px.use_count() == 0); BOOST_TEST(X::instances == 0); } @@ -1624,6 +1634,7 @@ void plain_reset() BOOST_TEST(pv? false: true); BOOST_TEST(!pv); BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 0); } { @@ -1634,6 +1645,7 @@ void plain_reset() BOOST_TEST(pv? false: true); BOOST_TEST(!pv); BOOST_TEST(pv.get() == 0); + BOOST_TEST(pv.use_count() == 0); BOOST_TEST(X::instances == 0); } } diff --git a/test/spinlock_pool_test.cpp b/test/spinlock_pool_test.cpp new file mode 100644 index 0000000..00e7558 --- /dev/null +++ b/test/spinlock_pool_test.cpp @@ -0,0 +1,30 @@ +// +// spinlock_pool_test.cpp +// +// Copyright 2008 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 + +// Sanity check only + +int main() +{ + int x = 0; + + { + boost::detail::spinlock_pool<0>::scoped_lock lock( &x ); + ++x; + } + + { + boost::detail::spinlock_pool<1>::scoped_lock lock( &x ); + boost::detail::spinlock_pool<2>::scoped_lock lock2( &x ); + } + + return 0; +} diff --git a/test/spinlock_test.cpp b/test/spinlock_test.cpp new file mode 100644 index 0000000..0820b96 --- /dev/null +++ b/test/spinlock_test.cpp @@ -0,0 +1,31 @@ +// +// spinlock_test.cpp +// +// Copyright 2008 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 + +// Sanity check only + +static boost::detail::spinlock sp = BOOST_DETAIL_SPINLOCK_INIT; +static boost::detail::spinlock sp2 = BOOST_DETAIL_SPINLOCK_INIT; + +int main() +{ + sp.lock(); + sp2.lock(); + sp.unlock(); + sp2.unlock(); + + { + boost::detail::spinlock::scoped_lock lock( sp ); + boost::detail::spinlock::scoped_lock lock2( sp2 ); + } + + return 0; +} diff --git a/test/spinlock_try_test.cpp b/test/spinlock_try_test.cpp new file mode 100644 index 0000000..59e3390 --- /dev/null +++ b/test/spinlock_try_test.cpp @@ -0,0 +1,46 @@ +// +// spinlock_try_test.cpp +// +// Copyright 2008 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 + +// Sanity check only + +static boost::detail::spinlock sp = BOOST_DETAIL_SPINLOCK_INIT; +static boost::detail::spinlock sp2 = BOOST_DETAIL_SPINLOCK_INIT; + +int main() +{ + BOOST_TEST( sp.try_lock() ); + BOOST_TEST( !sp.try_lock() ); + BOOST_TEST( sp2.try_lock() ); + BOOST_TEST( !sp.try_lock() ); + BOOST_TEST( !sp2.try_lock() ); + sp.unlock(); + sp2.unlock(); + + sp.lock(); + BOOST_TEST( !sp.try_lock() ); + sp2.lock(); + BOOST_TEST( !sp.try_lock() ); + BOOST_TEST( !sp2.try_lock() ); + sp.unlock(); + sp2.unlock(); + + { + boost::detail::spinlock::scoped_lock lock( sp ); + BOOST_TEST( !sp.try_lock() ); + boost::detail::spinlock::scoped_lock lock2( sp2 ); + BOOST_TEST( !sp.try_lock() ); + BOOST_TEST( !sp2.try_lock() ); + } + + return boost::report_errors(); +} diff --git a/test/yield_k_test.cpp b/test/yield_k_test.cpp new file mode 100644 index 0000000..1e6ab13 --- /dev/null +++ b/test/yield_k_test.cpp @@ -0,0 +1,23 @@ +// +// yield_k_test.cpp +// +// Copyright 2008 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 + +// Sanity check only + +int main() +{ + for( unsigned k = 0; k < 256; ++k ) + { + boost::detail::yield( k ); + } + + return 0; +}