Added copyright and license
[libcds.git] / cds / urcu / raw_ptr.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8     
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
29 */
30
31 #ifndef CDSLIB_URCU_RAW_PTR_H
32 #define CDSLIB_URCU_RAW_PTR_H
33
34 #include <utility> // std::move
35 #include <type_traits>
36 #include <cds/details/defs.h>
37
38 namespace cds { namespace urcu {
39
40     /// Raw pointer to node of RCU-based container
41     /**
42         This class is intented for returning a pointer to node of RCU-based container.
43         The objects of \p %raw_ptr class is returned by functions like \p get() of that containers.
44         Those functions must be called only under RCU-lock, otherwise the node returned can be reclaimed.
45         On the other hand, traversing the container can remove a lot of nodes marked as deleted ones.
46         Since RCU is locked, such nodes cannot be reclaimed immediately and must be retired only
47         outside RCU lock.
48
49         The object of \p %raw_ptr solves that problem: it contains the pointer to the node found
50         and a chain of nodes that were reclaimed during traversing. The \p %raw_ptr object destructor
51         frees the chain (but not the node found) passing it to RCU \p batch_retire().
52
53         The object of \p %raw_ptr class must be destructed only outside RCU-lock of current thread.
54
55         Usually, you do not need to use \p %raw_ptr class directly. Each RCU container declares
56         a \p %raw_ptr typedef suitable for the container.
57
58         Template arguments:
59         - \p RCU - one of \ref cds_urcu_gc "RCU type"
60         - \p ValueType - type of values stored in container
61         - \p ReclaimedEnumerator - implementation-defined for each type of container
62
63         Example: let \p Container is an RCU container
64         @code
65             Container c;
66             // ...
67             // Find a key
68             typename Container::raw_ptr pRaw;
69
70             // RCU locked section
71             {
72                 typename Container::rcu_lock l;
73                 pRaw = c.get( key );
74                 if ( pRaw ) {
75                     // Deal with pRaw
76                 }
77             }
78             // Release outside RCU-lock
79             pRaw.release();
80         @endcode
81     */
82     template <
83         class RCU,
84         typename ValueType,
85         typename ReclaimedEnumerator
86     >
87     class raw_ptr
88     {
89     public:
90         typedef RCU rcu;    ///< RCU type - one of <tt>cds::urcu::gc< ... ></tt>
91         typedef ValueType   value_type; ///< Value type pointed by \p %raw_ptr
92         typedef ReclaimedEnumerator reclaimed_enumerator; ///< implementation-defined, for internal use only
93
94     private:
95         //@cond
96         value_type *            m_ptr;  ///< pointer to node
97         reclaimed_enumerator    m_Enum; ///< reclaimed node enumerator
98         //@endcond
99
100     public:
101         /// Constructs an empty raw pointer
102         raw_ptr()
103             : m_ptr( nullptr )
104         {}
105
106         /// Move ctor
107         raw_ptr( raw_ptr&& p )
108             : m_ptr( p.m_ptr )
109             , m_Enum(std::move( p.m_Enum ))
110         {
111             p.m_ptr = nullptr;
112         }
113
114         /// Copy ctor is prohibited
115         raw_ptr( raw_ptr const& ) = delete;
116
117         //@cond
118         // Only for internal use
119         raw_ptr( value_type * p, reclaimed_enumerator&& e )
120             : m_ptr( p )
121             , m_Enum(std::move( e ))
122         {}
123         raw_ptr( reclaimed_enumerator&& e )
124             : m_ptr( nullptr )
125             , m_Enum(std::move( e ))
126         {}
127         //@endcond
128
129         /// Releases the raw pointer
130         ~raw_ptr()
131         {
132             release();
133         }
134
135     public:
136         /// Move assignment operator
137         /**
138             This operator may be called only inside RCU-lock.
139             The \p this should be empty.
140         */
141         raw_ptr& operator=( raw_ptr&& p ) CDS_NOEXCEPT
142         {
143             assert( empty() );
144             if ( !rcu::is_locked() )
145                 release();
146
147             m_ptr = p.m_ptr;
148             m_Enum = std::move( p.m_Enum );
149             p.m_ptr = nullptr;
150             return *this;
151         }
152
153         /// Copy assignment is prohibited
154         raw_ptr& operator=( raw_ptr const& ) = delete;
155
156         /// Returns a pointer to stored value
157         value_type * operator ->() const CDS_NOEXCEPT
158         {
159             return m_ptr;
160         }
161
162         /// Returns a reference to stored value
163         value_type& operator *()
164         {
165             assert( m_ptr != nullptr );
166             return *m_ptr;
167         }
168
169         /// Returns a reference to stored value
170         value_type const& operator *() const
171         {
172             assert( m_ptr != nullptr );
173             return *m_ptr;
174         }
175
176         /// Checks if the \p %raw_ptr is \p nullptr
177         bool empty() const CDS_NOEXCEPT
178         {
179             return m_ptr == nullptr;
180         }
181
182         /// Checks if the \p %raw_ptr is not empty
183         explicit operator bool() const CDS_NOEXCEPT
184         {
185             return !empty();
186         }
187
188         /// Releases the \p %raw_ptr object
189         /**
190             This function may be called only outside RCU locked region.
191             After \p %release() the object becomes empty and can be reused.
192         */
193         void release()
194         {
195             m_Enum.apply();
196             m_ptr = nullptr;
197         }
198     };
199
200     //@cond
201     // Adapter of \p raw_ptr for non-intrusive containers based on intrusive counterpart
202     template <
203         typename ValueType,
204         typename RawPtr,
205         typename Converter
206     >
207     class raw_ptr_adaptor: private RawPtr
208     {
209     public:
210         typedef RawPtr      intrusive_raw_ptr;
211         typedef ValueType   value_type;
212         typedef typename intrusive_raw_ptr::value_type node_type;
213         typedef Converter   converter_type;
214
215     public:
216         // Constructs an empty raw pointer
217         raw_ptr_adaptor()
218             : intrusive_raw_ptr()
219         {}
220
221         // Move ctor
222         raw_ptr_adaptor( intrusive_raw_ptr&& p )
223             : intrusive_raw_ptr( std::move(p))
224         {}
225
226         // Move ctor
227         raw_ptr_adaptor( raw_ptr_adaptor&& p )
228             : intrusive_raw_ptr( std::move(p))
229         {}
230
231         // Copy ctor is prohibited
232         raw_ptr_adaptor( raw_ptr_adaptor const& ) = delete;
233
234         // Releases the raw pointer
235         ~raw_ptr_adaptor()
236         {
237             release();
238         }
239
240     public:
241         // Move assignment operator
242         /*
243             This operator may be called only inside RCU-lock.
244             The \p this should be empty.
245
246             In general, move assignment is intented for internal use.
247         */
248         raw_ptr_adaptor& operator=( raw_ptr_adaptor&& p ) CDS_NOEXCEPT
249         {
250             intrusive_raw_ptr::operator =(std::move(p));
251             return *this;
252         }
253
254         // Copy assignment is prohibited
255         raw_ptr_adaptor& operator=( raw_ptr_adaptor const& ) = delete;
256
257         // Returns a pointer to stored value
258         value_type * operator ->() const CDS_NOEXCEPT
259         {
260             return converter_type()( intrusive_raw_ptr::operator->());
261         }
262
263         // Returns a reference to stored value
264         value_type& operator *()
265         {
266             return converter_type()( intrusive_raw_ptr::operator*());
267         }
268
269         // Returns a reference to stored value
270         value_type const& operator *() const
271         {
272             return converter_type()( intrusive_raw_ptr::operator*());
273         }
274
275         // Checks if the \p %raw_ptr is \p nullptr
276         bool empty() const CDS_NOEXCEPT
277         {
278             return intrusive_raw_ptr::empty();
279         }
280
281         // Checks if the \p %raw_ptr is not empty
282         explicit operator bool() const CDS_NOEXCEPT
283         {
284             return !empty();
285         }
286
287         // Releases the \p %raw_ptr object
288         /*
289             This function may be called only outside RCU section.
290             After \p %release() the object can be reused.
291         */
292         void release()
293         {
294             intrusive_raw_ptr::release();
295         }
296     };
297     //@endcond
298
299 }} // namespace cds::urcu
300
301 #endif // #ifndef CDSLIB_URCU_RAW_PTR_H