diff --git a/include/boost/smart_ptr/atomic_shared_ptr.hpp b/include/boost/smart_ptr/atomic_shared_ptr.hpp new file mode 100644 index 0000000..60136e5 --- /dev/null +++ b/include/boost/smart_ptr/atomic_shared_ptr.hpp @@ -0,0 +1,142 @@ +#ifndef BOOST_SMART_PTR_ATOMIC_SHARED_PTR_HPP_INCLUDED +#define BOOST_SMART_PTR_ATOMIC_SHARED_PTR_HPP_INCLUDED + +// +// atomic_shared_ptr.hpp +// +// Copyright 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) +// +// See http://www.boost.org/libs/smart_ptr/ for documentation. +// + +#include + +namespace boost +{ + +template class atomic_shared_ptr +{ +private: + + boost::shared_ptr p_; + + atomic_shared_ptr(const atomic_shared_ptr&); + atomic_shared_ptr& operator=(const atomic_shared_ptr&); + +public: + + atomic_shared_ptr() BOOST_SP_NOEXCEPT + { + } + + BOOST_CONSTEXPR atomic_shared_ptr( shared_ptr p ) BOOST_SP_NOEXCEPT: p_( p ) + { + } + + atomic_shared_ptr& operator=( shared_ptr r ) BOOST_SP_NOEXCEPT + { +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + atomic_store( &p_, std::move( r ) ); + +#else + + atomic_store( &p_, r ); + +#endif + return *this; + } + + BOOST_CONSTEXPR bool is_lock_free() const BOOST_SP_NOEXCEPT + { + return false; + } + + shared_ptr load( int = 0 ) const BOOST_SP_NOEXCEPT + { + return atomic_load( &p_ ); + } + + operator shared_ptr() const BOOST_SP_NOEXCEPT + { + return atomic_load( &p_ ); + } + + void store( shared_ptr r, int = 0 ) BOOST_SP_NOEXCEPT + { +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + atomic_store( &p_, std::move( r ) ); + +#else + + atomic_store( &p_, r ); + +#endif + } + + shared_ptr exchange( shared_ptr r, int = 0 ) BOOST_SP_NOEXCEPT + { +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + return atomic_exchange( &p_, std::move( r ) ); + +#else + + return atomic_exchange( &p_, r ); + +#endif + } + + bool compare_exchange_weak( shared_ptr& v, const shared_ptr& w, int, int ) BOOST_SP_NOEXCEPT + { + return atomic_compare_exchange( &p_, &v, w ); + } + + bool compare_exchange_weak( shared_ptr& v, const shared_ptr& w, int = 0 ) BOOST_SP_NOEXCEPT + { + return atomic_compare_exchange( &p_, &v, w ); + } + + bool compare_exchange_strong( shared_ptr& v, const shared_ptr& w, int, int ) BOOST_SP_NOEXCEPT + { + return atomic_compare_exchange( &p_, &v, w ); + } + + bool compare_exchange_strong( shared_ptr& v, const shared_ptr& w, int = 0 ) BOOST_SP_NOEXCEPT + { + return atomic_compare_exchange( &p_, &v, w ); + } + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + bool compare_exchange_weak( shared_ptr& v, shared_ptr&& w, int, int ) BOOST_SP_NOEXCEPT + { + return atomic_compare_exchange( &p_, &v, std::move( w ) ); + } + + bool compare_exchange_weak( shared_ptr& v, shared_ptr&& w, int = 0 ) BOOST_SP_NOEXCEPT + { + return atomic_compare_exchange( &p_, &v, std::move( w ) ); + } + + bool compare_exchange_strong( shared_ptr& v, shared_ptr&& w, int, int ) BOOST_SP_NOEXCEPT + { + return atomic_compare_exchange( &p_, &v, std::move( w ) ); + } + + bool compare_exchange_strong( shared_ptr& v, shared_ptr&& w, int = 0 ) BOOST_SP_NOEXCEPT + { + return atomic_compare_exchange( &p_, &v, std::move( w ) ); + } + +#endif +}; + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_ATOMIC_SHARED_PTR_HPP_INCLUDED diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 9235970..a6f6b0c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,6 +1,6 @@ # Boost.SmartPtr Library test Jamfile # -# Copyright (c) 2003-2013 Peter Dimov +# Copyright (c) 2003-2017 Peter Dimov # Copyright (c) 2003 Dave Abrahams # # Distributed under the Boost Software License, Version 1.0. (See @@ -211,6 +211,8 @@ import testing ; [ compile lwm_win32_cs_test.cpp ] + [ run atomic_sp_test.cpp ] + [ run local_sp_test.cpp ] [ run lsp_array_test.cpp ] [ run lsp_array_n_test.cpp ] diff --git a/test/atomic_sp_test.cpp b/test/atomic_sp_test.cpp new file mode 100644 index 0000000..1b0b839 --- /dev/null +++ b/test/atomic_sp_test.cpp @@ -0,0 +1,325 @@ +#include + +// atomic_sp_test.cpp +// +// Copyright 2008, 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 + +// + +struct X +{ +}; + +#define BOOST_TEST_SP_EQ( p, q ) BOOST_TEST( p == q && !( p < q ) && !( q < p ) ) + +int main() +{ + // default constructor + + { + boost::atomic_shared_ptr apx; + + boost::shared_ptr p2 = apx.load(); + + BOOST_TEST_EQ( p2.get(), (X*)0 ); + BOOST_TEST_EQ( p2.use_count(), 0 ); + } + + // shared_ptr constructor + + { + boost::shared_ptr px( new X ); + boost::atomic_shared_ptr apx( px ); + + boost::shared_ptr p2 = apx.load(); + + BOOST_TEST_EQ( px, p2 ); + BOOST_TEST_EQ( px.use_count(), 3 ); + BOOST_TEST_EQ( p2.use_count(), 3 ); + } + + // shared_ptr assignment + + { + boost::shared_ptr px0( new X ); + boost::atomic_shared_ptr apx( px0 ); + + boost::shared_ptr px( new X ); + apx = px; + + boost::shared_ptr p2 = apx.load(); + + BOOST_TEST_EQ( px, p2 ); + BOOST_TEST_EQ( px.use_count(), 3 ); + BOOST_TEST_EQ( p2.use_count(), 3 ); + } + + // load, w/ mo + + { + boost::shared_ptr px( new X ); + boost::atomic_shared_ptr apx( px ); + + boost::shared_ptr p2 = apx.load( boost::memory_order_acquire ); + + BOOST_TEST_EQ( px, p2 ); + BOOST_TEST_EQ( px.use_count(), 3 ); + BOOST_TEST_EQ( p2.use_count(), 3 ); + } + + // operator shared_ptr + + { + boost::shared_ptr px( new X ); + boost::atomic_shared_ptr apx( px ); + + boost::shared_ptr p2 = apx; + + BOOST_TEST_EQ( px, p2 ); + BOOST_TEST_EQ( px.use_count(), 3 ); + BOOST_TEST_EQ( p2.use_count(), 3 ); + } + + // store + + { + boost::shared_ptr px0( new X ); + boost::atomic_shared_ptr apx( px0 ); + + boost::shared_ptr px( new X ); + apx.store( px ); + + boost::shared_ptr p2 = apx.load(); + + BOOST_TEST_EQ( px, p2 ); + BOOST_TEST_EQ( px.use_count(), 3 ); + BOOST_TEST_EQ( p2.use_count(), 3 ); + } + + // store, w/ mo + + { + boost::shared_ptr px0( new X ); + boost::atomic_shared_ptr apx( px0 ); + + boost::shared_ptr px( new X ); + apx.store( px, boost::memory_order_release ); + + boost::shared_ptr p2 = apx.load(); + + BOOST_TEST_EQ( px, p2 ); + BOOST_TEST_EQ( px.use_count(), 3 ); + BOOST_TEST_EQ( p2.use_count(), 3 ); + } + + // exchange + + { + boost::shared_ptr px0( new X ); + boost::atomic_shared_ptr apx( px0 ); + + boost::shared_ptr px( new X ); + boost::shared_ptr p1 = apx.exchange( px ); + + BOOST_TEST_EQ( px0, p1 ); + BOOST_TEST_EQ( px0.use_count(), 2 ); + BOOST_TEST_EQ( p1.use_count(), 2 ); + + boost::shared_ptr p2 = apx.load(); + + BOOST_TEST_EQ( px, p2 ); + BOOST_TEST_EQ( px.use_count(), 3 ); + BOOST_TEST_EQ( p2.use_count(), 3 ); + } + + // exchange, w/ mo + + { + boost::shared_ptr px0( new X ); + boost::atomic_shared_ptr apx( px0 ); + + boost::shared_ptr px( new X ); + boost::shared_ptr p1 = apx.exchange( px, boost::memory_order_acq_rel ); + + BOOST_TEST_EQ( px0, p1 ); + BOOST_TEST_EQ( px0.use_count(), 2 ); + BOOST_TEST_EQ( p1.use_count(), 2 ); + + boost::shared_ptr p2 = apx.load(); + + BOOST_TEST_EQ( px, p2 ); + BOOST_TEST_EQ( px.use_count(), 3 ); + BOOST_TEST_EQ( p2.use_count(), 3 ); + } + + // compare_exchange_weak + + { + boost::shared_ptr px( new X ); + boost::atomic_shared_ptr apx( px ); + + boost::shared_ptr px2( new X ); + boost::shared_ptr cmp; + + bool r = apx.compare_exchange_weak( cmp, px2 ); + BOOST_TEST( !r ); + BOOST_TEST_SP_EQ( apx.load(), px ); + BOOST_TEST_SP_EQ( cmp, px ); + + r = apx.compare_exchange_weak( cmp, px2 ); + BOOST_TEST( r ); + BOOST_TEST_SP_EQ( apx.load(), px2 ); + } + + // compare_exchange_weak, w/ mo + + { + boost::shared_ptr px( new X ); + boost::atomic_shared_ptr apx( px ); + + boost::shared_ptr px2( new X ); + boost::shared_ptr cmp; + + bool r = apx.compare_exchange_weak( cmp, px2, boost::memory_order_seq_cst, boost::memory_order_seq_cst ); + BOOST_TEST( !r ); + BOOST_TEST_SP_EQ( apx.load(), px ); + BOOST_TEST_SP_EQ( cmp, px ); + + r = apx.compare_exchange_weak( cmp, px2, boost::memory_order_seq_cst, boost::memory_order_seq_cst ); + BOOST_TEST( r ); + BOOST_TEST_SP_EQ( apx.load(), px2 ); + } + + // compare_exchange_weak, rv + + { + boost::shared_ptr px( new X ); + boost::atomic_shared_ptr apx( px ); + + boost::shared_ptr cmp; + + bool r = apx.compare_exchange_weak( cmp, boost::shared_ptr() ); + + BOOST_TEST( !r ); + BOOST_TEST_SP_EQ( apx.load(), px ); + BOOST_TEST_SP_EQ( cmp, px ); + + r = apx.compare_exchange_weak( cmp, boost::shared_ptr() ); + + BOOST_TEST( r ); + BOOST_TEST( apx.load().get() == 0 ); + BOOST_TEST( apx.load().use_count() == 0 ); + } + + // compare_exchange_weak, rv, w/ mo + + { + boost::shared_ptr px( new X ); + boost::atomic_shared_ptr apx( px ); + + boost::shared_ptr cmp; + + bool r = apx.compare_exchange_weak( cmp, boost::shared_ptr(), boost::memory_order_seq_cst, boost::memory_order_seq_cst ); + + BOOST_TEST( !r ); + BOOST_TEST_SP_EQ( apx.load(), px ); + BOOST_TEST_SP_EQ( cmp, px ); + + r = apx.compare_exchange_weak( cmp, boost::shared_ptr(), boost::memory_order_seq_cst, boost::memory_order_seq_cst ); + + BOOST_TEST( r ); + BOOST_TEST( apx.load().get() == 0 ); + BOOST_TEST( apx.load().use_count() == 0 ); + } + + // compare_exchange_strong + + { + boost::shared_ptr px( new X ); + boost::atomic_shared_ptr apx( px ); + + boost::shared_ptr px2( new X ); + boost::shared_ptr cmp; + + bool r = apx.compare_exchange_strong( cmp, px2 ); + BOOST_TEST( !r ); + BOOST_TEST_SP_EQ( apx.load(), px ); + BOOST_TEST_SP_EQ( cmp, px ); + + r = apx.compare_exchange_strong( cmp, px2 ); + BOOST_TEST( r ); + BOOST_TEST_SP_EQ( apx.load(), px2 ); + } + + // compare_exchange_strong, w/ mo + + { + boost::shared_ptr px( new X ); + boost::atomic_shared_ptr apx( px ); + + boost::shared_ptr px2( new X ); + boost::shared_ptr cmp; + + bool r = apx.compare_exchange_strong( cmp, px2, boost::memory_order_seq_cst, boost::memory_order_seq_cst ); + BOOST_TEST( !r ); + BOOST_TEST_SP_EQ( apx.load(), px ); + BOOST_TEST_SP_EQ( cmp, px ); + + r = apx.compare_exchange_strong( cmp, px2, boost::memory_order_seq_cst, boost::memory_order_seq_cst ); + BOOST_TEST( r ); + BOOST_TEST_SP_EQ( apx.load(), px2 ); + } + + // compare_exchange_strong, rv + + { + boost::shared_ptr px( new X ); + boost::atomic_shared_ptr apx( px ); + + boost::shared_ptr cmp; + + bool r = apx.compare_exchange_strong( cmp, boost::shared_ptr() ); + + BOOST_TEST( !r ); + BOOST_TEST_SP_EQ( apx.load(), px ); + BOOST_TEST_SP_EQ( cmp, px ); + + r = apx.compare_exchange_strong( cmp, boost::shared_ptr() ); + + BOOST_TEST( r ); + BOOST_TEST( apx.load().get() == 0 ); + BOOST_TEST( apx.load().use_count() == 0 ); + } + + // compare_exchange_strong, rv, w/ mo + + { + boost::shared_ptr px( new X ); + boost::atomic_shared_ptr apx( px ); + + boost::shared_ptr cmp; + + bool r = apx.compare_exchange_strong( cmp, boost::shared_ptr(), boost::memory_order_seq_cst, boost::memory_order_seq_cst ); + + BOOST_TEST( !r ); + BOOST_TEST_SP_EQ( apx.load(), px ); + BOOST_TEST_SP_EQ( cmp, px ); + + r = apx.compare_exchange_strong( cmp, boost::shared_ptr(), boost::memory_order_seq_cst, boost::memory_order_seq_cst ); + + BOOST_TEST( r ); + BOOST_TEST( apx.load().get() == 0 ); + BOOST_TEST( apx.load().use_count() == 0 ); + } + + return boost::report_errors(); +}