Changed SkipListSet/Map<RCU> for new get() semantics (with raw_ptr)
[libcds.git] / cds / urcu / raw_ptr.h
1 //$$CDS-header$$
2
3 #ifndef CDSLIB_URCU_RAW_PTR_H
4 #define CDSLIB_URCU_RAW_PTR_H
5
6 #include <utility> // std::move
7 #include <type_traits>
8 #include <cds/details/defs.h>
9
10 namespace cds { namespace urcu {
11
12     /// Raw pointer to node of RCU-based container
13     /**
14         This class is intented for returning a pointer to node of RCU-based container.
15         The objects of \p %raw_ptr class is returned by functions like \p get() of that containers.
16         Those functions must be called only under RCU-lock, otherwise the node returned can be reclaimed.
17         On the other hand, traversing the container can remove a lot of nodes marked as deleted ones.
18         Since RCU is locked, such nodes cannot be reclaimed immediately and must be retired only
19         outside RCU lock.
20
21         The object of \p %raw_ptr solves that problem: it contains the pointer to the node found
22         and a chain of nodes that were reclaimed during traversing. The \p %raw_ptr object destructor
23         frees the chain (but not the node found) passing it to RCU \p batch_retire().
24
25         The object of \p %raw_ptr class must be destructed only outside RCU-lock of current thread.
26
27         Usually, you do not need to use \p %raw_ptr class directly. Each RCU container declares
28         a \p %raw_ptr typedef suitable for the container.
29
30         Template arguments:
31         - \p RCU - one of \ref cds_urcu_gc "RCU type"
32         - \p ValueType - type of values stored in container
33         - \p ReclaimedEnumerator - implementation-defined for each type of container
34
35         Example: let \p Container is an RCU container
36         @code
37             Container c;
38             // ...
39             // Find a key
40             typename Container::raw_ptr pRaw;
41
42             // RCU locked section
43             {
44                 typename Container::rcu_lock l;
45                 pRaw = c.get( key );
46                 if ( pRaw ) {
47                     // Deal with pRaw
48                 }
49             }
50             // Release outside RCU-lock
51             pRaw.release();
52         @endcode
53     */
54     template <
55         class RCU,
56         typename ValueType,
57         typename ReclaimedEnumerator
58     >
59     class raw_ptr
60     {
61     public:
62         typedef RCU rcu;    ///< RCU type - one of <tt>cds::urcu::gc< ... ></tt>
63         typedef ValueType   value_type; ///< Value type pointed by \p %raw_ptr
64         typedef ReclaimedEnumerator reclaimed_enumerator; ///< implementation-defined, for internal use only
65
66     private:
67         //@cond
68         value_type *            m_ptr;  ///< pointer to node
69         reclaimed_enumerator    m_Enum; ///< reclaimed node enumerator
70         //@endcond
71
72     public:
73         /// Constructs an empty raw pointer
74         raw_ptr()
75             : m_ptr( nullptr )
76         {}
77
78         /// Move ctor
79         raw_ptr( raw_ptr&& p )
80             : m_ptr( p.m_ptr )
81             , m_Enum(std::move( p.m_Enum ))
82         {
83             p.m_ptr = nullptr;
84         }
85
86         /// Copy ctor is prohibited
87         raw_ptr( raw_ptr const& ) = delete;
88
89         //@cond
90         // Only for internal use
91         raw_ptr( value_type * p, reclaimed_enumerator&& e )
92             : m_ptr( p )
93             , m_Enum(std::move( e ))
94         {}
95         raw_ptr( reclaimed_enumerator&& e )
96             : m_ptr( nullptr )
97             , m_Enum(std::move( e ))
98         {}
99         //@endcond
100
101         /// Releases the raw pointer
102         ~raw_ptr()
103         {
104             release();
105         }
106
107     public:
108         /// Move assignment operator
109         /**
110             This operator may be called only inside RCU-lock.
111             The \p this should be empty.
112         */
113         raw_ptr& operator=( raw_ptr&& p ) CDS_NOEXCEPT
114         {
115             assert( empty() );
116             if ( !rcu::is_locked() )
117                 release();
118
119             m_ptr = p.m_ptr;
120             m_Enum = std::move( p.m_Enum );
121             p.m_ptr = nullptr;
122             return *this;
123         }
124
125         /// Copy assignment is prohibited
126         raw_ptr& operator=( raw_ptr const& ) = delete;
127
128         /// Returns a pointer to stored value
129         value_type * operator ->() const CDS_NOEXCEPT
130         {
131             return m_ptr;
132         }
133
134         /// Returns a reference to stored value
135         value_type& operator *()
136         {
137             assert( m_ptr != nullptr );
138             return *m_ptr;
139         }
140
141         /// Returns a reference to stored value
142         value_type const& operator *() const
143         {
144             assert( m_ptr != nullptr );
145             return *m_ptr;
146         }
147
148         /// Checks if the \p %raw_ptr is \p nullptr
149         bool empty() const CDS_NOEXCEPT
150         {
151             return m_ptr == nullptr;
152         }
153
154         /// Checks if the \p %raw_ptr is not empty
155         explicit operator bool() const CDS_NOEXCEPT
156         {
157             return !empty();
158         }
159
160         /// Releases the \p %raw_ptr object
161         /**
162             This function may be called only outside RCU locked region.
163             After \p %release() the object becomes empty and can be reused.
164         */
165         void release()
166         {
167             m_Enum.apply();
168             m_ptr = nullptr;
169         }
170     };
171
172     //@cond
173     // Adapter of \p raw_ptr for non-intrusive containers based on intrusive counterpart
174     template <
175         typename ValueType,
176         typename RawPtr,
177         typename Converter
178     >
179     class raw_ptr_adaptor: private RawPtr
180     {
181     public:
182         typedef RawPtr      intrusive_raw_ptr;
183         typedef ValueType   value_type;
184         typedef typename intrusive_raw_ptr::value_type node_type;
185         typedef Converter   converter_type;
186
187     public:
188         // Constructs an empty raw pointer
189         raw_ptr_adaptor()
190             : intrusive_raw_ptr()
191         {}
192
193         // Move ctor
194         raw_ptr_adaptor( intrusive_raw_ptr&& p )
195             : intrusive_raw_ptr( std::move(p))
196         {}
197
198         // Move ctor
199         raw_ptr_adaptor( raw_ptr_adaptor&& p )
200             : intrusive_raw_ptr( std::move(p))
201         {}
202
203         // Copy ctor is prohibited
204         raw_ptr_adaptor( raw_ptr_adaptor const& ) = delete;
205
206         // Releases the raw pointer
207         ~raw_ptr_adaptor()
208         {
209             release();
210         }
211
212     public:
213         // Move assignment operator
214         /*
215             This operator may be called only inside RCU-lock.
216             The \p this should be empty.
217
218             In general, move assignment is intented for internal use.
219         */
220         raw_ptr_adaptor& operator=( raw_ptr_adaptor&& p ) CDS_NOEXCEPT
221         {
222             intrusive_raw_ptr::operator =(std::move(p));
223             return *this;
224         }
225
226         // Copy assignment is prohibited
227         raw_ptr_adaptor& operator=( raw_ptr_adaptor const& ) = delete;
228
229         // Returns a pointer to stored value
230         value_type * operator ->() const CDS_NOEXCEPT
231         {
232             return converter_type()( intrusive_raw_ptr::operator->());
233         }
234
235         // Returns a reference to stored value
236         value_type& operator *()
237         {
238             return converter_type()( intrusive_raw_ptr::operator*());
239         }
240
241         // Returns a reference to stored value
242         value_type const& operator *() const
243         {
244             return converter_type()( intrusive_raw_ptr::operator*());
245         }
246
247         // Checks if the \p %raw_ptr is \p nullptr
248         bool empty() const CDS_NOEXCEPT
249         {
250             return intrusive_raw_ptr::empty();
251         }
252
253         // Checks if the \p %raw_ptr is not empty
254         explicit operator bool() const CDS_NOEXCEPT
255         {
256             return !empty();
257         }
258
259         // Releases the \p %raw_ptr object
260         /*
261             This function may be called only outside RCU section.
262             After \p %release() the object can be reused.
263         */
264         void release()
265         {
266             intrusive_raw_ptr::release();
267         }
268     };
269     //@endcond
270
271 }} // namespace cds::urcu
272
273 #endif // #ifndef CDSLIB_URCU_RAW_PTR_H