3 #ifndef __CDS_INTRUSIVE_MICHAEL_LIST_IMPL_H
4 #define __CDS_INTRUSIVE_MICHAEL_LIST_IMPL_H
6 #include <cds/intrusive/michael_list_base.h>
7 #include <cds/gc/guarded_ptr.h>
9 namespace cds { namespace intrusive {
11 /// Michael's lock-free ordered single-linked list
12 /** @ingroup cds_intrusive_list
13 \anchor cds_intrusive_MichaelList_hp
15 Usually, ordered single-linked list is used as a building block for the hash table implementation.
16 The complexity of searching is <tt>O(N)</tt>.
19 - [2002] Maged Michael "High performance dynamic lock-free hash tables and list-based sets"
22 - \p GC - Garbage collector used. Note the \p GC must be the same as the GC used for item type \p T (see michael_list::node).
23 - \p T - type to be stored in the list. The type must be based on michael_list::node (for michael_list::base_hook)
24 or it must have a member of type michael_list::node (for michael_list::member_hook).
25 - \p Traits - type traits. See michael_list::type_traits for explanation.
27 It is possible to declare option-based list with cds::intrusive::michael_list::make_traits metafunction istead of \p Traits template
30 Template argument list \p Options of cds::intrusive::michael_list::make_traits metafunction are:
31 - opt::hook - hook used. Possible values are: michael_list::base_hook, michael_list::member_hook, michael_list::traits_hook.
32 If the option is not specified, <tt>michael_list::base_hook<></tt> and gc::HP is used.
33 - opt::compare - key comparison functor. No default functor is provided.
34 If the option is not specified, the opt::less is used.
35 - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
36 - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::Default is used.
37 - opt::disposer - the functor used for dispose removed items. Default is opt::v::empty_disposer. Due the nature
38 of GC schema the disposer may be called asynchronously.
39 - opt::link_checker - the type of node's link fields checking. Default is \ref opt::debug_check_link
40 - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that is no item counting.
41 - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
42 or opt::v::sequential_consistent (sequentially consisnent memory model).
44 For example, the following traits-based declaration of gc::HP Michael's list
46 #include <cds/intrusive/michael_list_hp.h>
47 // Declare item stored in your list
48 struct item: public cds::intrusive::michael_list::node< cds::gc::HP >
54 // Declare comparator for the item
56 int operator()( item const& i1, item const& i2 ) const
58 return i1.nKey - i2.nKey;
62 // Declare type_traits
63 struct my_traits: public cds::intrusive::michael_list::type_traits
65 typedef cds::intrusive::michael_list::base_hook< cds::opt::gc< cds::gc::HP > > hook;
66 typedef my_compare compare;
69 // Declare traits-based list
70 typedef cds::intrusive::MichaelList< cds::gc::HP, item, my_traits > traits_based_list;
73 is equivalent for the following option-based list
75 #include <cds/intrusive/michael_list_hp.h>
77 // item struct and my_compare are the same
79 // Declare option-based list
80 typedef cds::intrusive::MichaelList< cds::gc::HP, item,
81 typename cds::intrusive::michael_list::make_traits<
82 cds::intrusive::opt::hook< cds::intrusive::michael_list::base_hook< cds::opt::gc< cds::gc::HP > > > // hook option
83 ,cds::intrusive::opt::compare< my_compare > // item comparator option
89 There are different specializations of this template for each garbage collecting schema used.
90 You should select GC needed and include appropriate .h-file:
91 - for gc::HP: \code #include <cds/intrusive/michael_list_hp.h> \endcode
92 - for gc::PTB: \code #include <cds/intrusive/michael_list_ptb.h> \endcode
93 - for gc::HRC: \code #include <cds/intrusive/michael_list_hrc.h> \endcode
94 - for \ref cds_urcu_gc "RCU type" - see \ref cds_intrusive_MichaelList_rcu "RCU-based MichaelList"
95 - for gc::nogc: \code #include <cds/intrusive/michael_list_nogc.h> \endcode
96 See \ref cds_intrusive_MichaelList_nogc "non-GC MichaelList"
98 Then, you should incorporate michael_list::node into your struct \p T and provide
99 appropriate michael_list::type_traits::hook in your \p Traits template parameters. Usually, for \p Traits you
100 define a struct based on michael_list::type_traits.
102 Example for gc::PTB and base hook:
104 // Include GC-related Michael's list specialization
105 #include <cds/intrusive/michael_list_ptb.h>
107 // Data stored in Michael's list
108 struct my_data: public cds::intrusive::michael_list::node< cds::gc::PTB >
117 // my_data comparing functor
119 int operator()( const my_data& d1, const my_data& d2 )
121 return d1.strKey.compare( d2.strKey );
124 int operator()( const my_data& d, const std::string& s )
126 return d.strKey.compare(s);
129 int operator()( const std::string& s, const my_data& d )
131 return s.compare( d.strKey );
136 // Declare type_traits
137 struct my_traits: public cds::intrusive::michael_list::type_traits
139 typedef cds::intrusive::michael_list::base_hook< cds::opt::gc< cds::gc::PTB > > hook;
140 typedef my_data_cmp compare;
144 typedef cds::intrusive::MichaelList< cds::gc::PTB, my_data, my_traits > traits_based_list;
147 Equivalent option-based code:
149 // GC-related specialization
150 #include <cds/intrusive/michael_list_ptb.h>
159 // Declare option-based list
160 typedef cds::intrusive::MichaelList< cds::gc::PTB
162 , typename cds::intrusive::michael_list::make_traits<
163 cds::intrusive::opt::hook< cds::intrusive::michael_list::base_hook< cds::opt::gc< cds::gc::PTB > > >
164 ,cds::intrusive::opt::compare< my_data_cmp >
173 #ifdef CDS_DOXYGEN_INVOKED
174 ,class Traits = michael_list::type_traits
182 typedef T value_type ; ///< type of value stored in the list
183 typedef Traits options ; ///< Traits template parameter
185 typedef typename options::hook hook ; ///< hook type
186 typedef typename hook::node_type node_type ; ///< node type
188 # ifdef CDS_DOXYGEN_INVOKED
189 typedef implementation_defined key_comparator ; ///< key comparison functor based on opt::compare and opt::less option setter.
191 typedef typename opt::details::make_comparator< value_type, options >::type key_comparator;
194 typedef typename options::disposer disposer ; ///< disposer used
195 typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ; ///< node traits
196 typedef typename michael_list::get_link_checker< node_type, options::link_checker >::type link_checker ; ///< link checker
198 typedef GC gc ; ///< Garbage collector
199 typedef typename options::back_off back_off ; ///< back-off strategy
200 typedef typename options::item_counter item_counter ; ///< Item counting policy used
201 typedef typename options::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
203 typedef cds::gc::guarded_ptr< gc, value_type > guarded_ptr; ///< Guarded pointer
206 // Rebind options (split-list support)
207 template <CDS_DECL_OPTIONS7>
208 struct rebind_options {
212 , typename cds::opt::make_options< options, CDS_OPTIONS7>::type
218 typedef typename node_type::atomic_marked_ptr atomic_node_ptr ; ///< Atomic node pointer
219 typedef typename node_type::marked_ptr marked_node_ptr ; ///< Node marked pointer
221 typedef atomic_node_ptr auxiliary_head ; ///< Auxiliary head type (for split-list support)
223 atomic_node_ptr m_pHead ; ///< Head pointer
224 item_counter m_ItemCounter ; ///< Item counter
227 /// Position pointer for item search
229 atomic_node_ptr * pPrev ; ///< Previous node
230 node_type * pCur ; ///< Current node
231 node_type * pNext ; ///< Next node
233 typename gc::template GuardArray<3> guards ; ///< Guards array
242 # ifndef CDS_CXX11_LAMBDA_SUPPORT
243 struct empty_erase_functor {
244 void operator()( value_type const & item )
249 struct clean_disposer {
250 void operator()( value_type * p )
252 michael_list::node_cleaner<gc, node_type, memory_model>()( node_traits::to_node_ptr( p ) );
261 void retire_node( node_type * pNode )
263 assert( pNode != null_ptr<node_type *>() );
264 gc::template retire<clean_disposer>( node_traits::to_value_ptr( *pNode ) );
267 bool link_node( node_type * pNode, position& pos )
269 assert( pNode != null_ptr<node_type *>() );
270 link_checker::is_empty( pNode );
272 marked_node_ptr cur(pos.pCur);
273 pNode->m_pNext.store( cur, memory_model::memory_order_relaxed );
274 return pos.pPrev->compare_exchange_strong( cur, marked_node_ptr(pNode), memory_model::memory_order_release, CDS_ATOMIC::memory_order_relaxed );
277 bool unlink_node( position& pos )
279 assert( pos.pPrev != null_ptr<atomic_node_ptr *>() );
280 assert( pos.pCur != null_ptr<node_type *>() );
282 // Mark the node (logical deleting)
283 marked_node_ptr next(pos.pNext, 0);
284 if ( pos.pCur->m_pNext.compare_exchange_strong( next, marked_node_ptr(pos.pNext, 1), memory_model::memory_order_release, CDS_ATOMIC::memory_order_relaxed )) {
285 // physical deletion may be performed by search function if it detects that a node is logically deleted (marked)
286 // CAS may be successful here or in other thread that searching something
287 marked_node_ptr cur(pos.pCur);
288 if ( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr( pos.pNext ), memory_model::memory_order_release, CDS_ATOMIC::memory_order_relaxed ))
289 retire_node( pos.pCur );
298 template <bool IsConst>
301 friend class MichaelList;
304 value_type * m_pNode;
305 typename gc::Guard m_Guard;
310 typename gc::Guard g;
311 node_type * pCur = node_traits::to_node_ptr( *m_pNode );
313 marked_node_ptr pNext;
315 pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed);
316 g.assign( node_traits::to_value_ptr( pNext.ptr() ));
317 } while ( pNext != pCur->m_pNext.load(memory_model::memory_order_acquire) );
320 m_pNode = m_Guard.assign( g.template get<value_type>() );
323 m_pNode = null_ptr<value_type *>();
329 iterator_type( atomic_node_ptr const& pNode )
332 marked_node_ptr p = pNode.load(memory_model::memory_order_relaxed);
334 m_pNode = m_Guard.assign( node_traits::to_value_ptr( p.ptr() ) );
337 m_pNode = null_ptr<value_type *>();
340 if ( p == pNode.load(memory_model::memory_order_acquire) )
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;
350 : m_pNode( null_ptr<value_type *>() )
353 iterator_type( iterator_type const& src )
356 m_pNode = m_Guard.assign( src.m_pNode );
359 m_pNode = null_ptr<value_type *>();
362 value_ptr operator ->() const
367 value_ref operator *() const
369 assert( m_pNode != null_ptr<value_type *>() );
374 iterator_type& operator ++()
380 iterator_type& operator = (iterator_type const& src)
382 m_pNode = src.m_pNode;
383 m_Guard.assign( m_pNode );
389 void operator ++(int)
396 bool operator ==(iterator_type<C> const& i ) const
398 return m_pNode == i.m_pNode;
401 bool operator !=(iterator_type<C> const& i ) const
403 return m_pNode != i.m_pNode;
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 (gc::HP, gc::HRC), a guard is limited resource per thread, so an exception (or assertion) "no free guard"
415 may be thrown if a limit of guard count per thread is exceeded.
416 - The iterator cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
417 - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
418 deleting operations it is no guarantee that you iterate all item in the list.
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.
423 The iterator interface:
427 // Default constructor
431 iterator( iterator const& src );
433 // Dereference operator
434 value_type * operator ->() const;
436 // Dereference operator
437 value_type& operator *() const;
439 // Preincrement operator
440 iterator& operator ++();
442 // Assignment operator
443 iterator& operator = (iterator const& src);
445 // Equality operators
446 bool operator ==(iterator const& i ) const;
447 bool operator !=(iterator const& i ) const;
451 typedef iterator_type<false> iterator;
452 /// Const forward iterator
454 For iterator's features and requirements see \ref iterator
456 typedef iterator_type<true> const_iterator;
458 /// Returns a forward iterator addressing the first element in a list
460 For empty list \code begin() == end() \endcode
464 return iterator( m_pHead );
467 /// Returns an iterator that addresses the location succeeding the last element in a list
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 <tt>NULL</tt>.
472 The returned value can be used only to control reaching the end of the list.
473 For empty list <tt>begin() == end()</tt>
480 /// Returns a forward const iterator addressing the first element in a list
481 const_iterator cbegin()
483 return const_iterator( m_pHead );
486 /// Returns a forward const iterator addressing the first element in a list
487 const_iterator begin() const
489 return const_iterator( m_pHead );
492 /// Returns an const iterator that addresses the location succeeding the last element in a list
493 const_iterator end() const
495 return const_iterator();
498 /// Returns an const iterator that addresses the location succeeding the last element in a list
499 const_iterator cend()
501 return const_iterator();
505 /// Default constructor initializes empty list
507 : m_pHead(null_ptr<node_type *>())
509 static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
512 /// Destroys the list object
520 The function inserts \p val in the list if the list does not contain
521 an item with key equal to \p val.
523 Returns \p true if \p val is linked into the list, \p false otherwise.
525 bool insert( value_type& val )
527 return insert_at( m_pHead, val );
532 This function is intended for derived non-intrusive containers.
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.
539 The functor signature is:
541 void func( value_type& val );
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 and may be passed by reference
546 using <tt>boost::ref</tt>.
548 template <typename Func>
549 bool insert( value_type& val, Func f )
551 return insert_at( m_pHead, val, f );
554 /// Ensures that the \p item exists in the list
556 The operation performs inserting or changing data with lock-free manner.
558 If the item \p val not found in the list, then \p val is inserted into the list.
559 Otherwise, the functor \p func is called with item found.
560 The functor signature is:
562 void func( bool bNew, value_type& item, value_type& val );
565 - \p bNew - \p true if the item has been inserted, \p false otherwise
566 - \p item - item of the list
567 - \p val - argument \p val passed into the \p ensure function
568 If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
569 refers to the same thing.
571 The functor may change non-key fields of the \p item; however, \p func must guarantee
572 that during changing no any other modifications could be made on this item by concurrent threads.
574 You may pass \p func argument by reference using <tt>boost::ref</tt> or cds::ref.
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.
580 template <typename Func>
581 std::pair<bool, bool> ensure( value_type& val, Func func )
583 return ensure_at( m_pHead, val, func );
586 /// Unlinks the item \p val from the list
588 The function searches the item \p val in the list and unlink it from the list
589 if it is found and it is equal to \p val.
591 Difference between \ref erase and \p unlink functions: \p erase finds <i>a key</i>
592 and deletes the item found. \p unlink finds an item by key and deletes it
593 only if \p val is an item of that list, i.e. the pointer to item found
594 is equal to <tt> &val </tt>.
596 The function returns \p true if success and \p false otherwise.
598 bool unlink( value_type& val )
600 return unlink_at( m_pHead, val );
603 /// Deletes the item from the list
604 /** \anchor cds_intrusive_MichaelList_hp_erase_val
605 The function searches an item with key equal to \p val in the list,
606 unlinks it from the list, and returns \p true.
607 If the item with the key equal to \p val is not found the function return \p false.
609 template <typename Q>
610 bool erase( Q const& val )
612 return erase_at( m_pHead, val, key_comparator() );
615 /// Deletes the item from the list using \p pred predicate for searching
617 The function is an analog of \ref cds_intrusive_MichaelList_hp_erase_val "erase(Q const&)"
618 but \p pred is used for key comparing.
619 \p Less functor has the interface like \p std::less.
620 \p pred must imply the same element order as the comparator used for building the list.
622 template <typename Q, typename Less>
623 bool erase_with( Q const& val, Less pred )
625 return erase_at( m_pHead, val, cds::opt::details::make_comparator_from_less<Less>());
628 /// Deletes the item from the list
629 /** \anchor cds_intrusive_MichaelList_hp_erase_func
630 The function searches an item with key equal to \p val in the list,
631 call \p func functor with item found, unlinks it from the list, and returns \p true.
632 The \p Func interface is
635 void operator()( value_type const& item );
638 The functor may be passed by reference using <tt>boost:ref</tt>
640 If the item with the key equal to \p val is not found the function return \p false.
642 template <typename Q, typename Func>
643 bool erase( Q const& val, Func func )
645 return erase_at( m_pHead, val, key_comparator(), func );
648 /// Deletes the item from the list using \p pred predicate for searching
650 The function is an analog of \ref cds_intrusive_MichaelList_hp_erase_func "erase(Q const&, Func)"
651 but \p pred is used for key comparing.
652 \p Less functor has the interface like \p std::less.
653 \p pred must imply the same element order as the comparator used for building the list.
655 template <typename Q, typename Less, typename Func>
656 bool erase_with( Q const& val, Less pred, Func f )
658 return erase_at( m_pHead, val, cds::opt::details::make_comparator_from_less<Less>(), f );
661 /// Extracts the item from the list with specified \p key
662 /** \anchor cds_intrusive_MichaelList_hp_extract
663 The function searches an item with key equal to \p key,
664 unlinks it from the list, and returns it in \p dest parameter.
665 If the item with key equal to \p key is not found the function returns \p false.
667 Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
669 The \ref disposer specified in \p Traits class template parameter is called automatically
670 by garbage collector \p GC when returned \ref guarded_ptr object will be destroyed or released.
671 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
675 typedef cds::intrusive::MichaelList< cds::gc::HP, foo, my_traits > ord_list;
679 ord_list::guarded_ptr gp;
680 theList.extract( gp, 5 );
684 // Destructor of gp releases internal HP guard
688 template <typename Q>
689 bool extract( guarded_ptr& dest, Q const& key )
691 return extract_at( m_pHead, dest.guard(), key, key_comparator() );
694 /// Extracts the item using compare functor \p pred
696 The function is an analog of \ref cds_intrusive_MichaelList_hp_extract "extract(guarded_ptr&, Q const&)"
697 but \p pred predicate is used for key comparing.
699 \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
701 \p pred must imply the same element order as the comparator used for building the list.
703 template <typename Q, typename Less>
704 bool extract_with( guarded_ptr& dest, Q const& key, Less pred )
706 return extract_at( m_pHead, dest.guard(), key, cds::opt::details::make_comparator_from_less<Less>() );
709 /// Finds the key \p val
710 /** \anchor cds_intrusive_MichaelList_hp_find_func
711 The function searches the item with key equal to \p val and calls the functor \p f for item found.
712 The interface of \p Func functor is:
715 void operator()( value_type& item, Q& val );
718 where \p item is the item found, \p val is the <tt>find</tt> function argument.
720 You may pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
722 The functor may change non-key fields of \p item. Note that the function is only guarantee
723 that \p item cannot be disposed during functor is executing.
724 The function does not serialize simultaneous access to the list \p item. If such access is
725 possible you must provide your own synchronization schema to exclude unsafe item modifications.
727 The \p val argument is non-const since it can be used as \p f functor destination i.e., the functor
728 may modify both arguments.
730 The function returns \p true if \p val is found, \p false otherwise.
732 template <typename Q, typename Func>
733 bool find( Q& val, Func f )
735 return find_at( m_pHead, val, key_comparator(), f );
738 /// Finds the key \p val using \p pred predicate for searching
740 The function is an analog of \ref cds_intrusive_MichaelList_hp_find_func "find(Q&, Func)"
741 but \p pred is used for key comparing.
742 \p Less functor has the interface like \p std::less.
743 \p pred must imply the same element order as the comparator used for building the list.
745 template <typename Q, typename Less, typename Func>
746 bool find_with( Q& val, Less pred, Func f )
748 return find_at( m_pHead, val, cds::opt::details::make_comparator_from_less<Less>(), f );
751 /// Finds the key \p val
752 /** \anchor cds_intrusive_MichaelList_hp_find_cfunc
753 The function searches the item with key equal to \p val and calls the functor \p f for item found.
754 The interface of \p Func functor is:
757 void operator()( value_type& item, Q const& val );
760 where \p item is the item found, \p val is the <tt>find</tt> function argument.
762 You may pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
764 The functor may change non-key fields of \p item. Note that the function is only guarantee
765 that \p item cannot be disposed during functor is executing.
766 The function does not serialize simultaneous access to the list \p item. If such access is
767 possible you must provide your own synchronization schema to exclude unsafe item modifications.
769 The function returns \p true if \p val is found, \p false otherwise.
771 template <typename Q, typename Func>
772 bool find( Q const& val, Func f )
774 return find_at( m_pHead, val, key_comparator(), f );
777 /// Finds the key \p val using \p pred predicate for searching
779 The function is an analog of \ref cds_intrusive_MichaelList_hp_find_cfunc "find(Q const&, Func)"
780 but \p pred is used for key comparing.
781 \p Less functor has the interface like \p std::less.
782 \p pred must imply the same element order as the comparator used for building the list.
784 template <typename Q, typename Less, typename Func>
785 bool find_with( Q const& val, Less pred, Func f )
787 return find_at( m_pHead, val, cds::opt::details::make_comparator_from_less<Less>(), f );
790 /// Finds the key \p val
791 /** \anchor cds_intrusive_MichaelList_hp_find_val
792 The function searches the item with key equal to \p val
793 and returns \p true if it is found, and \p false otherwise
795 template <typename Q>
796 bool find( Q const & val )
798 return find_at( m_pHead, val, key_comparator() );
801 /// Finds the key \p val using \p pred predicate for searching
803 The function is an analog of \ref cds_intrusive_MichaelList_hp_find_val "find(Q const&)"
804 but \p pred is used for key comparing.
805 \p Less functor has the interface like \p std::less.
806 \p pred must imply the same element order as the comparator used for building the list.
808 template <typename Q, typename Less>
809 bool find_with( Q const& val, Less pred )
811 return find_at( m_pHead, val, cds::opt::details::make_comparator_from_less<Less>() );
814 /// Finds the key \p val and return the item found
815 /** \anchor cds_intrusive_MichaelList_hp_get
816 The function searches the item with key equal to \p val
817 and assigns the item found to guarded pointer \p ptr.
818 The function returns \p true if \p val is found, and \p false otherwise.
819 If \p val is not found the \p ptr parameter is not changed.
821 The \ref disposer specified in \p Traits class template parameter is called
822 by garbage collector \p GC automatically when returned \ref guarded_ptr object
823 will be destroyed or released.
824 @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
828 typedef cds::intrusive::MichaelList< cds::gc::HP, foo, my_traits > ord_list;
832 ord_list::guarded_ptr gp;
833 if ( theList.get( gp, 5 )) {
837 // Destructor of guarded_ptr releases internal HP guard
841 Note the compare functor specified for \p Traits template parameter
842 should accept a parameter of type \p Q that can be not the same as \p value_type.
844 template <typename Q>
845 bool get( guarded_ptr& ptr, Q const& val )
847 return get_at( m_pHead, ptr.guard(), val, key_comparator() );
850 /// Finds the key \p val and return the item found
852 The function is an analog of \ref cds_intrusive_MichaelList_hp_get "get( guarded_ptr& ptr, Q const&)"
853 but \p pred is used for comparing the keys.
855 \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
857 \p pred must imply the same element order as the comparator used for building the list.
859 template <typename Q, typename Less>
860 bool get_with( guarded_ptr& ptr, Q const& val, Less pred )
862 return get_at( m_pHead, ptr.guard(), val, cds::opt::details::make_comparator_from_less<Less>() );
867 The function unlink all items from the list.
871 typename gc::Guard guard;
872 marked_node_ptr head;
874 head = m_pHead.load(memory_model::memory_order_relaxed);
876 guard.assign( node_traits::to_value_ptr( *head.ptr() ));
877 if ( m_pHead.load(memory_model::memory_order_acquire) == head ) {
878 if ( head.ptr() == null_ptr<node_type *>() )
880 value_type& val = *node_traits::to_value_ptr( *head.ptr() );
886 /// Checks if the list is empty
889 return m_pHead.load(memory_model::memory_order_relaxed).all() == null_ptr<node_type *>();
892 /// Returns list's item count
894 The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
895 this function always returns 0.
897 <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
898 is empty. To check list emptyness use \ref empty() method.
902 return m_ItemCounter.value();
907 // split-list support
908 bool insert_aux_node( node_type * pNode )
910 return insert_aux_node( m_pHead, pNode );
913 // split-list support
914 bool insert_aux_node( atomic_node_ptr& refHead, node_type * pNode )
916 assert( pNode != null_ptr<node_type *>() );
918 // Hack: convert node_type to value_type.
919 // In principle, auxiliary node can be non-reducible to value_type
920 // We assume that comparator can correctly distinguish aux and regular node.
921 return insert_at( refHead, *node_traits::to_value_ptr( pNode ) );
924 bool insert_at( atomic_node_ptr& refHead, value_type& val )
926 node_type * pNode = node_traits::to_node_ptr( val );
927 link_checker::is_empty( pNode );
931 if ( search( refHead, val, pos, key_comparator() ) )
934 if ( link_node( pNode, pos ) ) {
940 pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
944 template <typename Func>
945 bool insert_at( atomic_node_ptr& refHead, value_type& val, Func f )
947 node_type * pNode = node_traits::to_node_ptr( val );
948 link_checker::is_empty( pNode );
952 if ( search( refHead, val, pos, key_comparator() ) )
955 typename gc::Guard guard;
956 guard.assign( &val );
957 if ( link_node( pNode, pos ) ) {
958 cds::unref(f)( val );
964 pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
968 template <typename Func>
969 std::pair<bool, bool> ensure_at( atomic_node_ptr& refHead, value_type& val, Func func )
973 node_type * pNode = node_traits::to_node_ptr( val );
975 if ( search( refHead, val, pos, key_comparator() ) ) {
976 if ( pos.pCur->m_pNext.load(memory_model::memory_order_acquire).bits() ) {
978 continue ; // the node found is marked as deleted
980 assert( key_comparator()( val, *node_traits::to_value_ptr( *pos.pCur ) ) == 0 );
982 unref(func)( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
983 return std::make_pair( true, false );
986 typename gc::Guard guard;
987 guard.assign( &val );
988 if ( link_node( pNode, pos ) ) {
990 unref(func)( true, val, val );
991 return std::make_pair( true, true );
994 pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
999 bool unlink_at( atomic_node_ptr& refHead, value_type& val )
1004 while ( search( refHead, val, pos, key_comparator() ) ) {
1005 if ( node_traits::to_value_ptr( *pos.pCur ) == &val ) {
1006 if ( unlink_node( pos ) ) {
1019 template <typename Q, typename Compare, typename Func>
1020 bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f, position& pos )
1023 while ( search( refHead, val, pos, cmp )) {
1024 if ( unlink_node( pos ) ) {
1025 cds::unref(f)( *node_traits::to_value_ptr( *pos.pCur ) );
1035 template <typename Q, typename Compare, typename Func>
1036 bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f )
1039 return erase_at( refHead, val, cmp, f, pos );
1042 template <typename Q, typename Compare>
1043 bool erase_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
1046 # ifdef CDS_CXX11_LAMBDA_SUPPORT
1047 return erase_at( refHead, val, cmp, [](value_type const&){}, pos );
1049 return erase_at( refHead, val, cmp, empty_erase_functor(), pos );
1053 template <typename Q, typename Compare>
1054 bool extract_at( atomic_node_ptr& refHead, typename gc::Guard& dest, Q const& val, Compare cmp )
1058 while ( search( refHead, val, pos, cmp )) {
1059 if ( unlink_node( pos ) ) {
1060 dest.assign( pos.guards.template get<value_type>( position::guard_current_item ) );
1070 template <typename Q, typename Compare>
1071 bool find_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
1074 return search( refHead, val, pos, cmp );
1077 template <typename Q, typename Compare, typename Func>
1078 bool find_at( atomic_node_ptr& refHead, Q& val, Compare cmp, Func f )
1081 if ( search( refHead, val, pos, cmp )) {
1082 cds::unref(f)( *node_traits::to_value_ptr( *pos.pCur ), val );
1088 template <typename Q, typename Compare>
1089 bool get_at( atomic_node_ptr& refHead, typename gc::Guard& guard, Q const& val, Compare cmp )
1092 if ( search( refHead, val, pos, cmp )) {
1093 guard.assign( pos.guards.template get<value_type>( position::guard_current_item ));
1104 template <typename Q, typename Compare >
1105 bool search( atomic_node_ptr& refHead, const Q& val, position& pos, Compare cmp )
1107 atomic_node_ptr * pPrev;
1108 marked_node_ptr pNext;
1109 marked_node_ptr pCur;
1115 pNext = null_ptr<node_type *>();
1117 pCur = pPrev->load(memory_model::memory_order_relaxed);
1118 pos.guards.assign( position::guard_current_item, node_traits::to_value_ptr( pCur.ptr() ) );
1119 if ( pPrev->load(memory_model::memory_order_acquire) != pCur.ptr() )
1123 if ( pCur.ptr() == null_ptr<node_type *>() ) {
1125 pos.pCur = pCur.ptr();
1126 pos.pNext = pNext.ptr();
1130 pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed);
1131 pos.guards.assign( position::guard_next_item, node_traits::to_value_ptr( pNext.ptr() ));
1132 if ( pCur->m_pNext.load(memory_model::memory_order_relaxed).all() != pNext.all() ) {
1137 if ( pPrev->load(memory_model::memory_order_relaxed).all() != pCur.ptr() ) {
1142 // pNext contains deletion mark for pCur
1143 if ( pNext.bits() == 1 ) {
1144 // pCur marked i.e. logically deleted. Help the erase/unlink function to unlink pCur node
1145 marked_node_ptr cur( pCur.ptr());
1146 if ( pPrev->compare_exchange_strong( cur, marked_node_ptr( pNext.ptr() ), memory_model::memory_order_release, CDS_ATOMIC::memory_order_relaxed )) {
1147 retire_node( pCur.ptr() );
1155 assert( pCur.ptr() != null_ptr<node_type *>() );
1156 int nCmp = cmp( *node_traits::to_value_ptr( pCur.ptr() ), val );
1159 pos.pCur = pCur.ptr();
1160 pos.pNext = pNext.ptr();
1163 pPrev = &( pCur->m_pNext );
1164 pos.guards.assign( position::guard_prev_item, node_traits::to_value_ptr( pCur.ptr() ) );
1167 pos.guards.assign( position::guard_current_item, node_traits::to_value_ptr( pCur.ptr() ));
1172 }} // namespace cds::intrusive
1174 #endif // #ifndef __CDS_INTRUSIVE_MICHAEL_LIST_IMPL_H