12106f287ed1cba3c4e7aaf503c2a51525a0defd
[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
709         /// Finds the \p key using \p pred predicate for searching
710         /**
711             The function is an analog of \ref cds_intrusive_MichaelList_hp_find_func "find(Q&, Func)"
712             but \p pred is used for key comparing.
713             \p Less functor has the interface like \p std::less.
714             \p pred must imply the same element order as the comparator used for building the list.
715         */
716         template <typename Q, typename Less, typename Func>
717         bool find_with( Q& key, Less pred, Func f )
718         {
719             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
720         }
721
722         /// Finds the \p key
723         /** \anchor cds_intrusive_MichaelList_hp_find_val
724             The function searches the item with key equal to \p key
725             and returns \p true if it is found, and \p false otherwise
726         */
727         template <typename Q>
728         bool find( Q const& key )
729         {
730             return find_at( m_pHead, key, key_comparator() );
731         }
732
733         /// Finds the key \p val using \p pred predicate for searching
734         /**
735             The function is an analog of \ref cds_intrusive_MichaelList_hp_find_val "find(Q const&)"
736             but \p pred is used for key comparing.
737             \p Less functor has the interface like \p std::less.
738             \p pred must imply the same element order as the comparator used for building the list.
739         */
740         template <typename Q, typename Less>
741         bool find_with( Q const& key, Less pred )
742         {
743             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>() );
744         }
745
746         /// Finds the \p key and return the item found
747         /** \anchor cds_intrusive_MichaelList_hp_get
748             The function searches the item with key equal to \p key
749             and assigns the item found to guarded pointer \p ptr.
750             The function returns \p true if \p key is found, and \p false otherwise.
751             If \p key is not found the \p ptr parameter is not changed.
752
753             The \ref disposer specified in \p Traits class template parameter is called
754             by garbage collector \p GC automatically when returned \ref guarded_ptr object
755             will be destroyed or released.
756             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
757
758             Usage:
759             \code
760             typedef cds::intrusive::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
761             ord_list theList;
762             // ...
763             {
764                 ord_list::guarded_ptr gp;
765                 if ( theList.get( gp, 5 )) {
766                     // Deal with gp
767                     //...
768                 }
769                 // Destructor of guarded_ptr releases internal HP guard
770             }
771             \endcode
772
773             Note the compare functor specified for \p Traits template parameter
774             should accept a parameter of type \p Q that can be not the same as \p value_type.
775         */
776         template <typename Q>
777         bool get( guarded_ptr& ptr, Q const& key )
778         {
779             return get_at( m_pHead, ptr.guard(), key, key_comparator() );
780         }
781
782         /// Finds the \p key and return the item found
783         /**
784             The function is an analog of \ref cds_intrusive_MichaelList_hp_get "get( guarded_ptr& ptr, Q const&)"
785             but \p pred is used for comparing the keys.
786
787             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
788             in any order.
789             \p pred must imply the same element order as the comparator used for building the list.
790         */
791         template <typename Q, typename Less>
792         bool get_with( guarded_ptr& ptr, Q const& key, Less pred )
793         {
794             return get_at( m_pHead, ptr.guard(), key, cds::opt::details::make_comparator_from_less<Less>() );
795         }
796
797         /// Clears the list
798         /**
799             The function unlink all items from the list.
800         */
801         void clear()
802         {
803             typename gc::Guard guard;
804             marked_node_ptr head;
805             while ( true ) {
806                 head = m_pHead.load(memory_model::memory_order_relaxed);
807                 if ( head.ptr() )
808                     guard.assign( node_traits::to_value_ptr( *head.ptr() ));
809                 if ( m_pHead.load(memory_model::memory_order_acquire) == head ) {
810                     if ( head.ptr() == nullptr )
811                         break;
812                     value_type& val = *node_traits::to_value_ptr( *head.ptr() );
813                     unlink( val );
814                 }
815             }
816         }
817
818         /// Checks whether the list is empty
819         bool empty() const
820         {
821             return m_pHead.load( memory_model::memory_order_relaxed ).all() == nullptr;
822         }
823
824         /// Returns list's item count
825         /**
826             The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
827             this function always returns 0.
828
829             @note Even if you use real item counter and it returns 0, this fact does not mean that the list
830             is empty. To check list emptyness use \p empty() method.
831         */
832         size_t size() const
833         {
834             return m_ItemCounter.value();
835         }
836
837     protected:
838         //@cond
839         // split-list support
840         bool insert_aux_node( node_type * pNode )
841         {
842             return insert_aux_node( m_pHead, pNode );
843         }
844
845         // split-list support
846         bool insert_aux_node( atomic_node_ptr& refHead, node_type * pNode )
847         {
848             assert( pNode != nullptr );
849
850             // Hack: convert node_type to value_type.
851             // In principle, auxiliary node can be non-reducible to value_type
852             // We assume that comparator can correctly distinguish aux and regular node.
853             return insert_at( refHead, *node_traits::to_value_ptr( pNode ) );
854         }
855
856         bool insert_at( atomic_node_ptr& refHead, value_type& val )
857         {
858             node_type * pNode = node_traits::to_node_ptr( val );
859             link_checker::is_empty( pNode );
860             position pos;
861
862             while ( true ) {
863                 if ( search( refHead, val, pos, key_comparator() ) )
864                     return false;
865
866                 if ( link_node( pNode, pos ) ) {
867                     ++m_ItemCounter;
868                     return true;
869                 }
870
871                 // clear next field
872                 pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
873             }
874         }
875
876         template <typename Func>
877         bool insert_at( atomic_node_ptr& refHead, value_type& val, Func f )
878         {
879             node_type * pNode = node_traits::to_node_ptr( val );
880             link_checker::is_empty( pNode );
881             position pos;
882
883             while ( true ) {
884                 if ( search( refHead, val, pos, key_comparator() ) )
885                     return false;
886
887                 typename gc::Guard guard;
888                 guard.assign( &val );
889                 if ( link_node( pNode, pos ) ) {
890                     f( val );
891                     ++m_ItemCounter;
892                     return true;
893                 }
894
895                 // clear next field
896                 pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
897             }
898         }
899
900         template <typename Func>
901         std::pair<bool, bool> ensure_at( atomic_node_ptr& refHead, value_type& val, Func func )
902         {
903             position pos;
904
905             node_type * pNode = node_traits::to_node_ptr( val );
906             while ( true ) {
907                 if ( search( refHead, val, pos, key_comparator() ) ) {
908                     if ( pos.pCur->m_pNext.load(memory_model::memory_order_acquire).bits() ) {
909                         back_off()();
910                         continue        ;   // the node found is marked as deleted
911                     }
912                     assert( key_comparator()( val, *node_traits::to_value_ptr( *pos.pCur ) ) == 0 );
913
914                     func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
915                     return std::make_pair( true, false );
916                 }
917                 else {
918                     typename gc::Guard guard;
919                     guard.assign( &val );
920                     if ( link_node( pNode, pos ) ) {
921                         ++m_ItemCounter;
922                         func( true, val, val );
923                         return std::make_pair( true, true );
924                     }
925                     // clear next field
926                     pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
927                 }
928             }
929         }
930
931         bool unlink_at( atomic_node_ptr& refHead, value_type& val )
932         {
933             position pos;
934
935             back_off bkoff;
936             while ( search( refHead, val, pos, key_comparator() ) ) {
937                 if ( node_traits::to_value_ptr( *pos.pCur ) == &val ) {
938                     if ( unlink_node( pos ) ) {
939                         --m_ItemCounter;
940                         return true;
941                     }
942                     else
943                         bkoff();
944                 }
945                 else
946                     break;
947             }
948             return false;
949         }
950
951         template <typename Q, typename Compare, typename Func>
952         bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f, position& pos )
953         {
954             back_off bkoff;
955             while ( search( refHead, val, pos, cmp )) {
956                 if ( unlink_node( pos ) ) {
957                     f( *node_traits::to_value_ptr( *pos.pCur ) );
958                     --m_ItemCounter;
959                     return true;
960                 }
961                 else
962                     bkoff();
963             }
964             return false;
965         }
966
967         template <typename Q, typename Compare, typename Func>
968         bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f )
969         {
970             position pos;
971             return erase_at( refHead, val, cmp, f, pos );
972         }
973
974         template <typename Q, typename Compare>
975         bool erase_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
976         {
977             position pos;
978             return erase_at( refHead, val, cmp, [](value_type const&){}, pos );
979         }
980
981         template <typename Q, typename Compare>
982         bool extract_at( atomic_node_ptr& refHead, typename gc::Guard& dest, Q const& val, Compare cmp )
983         {
984             position pos;
985             back_off bkoff;
986             while ( search( refHead, val, pos, cmp )) {
987                 if ( unlink_node( pos ) ) {
988                     dest.assign( pos.guards.template get<value_type>( position::guard_current_item ) );
989                     --m_ItemCounter;
990                     return true;
991                 }
992                 else
993                     bkoff();
994             }
995             return false;
996         }
997
998         template <typename Q, typename Compare>
999         bool find_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
1000         {
1001             position pos;
1002             return search( refHead, val, pos, cmp );
1003         }
1004
1005         template <typename Q, typename Compare, typename Func>
1006         bool find_at( atomic_node_ptr& refHead, Q& val, Compare cmp, Func f )
1007         {
1008             position pos;
1009             if ( search( refHead, val, pos, cmp )) {
1010                 f( *node_traits::to_value_ptr( *pos.pCur ), val );
1011                 return true;
1012             }
1013             return false;
1014         }
1015
1016         template <typename Q, typename Compare>
1017         bool get_at( atomic_node_ptr& refHead, typename gc::Guard& guard, Q const& val, Compare cmp )
1018         {
1019             position pos;
1020             if ( search( refHead, val, pos, cmp )) {
1021                 guard.assign( pos.guards.template get<value_type>( position::guard_current_item ));
1022                 return true;
1023             }
1024             return false;
1025         }
1026
1027         //@endcond
1028
1029     protected:
1030
1031         //@cond
1032         template <typename Q, typename Compare >
1033         bool search( atomic_node_ptr& refHead, const Q& val, position& pos, Compare cmp )
1034         {
1035             atomic_node_ptr * pPrev;
1036             marked_node_ptr pNext;
1037             marked_node_ptr pCur;
1038
1039             back_off        bkoff;
1040
1041 try_again:
1042             pPrev = &refHead;
1043             pNext = nullptr;
1044
1045             pCur = pPrev->load(memory_model::memory_order_relaxed);
1046             pos.guards.assign( position::guard_current_item, node_traits::to_value_ptr( pCur.ptr() ) );
1047             if ( pPrev->load(memory_model::memory_order_acquire) != pCur.ptr() )
1048                 goto try_again;
1049
1050             while ( true ) {
1051                 if ( pCur.ptr() == nullptr ) {
1052                     pos.pPrev = pPrev;
1053                     pos.pCur = pCur.ptr();
1054                     pos.pNext = pNext.ptr();
1055                     return false;
1056                 }
1057
1058                 pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed);
1059                 pos.guards.assign( position::guard_next_item, node_traits::to_value_ptr( pNext.ptr() ));
1060                 if ( pCur->m_pNext.load(memory_model::memory_order_relaxed).all() != pNext.all() ) {
1061                     bkoff();
1062                     goto try_again;
1063                 }
1064
1065                 if ( pPrev->load(memory_model::memory_order_relaxed).all() != pCur.ptr() ) {
1066                     bkoff();
1067                     goto try_again;
1068                 }
1069
1070                 // pNext contains deletion mark for pCur
1071                 if ( pNext.bits() == 1 ) {
1072                     // pCur marked i.e. logically deleted. Help the erase/unlink function to unlink pCur node
1073                     marked_node_ptr cur( pCur.ptr());
1074                     if ( pPrev->compare_exchange_strong( cur, marked_node_ptr( pNext.ptr() ), memory_model::memory_order_release, atomics::memory_order_relaxed )) {
1075                         retire_node( pCur.ptr() );
1076                     }
1077                     else {
1078                         bkoff();
1079                         goto try_again;
1080                     }
1081                 }
1082                 else {
1083                     assert( pCur.ptr() != nullptr );
1084                     int nCmp = cmp( *node_traits::to_value_ptr( pCur.ptr() ), val );
1085                     if ( nCmp >= 0 ) {
1086                         pos.pPrev = pPrev;
1087                         pos.pCur = pCur.ptr();
1088                         pos.pNext = pNext.ptr();
1089                         return nCmp == 0;
1090                     }
1091                     pPrev = &( pCur->m_pNext );
1092                     pos.guards.assign( position::guard_prev_item, node_traits::to_value_ptr( pCur.ptr() ) );
1093                 }
1094                 pCur = pNext;
1095                 pos.guards.assign( position::guard_current_item, node_traits::to_value_ptr( pCur.ptr() ));
1096             }
1097         }
1098         //@endcond
1099     };
1100 }} // namespace cds::intrusive
1101
1102 #endif // #ifndef __CDS_INTRUSIVE_IMPL_MICHAEL_LIST_H