Line data Source code
1 : /* 2 : * Copyright Andrey Semashev 2007 - 2013. 3 : * Distributed under the Boost Software License, Version 1.0. 4 : * (See accompanying file LICENSE_1_0.txt or copy at 5 : * http://www.boost.org/LICENSE_1_0.txt) 6 : */ 7 : /*! 8 : * \file intrusive_ref_counter.hpp 9 : * \author Andrey Semashev 10 : * \date 12.03.2009 11 : * 12 : * This header contains a reference counter class for \c intrusive_ptr. 13 : */ 14 : 15 : #ifndef BOOST_SMART_PTR_INTRUSIVE_REF_COUNTER_HPP_INCLUDED_ 16 : #define BOOST_SMART_PTR_INTRUSIVE_REF_COUNTER_HPP_INCLUDED_ 17 : 18 : #include <boost/config.hpp> 19 : #include <boost/smart_ptr/detail/atomic_count.hpp> 20 : #include <boost/smart_ptr/detail/sp_noexcept.hpp> 21 : 22 : #ifdef BOOST_HAS_PRAGMA_ONCE 23 : #pragma once 24 : #endif 25 : 26 : #if defined(_MSC_VER) 27 : #pragma warning(push) 28 : // This is a bogus MSVC warning, which is flagged by friend declarations of intrusive_ptr_add_ref and intrusive_ptr_release in intrusive_ref_counter: 29 : // 'name' : the inline specifier cannot be used when a friend declaration refers to a specialization of a function template 30 : // Note that there is no inline specifier in the declarations. 31 : #pragma warning(disable: 4396) 32 : #endif 33 : 34 : namespace boost { 35 : 36 : namespace sp_adl_block { 37 : 38 : /*! 39 : * \brief Thread unsafe reference counter policy for \c intrusive_ref_counter 40 : * 41 : * The policy instructs the \c intrusive_ref_counter base class to implement 42 : * a reference counter suitable for single threaded use only. Pointers to the same 43 : * object with this kind of reference counter must not be used by different threads. 44 : */ 45 : struct thread_unsafe_counter 46 : { 47 : typedef unsigned int type; 48 : 49 : static unsigned int load(unsigned int const& counter) BOOST_SP_NOEXCEPT 50 : { 51 : return counter; 52 : } 53 : 54 : static void increment(unsigned int& counter) BOOST_SP_NOEXCEPT 55 : { 56 : ++counter; 57 : } 58 : 59 : static unsigned int decrement(unsigned int& counter) BOOST_SP_NOEXCEPT 60 : { 61 : return --counter; 62 : } 63 : }; 64 : 65 : /*! 66 : * \brief Thread safe reference counter policy for \c intrusive_ref_counter 67 : * 68 : * The policy instructs the \c intrusive_ref_counter base class to implement 69 : * a thread-safe reference counter, if the target platform supports multithreading. 70 : */ 71 : struct thread_safe_counter 72 : { 73 : typedef boost::detail::atomic_count type; 74 : 75 : static unsigned int load(boost::detail::atomic_count const& counter) BOOST_SP_NOEXCEPT 76 : { 77 : return static_cast< unsigned int >(static_cast< long >(counter)); 78 : } 79 : 80 0 : static void increment(boost::detail::atomic_count& counter) BOOST_SP_NOEXCEPT 81 : { 82 0 : ++counter; 83 : } 84 : 85 0 : static unsigned int decrement(boost::detail::atomic_count& counter) BOOST_SP_NOEXCEPT 86 : { 87 0 : return static_cast< unsigned int >(--counter); 88 : } 89 : }; 90 : 91 : template< typename DerivedT, typename CounterPolicyT = thread_safe_counter > 92 : class intrusive_ref_counter; 93 : 94 : template< typename DerivedT, typename CounterPolicyT > 95 : void intrusive_ptr_add_ref(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT; 96 : template< typename DerivedT, typename CounterPolicyT > 97 : void intrusive_ptr_release(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT; 98 : 99 : /*! 100 : * \brief A reference counter base class 101 : * 102 : * This base class can be used with user-defined classes to add support 103 : * for \c intrusive_ptr. The class contains a reference counter defined by the \c CounterPolicyT. 104 : * Upon releasing the last \c intrusive_ptr referencing the object 105 : * derived from the \c intrusive_ref_counter class, operator \c delete 106 : * is automatically called on the pointer to the object. 107 : * 108 : * The other template parameter, \c DerivedT, is the user's class that derives from \c intrusive_ref_counter. 109 : */ 110 : template< typename DerivedT, typename CounterPolicyT > 111 : class intrusive_ref_counter 112 : { 113 : private: 114 : //! Reference counter type 115 : typedef typename CounterPolicyT::type counter_type; 116 : //! Reference counter 117 : mutable counter_type m_ref_counter; 118 : 119 : public: 120 : /*! 121 : * Default constructor 122 : * 123 : * \post <tt>use_count() == 0</tt> 124 : */ 125 0 : intrusive_ref_counter() BOOST_SP_NOEXCEPT : m_ref_counter(0) 126 : { 127 : } 128 : 129 : /*! 130 : * Copy constructor 131 : * 132 : * \post <tt>use_count() == 0</tt> 133 : */ 134 : intrusive_ref_counter(intrusive_ref_counter const&) BOOST_SP_NOEXCEPT : m_ref_counter(0) 135 : { 136 : } 137 : 138 : /*! 139 : * Assignment 140 : * 141 : * \post The reference counter is not modified after assignment 142 : */ 143 : intrusive_ref_counter& operator= (intrusive_ref_counter const&) BOOST_SP_NOEXCEPT { return *this; } 144 : 145 : /*! 146 : * \return The reference counter 147 : */ 148 : unsigned int use_count() const BOOST_SP_NOEXCEPT 149 : { 150 : return CounterPolicyT::load(m_ref_counter); 151 : } 152 : 153 : protected: 154 : /*! 155 : * Destructor 156 : */ 157 : BOOST_DEFAULTED_FUNCTION(~intrusive_ref_counter(), {}) 158 : 159 : friend void intrusive_ptr_add_ref< DerivedT, CounterPolicyT >(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT; 160 : friend void intrusive_ptr_release< DerivedT, CounterPolicyT >(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT; 161 : }; 162 : 163 : template< typename DerivedT, typename CounterPolicyT > 164 0 : inline void intrusive_ptr_add_ref(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT 165 : { 166 0 : CounterPolicyT::increment(p->m_ref_counter); 167 0 : } 168 : 169 : template< typename DerivedT, typename CounterPolicyT > 170 0 : inline void intrusive_ptr_release(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT 171 : { 172 0 : if (CounterPolicyT::decrement(p->m_ref_counter) == 0) 173 0 : delete static_cast< const DerivedT* >(p); 174 0 : } 175 : 176 : } // namespace sp_adl_block 177 : 178 : using sp_adl_block::intrusive_ref_counter; 179 : using sp_adl_block::thread_unsafe_counter; 180 : using sp_adl_block::thread_safe_counter; 181 : 182 : } // namespace boost 183 : 184 : #if defined(_MSC_VER) 185 : #pragma warning(pop) 186 : #endif 187 : 188 : #endif // BOOST_SMART_PTR_INTRUSIVE_REF_COUNTER_HPP_INCLUDED_