1b052691aa7b55e4ca40bf4df823cb1155e5a604
[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 <type_traits>
7 #include <cds/details/defs.h>
8
9 namespace cds { namespace urcu {
10
11     //@cond
12     namespace details {
13         template <typename Node, typename Value>
14         struct conventional_exempt_member_cast
15         {
16             Value * operator()( Node * p ) const
17             {
18                 return &p->m_Value;
19             }
20         };
21
22         template <typename Node, typename Value>
23         struct conventional_exempt_pair_cast
24         {
25             Value * operator()( Node * p ) const
26             {
27                 return &p->m_Data;
28             }
29         };
30     } // namespace details
31     //@endcond
32
33     /// Exempt pointer for RCU
34     /**
35         This special pointer class is intended for returning extracted node from RCU-based container.
36         The destructor (and \p release() member function) invokes <tt>RCU::retire_ptr< Disposer >()</tt> function to dispose the node.
37         For non-intrusive containers from \p cds::container namespace \p Disposer is usually an invocation
38         of node deallocator. For intrusive containers the disposer can be empty or it can trigger an event "node can be reused safely".
39         In any case, the exempt pointer concept keeps RCU semantics.
40
41         You don't need use this helper class directly. Any RCU-based container typedefs a simplified version of this template.
42
43         Template arguments:
44         - \p RCU - one of \ref cds_urcu_gc "RCU type"
45         - \p NodeType - container's node type
46         - \p ValueType - value type stored in container's node. For intrusive containers it is the same as \p NodeType
47         - \p Disposer - a disposer functor
48         - \p Cast - a functor for casting from \p NodeType to \p ValueType. For intrusive containers 
49             the casting is usually disabled, i.e. \p Cast is \p void.
50     */
51     template <
52         class RCU,
53         typename NodeType,
54         typename ValueType,
55         typename Disposer,
56 #ifdef CDS_DOXYGEN_INVOKED
57         typename Cast
58 #else
59         typename Cast=details::conventional_exempt_member_cast<NodeType, ValueType>
60 #endif
61     >
62     class exempt_ptr
63     {
64         //@cond
65         struct trivial_cast {
66             ValueType * operator()( NodeType * p ) const
67             {
68                 return p;
69             }
70         };
71         //@endcond
72     public:
73         typedef RCU         rcu         ;   ///< RCU type - one of <tt>cds::urcu::gc< ... ></tt>
74         typedef NodeType    node_type   ;   ///< Node type
75         typedef ValueType   value_type  ;   ///< Value type
76         typedef Disposer    disposer    ;   ///< Disposer calling when release
77         /// Functor converting \p node_type to \p value_type
78         typedef typename std::conditional< std::is_same< Cast, void >::value, trivial_cast, Cast>::type node_to_value_cast;
79
80     private:
81         //@cond
82         node_type *     m_pNode;
83         //@endcond
84
85     public:
86         /// Constructs empty pointer
87         exempt_ptr() CDS_NOEXCEPT
88             : m_pNode( nullptr )
89         {}
90
91         //@cond
92         /// Creates exempt pointer for \p pNode. Only for internal use.
93         explicit exempt_ptr( node_type * pNode ) CDS_NOEXCEPT
94             : m_pNode( pNode )
95         {}
96         explicit exempt_ptr( std::nullptr_t ) CDS_NOEXCEPT
97             : m_pNode( nullptr )
98         {}
99         //@endcond
100
101         /// Move ctor
102         exempt_ptr( exempt_ptr&& p ) CDS_NOEXCEPT
103             : m_pNode( p.m_pNode )
104         {
105             p.m_pNode = nullptr;
106         }
107
108         /// The exempt pointer is not copy-constructible
109         exempt_ptr( exempt_ptr const& ) = delete;
110
111         /// Releases the pointer
112         ~exempt_ptr()
113         {
114             release();
115         }
116
117         /// Checks if the pointer is \p nullptr
118         bool empty() const CDS_NOEXCEPT
119         {
120             return m_pNode == nullptr;
121         }
122
123         /// \p bool operator returns <tt>!empty()</tt>
124         explicit operator bool() const CDS_NOEXCEPT
125         {
126             return !empty();
127         }
128
129         /// Dereference operator
130         value_type * operator->() const CDS_NOEXCEPT
131         {
132             return !empty() ? node_to_value_cast()(m_pNode) : nullptr;
133         }
134
135         /// Returns a reference to the value
136         value_type& operator *() CDS_NOEXCEPT
137         {
138             assert( !empty());
139             return *node_to_value_cast()( m_pNode );
140         }
141
142         /// Move assignment. Can be called only outside of RCU critical section
143         exempt_ptr& operator =( exempt_ptr&& p ) CDS_NOEXCEPT
144         {
145             release();
146             m_pNode = p.m_pNode;
147             p.m_pNode = nullptr;
148             return *this;
149         }
150
151         /// The exempt pointer is not copy-assignable
152         exempt_ptr& operator=(exempt_ptr const&) = delete;
153
154         /// Disposes the pointer. Should be called only outside of RCU critical section
155         void release()
156         {
157             if ( !empty() ) {
158                 assert( !rcu::is_locked() );
159                 rcu::template retire_ptr<disposer>( m_pNode );
160                 m_pNode = nullptr;
161             }
162         }
163     };
164 }} // namespace cds::urcu
165
166 #endif //#ifndef __CDS_URCU_EXEMPT_PTR_H