Moved MichaelList<HP> unit test to gtest framework
[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         /// Forward iterator
412         /**
413             The forward iterator for Michael's list has some features:
414             - it has no post-increment operator
415             - to protect the value, the iterator contains a GC-specific guard + another guard is required locally for increment operator.
416               For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
417               may be thrown if the limit of guard count per thread is exceeded.
418             - The iterator cannot be moved across thread boundary since it contains thread-private GC's guard.
419             - Iterator ensures thread-safety even if you delete the item the iterator points to. However, in case of concurrent
420               deleting operations there is no guarantee that you iterate all item in the list.
421
422             Therefore, the use of iterators in concurrent environment is not good idea. Use the iterator on the concurrent container
423             for debug purpose only.
424
425             The iterator interface:
426             \code
427             class iterator {
428             public:
429                 // Default constructor
430                 iterator();
431
432                 // Copy construtor
433                 iterator( iterator const& src );
434
435                 // Dereference operator
436                 value_type * operator ->() const;
437
438                 // Dereference operator
439                 value_type& operator *() const;
440
441                 // Preincrement operator
442                 iterator& operator ++();
443
444                 // Assignment operator
445                 iterator& operator = (iterator const& src);
446
447                 // Equality operators
448                 bool operator ==(iterator const& i ) const;
449                 bool operator !=(iterator const& i ) const;
450             };
451             \endcode
452         */
453         typedef iterator_type<false>    iterator;
454         /// Const forward iterator
455         /**
456             For iterator's features and requirements see \ref iterator
457         */
458         typedef iterator_type<true>     const_iterator;
459
460         /// Returns a forward iterator addressing the first element in a list
461         /**
462             For empty list \code begin() == end() \endcode
463         */
464         iterator begin()
465         {
466             return iterator( m_pHead );
467         }
468
469         /// Returns an iterator that addresses the location succeeding the last element in a list
470         /**
471             Do not use the value returned by <tt>end</tt> function to access any item.
472             Internally, <tt>end</tt> returning value equals to \p nullptr.
473
474             The returned value can be used only to control reaching the end of the list.
475             For empty list <tt>begin() == end()</tt>
476         */
477         iterator end()
478         {
479             return iterator();
480         }
481
482         /// Returns a forward const iterator addressing the first element in a list
483         const_iterator cbegin() const
484         {
485             return const_iterator( m_pHead );
486         }
487
488         /// Returns a forward const iterator addressing the first element in a list
489         const_iterator begin() const
490         {
491             return const_iterator( m_pHead );
492         }
493
494         /// Returns an const iterator that addresses the location succeeding the last element in a list
495         const_iterator end() const
496         {
497             return const_iterator();
498         }
499
500         /// Returns an const iterator that addresses the location succeeding the last element in a list
501         const_iterator cend() const
502         {
503             return const_iterator();
504         }
505
506     public:
507         /// Default constructor initializes empty list
508         MichaelList()
509             : m_pHead( nullptr )
510         {
511             static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
512         }
513
514         /// Destroys the list object
515         ~MichaelList()
516         {
517             clear();
518         }
519
520         /// Inserts new node
521         /**
522             The function inserts \p val into the list if the list does not contain
523             an item with key equal to \p val.
524
525             Returns \p true if \p val has been linked to the list, \p false otherwise.
526         */
527         bool insert( value_type& val )
528         {
529             return insert_at( m_pHead, val );
530         }
531
532         /// Inserts new node
533         /**
534             This function is intended for derived non-intrusive containers.
535
536             The function allows to split new item creating into two part:
537             - create item with key only
538             - insert new item into the list
539             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
540
541             The functor signature is:
542             \code
543                 void func( value_type& val );
544             \endcode
545             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
546             \p val no any other changes could be made on this list's item by concurrent threads.
547             The user-defined functor is called only if the inserting is success.
548
549             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
550         */
551         template <typename Func>
552         bool insert( value_type& val, Func f )
553         {
554             return insert_at( m_pHead, val, f );
555         }
556
557         /// Updates the node
558         /**
559             The operation performs inserting or changing data with lock-free manner.
560
561             If the item \p val is not found in the list, then \p val is inserted
562             iff \p bInsert is \p true.
563             Otherwise, the functor \p func is called with item found.
564             The functor signature is:
565             \code
566                 void func( bool bNew, value_type& item, value_type& val );
567             \endcode
568             with arguments:
569             - \p bNew - \p true if the item has been inserted, \p false otherwise
570             - \p item - item of the list
571             - \p val - argument \p val passed into the \p update() function
572             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
573             refers to the same thing.
574
575             The functor may change non-key fields of the \p item; however, \p func must guarantee
576             that during changing no any other modifications could be made on this item by concurrent threads.
577
578             Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
579             \p second is \p true if new item has been added or \p false if the item with \p key
580             already is in the list.
581
582             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
583         */
584         template <typename Func>
585         std::pair<bool, bool> update( value_type& val, Func func, bool bInsert = true )
586         {
587             return update_at( m_pHead, val, func, bInsert );
588         }
589
590         //@cond
591         template <typename Func>
592         CDS_DEPRECATED("ensure() is deprecated, use update()")
593         std::pair<bool, bool> ensure( value_type& val, Func func )
594         {
595             return update( val, func, true );
596         }
597         //@endcond
598
599         /// Unlinks the item \p val from the list
600         /**
601             The function searches the item \p val in the list and unlinks it from the list
602             if it is found and it is equal to \p val.
603
604             Difference between \p erase() and \p %unlink(): \p %erase() finds <i>a key</i>
605             and deletes the item found. \p %unlink() finds an item by key and deletes it
606             only if \p val is an item of the list, i.e. the pointer to item found
607             is equal to <tt> &val </tt>.
608
609             \p disposer specified in \p Traits is called for deleted item.
610
611             The function returns \p true if success and \p false otherwise.
612         */
613         bool unlink( value_type& val )
614         {
615             return unlink_at( m_pHead, val );
616         }
617
618         /// Deletes the item from the list
619         /** \anchor cds_intrusive_MichaelList_hp_erase_val
620             The function searches an item with key equal to \p key in the list,
621             unlinks it from the list, and returns \p true.
622             If \p key is not found the function return \p false.
623
624             \p disposer specified in \p Traits is called for deleted item.
625         */
626         template <typename Q>
627         bool erase( Q const& key )
628         {
629             return erase_at( m_pHead, key, key_comparator());
630         }
631
632         /// Deletes the item from the list using \p pred predicate for searching
633         /**
634             The function is an analog of \ref cds_intrusive_MichaelList_hp_erase_val "erase(Q const&)"
635             but \p pred is used for key comparing.
636             \p Less functor has the interface like \p std::less.
637             \p pred must imply the same element order as the comparator used for building the list.
638
639             \p disposer specified in \p Traits is called for deleted item.
640         */
641         template <typename Q, typename Less>
642         bool erase_with( Q const& key, Less pred )
643         {
644             CDS_UNUSED( pred );
645             return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
646         }
647
648         /// Deletes the item from the list
649         /** \anchor cds_intrusive_MichaelList_hp_erase_func
650             The function searches an item with key equal to \p key in the list,
651             call \p func functor with item found, unlinks it from the list, and returns \p true.
652             The \p Func interface is
653             \code
654             struct functor {
655                 void operator()( value_type const& item );
656             };
657             \endcode
658             If \p key is not found the function return \p false, \p func is not called.
659
660             \p disposer specified in \p Traits is called for deleted item.
661         */
662         template <typename Q, typename Func>
663         bool erase( Q const& key, Func func )
664         {
665             return erase_at( m_pHead, key, key_comparator(), func );
666         }
667
668         /// Deletes the item from the list using \p pred predicate for searching
669         /**
670             The function is an analog of \ref cds_intrusive_MichaelList_hp_erase_func "erase(Q const&, Func)"
671             but \p pred is used for key comparing.
672             \p Less functor has the interface like \p std::less.
673             \p pred must imply the same element order as the comparator used for building the list.
674
675             \p disposer specified in \p Traits is called for deleted item.
676         */
677         template <typename Q, typename Less, typename Func>
678         bool erase_with( Q const& key, Less pred, Func f )
679         {
680             CDS_UNUSED( pred );
681             return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
682         }
683
684         /// Extracts the item from the list with specified \p key
685         /** \anchor cds_intrusive_MichaelList_hp_extract
686             The function searches an item with key equal to \p key,
687             unlinks it from the list, and returns it as \p guarded_ptr.
688             If \p key is not found returns an empty guarded pointer.
689
690             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
691
692             The \ref disposer specified in \p Traits class template parameter is called automatically
693             by garbage collector \p GC when returned \ref guarded_ptr object will be destroyed or released.
694             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
695
696             Usage:
697             \code
698             typedef cds::intrusive::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
699             ord_list theList;
700             // ...
701             {
702                 ord_list::guarded_ptr gp(theList.extract( 5 ));
703                 if ( gp ) {
704                     // Deal with gp
705                     // ...
706                 }
707                 // Destructor of gp releases internal HP guard
708             }
709             \endcode
710         */
711         template <typename Q>
712         guarded_ptr extract( Q const& key )
713         {
714             guarded_ptr gp;
715             extract_at( m_pHead, gp.guard(), key, key_comparator());
716             return gp;
717         }
718
719         /// Extracts the item using compare functor \p pred
720         /**
721             The function is an analog of \ref cds_intrusive_MichaelList_hp_extract "extract(Q const&)"
722             but \p pred predicate is used for key comparing.
723
724             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
725             in any order.
726             \p pred must imply the same element order as the comparator used for building the list.
727         */
728         template <typename Q, typename Less>
729         guarded_ptr extract_with( Q const& key, Less pred )
730         {
731             CDS_UNUSED( pred );
732             guarded_ptr gp;
733             extract_at( m_pHead, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
734             return gp;
735         }
736
737         /// Finds \p key in the list
738         /** \anchor cds_intrusive_MichaelList_hp_find_func
739             The function searches the item with key equal to \p key and calls the functor \p f for item found.
740             The interface of \p Func functor is:
741             \code
742             struct functor {
743                 void operator()( value_type& item, Q& key );
744             };
745             \endcode
746             where \p item is the item found, \p key is the <tt>find</tt> function argument.
747
748             The functor may change non-key fields of \p item. Note that the function is only guarantee
749             that \p item cannot be disposed during functor is executing.
750             The function does not serialize simultaneous access to the \p item. If such access is
751             possible you must provide your own synchronization schema to keep out unsafe item modifications.
752
753             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
754             may modify both arguments.
755
756             The function returns \p true if \p val is found, \p false otherwise.
757         */
758         template <typename Q, typename Func>
759         bool find( Q& key, Func f )
760         {
761             return find_at( m_pHead, key, key_comparator(), f );
762         }
763         //@cond
764         template <typename Q, typename Func>
765         bool find( Q const& key, Func f )
766         {
767             return find_at( m_pHead, key, key_comparator(), f );
768         }
769         //@endcond
770
771         /// Finds the \p key using \p pred predicate for searching
772         /**
773             The function is an analog of \ref cds_intrusive_MichaelList_hp_find_func "find(Q&, Func)"
774             but \p pred is used for key comparing.
775             \p Less functor has the interface like \p std::less.
776             \p pred must imply the same element order as the comparator used for building the list.
777         */
778         template <typename Q, typename Less, typename Func>
779         bool find_with( Q& key, Less pred, Func f )
780         {
781             CDS_UNUSED( pred );
782             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
783         }
784         //@cond
785         template <typename Q, typename Less, typename Func>
786         bool find_with( Q const& key, Less pred, Func f )
787         {
788             CDS_UNUSED( pred );
789             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
790         }
791         //@endcond
792
793         /// Checks whether the list contains \p key
794         /**
795             The function searches the item with key equal to \p key
796             and returns \p true if it is found, and \p false otherwise.
797         */
798         template <typename Q>
799         bool contains( Q const& key )
800         {
801             return find_at( m_pHead, key, key_comparator());
802         }
803         //@cond
804         template <typename Q>
805         CDS_DEPRECATED("deprecated, use contains()")
806         bool find( Q const& key )
807         {
808             return contains( key );
809         }
810         //@endcond
811
812         /// Checks whether the list contains \p key using \p pred predicate for searching
813         /**
814             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
815             \p Less functor has the interface like \p std::less.
816             \p Less must imply the same element order as the comparator used for building the list.
817         */
818         template <typename Q, typename Less>
819         bool contains( Q const& key, Less pred )
820         {
821             CDS_UNUSED( pred );
822             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
823         }
824         //@cond
825         template <typename Q, typename Less>
826         CDS_DEPRECATED("deprecated, use contains()")
827         bool find_with( Q const& key, Less pred )
828         {
829             return contains( key, pred );
830         }
831         //@endcond
832
833         /// Finds the \p key and return the item found
834         /** \anchor cds_intrusive_MichaelList_hp_get
835             The function searches the item with key equal to \p key
836             and returns it as \p guarded_ptr.
837             If \p key is not found the function returns an empty guarded pointer.
838
839             The \ref disposer specified in \p Traits class template parameter is called
840             by garbage collector \p GC automatically when returned \ref guarded_ptr object
841             will be destroyed or released.
842             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
843
844             Usage:
845             \code
846             typedef cds::intrusive::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
847             ord_list theList;
848             // ...
849             {
850                 ord_list::guarded_ptr gp(theList.get( 5 ));
851                 if ( gp ) {
852                     // Deal with gp
853                     //...
854                 }
855                 // Destructor of guarded_ptr releases internal HP guard
856             }
857             \endcode
858
859             Note the compare functor specified for \p Traits template parameter
860             should accept a parameter of type \p Q that can be not the same as \p value_type.
861         */
862         template <typename Q>
863         guarded_ptr get( Q const& key )
864         {
865             guarded_ptr gp;
866             get_at( m_pHead, gp.guard(), key, key_comparator());
867             return gp;
868         }
869
870         /// Finds the \p key and return the item found
871         /**
872             The function is an analog of \ref cds_intrusive_MichaelList_hp_get "get( Q const&)"
873             but \p pred is used for comparing the keys.
874
875             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
876             in any order.
877             \p pred must imply the same element order as the comparator used for building the list.
878         */
879         template <typename Q, typename Less>
880         guarded_ptr get_with( Q const& key, Less pred )
881         {
882             CDS_UNUSED( pred );
883             guarded_ptr gp;
884             get_at( m_pHead, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
885             return gp;
886         }
887
888         /// Clears the list
889         /**
890             The function unlink all items from the list.
891         */
892         void clear()
893         {
894             typename gc::Guard guard;
895             marked_node_ptr head;
896             while ( true ) {
897                 head = m_pHead.load(memory_model::memory_order_relaxed);
898                 if ( head.ptr())
899                     guard.assign( node_traits::to_value_ptr( *head.ptr()));
900                 if ( m_pHead.load(memory_model::memory_order_acquire) == head ) {
901                     if ( head.ptr() == nullptr )
902                         break;
903                     value_type& val = *node_traits::to_value_ptr( *head.ptr());
904                     unlink( val );
905                 }
906             }
907         }
908
909         /// Checks whether the list is empty
910         bool empty() const
911         {
912             return m_pHead.load( memory_model::memory_order_relaxed ).all() == nullptr;
913         }
914
915         /// Returns list's item count
916         /**
917             The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
918             this function always returns 0.
919
920             @note Even if you use real item counter and it returns 0, this fact does not mean that the list
921             is empty. To check list emptyness use \p empty() method.
922         */
923         size_t size() const
924         {
925             return m_ItemCounter.value();
926         }
927
928     protected:
929         //@cond
930         // split-list support
931         bool insert_aux_node( node_type * pNode )
932         {
933             return insert_aux_node( m_pHead, pNode );
934         }
935
936         // split-list support
937         bool insert_aux_node( atomic_node_ptr& refHead, node_type * pNode )
938         {
939             assert( pNode != nullptr );
940
941             // Hack: convert node_type to value_type.
942             // In principle, auxiliary node can be non-reducible to value_type
943             // We assume that comparator can correctly distinguish aux and regular node.
944             return insert_at( refHead, *node_traits::to_value_ptr( pNode ));
945         }
946
947         bool insert_at( atomic_node_ptr& refHead, value_type& val )
948         {
949             node_type * pNode = node_traits::to_node_ptr( val );
950             position pos;
951
952             while ( true ) {
953                 if ( search( refHead, val, pos, key_comparator()))
954                     return false;
955
956                 if ( link_node( pNode, pos )) {
957                     ++m_ItemCounter;
958                     return true;
959                 }
960
961                 // clear next field
962                 pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
963             }
964         }
965
966         template <typename Func>
967         bool insert_at( atomic_node_ptr& refHead, value_type& val, Func f )
968         {
969             node_type * pNode = node_traits::to_node_ptr( val );
970             position pos;
971
972             while ( true ) {
973                 if ( search( refHead, val, pos, key_comparator()))
974                     return false;
975
976                 typename gc::Guard guard;
977                 guard.assign( &val );
978                 if ( link_node( pNode, pos )) {
979                     f( val );
980                     ++m_ItemCounter;
981                     return true;
982                 }
983
984                 // clear next field
985                 pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
986             }
987         }
988
989         template <typename Func>
990         std::pair<bool, bool> update_at( atomic_node_ptr& refHead, value_type& val, Func func, bool bInsert )
991         {
992             position pos;
993
994             node_type * pNode = node_traits::to_node_ptr( val );
995             while ( true ) {
996                 if ( search( refHead, val, pos, key_comparator())) {
997                     if ( pos.pCur->m_pNext.load(memory_model::memory_order_acquire).bits()) {
998                         back_off()();
999                         continue;       // the node found is marked as deleted
1000                     }
1001                     assert( key_comparator()( val, *node_traits::to_value_ptr( *pos.pCur )) == 0 );
1002
1003                     func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
1004                     return std::make_pair( true, false );
1005                 }
1006                 else {
1007                     if ( !bInsert )
1008                         return std::make_pair( false, false );
1009
1010                     typename gc::Guard guard;
1011                     guard.assign( &val );
1012                     if ( link_node( pNode, pos )) {
1013                         ++m_ItemCounter;
1014                         func( true, val, val );
1015                         return std::make_pair( true, true );
1016                     }
1017                     // clear next field
1018                     pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
1019                 }
1020             }
1021         }
1022
1023         bool unlink_at( atomic_node_ptr& refHead, value_type& val )
1024         {
1025             position pos;
1026
1027             back_off bkoff;
1028             while ( search( refHead, val, pos, key_comparator())) {
1029                 if ( node_traits::to_value_ptr( *pos.pCur ) == &val ) {
1030                     if ( unlink_node( pos )) {
1031                         --m_ItemCounter;
1032                         return true;
1033                     }
1034                     else
1035                         bkoff();
1036                 }
1037                 else
1038                     break;
1039             }
1040             return false;
1041         }
1042
1043         template <typename Q, typename Compare, typename Func>
1044         bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f, position& pos )
1045         {
1046             back_off bkoff;
1047             while ( search( refHead, val, pos, cmp )) {
1048                 if ( unlink_node( pos )) {
1049                     f( *node_traits::to_value_ptr( *pos.pCur ));
1050                     --m_ItemCounter;
1051                     return true;
1052                 }
1053                 else
1054                     bkoff();
1055             }
1056             return false;
1057         }
1058
1059         template <typename Q, typename Compare, typename Func>
1060         bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f )
1061         {
1062             position pos;
1063             return erase_at( refHead, val, cmp, f, pos );
1064         }
1065
1066         template <typename Q, typename Compare>
1067         bool erase_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
1068         {
1069             position pos;
1070             return erase_at( refHead, val, cmp, [](value_type const&){}, pos );
1071         }
1072
1073         template <typename Q, typename Compare>
1074         bool extract_at( atomic_node_ptr& refHead, typename guarded_ptr::native_guard& dest, Q const& val, Compare cmp )
1075         {
1076             position pos;
1077             back_off bkoff;
1078             while ( search( refHead, val, pos, cmp )) {
1079                 if ( unlink_node( pos )) {
1080                     dest.set( pos.guards.template get<value_type>( position::guard_current_item ));
1081                     --m_ItemCounter;
1082                     return true;
1083                 }
1084                 else
1085                     bkoff();
1086             }
1087             return false;
1088         }
1089
1090         template <typename Q, typename Compare>
1091         bool find_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
1092         {
1093             position pos;
1094             return search( refHead, val, pos, cmp );
1095         }
1096
1097         template <typename Q, typename Compare, typename Func>
1098         bool find_at( atomic_node_ptr& refHead, Q& val, Compare cmp, Func f )
1099         {
1100             position pos;
1101             if ( search( refHead, val, pos, cmp )) {
1102                 f( *node_traits::to_value_ptr( *pos.pCur ), val );
1103                 return true;
1104             }
1105             return false;
1106         }
1107
1108         template <typename Q, typename Compare>
1109         bool get_at( atomic_node_ptr& refHead, typename guarded_ptr::native_guard& guard, Q const& val, Compare cmp )
1110         {
1111             position pos;
1112             if ( search( refHead, val, pos, cmp )) {
1113                 guard.set( pos.guards.template get<value_type>( position::guard_current_item ));
1114                 return true;
1115             }
1116             return false;
1117         }
1118
1119         //@endcond
1120
1121     protected:
1122
1123         //@cond
1124         template <typename Q, typename Compare >
1125         bool search( atomic_node_ptr& refHead, const Q& val, position& pos, Compare cmp )
1126         {
1127             atomic_node_ptr * pPrev;
1128             marked_node_ptr pNext;
1129             marked_node_ptr pCur;
1130
1131             back_off        bkoff;
1132
1133         try_again:
1134             pPrev = &refHead;
1135             pNext = nullptr;
1136
1137             pCur = pos.guards.protect( position::guard_current_item, *pPrev,
1138                    [](marked_node_ptr p) -> value_type *
1139                     {
1140                         return node_traits::to_value_ptr( p.ptr());
1141                     });
1142
1143             while ( true ) {
1144                 if ( pCur.ptr() == nullptr ) {
1145                     pos.pPrev = pPrev;
1146                     pos.pCur = nullptr;
1147                     pos.pNext = nullptr;
1148                     return false;
1149                 }
1150
1151                 pNext = pos.guards.protect( position::guard_next_item, pCur->m_pNext,
1152                         [](marked_node_ptr p ) -> value_type *
1153                         {
1154                             return node_traits::to_value_ptr( p.ptr());
1155                         });
1156                 if ( pPrev->load(memory_model::memory_order_acquire).all() != pCur.ptr()) {
1157                     bkoff();
1158                     goto try_again;
1159                 }
1160
1161                 // pNext contains deletion mark for pCur
1162                 if ( pNext.bits() == 1 ) {
1163                     // pCur marked i.e. logically deleted. Help the erase/unlink function to unlink pCur node
1164                     marked_node_ptr cur( pCur.ptr());
1165                     if ( pPrev->compare_exchange_strong( cur, marked_node_ptr( pNext.ptr()), memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
1166                         retire_node( pCur.ptr());
1167                     }
1168                     else {
1169                         bkoff();
1170                         goto try_again;
1171                     }
1172                 }
1173                 else {
1174                     assert( pCur.ptr() != nullptr );
1175                     int nCmp = cmp( *node_traits::to_value_ptr( pCur.ptr()), val );
1176                     if ( nCmp >= 0 ) {
1177                         pos.pPrev = pPrev;
1178                         pos.pCur = pCur.ptr();
1179                         pos.pNext = pNext.ptr();
1180                         return nCmp == 0;
1181                     }
1182                     pPrev = &( pCur->m_pNext );
1183                     pos.guards.copy( position::guard_prev_item, position::guard_current_item );
1184                 }
1185                 pCur = pNext;
1186                 pos.guards.copy( position::guard_current_item, position::guard_next_item );
1187             }
1188         }
1189         //@endcond
1190     };
1191 }} // namespace cds::intrusive
1192
1193 #endif // #ifndef CDSLIB_INTRUSIVE_IMPL_MICHAEL_LIST_H