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 
loadboost::sp_adl_block::thread_unsafe_counter49     static unsigned int load(unsigned int const& counter) BOOST_SP_NOEXCEPT
50     {
51         return counter;
52     }
53 
incrementboost::sp_adl_block::thread_unsafe_counter54     static void increment(unsigned int& counter) BOOST_SP_NOEXCEPT
55     {
56         ++counter;
57     }
58 
decrementboost::sp_adl_block::thread_unsafe_counter59     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 
loadboost::sp_adl_block::thread_safe_counter75     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 
incrementboost::sp_adl_block::thread_safe_counter80     static void increment(boost::detail::atomic_count& counter) BOOST_SP_NOEXCEPT
81     {
82         ++counter;
83     }
84 
decrementboost::sp_adl_block::thread_safe_counter85     static unsigned int decrement(boost::detail::atomic_count& counter) BOOST_SP_NOEXCEPT
86     {
87         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      */
intrusive_ref_counter()125     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      */
intrusive_ref_counter(intrusive_ref_counter const &)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      */
operator =(intrusive_ref_counter const &)143     intrusive_ref_counter& operator= (intrusive_ref_counter const&) BOOST_SP_NOEXCEPT { return *this; }
144 
145     /*!
146      * \return The reference counter
147      */
use_count() const148     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 >
intrusive_ptr_add_ref(const intrusive_ref_counter<DerivedT,CounterPolicyT> * p)164 inline void intrusive_ptr_add_ref(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT
165 {
166     CounterPolicyT::increment(p->m_ref_counter);
167 }
168 
169 template< typename DerivedT, typename CounterPolicyT >
intrusive_ptr_release(const intrusive_ref_counter<DerivedT,CounterPolicyT> * p)170 inline void intrusive_ptr_release(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT
171 {
172     if (CounterPolicyT::decrement(p->m_ref_counter) == 0)
173         delete static_cast< const DerivedT* >(p);
174 }
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_
189