Move libcds 1.6.0 from SVN
[libcds.git] / cds / urcu / exempt_ptr.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_URCU_EXEMPT_PTR_H
4 #define __CDS_URCU_EXEMPT_PTR_H
5
6 #include <cds/details/defs.h>
7
8 namespace cds { namespace urcu {
9
10     //@cond
11     namespace details {
12         template <typename Node, typename Value>
13         struct conventional_exempt_member_cast
14         {
15             Value * operator()( Node * p ) const
16             {
17                 return &p->m_Value;
18             }
19         };
20
21         template <typename Node, typename Value>
22         struct conventional_exempt_pair_cast
23         {
24             Value * operator()( Node * p ) const
25             {
26                 return &p->m_Data;
27             }
28         };
29     } // namespace details
30     //@endcond
31
32     /// Exempt pointer for RCU
33     /**
34         This special pointer class is intended for returning extracted node from RCU-based container.
35         The destructor (and \p release() member function) invokes <tt>RCU::retire_ptr< Disposer >()</tt> function to dispose the node.
36         For non-intrusive containers from \p cds::container namespace \p Disposer is an invocation
37         of node deallocator. For intrusive containers the disposer can be empty or it can trigger an event "node can be reused safely".
38         In any case, the exempt pointer concept keeps RCU semantics.
39
40         You don't need use this helper class directly. Any RCU-based container defines a proper typedef for this template.
41
42         Template arguments:
43         - \p RCU - one of \ref cds_urcu_gc "RCU type"
44         - \p NodeType - container's node type
45         - \p ValueType - value type stored in container's node. For intrusive containers it is the same as \p NodeType
46         - \p Disposer - a disposer functor
47         - \p Cast - a functor for casting from \p NodeType to \p ValueType. Usually, for intrusive containers \p Cast may be \p void.
48     */
49     template <
50         class RCU,
51         typename NodeType,
52         typename ValueType,
53         typename Disposer,
54 #ifdef CDS_DOXYGEN_INVOKED
55         typename Cast
56 #else
57         typename Cast=details::conventional_exempt_member_cast<NodeType, ValueType>
58 #endif
59     >
60     class exempt_ptr
61     {
62         //TODO: use move semantics and explicit operator bool!
63     public:
64         typedef RCU         rcu         ;   ///< RCU type - one of <tt>cds::urcu::gc< ... ></tt>
65         typedef NodeType    node_type   ;   ///< Node type
66         typedef ValueType   value_type  ;   ///< Value type
67         typedef Disposer    disposer    ;   ///< Disposer calling when release
68         typedef Cast        node_to_value_cast  ;   ///< Functor converting \p node_type to \p value_type
69
70     private:
71         //@cond
72         node_type *     m_pNode;
73         //@endcond
74
75     private:
76         //@cond
77         // No copy-constructible
78         exempt_ptr( exempt_ptr const& );
79         exempt_ptr& operator=( exempt_ptr const& );
80         //@endcond
81
82     public:
83         /// Constructs empty pointer
84         exempt_ptr() CDS_NOEXCEPT
85             : m_pNode( null_ptr<node_type *>())
86         {}
87
88         /// Releases the pointer
89         ~exempt_ptr()
90         {
91             release();
92         }
93
94         /// Checks if the pointer is \p NULL
95         bool empty() const CDS_NOEXCEPT
96         {
97             return m_pNode == null_ptr<node_type *>();
98         }
99
100         /// Dereference operator
101         value_type * operator->() const CDS_NOEXCEPT
102         {
103             return !empty() ? node_to_value_cast()( m_pNode ) : null_ptr<value_type *>();
104         }
105
106         /// Returns a reference to the value
107         value_type& operator *() CDS_NOEXCEPT
108         {
109             assert( !empty());
110             return *node_to_value_cast()( m_pNode );
111         }
112
113         //@cond
114         /// Assignment operator, the object should be empty. For internal use only
115         exempt_ptr& operator =( node_type * pNode )
116         {
117             // release() cannot be called in this point since RCU should be locked
118             assert( empty() );
119             assert( rcu::is_locked() );
120             m_pNode = pNode;
121             return *this;
122         }
123         //@endcond
124
125         /// Disposes the pointer. Should be called only outside of RCU critical section
126         void release()
127         {
128             assert( !rcu::is_locked() );
129             if ( !empty() ) {
130                 rcu::template retire_ptr<disposer>( m_pNode );
131                 m_pNode = null_ptr<node_type *>();
132             }
133         }
134     };
135
136     //@cond
137     // Intrusive container specialization
138     template <
139         class RCU,
140             typename NodeType,
141             typename Disposer
142     >
143     class exempt_ptr< RCU, NodeType, NodeType, Disposer, void >
144     {
145         //TODO: use move semantics and explicit operator bool!
146     public:
147         typedef RCU         rcu         ;   ///< RCU type - one of <tt>cds::urcu::gc< ... ></tt>
148         typedef NodeType    node_type   ;   ///< Node type
149         typedef NodeType    value_type  ;   ///< Node type
150         typedef Disposer    disposer    ;   ///< Disposer calling when release
151         typedef void        node_to_value_cast; ///< No casting is needed
152
153     private:
154         node_type *     m_pNode;
155
156     private:
157         // No copy-constructible
158         exempt_ptr( exempt_ptr const& );
159         exempt_ptr& operator=( exempt_ptr const& );
160
161     public:
162         /// Constructs empty pointer
163         exempt_ptr() CDS_NOEXCEPT
164             : m_pNode( null_ptr<node_type *>())
165         {}
166
167         /// Releases the pointer
168         ~exempt_ptr()
169         {
170             release();
171         }
172
173         /// Checks if the pointer is \p NULL
174         bool empty() const CDS_NOEXCEPT
175         {
176             return m_pNode == null_ptr<node_type *>();
177         }
178
179         /// Dereference operator.
180         value_type * operator->() const CDS_NOEXCEPT
181         {
182             return !empty() ? m_pNode : null_ptr<value_type *>();
183         }
184
185         /// Returns a reference to the value
186         value_type& operator *() CDS_NOEXCEPT
187         {
188             assert( !empty());
189             return *m_pNode;
190         }
191
192         /// Assignment operator, the object should be empty. For internal use only
193         exempt_ptr& operator =( node_type * pNode )
194         {
195             // release() cannot be called in this point since RCU should be locked
196             assert( empty() );
197             assert( rcu::is_locked() );
198             m_pNode = pNode;
199             return *this;
200         }
201
202         /// Disposes the pointer. Should be called only outside of RCU critical section
203         void release()
204         {
205             assert( !rcu::is_locked() );
206             if ( !empty() ) {
207                 rcu::template retire_ptr<disposer>( m_pNode );
208                 m_pNode = null_ptr<node_type *>();
209             }
210         }
211     };
212     //@endcond
213
214 }} // namespace cds::urcu
215
216 #endif //#ifndef __CDS_URCU_EXEMPT_PTR_H