Improved docs
[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         //@cond
215         // Rebind traits (split-list support)
216         template <typename... Options>
217         struct rebind_traits {
218             typedef MichaelList<
219                 gc
220                 , value_type
221                 , typename cds::opt::make_options< traits, Options...>::type
222             >   type;
223         };
224         //@endcond
225
226     protected:
227         typedef typename node_type::atomic_marked_ptr   atomic_node_ptr;   ///< Atomic node pointer
228         typedef typename node_type::marked_ptr          marked_node_ptr;   ///< Node marked pointer
229
230         typedef atomic_node_ptr     auxiliary_head;   ///< Auxiliary head type (for split-list support)
231
232         atomic_node_ptr     m_pHead;        ///< Head pointer
233         item_counter        m_ItemCounter;  ///< Item counter
234
235         //@cond
236         /// Position pointer for item search
237         struct position {
238             atomic_node_ptr * pPrev ;   ///< Previous node
239             node_type * pCur        ;   ///< Current node
240             node_type * pNext       ;   ///< Next node
241
242             typename gc::template GuardArray<3> guards  ;   ///< Guards array
243
244             enum {
245                 guard_prev_item,
246                 guard_current_item,
247                 guard_next_item
248             };
249         };
250
251         struct clean_disposer {
252             void operator()( value_type * p )
253             {
254                 michael_list::node_cleaner<gc, node_type, memory_model>()( node_traits::to_node_ptr( p ));
255                 disposer()( p );
256             }
257         };
258         //@endcond
259
260     protected:
261         //@cond
262         static void retire_node( node_type * pNode )
263         {
264             assert( pNode != nullptr );
265             gc::template retire<clean_disposer>( node_traits::to_value_ptr( *pNode ));
266         }
267
268         static bool link_node( node_type * pNode, position& pos )
269         {
270             assert( pNode != nullptr );
271             link_checker::is_empty( pNode );
272
273             marked_node_ptr cur(pos.pCur);
274             pNode->m_pNext.store( cur, memory_model::memory_order_release );
275             return pos.pPrev->compare_exchange_strong( cur, marked_node_ptr(pNode), memory_model::memory_order_release, atomics::memory_order_relaxed );
276         }
277
278         static bool unlink_node( position& pos )
279         {
280             assert( pos.pPrev != nullptr );
281             assert( pos.pCur != nullptr );
282
283             // Mark the node (logical deleting)
284             marked_node_ptr next(pos.pNext, 0);
285             if ( pos.pCur->m_pNext.compare_exchange_strong( next, marked_node_ptr(pos.pNext, 1), memory_model::memory_order_release, atomics::memory_order_relaxed )) {
286                 // physical deletion may be performed by search function if it detects that a node is logically deleted (marked)
287                 // CAS may be successful here or in other thread that searching something
288                 marked_node_ptr cur(pos.pCur);
289                 if ( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr( pos.pNext ), memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
290                     retire_node( pos.pCur );
291                 return true;
292             }
293             return false;
294         }
295         //@endcond
296
297     protected:
298         //@cond
299         template <bool IsConst>
300         class iterator_type
301         {
302             friend class MichaelList;
303
304         protected:
305             value_type * m_pNode;
306             typename gc::Guard  m_Guard;
307
308             void next()
309             {
310                 if ( m_pNode ) {
311                     typename gc::Guard g;
312                     node_type * pCur = node_traits::to_node_ptr( *m_pNode );
313
314                     marked_node_ptr pNext;
315                     do {
316                         pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed);
317                         g.assign( node_traits::to_value_ptr( pNext.ptr()));
318                     } while ( pNext != pCur->m_pNext.load(memory_model::memory_order_acquire));
319
320                     if ( pNext.ptr())
321                         m_pNode = m_Guard.assign( g.template get<value_type>());
322                     else {
323                         m_pNode = nullptr;
324                         m_Guard.clear();
325                     }
326                 }
327             }
328
329             iterator_type( atomic_node_ptr const& pNode )
330             {
331                 for (;;) {
332                     marked_node_ptr p = pNode.load(memory_model::memory_order_relaxed);
333                     if ( p.ptr()) {
334                         m_pNode = m_Guard.assign( node_traits::to_value_ptr( p.ptr()));
335                     }
336                     else {
337                         m_pNode = nullptr;
338                         m_Guard.clear();
339                     }
340                     if ( p == pNode.load(memory_model::memory_order_acquire))
341                         break;
342                 }
343             }
344
345         public:
346             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
347             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
348
349             iterator_type()
350                 : m_pNode( nullptr )
351             {}
352
353             iterator_type( iterator_type const& src )
354             {
355                 if ( src.m_pNode ) {
356                     m_pNode = m_Guard.assign( src.m_pNode );
357                 }
358                 else
359                     m_pNode = nullptr;
360             }
361
362             value_ptr operator ->() const
363             {
364                 return m_pNode;
365             }
366
367             value_ref operator *() const
368             {
369                 assert( m_pNode != nullptr );
370                 return *m_pNode;
371             }
372
373             /// Pre-increment
374             iterator_type& operator ++()
375             {
376                 next();
377                 return *this;
378             }
379
380             iterator_type& operator = (iterator_type const& src)
381             {
382                 m_pNode = src.m_pNode;
383                 m_Guard.assign( m_pNode );
384                 return *this;
385             }
386
387             /*
388             /// Post-increment
389             void operator ++(int)
390             {
391                 next();
392             }
393             */
394
395             template <bool C>
396             bool operator ==(iterator_type<C> const& i ) const
397             {
398                 return m_pNode == i.m_pNode;
399             }
400             template <bool C>
401             bool operator !=(iterator_type<C> const& i ) const
402             {
403                 return m_pNode != i.m_pNode;
404             }
405         };
406         //@endcond
407
408     public:
409         /// Forward iterator
410         /**
411             The forward iterator for Michael's list has some features:
412             - it has no post-increment operator
413             - to protect the value, the iterator contains a GC-specific guard + another guard is required locally for increment operator.
414               For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
415               may be thrown if the limit of guard count per thread is exceeded.
416             - The iterator cannot be moved across thread boundary since it contains thread-private GC's guard.
417             - Iterator ensures thread-safety even if you delete the item the iterator points to. However, in case of concurrent
418               deleting operations there is no guarantee that you iterate all item in the list.
419
420             Therefore, the use of iterators in concurrent environment is not good idea. Use the iterator on the concurrent container
421             for debug purpose only.
422
423             The iterator interface:
424             \code
425             class iterator {
426             public:
427                 // Default constructor
428                 iterator();
429
430                 // Copy construtor
431                 iterator( iterator const& src );
432
433                 // Dereference operator
434                 value_type * operator ->() const;
435
436                 // Dereference operator
437                 value_type& operator *() const;
438
439                 // Preincrement operator
440                 iterator& operator ++();
441
442                 // Assignment operator
443                 iterator& operator = (iterator const& src);
444
445                 // Equality operators
446                 bool operator ==(iterator const& i ) const;
447                 bool operator !=(iterator const& i ) const;
448             };
449             \endcode
450         */
451         typedef iterator_type<false>    iterator;
452         /// Const forward iterator
453         /**
454             For iterator's features and requirements see \ref iterator
455         */
456         typedef iterator_type<true>     const_iterator;
457
458         /// Returns a forward iterator addressing the first element in a list
459         /**
460             For empty list \code begin() == end() \endcode
461         */
462         iterator begin()
463         {
464             return iterator( m_pHead );
465         }
466
467         /// Returns an iterator that addresses the location succeeding the last element in a list
468         /**
469             Do not use the value returned by <tt>end</tt> function to access any item.
470             Internally, <tt>end</tt> returning value equals to \p nullptr.
471
472             The returned value can be used only to control reaching the end of the list.
473             For empty list <tt>begin() == end()</tt>
474         */
475         iterator end()
476         {
477             return iterator();
478         }
479
480         /// Returns a forward const iterator addressing the first element in a list
481         const_iterator cbegin() const
482         {
483             return const_iterator( m_pHead );
484         }
485
486         /// Returns a forward const iterator addressing the first element in a list
487         const_iterator begin() const
488         {
489             return const_iterator( m_pHead );
490         }
491
492         /// Returns an const iterator that addresses the location succeeding the last element in a list
493         const_iterator end() const
494         {
495             return const_iterator();
496         }
497
498         /// Returns an const iterator that addresses the location succeeding the last element in a list
499         const_iterator cend() const
500         {
501             return const_iterator();
502         }
503
504     public:
505         /// Default constructor initializes empty list
506         MichaelList()
507             : m_pHead( nullptr )
508         {
509             static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
510         }
511
512         /// Destroys the list object
513         ~MichaelList()
514         {
515             clear();
516         }
517
518         /// Inserts new node
519         /**
520             The function inserts \p val into the list if the list does not contain
521             an item with key equal to \p val.
522
523             Returns \p true if \p val has been linked to the list, \p false otherwise.
524         */
525         bool insert( value_type& val )
526         {
527             return insert_at( m_pHead, val );
528         }
529
530         /// Inserts new node
531         /**
532             This function is intended for derived non-intrusive containers.
533
534             The function allows to split new item creating into two part:
535             - create item with key only
536             - insert new item into the list
537             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
538
539             The functor signature is:
540             \code
541                 void func( value_type& val );
542             \endcode
543             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
544             \p val no any other changes could be made on this list's item by concurrent threads.
545             The user-defined functor is called only if the inserting is success.
546
547             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
548         */
549         template <typename Func>
550         bool insert( value_type& val, Func f )
551         {
552             return insert_at( m_pHead, val, f );
553         }
554
555         /// Updates the node
556         /**
557             The operation performs inserting or changing data with lock-free manner.
558
559             If the item \p val is not found in the list, then \p val is inserted
560             iff \p bInsert is \p true.
561             Otherwise, the functor \p func is called with item found.
562             The functor signature is:
563             \code
564                 void func( bool bNew, value_type& item, value_type& val );
565             \endcode
566             with arguments:
567             - \p bNew - \p true if the item has been inserted, \p false otherwise
568             - \p item - item of the list
569             - \p val - argument \p val passed into the \p update() function
570             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
571             refers to the same thing.
572
573             The functor may change non-key fields of the \p item; however, \p func must guarantee
574             that during changing no any other modifications could be made on this item by concurrent threads.
575
576             Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
577             \p second is \p true if new item has been added or \p false if the item with \p key
578             already is in the list.
579
580             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
581         */
582         template <typename Func>
583         std::pair<bool, bool> update( value_type& val, Func func, bool bInsert = true )
584         {
585             return update_at( m_pHead, val, func, bInsert );
586         }
587
588         //@cond
589         template <typename Func>
590         CDS_DEPRECATED("ensure() is deprecated, use update()")
591         std::pair<bool, bool> ensure( value_type& val, Func func )
592         {
593             return update( val, func, true );
594         }
595         //@endcond
596
597         /// Unlinks the item \p val from the list
598         /**
599             The function searches the item \p val in the list and unlinks it from the list
600             if it is found and it is equal to \p val.
601
602             Difference between \p erase() and \p %unlink(): \p %erase() finds <i>a key</i>
603             and deletes the item found. \p %unlink() finds an item by key and deletes it
604             only if \p val is an item of the list, i.e. the pointer to item found
605             is equal to <tt> &val </tt>.
606
607             \p disposer specified in \p Traits is called for deleted item.
608
609             The function returns \p true if success and \p false otherwise.
610         */
611         bool unlink( value_type& val )
612         {
613             return unlink_at( m_pHead, val );
614         }
615
616         /// Deletes the item from the list
617         /** \anchor cds_intrusive_MichaelList_hp_erase_val
618             The function searches an item with key equal to \p key in the list,
619             unlinks it from the list, and returns \p true.
620             If \p key is not found the function return \p false.
621
622             \p disposer specified in \p Traits is called for deleted item.
623         */
624         template <typename Q>
625         bool erase( Q const& key )
626         {
627             return erase_at( m_pHead, key, key_comparator());
628         }
629
630         /// Deletes the item from the list using \p pred predicate for searching
631         /**
632             The function is an analog of \ref cds_intrusive_MichaelList_hp_erase_val "erase(Q const&)"
633             but \p pred is used for key comparing.
634             \p Less functor has the interface like \p std::less.
635             \p pred must imply the same element order as the comparator used for building the list.
636
637             \p disposer specified in \p Traits is called for deleted item.
638         */
639         template <typename Q, typename Less>
640         bool erase_with( Q const& key, Less pred )
641         {
642             CDS_UNUSED( pred );
643             return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
644         }
645
646         /// Deletes the item from the list
647         /** \anchor cds_intrusive_MichaelList_hp_erase_func
648             The function searches an item with key equal to \p key in the list,
649             call \p func functor with item found, unlinks it from the list, and returns \p true.
650             The \p Func interface is
651             \code
652             struct functor {
653                 void operator()( value_type const& item );
654             };
655             \endcode
656             If \p key is not found the function return \p false, \p func is not called.
657
658             \p disposer specified in \p Traits is called for deleted item.
659         */
660         template <typename Q, typename Func>
661         bool erase( Q const& key, Func func )
662         {
663             return erase_at( m_pHead, key, key_comparator(), func );
664         }
665
666         /// Deletes the item from the list using \p pred predicate for searching
667         /**
668             The function is an analog of \ref cds_intrusive_MichaelList_hp_erase_func "erase(Q const&, Func)"
669             but \p pred is used for key comparing.
670             \p Less functor has the interface like \p std::less.
671             \p pred must imply the same element order as the comparator used for building the list.
672
673             \p disposer specified in \p Traits is called for deleted item.
674         */
675         template <typename Q, typename Less, typename Func>
676         bool erase_with( Q const& key, Less pred, Func f )
677         {
678             CDS_UNUSED( pred );
679             return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
680         }
681
682         /// Extracts the item from the list with specified \p key
683         /** \anchor cds_intrusive_MichaelList_hp_extract
684             The function searches an item with key equal to \p key,
685             unlinks it from the list, and returns it as \p guarded_ptr.
686             If \p key is not found returns an empty guarded pointer.
687
688             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
689
690             The \ref disposer specified in \p Traits class template parameter is called automatically
691             by garbage collector \p GC when returned \ref guarded_ptr object will be destroyed or released.
692             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
693
694             Usage:
695             \code
696             typedef cds::intrusive::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
697             ord_list theList;
698             // ...
699             {
700                 ord_list::guarded_ptr gp(theList.extract( 5 ));
701                 if ( gp ) {
702                     // Deal with gp
703                     // ...
704                 }
705                 // Destructor of gp releases internal HP guard
706             }
707             \endcode
708         */
709         template <typename Q>
710         guarded_ptr extract( Q const& key )
711         {
712             guarded_ptr gp;
713             extract_at( m_pHead, gp.guard(), key, key_comparator());
714             return gp;
715         }
716
717         /// Extracts the item using compare functor \p pred
718         /**
719             The function is an analog of \ref cds_intrusive_MichaelList_hp_extract "extract(Q const&)"
720             but \p pred predicate is used for key comparing.
721
722             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
723             in any order.
724             \p pred must imply the same element order as the comparator used for building the list.
725         */
726         template <typename Q, typename Less>
727         guarded_ptr extract_with( Q const& key, Less pred )
728         {
729             CDS_UNUSED( pred );
730             guarded_ptr gp;
731             extract_at( m_pHead, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
732             return gp;
733         }
734
735         /// Finds \p key in the list
736         /** \anchor cds_intrusive_MichaelList_hp_find_func
737             The function searches the item with key equal to \p key and calls the functor \p f for item found.
738             The interface of \p Func functor is:
739             \code
740             struct functor {
741                 void operator()( value_type& item, Q& key );
742             };
743             \endcode
744             where \p item is the item found, \p key is the <tt>find</tt> function argument.
745
746             The functor may change non-key fields of \p item. Note that the function is only guarantee
747             that \p item cannot be disposed during functor is executing.
748             The function does not serialize simultaneous access to the \p item. If such access is
749             possible you must provide your own synchronization schema to keep out unsafe item modifications.
750
751             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
752             may modify both arguments.
753
754             The function returns \p true if \p val is found, \p false otherwise.
755         */
756         template <typename Q, typename Func>
757         bool find( Q& key, Func f )
758         {
759             return find_at( m_pHead, key, key_comparator(), f );
760         }
761         //@cond
762         template <typename Q, typename Func>
763         bool find( Q const& key, Func f )
764         {
765             return find_at( m_pHead, key, key_comparator(), f );
766         }
767         //@endcond
768
769         /// Finds the \p key using \p pred predicate for searching
770         /**
771             The function is an analog of \ref cds_intrusive_MichaelList_hp_find_func "find(Q&, Func)"
772             but \p pred is used for key comparing.
773             \p Less functor has the interface like \p std::less.
774             \p pred must imply the same element order as the comparator used for building the list.
775         */
776         template <typename Q, typename Less, typename Func>
777         bool find_with( Q& key, Less pred, Func f )
778         {
779             CDS_UNUSED( pred );
780             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
781         }
782         //@cond
783         template <typename Q, typename Less, typename Func>
784         bool find_with( Q const& key, Less pred, Func f )
785         {
786             CDS_UNUSED( pred );
787             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
788         }
789         //@endcond
790
791         /// Checks whether the list contains \p key
792         /**
793             The function searches the item with key equal to \p key
794             and returns \p true if it is found, and \p false otherwise.
795         */
796         template <typename Q>
797         bool contains( Q const& key )
798         {
799             return find_at( m_pHead, key, key_comparator());
800         }
801         //@cond
802         template <typename Q>
803         CDS_DEPRECATED("deprecated, use contains()")
804         bool find( Q const& key )
805         {
806             return contains( key );
807         }
808         //@endcond
809
810         /// Checks whether the list contains \p key using \p pred predicate for searching
811         /**
812             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
813             \p Less functor has the interface like \p std::less.
814             \p Less must imply the same element order as the comparator used for building the list.
815         */
816         template <typename Q, typename Less>
817         bool contains( Q const& key, Less pred )
818         {
819             CDS_UNUSED( pred );
820             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
821         }
822         //@cond
823         template <typename Q, typename Less>
824         CDS_DEPRECATED("deprecated, use contains()")
825         bool find_with( Q const& key, Less pred )
826         {
827             return contains( key, pred );
828         }
829         //@endcond
830
831         /// Finds the \p key and return the item found
832         /** \anchor cds_intrusive_MichaelList_hp_get
833             The function searches the item with key equal to \p key
834             and returns it as \p guarded_ptr.
835             If \p key is not found the function returns an empty guarded pointer.
836
837             The \ref disposer specified in \p Traits class template parameter is called
838             by garbage collector \p GC automatically when returned \ref guarded_ptr object
839             will be destroyed or released.
840             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
841
842             Usage:
843             \code
844             typedef cds::intrusive::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
845             ord_list theList;
846             // ...
847             {
848                 ord_list::guarded_ptr gp(theList.get( 5 ));
849                 if ( gp ) {
850                     // Deal with gp
851                     //...
852                 }
853                 // Destructor of guarded_ptr releases internal HP guard
854             }
855             \endcode
856
857             Note the compare functor specified for \p Traits template parameter
858             should accept a parameter of type \p Q that can be not the same as \p value_type.
859         */
860         template <typename Q>
861         guarded_ptr get( Q const& key )
862         {
863             guarded_ptr gp;
864             get_at( m_pHead, gp.guard(), key, key_comparator());
865             return gp;
866         }
867
868         /// Finds the \p key and return the item found
869         /**
870             The function is an analog of \ref cds_intrusive_MichaelList_hp_get "get( Q const&)"
871             but \p pred is used for comparing the keys.
872
873             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
874             in any order.
875             \p pred must imply the same element order as the comparator used for building the list.
876         */
877         template <typename Q, typename Less>
878         guarded_ptr get_with( Q const& key, Less pred )
879         {
880             CDS_UNUSED( pred );
881             guarded_ptr gp;
882             get_at( m_pHead, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
883             return gp;
884         }
885
886         /// Clears the list
887         /**
888             The function unlink all items from the list.
889         */
890         void clear()
891         {
892             typename gc::Guard guard;
893             marked_node_ptr head;
894             while ( true ) {
895                 head = m_pHead.load(memory_model::memory_order_relaxed);
896                 if ( head.ptr())
897                     guard.assign( node_traits::to_value_ptr( *head.ptr()));
898                 if ( m_pHead.load(memory_model::memory_order_acquire) == head ) {
899                     if ( head.ptr() == nullptr )
900                         break;
901                     value_type& val = *node_traits::to_value_ptr( *head.ptr());
902                     unlink( val );
903                 }
904             }
905         }
906
907         /// Checks whether the list is empty
908         bool empty() const
909         {
910             return m_pHead.load( memory_model::memory_order_relaxed ).all() == nullptr;
911         }
912
913         /// Returns list's item count
914         /**
915             The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
916             this function always returns 0.
917
918             @note Even if you use real item counter and it returns 0, this fact does not mean that the list
919             is empty. To check list emptyness use \p empty() method.
920         */
921         size_t size() const
922         {
923             return m_ItemCounter.value();
924         }
925
926     protected:
927         //@cond
928         // split-list support
929         bool insert_aux_node( node_type * pNode )
930         {
931             return insert_aux_node( m_pHead, pNode );
932         }
933
934         // split-list support
935         bool insert_aux_node( atomic_node_ptr& refHead, node_type * pNode )
936         {
937             assert( pNode != nullptr );
938
939             // Hack: convert node_type to value_type.
940             // In principle, auxiliary node can be non-reducible to value_type
941             // We assume that comparator can correctly distinguish aux and regular node.
942             return insert_at( refHead, *node_traits::to_value_ptr( pNode ));
943         }
944
945         bool insert_at( atomic_node_ptr& refHead, value_type& val )
946         {
947             node_type * pNode = node_traits::to_node_ptr( val );
948             link_checker::is_empty( pNode );
949             position pos;
950
951             while ( true ) {
952                 if ( search( refHead, val, pos, key_comparator()))
953                     return false;
954
955                 if ( link_node( pNode, pos )) {
956                     ++m_ItemCounter;
957                     return true;
958                 }
959
960                 // clear next field
961                 pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
962             }
963         }
964
965         template <typename Func>
966         bool insert_at( atomic_node_ptr& refHead, value_type& val, Func f )
967         {
968             node_type * pNode = node_traits::to_node_ptr( val );
969             link_checker::is_empty( pNode );
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