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