Removed redundant spaces
[libcds.git] / cds / intrusive / michael_list_rcu.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_INTRUSIVE_MICHAEL_LIST_RCU_H
32 #define CDSLIB_INTRUSIVE_MICHAEL_LIST_RCU_H
33
34 #include <cds/intrusive/details/michael_list_base.h>
35 #include <cds/urcu/details/check_deadlock.h>
36 #include <cds/details/binary_functor_wrapper.h>
37 #include <cds/details/make_const_type.h>
38 #include <cds/urcu/exempt_ptr.h>
39 #include <cds/urcu/raw_ptr.h>
40 #include <cds/intrusive/details/raw_ptr_disposer.h>
41
42 namespace cds { namespace intrusive {
43
44     //@cond
45     namespace michael_list {
46
47         /// Node specialization for uRCU
48         template <class RCU, typename Tag>
49         struct node< cds::urcu::gc< RCU >, Tag >
50         {
51             typedef cds::urcu::gc< RCU > gc;   ///< Garbage collector
52             typedef Tag                  tag;  ///< tag
53
54             typedef cds::details::marked_ptr<node, 3>   marked_ptr; ///< marked pointer
55             typedef typename gc::template atomic_marked_ptr<marked_ptr> atomic_marked_ptr; ///< atomic marked pointer specific for GC
56
57             atomic_marked_ptr m_pNext; ///< pointer to the next node in the container
58             node *            m_pDelChain; ///< Deleted node chain (local for a thread)
59
60             CDS_CONSTEXPR node() CDS_NOEXCEPT
61                 : m_pNext( nullptr )
62                 , m_pDelChain( nullptr )
63             {}
64         };
65     } // namespace michael_list
66     //@endcond
67
68     /// Michael's lock-free ordered single-linked list (template specialization for \ref cds_urcu_desc "RCU")
69     /** @ingroup cds_intrusive_list
70         \anchor cds_intrusive_MichaelList_rcu
71
72         Usually, ordered single-linked list is used as a building block for the hash table implementation.
73         The complexity of searching is <tt>O(N)</tt>.
74
75         Template arguments:
76         - \p RCU - one of \ref cds_urcu_gc "RCU type"
77         - \p T - type to be stored in the list; the type \p T should be based on (or has a member of type)
78             cds::intrusive::micheal_list::node
79         - \p Traits - type traits. See \p michael_list::traits for explanation. It is possible to declare option-based
80              list with \p cds::intrusive::michael_list::make_traits metafunction,
81              see \ref cds_intrusive_MichaelList_hp "here" for explanations.
82
83         \par Usage
84             Before including <tt><cds/intrusive/michael_list_rcu.h></tt> you should include appropriate RCU header file,
85             see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
86             For example, for \ref cds_urcu_general_buffered_gc "general-purpose buffered RCU" you should include:
87             \code
88             #include <cds/urcu/general_buffered.h>
89             #include <cds/intrusive/michael_list_rcu.h>
90
91             // Now, you can declare Michael's list for type Foo and default traits:
92             typedef cds::intrusive::MichaelList<cds::urcu::gc< cds::urcu::general_buffered<> >, Foo > rcu_michael_list;
93             \endcode
94     */
95     template < typename RCU, typename T,
96 #ifdef CDS_DOXYGEN_INVOKED
97     class Traits = michael_list::traits
98 #else
99     class Traits
100 #endif
101     >
102     class MichaelList<cds::urcu::gc<RCU>, T, Traits>
103     {
104     public:
105         typedef T       value_type; ///< type of value stored in the list
106         typedef Traits  traits;     ///< Traits template parameter
107
108         typedef typename traits::hook    hook;      ///< hook type
109         typedef typename hook::node_type node_type; ///< node type
110
111 #   ifdef CDS_DOXYGEN_INVOKED
112         typedef implementation_defined key_comparator  ;    ///< key comparison functor based on opt::compare and opt::less option setter.
113 #   else
114         typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;
115 #   endif
116
117         typedef typename traits::disposer  disposer;   ///< disposer used
118         typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ;    ///< node traits
119         typedef typename michael_list::get_link_checker< node_type, traits::link_checker >::type link_checker;   ///< link checker
120
121         typedef cds::urcu::gc<RCU>                  gc;           ///< RCU schema
122         typedef typename traits::back_off           back_off;     ///< back-off strategy
123         typedef typename traits::item_counter       item_counter; ///< Item counting policy used
124         typedef typename traits::memory_model       memory_model; ///< Memory ordering. See cds::opt::memory_model option
125         typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
126         typedef typename traits::stat               stat;     ///< Internal statistics
127
128         typedef typename gc::scoped_lock    rcu_lock ;  ///< RCU scoped lock
129         static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions do not require external locking
130
131         //@cond
132         // Rebind traits (split-list support)
133         template <typename... Options>
134         struct rebind_traits {
135             typedef MichaelList<
136                 gc
137                 , value_type
138                 , typename cds::opt::make_options< traits, Options...>::type
139             >   type;
140         };
141
142         // Stat selector
143         template <typename Stat>
144         using select_stat_wrapper = michael_list::select_stat_wrapper< Stat >;
145         //@endcond
146
147     protected:
148         typedef typename node_type::marked_ptr        marked_node_ptr; ///< Marked node pointer
149         typedef typename node_type::atomic_marked_ptr atomic_node_ptr; ///< Atomic node pointer
150         typedef atomic_node_ptr                       auxiliary_head;  ///< Auxiliary head type (for split-list support)
151
152         atomic_node_ptr m_pHead;        ///< Head pointer
153         item_counter    m_ItemCounter;  ///< Item counter
154         stat            m_Stat;         ///< Internal statistics
155
156     protected:
157         //@cond
158         enum erase_node_mask
159         {
160             erase_mask   = 1,
161             extract_mask = 3
162         };
163
164         typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock>   check_deadlock_policy;
165
166         struct clear_and_dispose {
167             void operator()( value_type * p )
168             {
169                 assert( p != nullptr );
170                 clear_links( node_traits::to_node_ptr(p));
171                 disposer()( p );
172             }
173         };
174
175         /// Position pointer for item search
176         struct position {
177             atomic_node_ptr * pPrev ;   ///< Previous node
178             node_type * pCur        ;   ///< Current node
179             node_type * pNext       ;   ///< Next node
180
181             atomic_node_ptr& refHead;
182             node_type * pDelChain; ///< Head of deleted node chain
183
184             position( atomic_node_ptr& head )
185                 : refHead( head )
186                 , pDelChain( nullptr )
187             {}
188
189             ~position()
190             {
191                 dispose_chain( pDelChain );
192             }
193         };
194         //@endcond
195
196     public:
197         using exempt_ptr = cds::urcu::exempt_ptr< gc, value_type, value_type, clear_and_dispose, void >; ///< pointer to extracted node
198
199     private:
200         //@cond
201         struct chain_disposer {
202             void operator()( node_type * pChain ) const
203             {
204                 dispose_chain( pChain );
205             }
206         };
207         typedef cds::intrusive::details::raw_ptr_disposer< gc, node_type, chain_disposer> raw_ptr_disposer;
208         //@endcond
209
210     public:
211         /// Result of \p get(), \p get_with() functions - pointer to the node found
212         typedef cds::urcu::raw_ptr< gc, value_type, raw_ptr_disposer > raw_ptr;
213
214     protected:
215         //@cond
216         template <bool IsConst>
217         class iterator_type
218         {
219             friend class MichaelList;
220             value_type * m_pNode;
221
222             void next()
223             {
224                 if ( m_pNode ) {
225                     node_type * p = node_traits::to_node_ptr( *m_pNode )->m_pNext.load(memory_model::memory_order_relaxed).ptr();
226                     m_pNode = p ? node_traits::to_value_ptr( p ) : nullptr;
227                 }
228             }
229
230         protected:
231             explicit iterator_type( node_type * pNode)
232             {
233                 if ( pNode )
234                     m_pNode = node_traits::to_value_ptr( *pNode );
235                 else
236                     m_pNode = nullptr;
237             }
238             explicit iterator_type( atomic_node_ptr const& refNode)
239             {
240                 node_type * pNode = refNode.load(memory_model::memory_order_relaxed).ptr();
241                 m_pNode = pNode ? node_traits::to_value_ptr( *pNode ) : nullptr;
242             }
243
244         public:
245             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
246             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
247
248             iterator_type()
249                 : m_pNode( nullptr )
250             {}
251
252             iterator_type( const iterator_type& src )
253                 : m_pNode( src.m_pNode )
254             {}
255
256             value_ptr operator ->() const
257             {
258                 return m_pNode;
259             }
260
261             value_ref operator *() const
262             {
263                 assert( m_pNode != nullptr );
264                 return *m_pNode;
265             }
266
267             /// Pre-increment
268             iterator_type& operator ++()
269             {
270                 next();
271                 return *this;
272             }
273
274             /// Post-increment
275             iterator_type operator ++(int)
276             {
277                 iterator_type i(*this);
278                 next();
279                 return i;
280             }
281
282             iterator_type& operator = (const iterator_type& src)
283             {
284                 m_pNode = src.m_pNode;
285                 return *this;
286             }
287
288             template <bool C>
289             bool operator ==(iterator_type<C> const& i ) const
290             {
291                 return m_pNode == i.m_pNode;
292             }
293             template <bool C>
294             bool operator !=(iterator_type<C> const& i ) const
295             {
296                 return m_pNode != i.m_pNode;
297             }
298         };
299         //@endcond
300
301     public:
302     ///@name Forward iterators (thread-safe only under RCU lock)
303     //@{
304         /// Forward iterator
305         /**
306             You may safely use iterators in multi-threaded environment only under RCU lock.
307             Otherwise, a crash is possible if another thread deletes the item the iterator points to.
308         */
309         typedef iterator_type<false>    iterator;
310
311         /// Const forward iterator
312         typedef iterator_type<true>     const_iterator;
313
314         /// Returns a forward iterator addressing the first element in a list
315         /**
316             For empty list \code begin() == end() \endcode
317         */
318         iterator begin()
319         {
320             return iterator( m_pHead );
321         }
322
323         /// Returns an iterator that addresses the location succeeding the last element in a list
324         /**
325             Do not use the value returned by <tt>end</tt> function to access any item.
326             Internally, <tt>end</tt> returning value equals to \p nullptr.
327
328             The returned value can be used only to control reaching the end of the list.
329             For empty list \code begin() == end() \endcode
330         */
331         iterator end()
332         {
333             return iterator();
334         }
335
336         /// Returns a forward const iterator addressing the first element in a list
337         const_iterator begin() const
338         {
339             return const_iterator(m_pHead );
340         }
341         /// Returns a forward const iterator addressing the first element in a list
342         const_iterator cbegin() const
343         {
344             return const_iterator(m_pHead );
345         }
346
347         /// Returns an const iterator that addresses the location succeeding the last element in a list
348         const_iterator end() const
349         {
350             return const_iterator();
351         }
352         /// Returns an const iterator that addresses the location succeeding the last element in a list
353         const_iterator cend() const
354         {
355             return const_iterator();
356         }
357     //@}
358
359     public:
360         /// Default constructor initializes empty list
361         MichaelList()
362             : m_pHead( nullptr )
363         {
364             static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
365         }
366
367         //@cond
368         template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
369         explicit MichaelList( Stat& st )
370             : m_pHead( nullptr )
371             , m_Stat( st )
372         {}
373         //@endcond
374
375         /// Destroy list
376         ~MichaelList()
377         {
378             clear();
379         }
380
381         /// Inserts new node
382         /**
383             The function inserts \p val in the list if the list does not contain
384             an item with key equal to \p val.
385
386             The function makes RCU lock internally.
387
388             Returns \p true if \p val is linked into the list, \p false otherwise.
389         */
390         bool insert( value_type& val )
391         {
392             return insert_at( m_pHead, val );
393         }
394
395         /// Inserts new node
396         /**
397             This function is intended for derived non-intrusive containers.
398
399             The function allows to split new item creating into two part:
400             - create item with key only
401             - insert new item into the list
402             - if inserting is success, calls \p f functor to initialize value-field of \p val.
403
404             The functor signature is:
405             \code
406                 void func( value_type& val );
407             \endcode
408             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
409             \p val no any other changes could be made on this list's item by concurrent threads.
410             The user-defined functor is called only if the inserting is success.
411
412             The function makes RCU lock internally.
413
414             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
415         */
416         template <typename Func>
417         bool insert( value_type& val, Func f )
418         {
419             return insert_at( m_pHead, val, f );
420         }
421
422         /// Updates the item
423         /**
424             The operation performs inserting or changing data with lock-free manner.
425
426             If the item \p val not found in the list, then \p val is inserted into the list
427             iff \p bAllowInsert is \p true.
428             Otherwise, the functor \p func is called with item found.
429             The functor signature is:
430             \code
431             struct functor {
432                 void operator()( bool bNew, value_type& item, value_type& val );
433             };
434             \endcode
435             with arguments:
436             - \p bNew - \p true if the item has been inserted, \p false otherwise
437             - \p item - item of the list
438             - \p val - argument \p val passed into the \p update() function
439             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
440             refer to the same thing.
441
442             The functor may change non-key fields of the \p item; however, \p func must guarantee
443             that during changing no any other modifications could be made on this item by concurrent threads.
444
445             Returns <tt> std::pair<bool, bool>  </tt> where \p first is \p true if operation is successful,
446             \p second is \p true if new item has been added or \p false if the item with \p key
447             already is in the list.
448
449             The function makes RCU lock internally.
450
451             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
452         */
453         template <typename Func>
454         std::pair<bool, bool> update( value_type& val, Func func, bool bAllowInsert = true )
455         {
456             return update_at( m_pHead, val, func, bAllowInsert );
457         }
458         //@cond
459         template <typename Func>
460         CDS_DEPRECATED("ensure() is deprecated, use update()")
461         std::pair<bool, bool> ensure( value_type& val, Func func )
462         {
463             return update( val, func, true );
464         }
465         //@endcond
466
467         /// Unlinks the item \p val from the list
468         /**
469             The function searches the item \p val in the list and unlink it from the list
470             if it is found and it is equal to \p val.
471
472             Difference between \p erase() and \p %unlink() functions: \p %erase() finds <i>a key</i>
473             and deletes the item found. \p %unlink() finds an item by key and deletes it
474             only if \p val is an item of that list, i.e. the pointer to the item found
475             is equal to <tt> &val </tt>.
476
477             The function returns \p true if success and \p false otherwise.
478
479             RCU \p synchronize method can be called.
480             Note that depending on RCU type used the \ref disposer call can be deferred.
481
482             \p disposer specified in \p Traits is called for unlinked item.
483
484             The function can throw cds::urcu::rcu_deadlock exception if deadlock is encountered and
485             deadlock checking policy is opt::v::rcu_throw_deadlock.
486         */
487         bool unlink( value_type& val )
488         {
489             return unlink_at( m_pHead, val );
490         }
491
492         /// Deletes the item from the list
493         /**
494             The function searches an item with key equal to \p key in the list,
495             unlinks it from the list, and returns \p true.
496             If the item with the key equal to \p key is not found the function return \p false.
497
498             RCU \p synchronize method can be called.
499             Note that depending on RCU type used the \ref disposer call can be deferred.
500
501             \p disposer specified in \p Traits is called for deleted item.
502
503             The function can throw \ref cds_urcu_rcu_deadlock "cds::urcu::rcu_deadlock" exception if a deadlock is detected and
504             the deadlock checking policy is \p opt::v::rcu_throw_deadlock.
505         */
506         template <typename Q>
507         bool erase( Q const& key )
508         {
509             return erase_at( m_pHead, key, key_comparator());
510         }
511
512         /// Deletes the item from the list using \p pred predicate for searching
513         /**
514             The function is an analog of \p erase(Q const&)
515             but \p pred is used for key comparing.
516             \p Less functor has the interface like \p std::less.
517             \p pred must imply the same element order as the comparator used for building the list.
518
519             \p disposer specified in \p Traits is called for deleted item.
520         */
521         template <typename Q, typename Less>
522         bool erase_with( Q const& key, Less pred )
523         {
524             CDS_UNUSED( pred );
525             return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
526         }
527
528         /// Deletes the item from the list
529         /**
530             The function searches an item with key equal to \p key in the list,
531             call \p func functor with item found, unlinks it from the list, and returns \p true.
532             The \p Func interface is
533             \code
534             struct functor {
535                 void operator()( value_type const& item );
536             };
537             \endcode
538
539             If the item with the key equal to \p key is not found the function return \p false.
540
541             RCU \p synchronize method can be called.
542             Note that depending on RCU type used the \ref disposer call can be deferred.
543
544             \p disposer specified in \p Traits is called for deleted item.
545
546             The function can throw \ref cds_urcu_rcu_deadlock "cds::urcu::rcu_deadlock" exception if a deadlock is detected and
547             the deadlock checking policy is \p opt::v::rcu_throw_deadlock.
548         */
549         template <typename Q, typename Func>
550         bool erase( Q const& key, Func func )
551         {
552             return erase_at( m_pHead, key, key_comparator(), func );
553         }
554
555         /// Deletes the item from the list using \p pred predicate for searching
556         /**
557             The function is an analog of \p erase(Q const&, Func)
558             but \p pred is used for key comparing.
559             \p Less functor has the interface like \p std::less.
560             \p pred must imply the same element order as the comparator used for building the list.
561
562             \p disposer specified in \p Traits is called for deleted item.
563         */
564         template <typename Q, typename Less, typename Func>
565         bool erase_with( Q const& key, Less pred, Func func )
566         {
567             CDS_UNUSED( pred );
568             return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), func );
569         }
570
571         /// Extracts an item from the list
572         /**
573             The function searches an item with key equal to \p key in the list,
574             unlinks it from the list, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
575             If \p key is not found the function returns an empty \p exempt_ptr.
576
577             @note The function does NOT dispose the item found. It just unlinks the item from the list
578             and returns a pointer to item found.
579             You shouldn't lock RCU for current thread before calling this function, and you should manually release
580             the returned exempt pointer before reusing it.
581
582             \code
583             #include <cds/urcu/general_buffered.h>
584             #include <cds/intrusive/michael_list_rcu.h>
585
586             typedef cds::urcu::gc< general_buffered<> > rcu;
587             typedef cds::intrusive::MichaelList< rcu, Foo > rcu_michael_list;
588
589             rcu_michael_list theList;
590             // ...
591
592             rcu_michael_list::exempt_ptr p1;
593
594             // The RCU should NOT be locked when extract() is called!
595             assert( !rcu::is_locked());
596
597             // You can call extract() function
598             p1 = theList.extract( 10 );
599             if ( p1 ) {
600                 // do something with p1
601                 ...
602             }
603
604             // We may safely release p1 here
605             // release() passes the pointer to RCU reclamation cycle:
606             // it invokes RCU retire_ptr function with the disposer you provided for the list.
607             p1.release();
608             \endcode
609         */
610         template <typename Q>
611         exempt_ptr extract( Q const& key )
612         {
613             return exempt_ptr( extract_at( m_pHead, key, key_comparator()));
614         }
615
616         /// Extracts an item from the list using \p pred predicate for searching
617         /**
618             This function is the analog for \p extract(Q const&)
619
620             The \p pred is a predicate used for key comparing.
621             \p Less has the interface like \p std::less.
622             \p pred must imply the same element order as \ref key_comparator.
623         */
624         template <typename Q, typename Less>
625         exempt_ptr extract_with( Q const& key, Less pred )
626         {
627             CDS_UNUSED( pred );
628             return exempt_ptr( extract_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>()));
629         }
630
631         /// Find the key \p val
632         /**
633             The function searches the item with key equal to \p key
634             and calls the functor \p f for item found.
635             The interface of \p Func functor is:
636             \code
637             struct functor {
638                 void operator()( value_type& item, Q& key );
639             };
640             \endcode
641             where \p item is the item found, \p key is the <tt>find</tt> function argument.
642
643             The functor can change non-key fields of \p item.
644             The function \p find does not serialize simultaneous access to the list \p item. If such access is
645             possible you must provide your own synchronization schema to exclude unsafe item modifications.
646
647             The function makes RCU lock internally.
648
649             The function returns \p true if \p val is found, \p false otherwise.
650         */
651         template <typename Q, typename Func>
652         bool find( Q& key, Func f )
653         {
654             return find_at( m_pHead, key, key_comparator(), f );
655         }
656         //@cond
657         template <typename Q, typename Func>
658         bool find( Q const& key, Func f )
659         {
660             return find_at( m_pHead, key, key_comparator(), f );
661         }
662         //@endcond
663
664         /// Finds \p key using \p pred predicate for searching
665         /**
666             The function is an analog of \p find(Q&, Func)
667             but \p pred is used for key comparing.
668             \p Less functor has the interface like \p std::less.
669             \p pred must imply the same element order as the comparator used for building the list.
670         */
671         template <typename Q, typename Less, typename Func>
672         bool find_with( Q& key, Less pred, Func f )
673         {
674             CDS_UNUSED( pred );
675             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
676         }
677         //@cond
678         template <typename Q, typename Less, typename Func>
679         bool find_with( Q const& key, Less pred, Func f )
680         {
681             CDS_UNUSED( pred );
682             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
683         }
684         //@endcond
685
686         /// Checks whether the list contains \p key
687         /**
688             The function searches the item with key equal to \p key
689             and returns \p true if it is found, and \p false otherwise.
690         */
691         template <typename Q>
692         bool contains( Q const& key )
693         {
694             return find_at( m_pHead, key, key_comparator());
695         }
696         //@cond
697         template <typename Q>
698         CDS_DEPRECATED("deprecated, use contains()")
699         bool find( Q const& key )
700         {
701             return contains( key );
702         }
703         //@endcond
704
705         /// Checks whether the map contains \p key using \p pred predicate for searching
706         /**
707             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
708             \p Less functor has the interface like \p std::less.
709             \p Less must imply the same element order as the comparator used for building the list.
710         */
711         template <typename Q, typename Less>
712         bool contains( Q const& key, Less pred )
713         {
714             CDS_UNUSED( pred );
715             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
716         }
717         //@cond
718         template <typename Q, typename Less>
719         CDS_DEPRECATED("deprecated, use contains()")
720         bool find_with( Q const& key, Less pred )
721         {
722             return contains( key, pred );
723         }
724         //@endcond
725
726         /// Finds \p key and return the item found
727         /** \anchor cds_intrusive_MichaelList_rcu_get
728             The function searches the item with key equal to \p key and returns the pointer to item found.
729             If \p key is not found it returns empty \p raw_ptr object.
730
731             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
732
733             RCU should be locked before call of this function.
734             Returned item is valid only while RCU is locked:
735             \code
736             typedef cds::intrusive::MichaelList< cds::urcu::gc< cds::urcu::general_buffered<> >, foo, my_traits > ord_list;
737             ord_list theList;
738             // ...
739             typename ord_list::raw_ptr rp;
740             {
741                 // Lock RCU
742                 ord_list::rcu_lock lock;
743
744                 rp = theList.get( 5 );
745                 if ( rp ) {
746                     // Deal with rp
747                     //...
748                 }
749                 // Unlock RCU by rcu_lock destructor
750                 // Node owned by rp can be retired by disposer at any time after RCU has been unlocked
751             }
752             // You can manually release rp after RCU-locked section
753             rp.release();
754             \endcode
755         */
756         template <typename Q>
757         raw_ptr get( Q const& key )
758         {
759             return get_at( m_pHead, key, key_comparator());
760         }
761
762         /// Finds \p key and return the item found
763         /**
764             The function is an analog of \ref cds_intrusive_MichaelList_rcu_get "get(Q const&)"
765             but \p pred is used for comparing the keys.
766
767             \p Less functor has the semantics like \p std::less but should take arguments of type \p value_type and \p Q
768             in any order.
769             \p pred must imply the same element order as the comparator used for building the list.
770         */
771         template <typename Q, typename Less>
772         raw_ptr get_with( Q const& key, Less pred )
773         {
774             CDS_UNUSED( pred );
775             return get_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
776         }
777
778         /// Clears the list using default disposer
779         /**
780             The function clears the list using default (provided by \p Traits class template argument) disposer functor.
781
782             RCU \p synchronize method can be called.
783             Note that depending on RCU type used the \ref disposer invocation can be deferred.
784
785             The function can throw \p cds::urcu::rcu_deadlock exception if a deadlock is encountered and
786             deadlock checking policy is \p opt::v::rcu_throw_deadlock.
787         */
788         void clear()
789         {
790             if( !empty()) {
791                 check_deadlock_policy::check();
792
793                 marked_node_ptr pHead;
794                 for (;;) {
795                     {
796                         rcu_lock l;
797                         pHead = m_pHead.load(memory_model::memory_order_acquire);
798                         if ( !pHead.ptr())
799                             break;
800                         marked_node_ptr pNext( pHead->m_pNext.load(memory_model::memory_order_relaxed));
801                         if ( cds_unlikely( !pHead->m_pNext.compare_exchange_weak( pNext, pNext | 1, memory_model::memory_order_acquire, memory_model::memory_order_relaxed )))
802                             continue;
803                         if ( cds_unlikely( !m_pHead.compare_exchange_weak( pHead, marked_node_ptr(pNext.ptr()), memory_model::memory_order_release, memory_model::memory_order_relaxed )))
804                             continue;
805                     }
806
807                     --m_ItemCounter;
808                     dispose_node( pHead.ptr());
809                 }
810             }
811         }
812
813         /// Check if the list is empty
814         bool empty() const
815         {
816             return m_pHead.load( memory_model::memory_order_relaxed ).all() == nullptr;
817         }
818
819         /// Returns list's item count
820         /**
821             The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
822             this function always returns 0.
823
824             @note Even if you use real item counter and it returns 0, this fact does not mean that the list
825             is empty. To check list emptyness use \p empty() method.
826         */
827         size_t size() const
828         {
829             return m_ItemCounter.value();
830         }
831
832         /// Returns const reference to internal statistics
833         stat const& statistics() const
834         {
835             return m_Stat;
836         }
837
838     protected:
839         //@cond
840         static void clear_links( node_type * pNode )
841         {
842             pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_release );
843             pNode->m_pDelChain = nullptr;
844         }
845
846         static void dispose_node( node_type * pNode )
847         {
848             assert( pNode );
849             assert( !gc::is_locked());
850
851             gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ));
852         }
853
854         static void dispose_chain( node_type * pChain )
855         {
856             if ( pChain ) {
857                 assert( !gc::is_locked());
858
859                 auto f = [&pChain]() -> cds::urcu::retired_ptr {
860                     node_type * p = pChain;
861                     if ( p ) {
862                         pChain = p->m_pDelChain;
863                         return cds::urcu::make_retired_ptr<clear_and_dispose>( node_traits::to_value_ptr( p ));
864                     }
865                     return cds::urcu::make_retired_ptr<clear_and_dispose>( static_cast<value_type *>(nullptr));
866                 };
867                 gc::batch_retire( std::ref( f ));
868             }
869         }
870
871         bool link_node( node_type * pNode, position& pos )
872         {
873             assert( pNode != nullptr );
874             link_checker::is_empty( pNode );
875
876             marked_node_ptr p( pos.pCur );
877             pNode->m_pNext.store( p, memory_model::memory_order_release );
878             if ( cds_likely( pos.pPrev->compare_exchange_strong( p, marked_node_ptr( pNode ), memory_model::memory_order_release, atomics::memory_order_relaxed )) )
879                 return true;
880
881             pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
882             return false;
883         }
884
885         static void link_to_remove_chain( position& pos, node_type * pDel )
886         {
887             assert( pDel->m_pDelChain == nullptr );
888
889             pDel->m_pDelChain = pos.pDelChain;
890             pos.pDelChain = pDel;
891         }
892
893         bool unlink_node( position& pos, erase_node_mask nMask )
894         {
895             assert( gc::is_locked());
896
897             // Mark the node (logical deletion)
898             marked_node_ptr next( pos.pNext, 0 );
899
900             if ( cds_likely( pos.pCur->m_pNext.compare_exchange_strong( next, next | nMask, memory_model::memory_order_release, atomics::memory_order_relaxed )) ) {
901
902                 // Try physical removal - fast path
903                 marked_node_ptr cur( pos.pCur );
904                 if ( cds_likely( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr( pos.pNext ), memory_model::memory_order_acquire, atomics::memory_order_relaxed )) ) {
905                     if ( nMask == erase_mask )
906                         link_to_remove_chain( pos, pos.pCur );
907                 }
908                 else {
909                     // Slow path
910                     search( pos.refHead, *node_traits::to_value_ptr( pos.pCur ), pos, key_comparator());
911                 }
912                 return true;
913             }
914             return false;
915         }
916
917         // split-list support
918         bool insert_aux_node( node_type * pNode )
919         {
920             return insert_aux_node( m_pHead, pNode );
921         }
922
923         // split-list support
924         bool insert_aux_node( atomic_node_ptr& refHead, node_type * pNode )
925         {
926             assert( pNode != nullptr );
927
928             // Hack: convert node_type to value_type.
929             // In principle, auxiliary node can be non-reducible to value_type
930             // We assume that comparator can correctly distinguish between aux and regular node.
931             return insert_at( refHead, *node_traits::to_value_ptr( pNode ));
932         }
933
934         bool insert_at( atomic_node_ptr& refHead, value_type& val )
935         {
936             position pos( refHead );
937             {
938                 rcu_lock l;
939                 return insert_at_locked( pos, val );
940             }
941         }
942
943         template <typename Func>
944         bool insert_at( atomic_node_ptr& refHead, value_type& val, Func f )
945         {
946             position pos( refHead );
947
948             {
949                 rcu_lock l;
950                 while ( true ) {
951                     if ( search( refHead, val, pos, key_comparator())) {
952                         m_Stat.onInsertFailed();
953                         return false;
954                     }
955
956                     if ( link_node( node_traits::to_node_ptr( val ), pos )) {
957                         f( val );
958                         ++m_ItemCounter;
959                         m_Stat.onInsertSuccess();
960                         return true;
961                     }
962
963                     // clear next field
964                     node_traits::to_node_ptr( val )->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
965                     m_Stat.onInsertRetry();
966                 }
967             }
968
969         }
970
971         iterator insert_at_( atomic_node_ptr& refHead, value_type& val )
972         {
973             rcu_lock l;
974             if ( insert_at_locked( refHead, val ))
975                 return iterator( node_traits::to_node_ptr( val ));
976             return end();
977         }
978
979         template <typename Func>
980         std::pair<iterator, bool> update_at_( atomic_node_ptr& refHead, value_type& val, Func func, bool bInsert )
981         {
982             position pos( refHead );
983             {
984                 rcu_lock l;
985                 return update_at_locked( pos, val, func, bInsert );
986             }
987         }
988
989         template <typename Func>
990         std::pair<bool, bool> update_at( atomic_node_ptr& refHead, value_type& val, Func func, bool bInsert )
991         {
992             position pos( refHead );
993             {
994                 rcu_lock l;
995                 std::pair<iterator, bool> ret = update_at_locked( pos, val, func, bInsert );
996                 return std::make_pair( ret.first != end(), ret.second );
997             }
998         }
999
1000         bool unlink_at( atomic_node_ptr& refHead, value_type& val )
1001         {
1002             position pos( refHead );
1003             back_off bkoff;
1004             check_deadlock_policy::check();
1005
1006             for (;;) {
1007                 {
1008                     rcu_lock l;
1009                     if ( !search( refHead, val, pos, key_comparator()) || node_traits::to_value_ptr( *pos.pCur ) != &val ) {
1010                         m_Stat.onEraseFailed();
1011                         return false;
1012                     }
1013                     if ( !unlink_node( pos, erase_mask )) {
1014                         bkoff();
1015                         m_Stat.onEraseRetry();
1016                         continue;
1017                     }
1018                 }
1019
1020                 --m_ItemCounter;
1021                 m_Stat.onEraseSuccess();
1022                 return true;
1023             }
1024         }
1025
1026         template <typename Q, typename Compare, typename Func>
1027         bool erase_at( position& pos, Q const& val, Compare cmp, Func f )
1028         {
1029             back_off bkoff;
1030             check_deadlock_policy::check();
1031
1032             node_type * pDel;
1033             for (;;) {
1034                 {
1035                     rcu_lock l;
1036                     if ( !search( pos.refHead, val, pos, cmp )) {
1037                         m_Stat.onEraseFailed();
1038                         return false;
1039                     }
1040
1041                     // store pCur since it may be changed by unlink_node() slow path
1042                     pDel = pos.pCur;
1043                     if ( !unlink_node( pos, erase_mask )) {
1044                         bkoff();
1045                         m_Stat.onEraseRetry();
1046                         continue;
1047                     }
1048                 }
1049                 assert( pDel );
1050                 f( *node_traits::to_value_ptr( pDel ));
1051                 --m_ItemCounter;
1052                 m_Stat.onEraseSuccess();
1053                 return true;
1054             }
1055         }
1056
1057         template <typename Q, typename Compare, typename Func>
1058         bool erase_at( atomic_node_ptr& refHead, Q const& val, Compare cmp, Func f )
1059         {
1060             position pos( refHead );
1061             return erase_at( pos, val, cmp, f );
1062         }
1063
1064         template <typename Q, typename Compare>
1065         bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp )
1066         {
1067             position pos( refHead );
1068             return erase_at( pos, val, cmp, [](value_type const&){} );
1069         }
1070
1071         template <typename Q, typename Compare >
1072         value_type * extract_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
1073         {
1074             position pos( refHead );
1075             back_off bkoff;
1076             assert( !gc::is_locked())  ;   // RCU must not be locked!!!
1077
1078             node_type * pExtracted;
1079             {
1080                 rcu_lock l;
1081                 for (;;) {
1082                     if ( !search( refHead, val, pos, cmp )) {
1083                         m_Stat.onEraseFailed();
1084                         return nullptr;
1085                     }
1086
1087                     // store pCur since it may be changed by unlink_node() slow path
1088                     pExtracted = pos.pCur;
1089                     if ( !unlink_node( pos, extract_mask )) {
1090                         bkoff();
1091                         m_Stat.onEraseRetry();
1092                         continue;
1093                     }
1094
1095                     --m_ItemCounter;
1096                     value_type * pRet = node_traits::to_value_ptr( pExtracted );
1097                     assert( pExtracted->m_pDelChain == nullptr );
1098                     m_Stat.onEraseSuccess();
1099                     return pRet;
1100                 }
1101             }
1102         }
1103
1104         template <typename Q, typename Compare, typename Func>
1105         bool find_at( atomic_node_ptr& refHead, Q& val, Compare cmp, Func f )
1106         {
1107             position pos( refHead );
1108
1109             {
1110                 rcu_lock l;
1111                 if ( search( refHead, val, pos, cmp )) {
1112                     assert( pos.pCur != nullptr );
1113                     f( *node_traits::to_value_ptr( *pos.pCur ), val );
1114                     m_Stat.onFindSuccess();
1115                     return true;
1116                 }
1117            }
1118
1119             m_Stat.onFindFailed();
1120             return false;
1121         }
1122
1123         template <typename Q, typename Compare>
1124         bool find_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
1125         {
1126             position pos( refHead );
1127             {
1128                 rcu_lock l;
1129                 return find_at_locked( pos, val, cmp ) != cend();
1130             }
1131         }
1132
1133         template <typename Q, typename Compare>
1134         raw_ptr get_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
1135         {
1136             // RCU should be locked!
1137             assert(gc::is_locked());
1138
1139             position pos( refHead );
1140
1141             if ( search( refHead, val, pos, cmp )) {
1142                 m_Stat.onFindSuccess();
1143                 return raw_ptr( node_traits::to_value_ptr( pos.pCur ), raw_ptr_disposer( pos ));
1144             }
1145
1146             m_Stat.onFindFailed();
1147             return raw_ptr( raw_ptr_disposer( pos ));
1148         }
1149         //@endcond
1150
1151     protected:
1152
1153         //@cond
1154         template <typename Q, typename Compare>
1155         bool search( atomic_node_ptr& refHead, const Q& val, position& pos, Compare cmp )
1156         {
1157             // RCU lock should be locked!!!
1158             assert( gc::is_locked());
1159
1160             atomic_node_ptr * pPrev;
1161             marked_node_ptr pNext;
1162             marked_node_ptr pCur;
1163
1164             back_off        bkoff;
1165
1166         try_again:
1167             pPrev = &refHead;
1168             pCur = pPrev->load(memory_model::memory_order_acquire);
1169             pNext = nullptr;
1170
1171             while ( true ) {
1172                 if ( !pCur.ptr()) {
1173                     pos.pPrev = pPrev;
1174                     pos.pCur = nullptr;
1175                     pos.pNext = nullptr;
1176                     return false;
1177                 }
1178
1179                 pNext = pCur->m_pNext.load(memory_model::memory_order_acquire);
1180
1181                 if ( cds_unlikely( pPrev->load(memory_model::memory_order_acquire) != pCur
1182                     || pNext != pCur->m_pNext.load(memory_model::memory_order_acquire )))
1183                 {
1184                     bkoff();
1185                     goto try_again;
1186                 }
1187
1188                 if ( pNext.bits()) {
1189                     // pCur is marked as deleted. Try to unlink it from the list
1190                     if ( cds_likely( pPrev->compare_exchange_weak( pCur, marked_node_ptr( pNext.ptr()), memory_model::memory_order_acquire, atomics::memory_order_relaxed ))) {
1191                         if ( pNext.bits() == erase_mask )
1192                             link_to_remove_chain( pos, pCur.ptr());
1193                         m_Stat.onHelpingSuccess();
1194                     }
1195
1196                     m_Stat.onHelpingFailed();
1197                     goto try_again;
1198                 }
1199
1200                 assert( pCur.ptr() != nullptr );
1201                 int nCmp = cmp( *node_traits::to_value_ptr( pCur.ptr()), val );
1202                 if ( nCmp >= 0 ) {
1203                     pos.pPrev = pPrev;
1204                     pos.pCur = pCur.ptr();
1205                     pos.pNext = pNext.ptr();
1206                     return nCmp == 0;
1207                 }
1208                 pPrev = &( pCur->m_pNext );
1209                 pCur = pNext;
1210             }
1211         }
1212         //@endcond
1213
1214     private:
1215         //@cond
1216         bool insert_at_locked( position& pos, value_type& val )
1217         {
1218             // RCU lock should be locked!!!
1219             assert( gc::is_locked());
1220
1221             while ( true ) {
1222                 if ( search( pos.refHead, val, pos, key_comparator())) {
1223                     m_Stat.onInsertFailed();
1224                     return false;
1225                 }
1226
1227                 if ( link_node( node_traits::to_node_ptr( val ), pos )) {
1228                     ++m_ItemCounter;
1229                     m_Stat.onInsertSuccess();
1230                     return true;
1231                 }
1232
1233                 // clear next field
1234                 node_traits::to_node_ptr( val )->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
1235                 m_Stat.onInsertRetry();
1236             }
1237         }
1238
1239         template <typename Func>
1240         std::pair<iterator, bool> update_at_locked( position& pos, value_type& val, Func func, bool bInsert )
1241         {
1242             // RCU should be locked!!!
1243             assert( gc::is_locked());
1244
1245             while ( true ) {
1246                 if ( search( pos.refHead, val, pos, key_comparator()) ) {
1247                     assert( key_comparator()( val, *node_traits::to_value_ptr( *pos.pCur )) == 0 );
1248
1249                     func( false, *node_traits::to_value_ptr( *pos.pCur ), val );
1250                     m_Stat.onUpdateExisting();
1251                     return std::make_pair( iterator( pos.pCur ), false );
1252                 }
1253                 else {
1254                     if ( !bInsert ) {
1255                         m_Stat.onUpdateFailed();
1256                         return std::make_pair( end(), false );
1257                     }
1258
1259                     if ( link_node( node_traits::to_node_ptr( val ), pos )) {
1260                         ++m_ItemCounter;
1261                         func( true, val , val );
1262                         m_Stat.onUpdateNew();
1263                         return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
1264                     }
1265
1266                     // clear the next field
1267                     node_traits::to_node_ptr( val )->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
1268                     m_Stat.onUpdateRetry();
1269                 }
1270             }
1271         }
1272
1273         template <typename Q, typename Compare>
1274         const_iterator find_at_locked( position& pos, Q const& val, Compare cmp )
1275         {
1276             assert( gc::is_locked());
1277
1278             if ( search( pos.refHead, val, pos, cmp )) {
1279                 assert( pos.pCur != nullptr );
1280                 m_Stat.onFindSuccess();
1281                 return const_iterator( pos.pCur );
1282             }
1283
1284             m_Stat.onFindFailed();
1285             return cend();
1286         }
1287         //@endcond
1288     };
1289
1290 }}  // namespace cds::intrusive
1291
1292 #endif  // #ifndef CDSLIB_INTRUSIVE_MICHAEL_LIST_NOGC_H