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 
21 #ifdef BOOST_HAS_PRAGMA_ONCE
22 #pragma once
23 #endif
24 
25 #if defined(_MSC_VER)
26 #pragma warning(push)
27 // 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:
28 // 'name' : the inline specifier cannot be used when a friend declaration refers to a specialization of a function template
29 // Note that there is no inline specifier in the declarations.
30 #pragma warning(disable: 4396)
31 #endif
32 
33 namespace boost {
34 
35 namespace sp_adl_block {
36 
37 /*!
38  * \brief Thread unsafe reference counter policy for \c intrusive_ref_counter
39  *
40  * The policy instructs the \c intrusive_ref_counter base class to implement
41  * a reference counter suitable for single threaded use only. Pointers to the same
42  * object with this kind of reference counter must not be used by different threads.
43  */
44 struct thread_unsafe_counter
45 {
46     typedef unsigned int type;
47 
loadboost::sp_adl_block::thread_unsafe_counter48     static unsigned int load(unsigned int const& counter) BOOST_NOEXCEPT
49     {
50         return counter;
51     }
52 
incrementboost::sp_adl_block::thread_unsafe_counter53     static void increment(unsigned int& counter) BOOST_NOEXCEPT
54     {
55         ++counter;
56     }
57 
decrementboost::sp_adl_block::thread_unsafe_counter58     static unsigned int decrement(unsigned int& counter) BOOST_NOEXCEPT
59     {
60         return --counter;
61     }
62 };
63 
64 /*!
65  * \brief Thread safe reference counter policy for \c intrusive_ref_counter
66  *
67  * The policy instructs the \c intrusive_ref_counter base class to implement
68  * a thread-safe reference counter, if the target platform supports multithreading.
69  */
70 struct thread_safe_counter
71 {
72     typedef boost::detail::atomic_count type;
73 
loadboost::sp_adl_block::thread_safe_counter74     static unsigned int load(boost::detail::atomic_count const& counter) BOOST_NOEXCEPT
75     {
76         return static_cast< unsigned int >(static_cast< long >(counter));
77     }
78 
incrementboost::sp_adl_block::thread_safe_counter79     static void increment(boost::detail::atomic_count& counter) BOOST_NOEXCEPT
80     {
81         ++counter;
82     }
83 
decrementboost::sp_adl_block::thread_safe_counter84     static unsigned int decrement(boost::detail::atomic_count& counter) BOOST_NOEXCEPT
85     {
86         return static_cast< unsigned int >(--counter);
87     }
88 };
89 
90 template< typename DerivedT, typename CounterPolicyT = thread_safe_counter >
91 class intrusive_ref_counter;
92 
93 template< typename DerivedT, typename CounterPolicyT >
94 void intrusive_ptr_add_ref(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT;
95 template< typename DerivedT, typename CounterPolicyT >
96 void intrusive_ptr_release(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT;
97 
98 /*!
99  * \brief A reference counter base class
100  *
101  * This base class can be used with user-defined classes to add support
102  * for \c intrusive_ptr. The class contains a reference counter defined by the \c CounterPolicyT.
103  * Upon releasing the last \c intrusive_ptr referencing the object
104  * derived from the \c intrusive_ref_counter class, operator \c delete
105  * is automatically called on the pointer to the object.
106  *
107  * The other template parameter, \c DerivedT, is the user's class that derives from \c intrusive_ref_counter.
108  */
109 template< typename DerivedT, typename CounterPolicyT >
110 class intrusive_ref_counter
111 {
112 private:
113     //! Reference counter type
114     typedef typename CounterPolicyT::type counter_type;
115     //! Reference counter
116     mutable counter_type m_ref_counter;
117 
118 public:
119     /*!
120      * Default constructor
121      *
122      * \post <tt>use_count() == 0</tt>
123      */
intrusive_ref_counter()124     intrusive_ref_counter() BOOST_NOEXCEPT : m_ref_counter(0)
125     {
126     }
127 
128     /*!
129      * Copy constructor
130      *
131      * \post <tt>use_count() == 0</tt>
132      */
intrusive_ref_counter(intrusive_ref_counter const &)133     intrusive_ref_counter(intrusive_ref_counter const&) BOOST_NOEXCEPT : m_ref_counter(0)
134     {
135     }
136 
137     /*!
138      * Assignment
139      *
140      * \post The reference counter is not modified after assignment
141      */
operator =(intrusive_ref_counter const &)142     intrusive_ref_counter& operator= (intrusive_ref_counter const&) BOOST_NOEXCEPT { return *this; }
143 
144     /*!
145      * \return The reference counter
146      */
use_count() const147     unsigned int use_count() const BOOST_NOEXCEPT
148     {
149         return CounterPolicyT::load(m_ref_counter);
150     }
151 
152 protected:
153     /*!
154      * Destructor
155      */
156     BOOST_DEFAULTED_FUNCTION(~intrusive_ref_counter(), {})
157 
158     friend void intrusive_ptr_add_ref< DerivedT, CounterPolicyT >(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT;
159     friend void intrusive_ptr_release< DerivedT, CounterPolicyT >(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT;
160 };
161 
162 template< typename DerivedT, typename CounterPolicyT >
intrusive_ptr_add_ref(const intrusive_ref_counter<DerivedT,CounterPolicyT> * p)163 inline void intrusive_ptr_add_ref(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT
164 {
165     CounterPolicyT::increment(p->m_ref_counter);
166 }
167 
168 template< typename DerivedT, typename CounterPolicyT >
intrusive_ptr_release(const intrusive_ref_counter<DerivedT,CounterPolicyT> * p)169 inline void intrusive_ptr_release(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_NOEXCEPT
170 {
171     if (CounterPolicyT::decrement(p->m_ref_counter) == 0)
172         delete static_cast< const DerivedT* >(p);
173 }
174 
175 } // namespace sp_adl_block
176 
177 using sp_adl_block::intrusive_ref_counter;
178 using sp_adl_block::thread_unsafe_counter;
179 using sp_adl_block::thread_safe_counter;
180 
181 } // namespace boost
182 
183 #if defined(_MSC_VER)
184 #pragma warning(pop)
185 #endif
186 
187 #endif // BOOST_SMART_PTR_INTRUSIVE_REF_COUNTER_HPP_INCLUDED_
188