757bc7a3340fffdb3891e4bb1928524bcac1e8f3
[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 \p michael_list::node (for \p michael_list::base_hook)
25             or it must have a member of type \p michael_list::node (for \p 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.
73         You should select GC needed and include appropriate .h-file:
74         - for \p gc::HP: <tt> <cds/intrusive/michael_list_hp.h> </tt>
75         - for \p gc::DHP: <tt> <cds/intrusive/michael_list_dhp.h> </tt>
76         - for \ref cds_urcu_gc "RCU type" - see \ref cds_intrusive_MichaelList_rcu "RCU-based MichaelList"
77         - for \p gc::nogc: <tt> <cds/intrusive/michael_list_nogc.h> </tt>
78             See \ref cds_intrusive_MichaelList_nogc "non-GC MichaelList"
79
80         Then, you should incorporate \p 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::DHP 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::DHP >
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::DHP > >   hook;
122             typedef my_data_cmp compare;
123         };
124
125         // Declare list type
126         typedef cds::intrusive::MichaelList< cds::gc::DHP, 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::DHP
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::DHP > > >
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() const
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() const
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             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
522         */
523         template <typename Func>
524         bool insert( value_type& val, Func f )
525         {
526             return insert_at( m_pHead, val, f );
527         }
528
529         /// Ensures that the \p val exists in the list
530         /**
531             The operation performs inserting or changing data with lock-free manner.
532
533             If the item \p val is not found in the list, then \p val is inserted.
534             Otherwise, the functor \p func is called with item found.
535             The functor signature is:
536             \code
537                 void func( bool bNew, value_type& item, value_type& val );
538             \endcode
539             with arguments:
540             - \p bNew - \p true if the item has been inserted, \p false otherwise
541             - \p item - item of the list
542             - \p val - argument \p val passed into the \p ensure function
543             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
544             refers to the same thing.
545
546             The functor may change non-key fields of the \p item; however, \p func must guarantee
547             that during changing no any other modifications could be made on this item by concurrent threads.
548
549             Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
550             \p second is \p true if new item has been added or \p false if the item with \p key
551             already is in the list.
552
553             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
554         */
555         template <typename Func>
556         std::pair<bool, bool> ensure( value_type& val, Func func )
557         {
558             return ensure_at( m_pHead, val, func );
559         }
560
561         /// Unlinks the item \p val from the list
562         /**
563             The function searches the item \p val in the list and unlinks it from the list
564             if it is found and it is equal to \p val.
565
566             Difference between \p erase() and \p %unlink(): \p %erase() finds <i>a key</i>
567             and deletes the item found. \p %unlink() finds an item by key and deletes it
568             only if \p val is an item of the list, i.e. the pointer to item found
569             is equal to <tt> &val </tt>.
570
571             The function returns \p true if success and \p false otherwise.
572         */
573         bool unlink( value_type& val )
574         {
575             return unlink_at( m_pHead, val );
576         }
577
578         /// Deletes the item from the list
579         /** \anchor cds_intrusive_MichaelList_hp_erase_val
580             The function searches an item with key equal to \p key in the list,
581             unlinks it from the list, and returns \p true.
582             If \p key is not found the function return \p false.
583         */
584         template <typename Q>
585         bool erase( Q const& key )
586         {
587             return erase_at( m_pHead, key, key_comparator() );
588         }
589
590         /// Deletes the item from the list using \p pred predicate for searching
591         /**
592             The function is an analog of \ref cds_intrusive_MichaelList_hp_erase_val "erase(Q const&)"
593             but \p pred is used for key comparing.
594             \p Less functor has the interface like \p std::less.
595             \p pred must imply the same element order as the comparator used for building the list.
596         */
597         template <typename Q, typename Less>
598         bool erase_with( Q const& key, Less pred )
599         {
600             return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
601         }
602
603         /// Deletes the item from the list
604         /** \anchor cds_intrusive_MichaelList_hp_erase_func
605             The function searches an item with key equal to \p key in the list,
606             call \p func functor with item found, unlinks it from the list, and returns \p true.
607             The \p Func interface is
608             \code
609             struct functor {
610                 void operator()( value_type const& item );
611             };
612             \endcode
613             If \p key is not found the function return \p false, \p func is not called.
614         */
615         template <typename Q, typename Func>
616         bool erase( Q const& key, Func func )
617         {
618             return erase_at( m_pHead, key, key_comparator(), func );
619         }
620
621         /// Deletes the item from the list using \p pred predicate for searching
622         /**
623             The function is an analog of \ref cds_intrusive_MichaelList_hp_erase_func "erase(Q const&, Func)"
624             but \p pred is used for key comparing.
625             \p Less functor has the interface like \p std::less.
626             \p pred must imply the same element order as the comparator used for building the list.
627         */
628         template <typename Q, typename Less, typename Func>
629         bool erase_with( Q const& key, Less pred, Func f )
630         {
631             return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
632         }
633
634         /// Extracts the item from the list with specified \p key
635         /** \anchor cds_intrusive_MichaelList_hp_extract
636             The function searches an item with key equal to \p key,
637             unlinks it from the list, and returns it in \p dest parameter.
638             If the item with key equal to \p key is not found the function returns \p false.
639
640             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
641
642             The \ref disposer specified in \p Traits class template parameter is called automatically
643             by garbage collector \p GC when returned \ref guarded_ptr object will be destroyed or released.
644             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
645
646             Usage:
647             \code
648             typedef cds::intrusive::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
649             ord_list theList;
650             // ...
651             {
652                 ord_list::guarded_ptr gp;
653                 theList.extract( gp, 5 );
654                 // Deal with gp
655                 // ...
656
657                 // Destructor of gp releases internal HP guard
658             }
659             \endcode
660         */
661         template <typename Q>
662         bool extract( guarded_ptr& dest, Q const& key )
663         {
664             return extract_at( m_pHead, dest.guard(), key, key_comparator() );
665         }
666
667         /// Extracts the item using compare functor \p pred
668         /**
669             The function is an analog of \ref cds_intrusive_MichaelList_hp_extract "extract(guarded_ptr&, Q const&)"
670             but \p pred predicate is used for key comparing.
671
672             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
673             in any order.
674             \p pred must imply the same element order as the comparator used for building the list.
675         */
676         template <typename Q, typename Less>
677         bool extract_with( guarded_ptr& dest, Q const& key, Less pred )
678         {
679             return extract_at( m_pHead, dest.guard(), key, cds::opt::details::make_comparator_from_less<Less>() );
680         }
681
682         /// Finds \p key in the list
683         /** \anchor cds_intrusive_MichaelList_hp_find_func
684             The function searches the item with key equal to \p key and calls the functor \p f for item found.
685             The interface of \p Func functor is:
686             \code
687             struct functor {
688                 void operator()( value_type& item, Q& key );
689             };
690             \endcode
691             where \p item is the item found, \p key is the <tt>find</tt> function argument.
692
693             The functor may change non-key fields of \p item. Note that the function is only guarantee
694             that \p item cannot be disposed during functor is executing.
695             The function does not serialize simultaneous access to the \p item. If such access is
696             possible you must provide your own synchronization schema to keep out unsafe item modifications.
697
698             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
699             may modify both arguments.
700
701             The function returns \p true if \p val is found, \p false otherwise.
702         */
703         template <typename Q, typename Func>
704         bool find( Q& key, Func f )
705         {
706             return find_at( m_pHead, key, key_comparator(), f );
707         }
708         //@cond
709         template <typename Q, typename Func>
710         bool find( Q const& key, Func f )
711         {
712             return find_at( m_pHead, key, key_comparator(), f );
713         }
714         //@endcond
715
716         /// Finds the \p key using \p pred predicate for searching
717         /**
718             The function is an analog of \ref cds_intrusive_MichaelList_hp_find_func "find(Q&, Func)"
719             but \p pred is used for key comparing.
720             \p Less functor has the interface like \p std::less.
721             \p pred must imply the same element order as the comparator used for building the list.
722         */
723         template <typename Q, typename Less, typename Func>
724         bool find_with( Q& key, Less pred, Func f )
725         {
726             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
727         }
728         //@cond
729         template <typename Q, typename Less, typename Func>
730         bool find_with( Q const& key, Less pred, Func f )
731         {
732             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
733         }
734         //@endcond
735
736         /// Finds the \p key
737         /** \anchor cds_intrusive_MichaelList_hp_find_val
738             The function searches the item with key equal to \p key
739             and returns \p true if it is found, and \p false otherwise
740         */
741         template <typename Q>
742         bool find( Q const& key )
743         {
744             return find_at( m_pHead, key, key_comparator() );
745         }
746
747         /// Finds the key \p val using \p pred predicate for searching
748         /**
749             The function is an analog of \ref cds_intrusive_MichaelList_hp_find_val "find(Q const&)"
750             but \p pred is used for key comparing.
751             \p Less functor has the interface like \p std::less.
752             \p pred must imply the same element order as the comparator used for building the list.
753         */
754         template <typename Q, typename Less>
755         bool find_with( Q const& key, Less pred )
756         {
757             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>() );
758         }
759
760         /// Finds the \p key and return the item found
761         /** \anchor cds_intrusive_MichaelList_hp_get
762             The function searches the item with key equal to \p key
763             and assigns the item found to guarded pointer \p ptr.
764             The function returns \p true if \p key is found, and \p false otherwise.
765             If \p key is not found the \p ptr parameter is not changed.
766
767             The \ref disposer specified in \p Traits class template parameter is called
768             by garbage collector \p GC automatically when returned \ref guarded_ptr object
769             will be destroyed or released.
770             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
771
772             Usage:
773             \code
774             typedef cds::intrusive::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
775             ord_list theList;
776             // ...
777             {
778                 ord_list::guarded_ptr gp;
779                 if ( theList.get( gp, 5 )) {
780                     // Deal with gp
781                     //...
782                 }
783                 // Destructor of guarded_ptr releases internal HP guard
784             }
785             \endcode
786
787             Note the compare functor specified for \p Traits template parameter
788             should accept a parameter of type \p Q that can be not the same as \p value_type.
789         */
790         template <typename Q>
791         bool get( guarded_ptr& ptr, Q const& key )
792         {
793             return get_at( m_pHead, ptr.guard(), key, key_comparator() );
794         }
795
796         /// Finds the \p key and return the item found
797         /**
798             The function is an analog of \ref cds_intrusive_MichaelList_hp_get "get( guarded_ptr& ptr, Q const&)"
799             but \p pred is used for comparing the keys.
800
801             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
802             in any order.
803             \p pred must imply the same element order as the comparator used for building the list.
804         */
805         template <typename Q, typename Less>
806         bool get_with( guarded_ptr& ptr, Q const& key, Less pred )
807         {
808             return get_at( m_pHead, ptr.guard(), key, cds::opt::details::make_comparator_from_less<Less>() );
809         }
810
811         /// Clears the list
812         /**
813             The function unlink all items from the list.
814         */
815         void clear()
816         {
817             typename gc::Guard guard;
818             marked_node_ptr head;
819             while ( true ) {
820                 head = m_pHead.load(memory_model::memory_order_relaxed);
821                 if ( head.ptr() )
822                     guard.assign( node_traits::to_value_ptr( *head.ptr() ));
823                 if ( m_pHead.load(memory_model::memory_order_acquire) == head ) {
824                     if ( head.ptr() == nullptr )
825                         break;
826                     value_type& val = *node_traits::to_value_ptr( *head.ptr() );
827                     unlink( val );
828                 }
829             }
830         }
831
832         /// Checks whether the list is empty
833         bool empty() const
834         {
835             return m_pHead.load( memory_model::memory_order_relaxed ).all() == nullptr;
836         }
837
838         /// Returns list's item count
839         /**
840             The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
841             this function always returns 0.
842
843             @note Even if you use real item counter and it returns 0, this fact does not mean that the list
844             is empty. To check list emptyness use \p empty() method.
845         */
846         size_t size() const
847         {
848             return m_ItemCounter.value();
849         }
850
851     protected:
852         //@cond
853         // split-list support
854         bool insert_aux_node( node_type * pNode )
855         {
856             return insert_aux_node( m_pHead, pNode );
857         }
858
859         // split-list support
860         bool insert_aux_node( atomic_node_ptr& refHead, node_type * pNode )
861         {
862             assert( pNode != nullptr );
863
864             // Hack: convert node_type to value_type.
865             // In principle, auxiliary node can be non-reducible to value_type
866             // We assume that comparator can correctly distinguish aux and regular node.
867             return insert_at( refHead, *node_traits::to_value_ptr( pNode ) );
868         }
869
870         bool insert_at( atomic_node_ptr& refHead, value_type& val )
871         {
872             node_type * pNode = node_traits::to_node_ptr( val );
873             link_checker::is_empty( pNode );
874             position pos;
875
876             while ( true ) {
877                 if ( search( refHead, val, pos, key_comparator() ) )
878                     return false;
879
880                 if ( link_node( pNode, pos ) ) {
881                     ++m_ItemCounter;
882                     return true;
883                 }
884
885                 // clear next field
886                 pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
887             }
888         }
889
890         template <typename Func>
891         bool insert_at( atomic_node_ptr& refHead, value_type& val, Func f )
892         {
893             node_type * pNode = node_traits::to_node_ptr( val );
894             link_checker::is_empty( pNode );
895             position pos;
896
897             while ( true ) {
898                 if ( search( refHead, val, pos, key_comparator() ) )
899                     return false;
900
901                 typename gc::Guard guard;
902                 guard.assign( &val );
903                 if ( link_node( pNode, pos ) ) {
904                     f( val );
905                     ++m_ItemCounter;
906                     return true;
907                 }
908
909                 // clear next field
910                 pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
911             }
912         }
913
914         template <typename Func>
915         std::pair<bool, bool> ensure_at( atomic_node_ptr& refHead, value_type& val, Func func )
916         {
917             position pos;
918
919             node_type * pNode = node_traits::to_node_ptr( val );
920             while ( true ) {
921                 if ( search( refHead, val, pos, key_comparator() ) ) {
922                     if ( pos.pCur->m_pNext.load(memory_model::memory_order_acquire).bits() ) {
923                         back_off()();
924                         continue        ;   // the node found is marked as deleted
925                     }
926                     assert( key_comparator()( val, *node_traits::to_value_ptr( *pos.pCur ) ) == 0 );
927
928                     func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
929                     return std::make_pair( true, false );
930                 }
931                 else {
932                     typename gc::Guard guard;
933                     guard.assign( &val );
934                     if ( link_node( pNode, pos ) ) {
935                         ++m_ItemCounter;
936                         func( true, val, val );
937                         return std::make_pair( true, true );
938                     }
939                     // clear next field
940                     pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
941                 }
942             }
943         }
944
945         bool unlink_at( atomic_node_ptr& refHead, value_type& val )
946         {
947             position pos;
948
949             back_off bkoff;
950             while ( search( refHead, val, pos, key_comparator() ) ) {
951                 if ( node_traits::to_value_ptr( *pos.pCur ) == &val ) {
952                     if ( unlink_node( pos ) ) {
953                         --m_ItemCounter;
954                         return true;
955                     }
956                     else
957                         bkoff();
958                 }
959                 else
960                     break;
961             }
962             return false;
963         }
964
965         template <typename Q, typename Compare, typename Func>
966         bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f, position& pos )
967         {
968             back_off bkoff;
969             while ( search( refHead, val, pos, cmp )) {
970                 if ( unlink_node( pos ) ) {
971                     f( *node_traits::to_value_ptr( *pos.pCur ) );
972                     --m_ItemCounter;
973                     return true;
974                 }
975                 else
976                     bkoff();
977             }
978             return false;
979         }
980
981         template <typename Q, typename Compare, typename Func>
982         bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f )
983         {
984             position pos;
985             return erase_at( refHead, val, cmp, f, pos );
986         }
987
988         template <typename Q, typename Compare>
989         bool erase_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
990         {
991             position pos;
992             return erase_at( refHead, val, cmp, [](value_type const&){}, pos );
993         }
994
995         template <typename Q, typename Compare>
996         bool extract_at( atomic_node_ptr& refHead, typename gc::Guard& dest, Q const& val, Compare cmp )
997         {
998             position pos;
999             back_off bkoff;
1000             while ( search( refHead, val, pos, cmp )) {
1001                 if ( unlink_node( pos ) ) {
1002                     dest.assign( pos.guards.template get<value_type>( position::guard_current_item ) );
1003                     --m_ItemCounter;
1004                     return true;
1005                 }
1006                 else
1007                     bkoff();
1008             }
1009             return false;
1010         }
1011
1012         template <typename Q, typename Compare>
1013         bool find_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
1014         {
1015             position pos;
1016             return search( refHead, val, pos, cmp );
1017         }
1018
1019         template <typename Q, typename Compare, typename Func>
1020         bool find_at( atomic_node_ptr& refHead, Q& val, Compare cmp, Func f )
1021         {
1022             position pos;
1023             if ( search( refHead, val, pos, cmp )) {
1024                 f( *node_traits::to_value_ptr( *pos.pCur ), val );
1025                 return true;
1026             }
1027             return false;
1028         }
1029
1030         template <typename Q, typename Compare>
1031         bool get_at( atomic_node_ptr& refHead, typename gc::Guard& guard, Q const& val, Compare cmp )
1032         {
1033             position pos;
1034             if ( search( refHead, val, pos, cmp )) {
1035                 guard.assign( pos.guards.template get<value_type>( position::guard_current_item ));
1036                 return true;
1037             }
1038             return false;
1039         }
1040
1041         //@endcond
1042
1043     protected:
1044
1045         //@cond
1046         template <typename Q, typename Compare >
1047         bool search( atomic_node_ptr& refHead, const Q& val, position& pos, Compare cmp )
1048         {
1049             atomic_node_ptr * pPrev;
1050             marked_node_ptr pNext;
1051             marked_node_ptr pCur;
1052
1053             back_off        bkoff;
1054
1055 try_again:
1056             pPrev = &refHead;
1057             pNext = nullptr;
1058
1059             pCur = pPrev->load(memory_model::memory_order_relaxed);
1060             pos.guards.assign( position::guard_current_item, node_traits::to_value_ptr( pCur.ptr() ) );
1061             if ( pPrev->load(memory_model::memory_order_acquire) != pCur.ptr() )
1062                 goto try_again;
1063
1064             while ( true ) {
1065                 if ( pCur.ptr() == nullptr ) {
1066                     pos.pPrev = pPrev;
1067                     pos.pCur = pCur.ptr();
1068                     pos.pNext = pNext.ptr();
1069                     return false;
1070                 }
1071
1072                 pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed);
1073                 pos.guards.assign( position::guard_next_item, node_traits::to_value_ptr( pNext.ptr() ));
1074                 if ( pCur->m_pNext.load(memory_model::memory_order_relaxed).all() != pNext.all() ) {
1075                     bkoff();
1076                     goto try_again;
1077                 }
1078
1079                 if ( pPrev->load(memory_model::memory_order_relaxed).all() != pCur.ptr() ) {
1080                     bkoff();
1081                     goto try_again;
1082                 }
1083
1084                 // pNext contains deletion mark for pCur
1085                 if ( pNext.bits() == 1 ) {
1086                     // pCur marked i.e. logically deleted. Help the erase/unlink function to unlink pCur node
1087                     marked_node_ptr cur( pCur.ptr());
1088                     if ( pPrev->compare_exchange_strong( cur, marked_node_ptr( pNext.ptr() ), memory_model::memory_order_release, atomics::memory_order_relaxed )) {
1089                         retire_node( pCur.ptr() );
1090                     }
1091                     else {
1092                         bkoff();
1093                         goto try_again;
1094                     }
1095                 }
1096                 else {
1097                     assert( pCur.ptr() != nullptr );
1098                     int nCmp = cmp( *node_traits::to_value_ptr( pCur.ptr() ), val );
1099                     if ( nCmp >= 0 ) {
1100                         pos.pPrev = pPrev;
1101                         pos.pCur = pCur.ptr();
1102                         pos.pNext = pNext.ptr();
1103                         return nCmp == 0;
1104                     }
1105                     pPrev = &( pCur->m_pNext );
1106                     pos.guards.assign( position::guard_prev_item, node_traits::to_value_ptr( pCur.ptr() ) );
1107                 }
1108                 pCur = pNext;
1109                 pos.guards.assign( position::guard_current_item, node_traits::to_value_ptr( pCur.ptr() ));
1110             }
1111         }
1112         //@endcond
1113     };
1114 }} // namespace cds::intrusive
1115
1116 #endif // #ifndef __CDS_INTRUSIVE_IMPL_MICHAEL_LIST_H