On dev: MIchaelList
[libcds.git] / cds / intrusive / impl / michael_list.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_INTRUSIVE_IMPL_MICHAEL_LIST_H
4 #define __CDS_INTRUSIVE_IMPL_MICHAEL_LIST_H
5
6 #include <cds/intrusive/details/michael_list_base.h>
7 #include <cds/gc/guarded_ptr.h>
8 #include <cds/details/make_const_type.h>
9
10 namespace cds { namespace intrusive {
11
12     /// Michael's lock-free ordered single-linked list
13     /** @ingroup cds_intrusive_list
14         \anchor cds_intrusive_MichaelList_hp
15
16         Usually, ordered single-linked list is used as a building block for the hash table implementation.
17         The complexity of searching is <tt>O(N)</tt>.
18
19         Source:
20             - [2002] Maged Michael "High performance dynamic lock-free hash tables and list-based sets"
21
22         Template arguments:
23         - \p GC - Garbage collector used. Note the \p GC must be the same as the GC used for item type \p T (see \p michael_list::node).
24         - \p T - type to be stored in the list. The type must be based on michael_list::node (for michael_list::base_hook)
25             or it must have a member of type michael_list::node (for michael_list::member_hook).
26         - \p Traits - type traits, default is \p michael_list::traits. It is possible to declare option-based 
27              list with \p cds::intrusive::michael_list::make_traits metafunction:
28             For example, the following traits-based declaration of \p gc::HP Michael's list
29             \code
30             #include <cds/intrusive/michael_list_hp.h>
31             // Declare item stored in your list
32             struct item: public cds::intrusive::michael_list::node< cds::gc::HP >
33             {
34                 int nKey;
35                 // .... other data
36             };
37
38             // Declare comparator for the item
39             struct my_compare {
40                 int operator()( item const& i1, item const& i2 ) const
41                 {
42                     return i1.nKey - i2.nKey;
43                 }
44             };
45
46             // Declare traits
47             struct my_traits: public cds::intrusive::michael_list::traits
48             {
49                 typedef cds::intrusive::michael_list::base_hook< cds::opt::gc< cds::gc::HP > >   hook;
50                 typedef my_compare compare;
51             };
52
53             // Declare traits-based list
54             typedef cds::intrusive::MichaelList< cds::gc::HP, item, my_traits >     traits_based_list;
55             \endcode
56             is equivalent for the following option-based list
57             \code
58             #include <cds/intrusive/michael_list_hp.h>
59
60             // item struct and my_compare are the same
61
62             // Declare option-based list
63             typedef cds::intrusive::MichaelList< cds::gc::HP, item,
64                 typename cds::intrusive::michael_list::make_traits<
65                     cds::intrusive::opt::hook< cds::intrusive::michael_list::base_hook< cds::opt::gc< cds::gc::HP > > >    // hook option
66                     ,cds::intrusive::opt::compare< my_compare >     // item comparator option
67                 >::type
68             >     option_based_list;
69             \endcode
70
71         \par Usage
72         There are different specializations of this template for each garbage collecting schema used.
73         You should select GC needed and include appropriate .h-file:
74         - for gc::HP: \code #include <cds/intrusive/michael_list_hp.h> \endcode
75         - for gc::DHP: \code #include <cds/intrusive/michael_list_dhp.h> \endcode
76         - for \ref cds_urcu_gc "RCU type" - see \ref cds_intrusive_MichaelList_rcu "RCU-based MichaelList"
77         - for gc::nogc: \code #include <cds/intrusive/michael_list_nogc.h> \endcode
78             See \ref cds_intrusive_MichaelList_nogc "non-GC MichaelList"
79
80         Then, you should incorporate michael_list::node into your struct \p T and provide
81         appropriate \p michael_list::traits::hook in your \p Traits template parameters. Usually, for \p Traits you
82         define a struct based on \p michael_list::traits.
83
84         Example for \p gc::PTB and base hook:
85         \code
86         // Include GC-related Michael's list specialization
87         #include <cds/intrusive/michael_list_dhp.h>
88
89         // Data stored in Michael's list
90         struct my_data: public cds::intrusive::michael_list::node< cds::gc::PTB >
91         {
92             // key field
93             std::string     strKey;
94
95             // other data
96             // ...
97         };
98
99         // my_data comparing functor
100         struct my_data_cmp {
101             int operator()( const my_data& d1, const my_data& d2 )
102             {
103                 return d1.strKey.compare( d2.strKey );
104             }
105
106             int operator()( const my_data& d, const std::string& s )
107             {
108                 return d.strKey.compare(s);
109             }
110
111             int operator()( const std::string& s, const my_data& d )
112             {
113                 return s.compare( d.strKey );
114             }
115         };
116
117
118         // Declare traits
119         struct my_traits: public cds::intrusive::michael_list::traits
120         {
121             typedef cds::intrusive::michael_list::base_hook< cds::opt::gc< cds::gc::PTB > >   hook;
122             typedef my_data_cmp compare;
123         };
124
125         // Declare list type
126         typedef cds::intrusive::MichaelList< cds::gc::PTB, my_data, my_traits >     traits_based_list;
127         \endcode
128
129         Equivalent option-based code:
130         \code
131         // GC-related specialization
132         #include <cds/intrusive/michael_list_dhp.h>
133
134         struct my_data {
135             // see above
136         };
137         struct compare {
138             // see above
139         };
140
141         // Declare option-based list
142         typedef cds::intrusive::MichaelList< cds::gc::PTB
143             ,my_data
144             , typename cds::intrusive::michael_list::make_traits<
145                 cds::intrusive::opt::hook< cds::intrusive::michael_list::base_hook< cds::opt::gc< cds::gc::PTB > > >
146                 ,cds::intrusive::opt::compare< my_data_cmp >
147             >::type
148         > option_based_list;
149
150         \endcode
151     */
152     template <
153         class GC
154         ,typename T
155 #ifdef CDS_DOXYGEN_INVOKED
156         ,class Traits = michael_list::traits
157 #else
158         ,class Traits
159 #endif
160     >
161     class MichaelList
162     {
163     public:
164         typedef T       value_type; ///< type of value stored in the list
165         typedef Traits  traits;     ///< Traits template parameter
166
167         typedef typename traits::hook    hook;      ///< hook type
168         typedef typename hook::node_type node_type; ///< node type
169
170 #   ifdef CDS_DOXYGEN_INVOKED
171         typedef implementation_defined key_comparator  ;    ///< key comparison functor based on opt::compare and opt::less option setter.
172 #   else
173         typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;
174 #   endif
175
176         typedef typename traits::disposer  disposer; ///< disposer used
177         typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ;    ///< node traits
178         typedef typename michael_list::get_link_checker< node_type, traits::link_checker >::type link_checker;   ///< link checker
179
180         typedef GC  gc          ;   ///< Garbage collector
181         typedef typename traits::back_off  back_off;   ///< back-off strategy
182         typedef typename traits::item_counter item_counter;   ///< Item counting policy used
183         typedef typename traits::memory_model  memory_model;   ///< Memory ordering. See cds::opt::memory_model option
184
185         typedef cds::gc::guarded_ptr< gc, value_type > guarded_ptr; ///< Guarded pointer
186
187         //@cond
188         // Rebind traits (split-list support)
189         template <typename... Options>
190         struct rebind_traits {
191             typedef MichaelList<
192                 gc
193                 , value_type
194                 , typename cds::opt::make_options< traits, Options...>::type
195             >   type;
196         };
197         //@endcond
198
199     protected:
200         typedef typename node_type::atomic_marked_ptr   atomic_node_ptr;   ///< Atomic node pointer
201         typedef typename node_type::marked_ptr          marked_node_ptr;   ///< Node marked pointer
202
203         typedef atomic_node_ptr     auxiliary_head;   ///< Auxiliary head type (for split-list support)
204
205         atomic_node_ptr     m_pHead;        ///< Head pointer
206         item_counter        m_ItemCounter;  ///< Item counter
207
208         //@cond
209         /// Position pointer for item search
210         struct position {
211             atomic_node_ptr * pPrev ;   ///< Previous node
212             node_type * pCur        ;   ///< Current node
213             node_type * pNext       ;   ///< Next node
214
215             typename gc::template GuardArray<3> guards  ;   ///< Guards array
216
217             enum {
218                 guard_prev_item,
219                 guard_current_item,
220                 guard_next_item
221             };
222         };
223
224         struct clean_disposer {
225             void operator()( value_type * p )
226             {
227                 michael_list::node_cleaner<gc, node_type, memory_model>()( node_traits::to_node_ptr( p ) );
228                 disposer()( p );
229             }
230         };
231         //@endcond
232
233     protected:
234         //@cond
235         static void retire_node( node_type * pNode )
236         {
237             assert( pNode != nullptr );
238             gc::template retire<clean_disposer>( node_traits::to_value_ptr( *pNode ) );
239         }
240
241         static bool link_node( node_type * pNode, position& pos )
242         {
243             assert( pNode != nullptr );
244             link_checker::is_empty( pNode );
245
246             marked_node_ptr cur(pos.pCur);
247             pNode->m_pNext.store( cur, memory_model::memory_order_relaxed );
248             return pos.pPrev->compare_exchange_strong( cur, marked_node_ptr(pNode), memory_model::memory_order_release, atomics::memory_order_relaxed );
249         }
250
251         static bool unlink_node( position& pos )
252         {
253             assert( pos.pPrev != nullptr );
254             assert( pos.pCur != nullptr );
255
256             // Mark the node (logical deleting)
257             marked_node_ptr next(pos.pNext, 0);
258             if ( pos.pCur->m_pNext.compare_exchange_strong( next, marked_node_ptr(pos.pNext, 1), memory_model::memory_order_release, atomics::memory_order_relaxed )) {
259                 // physical deletion may be performed by search function if it detects that a node is logically deleted (marked)
260                 // CAS may be successful here or in other thread that searching something
261                 marked_node_ptr cur(pos.pCur);
262                 if ( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr( pos.pNext ), memory_model::memory_order_release, atomics::memory_order_relaxed ))
263                     retire_node( pos.pCur );
264                 return true;
265             }
266             return false;
267         }
268         //@endcond
269
270     protected:
271         //@cond
272         template <bool IsConst>
273         class iterator_type
274         {
275             friend class MichaelList;
276
277         protected:
278             value_type * m_pNode;
279             typename gc::Guard  m_Guard;
280
281             void next()
282             {
283                 if ( m_pNode ) {
284                     typename gc::Guard g;
285                     node_type * pCur = node_traits::to_node_ptr( *m_pNode );
286
287                     marked_node_ptr pNext;
288                     do {
289                         pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed);
290                         g.assign( node_traits::to_value_ptr( pNext.ptr() ));
291                     } while ( pNext != pCur->m_pNext.load(memory_model::memory_order_acquire) );
292
293                     if ( pNext.ptr() ) {
294                         m_pNode = m_Guard.assign( g.template get<value_type>() );
295                     }
296                     else {
297                         m_pNode = nullptr;
298                         m_Guard.clear();
299                     }
300                 }
301             }
302
303             iterator_type( atomic_node_ptr const& pNode )
304             {
305                 for (;;) {
306                     marked_node_ptr p = pNode.load(memory_model::memory_order_relaxed);
307                     if ( p.ptr() ) {
308                         m_pNode = m_Guard.assign( node_traits::to_value_ptr( p.ptr() ) );
309                     }
310                     else {
311                         m_pNode = nullptr;
312                         m_Guard.clear();
313                     }
314                     if ( p == pNode.load(memory_model::memory_order_acquire) )
315                         break;
316                 }
317             }
318
319         public:
320             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
321             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
322
323             iterator_type()
324                 : m_pNode( nullptr )
325             {}
326
327             iterator_type( iterator_type const& src )
328             {
329                 if ( src.m_pNode ) {
330                     m_pNode = m_Guard.assign( src.m_pNode );
331                 }
332                 else
333                     m_pNode = nullptr;
334             }
335
336             value_ptr operator ->() const
337             {
338                 return m_pNode;
339             }
340
341             value_ref operator *() const
342             {
343                 assert( m_pNode != nullptr );
344                 return *m_pNode;
345             }
346
347             /// Pre-increment
348             iterator_type& operator ++()
349             {
350                 next();
351                 return *this;
352             }
353
354             iterator_type& operator = (iterator_type const& src)
355             {
356                 m_pNode = src.m_pNode;
357                 m_Guard.assign( m_pNode );
358                 return *this;
359             }
360
361             /*
362             /// Post-increment
363             void operator ++(int)
364             {
365                 next();
366             }
367             */
368
369             template <bool C>
370             bool operator ==(iterator_type<C> const& i ) const
371             {
372                 return m_pNode == i.m_pNode;
373             }
374             template <bool C>
375             bool operator !=(iterator_type<C> const& i ) const
376             {
377                 return m_pNode != i.m_pNode;
378             }
379         };
380         //@endcond
381
382     public:
383         /// Forward iterator
384         /**
385             The forward iterator for Michael's list has some features:
386             - it has no post-increment operator
387             - to protect the value, the iterator contains a GC-specific guard + another guard is required locally for increment operator.
388               For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
389               may be thrown if the limit of guard count per thread is exceeded.
390             - The iterator cannot be moved across thread boundary since it contains thread-private GC's guard.
391             - Iterator ensures thread-safety even if you delete the item the iterator points to. However, in case of concurrent
392               deleting operations there is no guarantee that you iterate all item in the list.
393
394             Therefore, the use of iterators in concurrent environment is not good idea. Use the iterator on the concurrent container
395             for debug purpose only.
396
397             The iterator interface:
398             \code
399             class iterator {
400             public:
401                 // Default constructor
402                 iterator();
403
404                 // Copy construtor
405                 iterator( iterator const& src );
406
407                 // Dereference operator
408                 value_type * operator ->() const;
409
410                 // Dereference operator
411                 value_type& operator *() const;
412
413                 // Preincrement operator
414                 iterator& operator ++();
415
416                 // Assignment operator
417                 iterator& operator = (iterator const& src);
418
419                 // Equality operators
420                 bool operator ==(iterator const& i ) const;
421                 bool operator !=(iterator const& i ) const;
422             };
423             \endcode
424         */
425         typedef iterator_type<false>    iterator;
426         /// Const forward iterator
427         /**
428             For iterator's features and requirements see \ref iterator
429         */
430         typedef iterator_type<true>     const_iterator;
431
432         /// Returns a forward iterator addressing the first element in a list
433         /**
434             For empty list \code begin() == end() \endcode
435         */
436         iterator begin()
437         {
438             return iterator( m_pHead );
439         }
440
441         /// Returns an iterator that addresses the location succeeding the last element in a list
442         /**
443             Do not use the value returned by <tt>end</tt> function to access any item.
444             Internally, <tt>end</tt> returning value equals to \p nullptr.
445
446             The returned value can be used only to control reaching the end of the list.
447             For empty list <tt>begin() == end()</tt>
448         */
449         iterator end()
450         {
451             return iterator();
452         }
453
454         /// Returns a forward const iterator addressing the first element in a list
455         const_iterator cbegin()
456         {
457             return const_iterator( m_pHead );
458         }
459
460         /// Returns a forward const iterator addressing the first element in a list
461         const_iterator begin() const
462         {
463             return const_iterator( m_pHead );
464         }
465
466         /// Returns an const iterator that addresses the location succeeding the last element in a list
467         const_iterator end() const
468         {
469             return const_iterator();
470         }
471
472         /// Returns an const iterator that addresses the location succeeding the last element in a list
473         const_iterator cend()
474         {
475             return const_iterator();
476         }
477
478     public:
479         /// Default constructor initializes empty list
480         MichaelList()
481             : m_pHead( nullptr )
482         {
483             static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
484         }
485
486         /// Destroys the list object
487         ~MichaelList()
488         {
489             clear();
490         }
491
492         /// Inserts new node
493         /**
494             The function inserts \p val into the list if the list does not contain
495             an item with key equal to \p val.
496
497             Returns \p true if \p val has been linked to the list, \p false otherwise.
498         */
499         bool insert( value_type& val )
500         {
501             return insert_at( m_pHead, val );
502         }
503
504         /// Inserts new node
505         /**
506             This function is intended for derived non-intrusive containers.
507
508             The function allows to split new item creating into two part:
509             - create item with key only
510             - insert new item into the list
511             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
512
513             The functor signature is:
514             \code
515                 void func( value_type& val );
516             \endcode
517             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
518             \p val no any other changes could be made on this list's item by concurrent threads.
519             The user-defined functor is called only if the inserting is success.
520         */
521         template <typename Func>
522         bool insert( value_type& val, Func f )
523         {
524             return insert_at( m_pHead, val, f );
525         }
526
527         /// Ensures that the \p val exists in the list
528         /**
529             The operation performs inserting or changing data with lock-free manner.
530
531             If the item \p val is not found in the list, then \p val is inserted.
532             Otherwise, the functor \p func is called with item found.
533             The functor signature is:
534             \code
535                 void func( bool bNew, value_type& item, value_type& val );
536             \endcode
537             with arguments:
538             - \p bNew - \p true if the item has been inserted, \p false otherwise
539             - \p item - item of the list
540             - \p val - argument \p val passed into the \p ensure function
541             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
542             refers to the same thing.
543
544             The functor may change non-key fields of the \p item; however, \p func must guarantee
545             that during changing no any other modifications could be made on this item by concurrent threads.
546
547             Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
548             \p second is \p true if new item has been added or \p false if the item with \p key
549             already is in the list.
550         */
551         template <typename Func>
552         std::pair<bool, bool> ensure( value_type& val, Func func )
553         {
554             return ensure_at( m_pHead, val, func );
555         }
556
557         /// Unlinks the item \p val from the list
558         /**
559             The function searches the item \p val in the list and unlinks it from the list
560             if it is found and it is equal to \p val.
561
562             Difference between \p erase() and \p %unlink(): \p %erase() finds <i>a key</i>
563             and deletes the item found. \p %unlink() finds an item by key and deletes it
564             only if \p val is an item of the list, i.e. the pointer to item found
565             is equal to <tt> &val </tt>.
566
567             The function returns \p true if success and \p false otherwise.
568         */
569         bool unlink( value_type& val )
570         {
571             return unlink_at( m_pHead, val );
572         }
573
574         /// Deletes the item from the list
575         /** \anchor cds_intrusive_MichaelList_hp_erase_val
576             The function searches an item with key equal to \p key in the list,
577             unlinks it from the list, and returns \p true.
578             If \p key is not found the function return \p false.
579         */
580         template <typename Q>
581         bool erase( Q const& key )
582         {
583             return erase_at( m_pHead, key, key_comparator() );
584         }
585
586         /// Deletes the item from the list using \p pred predicate for searching
587         /**
588             The function is an analog of \ref cds_intrusive_MichaelList_hp_erase_val "erase(Q const&)"
589             but \p pred is used for key comparing.
590             \p Less functor has the interface like \p std::less.
591             \p pred must imply the same element order as the comparator used for building the list.
592         */
593         template <typename Q, typename Less>
594         bool erase_with( Q const& key, Less pred )
595         {
596             return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
597         }
598
599         /// Deletes the item from the list
600         /** \anchor cds_intrusive_MichaelList_hp_erase_func
601             The function searches an item with key equal to \p key in the list,
602             call \p func functor with item found, unlinks it from the list, and returns \p true.
603             The \p Func interface is
604             \code
605             struct functor {
606                 void operator()( value_type const& item );
607             };
608             \endcode
609             If \p key is not found the function return \p false, \p func is not called.
610         */
611         template <typename Q, typename Func>
612         bool erase( Q const& key, Func func )
613         {
614             return erase_at( m_pHead, key, key_comparator(), func );
615         }
616
617         /// Deletes the item from the list using \p pred predicate for searching
618         /**
619             The function is an analog of \ref cds_intrusive_MichaelList_hp_erase_func "erase(Q const&, Func)"
620             but \p pred is used for key comparing.
621             \p Less functor has the interface like \p std::less.
622             \p pred must imply the same element order as the comparator used for building the list.
623         */
624         template <typename Q, typename Less, typename Func>
625         bool erase_with( Q const& key, Less pred, Func f )
626         {
627             return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
628         }
629
630         /// Extracts the item from the list with specified \p key
631         /** \anchor cds_intrusive_MichaelList_hp_extract
632             The function searches an item with key equal to \p key,
633             unlinks it from the list, and returns it in \p dest parameter.
634             If the item with key equal to \p key is not found the function returns \p false.
635
636             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
637
638             The \ref disposer specified in \p Traits class template parameter is called automatically
639             by garbage collector \p GC when returned \ref guarded_ptr object will be destroyed or released.
640             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
641
642             Usage:
643             \code
644             typedef cds::intrusive::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
645             ord_list theList;
646             // ...
647             {
648                 ord_list::guarded_ptr gp;
649                 theList.extract( gp, 5 );
650                 // Deal with gp
651                 // ...
652
653                 // Destructor of gp releases internal HP guard
654             }
655             \endcode
656         */
657         template <typename Q>
658         bool extract( guarded_ptr& dest, Q const& key )
659         {
660             return extract_at( m_pHead, dest.guard(), key, key_comparator() );
661         }
662
663         /// Extracts the item using compare functor \p pred
664         /**
665             The function is an analog of \ref cds_intrusive_MichaelList_hp_extract "extract(guarded_ptr&, Q const&)"
666             but \p pred predicate is used for key comparing.
667
668             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
669             in any order.
670             \p pred must imply the same element order as the comparator used for building the list.
671         */
672         template <typename Q, typename Less>
673         bool extract_with( guarded_ptr& dest, Q const& key, Less pred )
674         {
675             return extract_at( m_pHead, dest.guard(), key, cds::opt::details::make_comparator_from_less<Less>() );
676         }
677
678         /// Finds \p key in the list
679         /** \anchor cds_intrusive_MichaelList_hp_find_func
680             The function searches the item with key equal to \p key and calls the functor \p f for item found.
681             The interface of \p Func functor is:
682             \code
683             struct functor {
684                 void operator()( value_type& item, Q& key );
685             };
686             \endcode
687             where \p item is the item found, \p key is the <tt>find</tt> function argument.
688
689             The functor may change non-key fields of \p item. Note that the function is only guarantee
690             that \p item cannot be disposed during functor is executing.
691             The function does not serialize simultaneous access to the \p item. If such access is
692             possible you must provide your own synchronization schema to keep out unsafe item modifications.
693
694             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
695             may modify both arguments.
696
697             The function returns \p true if \p val is found, \p false otherwise.
698         */
699         template <typename Q, typename Func>
700         bool find( Q& key, Func f )
701         {
702             return find_at( m_pHead, key, key_comparator(), f );
703         }
704
705         /// Finds the \p key using \p pred predicate for searching
706         /**
707             The function is an analog of \ref cds_intrusive_MichaelList_hp_find_func "find(Q&, Func)"
708             but \p pred is used for key comparing.
709             \p Less functor has the interface like \p std::less.
710             \p pred must imply the same element order as the comparator used for building the list.
711         */
712         template <typename Q, typename Less, typename Func>
713         bool find_with( Q& key, Less pred, Func f )
714         {
715             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
716         }
717
718         /// Finds the \p key
719         /** \anchor cds_intrusive_MichaelList_hp_find_val
720             The function searches the item with key equal to \p key
721             and returns \p true if it is found, and \p false otherwise
722         */
723         template <typename Q>
724         bool find( Q const& key )
725         {
726             return find_at( m_pHead, key, key_comparator() );
727         }
728
729         /// Finds the key \p val using \p pred predicate for searching
730         /**
731             The function is an analog of \ref cds_intrusive_MichaelList_hp_find_val "find(Q const&)"
732             but \p pred is used for key comparing.
733             \p Less functor has the interface like \p std::less.
734             \p pred must imply the same element order as the comparator used for building the list.
735         */
736         template <typename Q, typename Less>
737         bool find_with( Q const& key, Less pred )
738         {
739             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>() );
740         }
741
742         /// Finds the \p key and return the item found
743         /** \anchor cds_intrusive_MichaelList_hp_get
744             The function searches the item with key equal to \p key
745             and assigns the item found to guarded pointer \p ptr.
746             The function returns \p true if \p key is found, and \p false otherwise.
747             If \p key is not found the \p ptr parameter is not changed.
748
749             The \ref disposer specified in \p Traits class template parameter is called
750             by garbage collector \p GC automatically when returned \ref guarded_ptr object
751             will be destroyed or released.
752             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
753
754             Usage:
755             \code
756             typedef cds::intrusive::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
757             ord_list theList;
758             // ...
759             {
760                 ord_list::guarded_ptr gp;
761                 if ( theList.get( gp, 5 )) {
762                     // Deal with gp
763                     //...
764                 }
765                 // Destructor of guarded_ptr releases internal HP guard
766             }
767             \endcode
768
769             Note the compare functor specified for \p Traits template parameter
770             should accept a parameter of type \p Q that can be not the same as \p value_type.
771         */
772         template <typename Q>
773         bool get( guarded_ptr& ptr, Q const& key )
774         {
775             return get_at( m_pHead, ptr.guard(), key, key_comparator() );
776         }
777
778         /// Finds the \p key and return the item found
779         /**
780             The function is an analog of \ref cds_intrusive_MichaelList_hp_get "get( guarded_ptr& ptr, Q const&)"
781             but \p pred is used for comparing the keys.
782
783             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
784             in any order.
785             \p pred must imply the same element order as the comparator used for building the list.
786         */
787         template <typename Q, typename Less>
788         bool get_with( guarded_ptr& ptr, Q const& key, Less pred )
789         {
790             return get_at( m_pHead, ptr.guard(), key, cds::opt::details::make_comparator_from_less<Less>() );
791         }
792
793         /// Clears the list
794         /**
795             The function unlink all items from the list.
796         */
797         void clear()
798         {
799             typename gc::Guard guard;
800             marked_node_ptr head;
801             while ( true ) {
802                 head = m_pHead.load(memory_model::memory_order_relaxed);
803                 if ( head.ptr() )
804                     guard.assign( node_traits::to_value_ptr( *head.ptr() ));
805                 if ( m_pHead.load(memory_model::memory_order_acquire) == head ) {
806                     if ( head.ptr() == nullptr )
807                         break;
808                     value_type& val = *node_traits::to_value_ptr( *head.ptr() );
809                     unlink( val );
810                 }
811             }
812         }
813
814         /// Checks whether the list is empty
815         bool empty() const
816         {
817             return m_pHead.load( memory_model::memory_order_relaxed ).all() == nullptr;
818         }
819
820         /// Returns list's item count
821         /**
822             The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
823             this function always returns 0.
824
825             @note Even if you use real item counter and it returns 0, this fact does not mean that the list
826             is empty. To check list emptyness use \p empty() method.
827         */
828         size_t size() const
829         {
830             return m_ItemCounter.value();
831         }
832
833     protected:
834         //@cond
835         // split-list support
836         bool insert_aux_node( node_type * pNode )
837         {
838             return insert_aux_node( m_pHead, pNode );
839         }
840
841         // split-list support
842         bool insert_aux_node( atomic_node_ptr& refHead, node_type * pNode )
843         {
844             assert( pNode != nullptr );
845
846             // Hack: convert node_type to value_type.
847             // In principle, auxiliary node can be non-reducible to value_type
848             // We assume that comparator can correctly distinguish aux and regular node.
849             return insert_at( refHead, *node_traits::to_value_ptr( pNode ) );
850         }
851
852         bool insert_at( atomic_node_ptr& refHead, value_type& val )
853         {
854             node_type * pNode = node_traits::to_node_ptr( val );
855             link_checker::is_empty( pNode );
856             position pos;
857
858             while ( true ) {
859                 if ( search( refHead, val, pos, key_comparator() ) )
860                     return false;
861
862                 if ( link_node( pNode, pos ) ) {
863                     ++m_ItemCounter;
864                     return true;
865                 }
866
867                 // clear next field
868                 pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
869             }
870         }
871
872         template <typename Func>
873         bool insert_at( atomic_node_ptr& refHead, value_type& val, Func f )
874         {
875             node_type * pNode = node_traits::to_node_ptr( val );
876             link_checker::is_empty( pNode );
877             position pos;
878
879             while ( true ) {
880                 if ( search( refHead, val, pos, key_comparator() ) )
881                     return false;
882
883                 typename gc::Guard guard;
884                 guard.assign( &val );
885                 if ( link_node( pNode, pos ) ) {
886                     f( val );
887                     ++m_ItemCounter;
888                     return true;
889                 }
890
891                 // clear next field
892                 pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
893             }
894         }
895
896         template <typename Func>
897         std::pair<bool, bool> ensure_at( atomic_node_ptr& refHead, value_type& val, Func func )
898         {
899             position pos;
900
901             node_type * pNode = node_traits::to_node_ptr( val );
902             while ( true ) {
903                 if ( search( refHead, val, pos, key_comparator() ) ) {
904                     if ( pos.pCur->m_pNext.load(memory_model::memory_order_acquire).bits() ) {
905                         back_off()();
906                         continue        ;   // the node found is marked as deleted
907                     }
908                     assert( key_comparator()( val, *node_traits::to_value_ptr( *pos.pCur ) ) == 0 );
909
910                     func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
911                     return std::make_pair( true, false );
912                 }
913                 else {
914                     typename gc::Guard guard;
915                     guard.assign( &val );
916                     if ( link_node( pNode, pos ) ) {
917                         ++m_ItemCounter;
918                         func( true, val, val );
919                         return std::make_pair( true, true );
920                     }
921                     // clear next field
922                     pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
923                 }
924             }
925         }
926
927         bool unlink_at( atomic_node_ptr& refHead, value_type& val )
928         {
929             position pos;
930
931             back_off bkoff;
932             while ( search( refHead, val, pos, key_comparator() ) ) {
933                 if ( node_traits::to_value_ptr( *pos.pCur ) == &val ) {
934                     if ( unlink_node( pos ) ) {
935                         --m_ItemCounter;
936                         return true;
937                     }
938                     else
939                         bkoff();
940                 }
941                 else
942                     break;
943             }
944             return false;
945         }
946
947         template <typename Q, typename Compare, typename Func>
948         bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f, position& pos )
949         {
950             back_off bkoff;
951             while ( search( refHead, val, pos, cmp )) {
952                 if ( unlink_node( pos ) ) {
953                     f( *node_traits::to_value_ptr( *pos.pCur ) );
954                     --m_ItemCounter;
955                     return true;
956                 }
957                 else
958                     bkoff();
959             }
960             return false;
961         }
962
963         template <typename Q, typename Compare, typename Func>
964         bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f )
965         {
966             position pos;
967             return erase_at( refHead, val, cmp, f, pos );
968         }
969
970         template <typename Q, typename Compare>
971         bool erase_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
972         {
973             position pos;
974             return erase_at( refHead, val, cmp, [](value_type const&){}, pos );
975         }
976
977         template <typename Q, typename Compare>
978         bool extract_at( atomic_node_ptr& refHead, typename gc::Guard& dest, Q const& val, Compare cmp )
979         {
980             position pos;
981             back_off bkoff;
982             while ( search( refHead, val, pos, cmp )) {
983                 if ( unlink_node( pos ) ) {
984                     dest.assign( pos.guards.template get<value_type>( position::guard_current_item ) );
985                     --m_ItemCounter;
986                     return true;
987                 }
988                 else
989                     bkoff();
990             }
991             return false;
992         }
993
994         template <typename Q, typename Compare>
995         bool find_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
996         {
997             position pos;
998             return search( refHead, val, pos, cmp );
999         }
1000
1001         template <typename Q, typename Compare, typename Func>
1002         bool find_at( atomic_node_ptr& refHead, Q& val, Compare cmp, Func f )
1003         {
1004             position pos;
1005             if ( search( refHead, val, pos, cmp )) {
1006                 f( *node_traits::to_value_ptr( *pos.pCur ), val );
1007                 return true;
1008             }
1009             return false;
1010         }
1011
1012         template <typename Q, typename Compare>
1013         bool get_at( atomic_node_ptr& refHead, typename gc::Guard& guard, Q const& val, Compare cmp )
1014         {
1015             position pos;
1016             if ( search( refHead, val, pos, cmp )) {
1017                 guard.assign( pos.guards.template get<value_type>( position::guard_current_item ));
1018                 return true;
1019             }
1020             return false;
1021         }
1022
1023         //@endcond
1024
1025     protected:
1026
1027         //@cond
1028         template <typename Q, typename Compare >
1029         bool search( atomic_node_ptr& refHead, const Q& val, position& pos, Compare cmp )
1030         {
1031             atomic_node_ptr * pPrev;
1032             marked_node_ptr pNext;
1033             marked_node_ptr pCur;
1034
1035             back_off        bkoff;
1036
1037 try_again:
1038             pPrev = &refHead;
1039             pNext = nullptr;
1040
1041             pCur = pPrev->load(memory_model::memory_order_relaxed);
1042             pos.guards.assign( position::guard_current_item, node_traits::to_value_ptr( pCur.ptr() ) );
1043             if ( pPrev->load(memory_model::memory_order_acquire) != pCur.ptr() )
1044                 goto try_again;
1045
1046             while ( true ) {
1047                 if ( pCur.ptr() == nullptr ) {
1048                     pos.pPrev = pPrev;
1049                     pos.pCur = pCur.ptr();
1050                     pos.pNext = pNext.ptr();
1051                     return false;
1052                 }
1053
1054                 pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed);
1055                 pos.guards.assign( position::guard_next_item, node_traits::to_value_ptr( pNext.ptr() ));
1056                 if ( pCur->m_pNext.load(memory_model::memory_order_relaxed).all() != pNext.all() ) {
1057                     bkoff();
1058                     goto try_again;
1059                 }
1060
1061                 if ( pPrev->load(memory_model::memory_order_relaxed).all() != pCur.ptr() ) {
1062                     bkoff();
1063                     goto try_again;
1064                 }
1065
1066                 // pNext contains deletion mark for pCur
1067                 if ( pNext.bits() == 1 ) {
1068                     // pCur marked i.e. logically deleted. Help the erase/unlink function to unlink pCur node
1069                     marked_node_ptr cur( pCur.ptr());
1070                     if ( pPrev->compare_exchange_strong( cur, marked_node_ptr( pNext.ptr() ), memory_model::memory_order_release, atomics::memory_order_relaxed )) {
1071                         retire_node( pCur.ptr() );
1072                     }
1073                     else {
1074                         bkoff();
1075                         goto try_again;
1076                     }
1077                 }
1078                 else {
1079                     assert( pCur.ptr() != nullptr );
1080                     int nCmp = cmp( *node_traits::to_value_ptr( pCur.ptr() ), val );
1081                     if ( nCmp >= 0 ) {
1082                         pos.pPrev = pPrev;
1083                         pos.pCur = pCur.ptr();
1084                         pos.pNext = pNext.ptr();
1085                         return nCmp == 0;
1086                     }
1087                     pPrev = &( pCur->m_pNext );
1088                     pos.guards.assign( position::guard_prev_item, node_traits::to_value_ptr( pCur.ptr() ) );
1089                 }
1090                 pCur = pNext;
1091                 pos.guards.assign( position::guard_current_item, node_traits::to_value_ptr( pCur.ptr() ));
1092             }
1093         }
1094         //@endcond
1095     };
1096 }} // namespace cds::intrusive
1097
1098 #endif // #ifndef __CDS_INTRUSIVE_IMPL_MICHAEL_LIST_H