From 75de3dbcf1379119ee21a8029845c65fb8ce38a6 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 22 Jan 2015 05:13:27 +0200 Subject: [PATCH] Add clang-specific sp_counted_base. --- .../smart_ptr/detail/sp_counted_base.hpp | 11 ++ .../detail/sp_counted_base_clang.hpp | 140 ++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 include/boost/smart_ptr/detail/sp_counted_base_clang.hpp diff --git a/include/boost/smart_ptr/detail/sp_counted_base.hpp b/include/boost/smart_ptr/detail/sp_counted_base.hpp index c415892..0addf07 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base.hpp @@ -20,6 +20,12 @@ #include #include +#if defined( __clang__ ) && defined( __has_extension ) +# if __has_extension( __c_atomic__ ) +# define BOOST_SP_HAS_CLANG_C11_ATOMICS +# endif +#endif + #if defined( BOOST_SP_DISABLE_THREADS ) # include @@ -35,6 +41,9 @@ #elif defined( BOOST_DISABLE_THREADS ) && !defined( BOOST_SP_ENABLE_THREADS ) && !defined( BOOST_DISABLE_WIN32 ) # include +#elif defined( BOOST_SP_HAS_CLANG_C11_ATOMICS ) +# include + #elif defined( __SNC__ ) # include @@ -79,4 +88,6 @@ #endif +#undef BOOST_SP_HAS_CLANG_C11_ATOMICS + #endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp b/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp new file mode 100644 index 0000000..c66b985 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp @@ -0,0 +1,140 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_CLANG_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_CLANG_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// detail/sp_counted_base_clang.hpp - __c11 clang intrinsics +// +// Copyright (c) 2007, 2013, 2015 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 +{ + +typedef _Atomic( boost::int_least32_t ) atomic_int_least32_t; + +inline void atomic_increment( atomic_int_least32_t * pw ) +{ + __c11_atomic_fetch_add( pw, 1, __ATOMIC_RELAXED ); +} + +inline boost::int_least32_t atomic_decrement( atomic_int_least32_t * pw ) +{ + return __c11_atomic_fetch_sub( pw, 1, __ATOMIC_ACQ_REL ); +} + +inline boost::int_least32_t atomic_conditional_increment( atomic_int_least32_t * pw ) +{ + // long r = *pw; + // if( r != 0 ) ++*pw; + // return r; + + boost::int_least32_t r = __c11_atomic_load( pw, __ATOMIC_RELAXED ); + + for( ;; ) + { + if( r == 0 ) + { + return r; + } + + if( __c11_atomic_compare_exchange_weak( pw, &r, r + 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED ) ) + { + return r; + } + } +} + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + atomic_int_least32_t use_count_; // #shared + atomic_int_least32_t weak_count_; // #weak + (#shared != 0) + +public: + + sp_counted_base() + { + __c11_atomic_init( &use_count_, 1 ); + __c11_atomic_init( &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; + virtual void * get_untyped_deleter() = 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_decrement( &use_count_ ) == 1 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_decrement( &weak_count_ ) == 1 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return __c11_atomic_load( const_cast< atomic_int_least32_t* >( &use_count_ ), __ATOMIC_ACQUIRE ); + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_CLANG_HPP_INCLUDED