Merge branch 'check' into dev
[libcds.git] / cds / gc / guarded_ptr.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_GC_GUARDED_PTR_H
4 #define __CDS_GC_GUARDED_PTR_H
5
6 #include <cds/details/defs.h>
7
8 namespace cds { namespace gc {
9
10     /// Guarded pointer
11     /**
12         A guarded pointer is a pair of the pointer and GC's guard.
13         Usually, it is used for returning a pointer to the item from an lock-free container.
14         The guard prevents the pointer to be early disposed (freed) by GC.
15         After destructing \p %guarded_ptr object the pointer can be automatically disposed (freed) at any time.
16
17         Template arguments:
18         - \p GC - a garbage collector type like \p cds::gc::HP and any other from cds::gc namespace
19         - \p GuardedType - a type which the guard stores
20         - \p ValueType - a value type
21         - \p Cast - a functor for converting <tt>GuardedType*</tt> to <tt>ValueType*</tt>. Default is \p void (no casting).
22
23         For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed.
24         In such case the \p %guarded_ptr is:
25         @code
26         typedef cds::gc::guarded_ptr< cds::gc::HP, foo > intrusive_guarded_ptr;
27         @endcode
28
29         For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed.
30         For example:
31         @code
32         struct foo {
33             int const   key;
34             std::string value;
35         };
36
37         struct value_accessor {
38             std::string* operator()( foo* pFoo ) const
39             {
40                 return &(pFoo->value);
41             }
42         };
43
44         // Guarded ptr
45         typedef cds::gc::guarded_ptr< cds::gc::HP, Foo, std::string, value_accessor > nonintrusive_guarded_ptr;
46         @endcode
47
48         Many set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor.
49     */
50     template <class GC, typename GuardedType, typename ValueType=GuardedType, typename Cast=void >
51     class guarded_ptr
52     {
53         //TODO: use moce semantics and explicit operator bool!
54     public:
55         typedef GC          gc;           ///< Garbage collector like cds::gc::HP and any other from cds::gc namespace
56         typedef GuardedType guarded_type; ///< Guarded type
57         typedef ValueType   value_type;   ///< Value type
58         typedef Cast        value_cast;   ///< Functor for casting \p guarded_type to \p value_type
59
60     private:
61         //@cond
62         typename gc::Guard  m_guard;
63         //@endcond
64
65     public:
66         /// Creates empty guarded pointer
67         guarded_ptr() CDS_NOEXCEPT
68         {}
69
70         //@cond
71         /// Initializes guarded pointer with \p p
72         guarded_ptr( guarded_type * p ) CDS_NOEXCEPT
73         {
74             m_guard.assign( p );
75         }
76         guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT
77         {}
78         //@endcond
79
80         /// Move ctor
81         guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
82         {
83             m_guard.assign( gp.m_guard.get_native() );
84             gp.release();
85         }
86
87         /// The guarded pointer is not copy-constructible
88         guarded_ptr( guarded_ptr const& gp ) = delete;
89
90         /// Clears the guarded pointer
91         /**
92             \ref release is called if guarded pointer is not \ref empty
93         */
94         ~guarded_ptr() CDS_NOEXCEPT
95         {
96             release();
97         }
98
99         /// Move-assignment operator
100         guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT
101         {
102             m_guard.assign( gp.m_guard.get_native() );
103             gp.release();
104             return *this;
105         }
106
107         /// The guarded pointer is not copy-assignable
108         guarded_ptr& operator=(guarded_ptr const& gp) = delete;
109
110         /// Returns a pointer to guarded value
111         value_type * operator ->() const CDS_NOEXCEPT
112         {
113             return value_cast()( m_guard.template get<guarded_type>() );
114         }
115
116         /// Returns a reference to guarded value
117         value_type& operator *() CDS_NOEXCEPT
118         {
119             assert( !empty());
120             return *value_cast()( m_guard.template get<guarded_type>() );
121         }
122
123         /// Returns const reference to guarded value
124         value_type const& operator *() const CDS_NOEXCEPT
125         {
126             assert( !empty());
127             return *value_cast()( m_guard.template get<guarded_type>() );
128         }
129
130         /// Checks if the guarded pointer is \p nullptr
131         bool empty() const CDS_NOEXCEPT
132         {
133             return m_guard.template get<guarded_type>() == nullptr;
134         }
135
136         /// \p bool operator returns <tt>!empty()</tt>
137         explicit operator bool() const CDS_NOEXCEPT
138         {
139             return !empty();
140         }
141
142         /// Clears guarded pointer
143         /**
144             If the guarded pointer has been released, the pointer can be disposed (freed) at any time.
145             Dereferncing the guarded pointer after \p release() is dangerous.
146         */
147         void release() CDS_NOEXCEPT
148         {
149             m_guard.clear();
150         }
151
152         //@cond
153         // For internal use only!!!
154         typename gc::Guard& guard() CDS_NOEXCEPT
155         {
156             return m_guard;
157         }
158         //@endcond
159     };
160
161
162     //@cond
163     // Intrusive specialization
164     template <class GC, typename T>
165     class guarded_ptr< GC, T, T, void >
166     {
167     public:
168         typedef GC  gc         ;   ///< Garbage collector like cds::gc::HP
169         typedef T   guarded_type;  ///< Guarded type
170         typedef T   value_type ;   ///< Value type
171
172     private:
173         typename gc::Guard  m_guard;
174
175     public:
176         guarded_ptr() CDS_NOEXCEPT
177         {}
178
179         guarded_ptr( value_type * p ) CDS_NOEXCEPT
180         {
181             m_guard.assign( p );
182         }
183
184         guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
185         {
186             m_guard.assign( gp.m_guard.get_native() );
187             gp.release();
188         }
189
190         guarded_ptr( guarded_ptr const& gp ) = delete;
191
192         ~guarded_ptr() CDS_NOEXCEPT
193         {
194             release();
195         }
196
197         guarded_ptr& operator=(guarded_ptr&& gp) CDS_NOEXCEPT
198         {
199             m_guard.assign( gp.m_guard.get_native() );
200             gp.release();
201             return *this;
202         }
203
204         guarded_ptr& operator=(guarded_ptr const& gp) = delete;
205
206         value_type * operator ->() const CDS_NOEXCEPT
207         {
208             return m_guard.template get<value_type>();
209         }
210
211         value_type& operator *() CDS_NOEXCEPT
212         {
213             assert( !empty());
214             return *m_guard.template get<value_type>();
215         }
216
217         value_type const& operator *() const CDS_NOEXCEPT
218         {
219             assert( !empty());
220             return *m_guard.template get<value_type>();
221         }
222
223         bool empty() const CDS_NOEXCEPT
224         {
225             return m_guard.template get<guarded_type>() == nullptr;
226         }
227
228         explicit operator bool() const CDS_NOEXCEPT
229         {
230             return !empty();
231         }
232
233         void release() CDS_NOEXCEPT
234         {
235             m_guard.clear();
236         }
237
238         typename gc::Guard& guard() CDS_NOEXCEPT
239         {
240             return m_guard;
241         }
242     };
243     //@endcond
244
245 }} // namespace cds::gc
246
247 #endif // #ifndef __CDS_GC_GUARDED_PTR_H