3 #ifndef __CDS_CONTAINER_MICHAEL_KVLIST_RCU_H
4 #define __CDS_CONTAINER_MICHAEL_KVLIST_RCU_H
7 #include <cds/container/michael_list_base.h>
8 #include <cds/intrusive/michael_list_rcu.h>
9 #include <cds/container/details/make_michael_kvlist.h>
11 #include <cds/details/functor_wrapper.h>
13 namespace cds { namespace container {
15 /// Michael's ordered list (key-value pair), template specialization for \ref cds_urcu_desc "RCU"
16 /** @ingroup cds_nonintrusive_list
17 \anchor cds_nonintrusive_MichaelKVList_rcu
19 This is key-value variation of non-intrusive \ref cds_nonintrusive_MichaelList_rcu "MichaelList".
20 Like standard container, this implementation split a value stored into two part -
21 constant key and alterable value.
23 Usually, ordered single-linked list is used as a building block for the hash table implementation.
24 The complexity of searching is <tt>O(N)</tt>.
27 - \p RCU - one of \ref cds_urcu_gc "RCU type"
28 - \p Key - key type of an item stored in the list. It should be copy-constructible
29 - \p Value - value type stored in a list
30 - \p Traits - type traits, default is michael_list::type_traits
32 @note Before including <tt><cds/container/michael_kvlist_rcu.h></tt> you should include appropriate RCU header file,
33 see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
35 It is possible to declare option-based list with cds::container::michael_list::make_traits metafunction istead of \p Traits template
36 argument. For example, the following traits-based declaration of Michael's list
38 #include <cds/urcu/general_buffered.h>
39 #include <cds/container/michael_kvlist_rcu.h>
40 // Declare comparator for the item
42 int operator ()( int i1, int i2 )
48 // Declare type_traits
49 struct my_traits: public cds::container::michael_list::type_traits
51 typedef my_compare compare;
54 // Declare traits-based list
55 typedef cds::container::MichaelKVList< cds::urcu::gc< cds::urcu::general_buffered<> >, int, int, my_traits > traits_based_list;
58 is equivalent for the following option-based list
60 #include <cds/urcu/general_buffered.h>
61 #include <cds/container/michael_kvlist_rcu.h>
63 // my_compare is the same
65 // Declare option-based list
66 typedef cds::container::MichaelKVList< cds::urcu::gc< cds::urcu::general_buffered<> >, int, int,
67 typename cds::container::michael_list::make_traits<
68 cds::container::opt::compare< my_compare > // item comparator option
73 Template argument list \p Options of cds::container::michael_list::make_traits metafunction are:
74 - opt::compare - key comparison functor. No default functor is provided.
75 If the option is not specified, the opt::less is used.
76 - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
77 - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used.
78 - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that is no item counting.
79 - opt::allocator - the allocator used for creating and freeing list's item. Default is \ref CDS_DEFAULT_ALLOCATOR macro.
80 - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
81 or opt::v::sequential_consistent (sequentially consisnent memory model).
82 - opt::rcu_check_deadlock - a deadlock checking policy. Default is opt::v::rcu_throw_deadlock
88 #ifdef CDS_DOXYGEN_INVOKED
89 typename Traits = michael_list::type_traits
94 class MichaelKVList< cds::urcu::gc<RCU>, Key, Value, Traits >:
95 #ifdef CDS_DOXYGEN_INVOKED
96 protected intrusive::MichaelList< cds::urcu::gc<RCU>, implementation_defined, Traits >
98 protected details::make_michael_kvlist< cds::urcu::gc<RCU>, Key, Value, Traits >::type
102 typedef details::make_michael_kvlist< cds::urcu::gc<RCU>, Key, Value, Traits > options;
103 typedef typename options::type base_class;
107 #ifdef CDS_DOXYGEN_INVOKED
108 typedef Key key_type ; ///< Key type
109 typedef Value mapped_type ; ///< Type of value stored in the list
110 typedef std::pair<key_type const, mapped_type> value_type ; ///< key/value pair stored in the list
112 typedef typename options::key_type key_type;
113 typedef typename options::value_type mapped_type;
114 typedef typename options::pair_type value_type;
117 typedef typename base_class::gc gc ; ///< Garbage collector used
118 typedef typename base_class::back_off back_off ; ///< Back-off strategy used
119 typedef typename options::allocator_type allocator_type ; ///< Allocator type used for allocate/deallocate the nodes
120 typedef typename base_class::item_counter item_counter ; ///< Item counting policy used
121 typedef typename options::key_comparator key_comparator ; ///< key comparison functor
122 typedef typename base_class::memory_model memory_model ; ///< Memory ordering. See cds::opt::memory_model option
123 typedef typename base_class::rcu_check_deadlock rcu_check_deadlock ; ///< RCU deadlock checking policy
125 typedef typename gc::scoped_lock rcu_lock ; ///< RCU scoped lock
126 static CDS_CONSTEXPR_CONST bool c_bExtractLockExternal = base_class::c_bExtractLockExternal; ///< Group of \p extract_xxx functions require external locking
130 typedef typename base_class::value_type node_type;
131 typedef typename options::cxx_allocator cxx_allocator;
132 typedef typename options::node_deallocator node_deallocator;
133 typedef typename options::type_traits::compare intrusive_key_comparator;
135 typedef typename base_class::atomic_node_ptr head_type;
139 /// pointer to extracted node
140 typedef cds::urcu::exempt_ptr< gc, node_type, value_type, typename options::type_traits::disposer,
141 cds::urcu::details::conventional_exempt_pair_cast<node_type, value_type>
146 # ifndef CDS_CXX11_LAMBDA_SUPPORT
147 template <typename Func>
148 class insert_functor: protected cds::details::functor_wrapper<Func>
150 typedef cds::details::functor_wrapper<Func> base_class;
152 insert_functor ( Func f )
156 void operator()( node_type& node )
158 base_class::get()( node.m_Data );
162 template <typename Func>
163 class ensure_functor: protected cds::details::functor_wrapper<Func>
165 typedef cds::details::functor_wrapper<Func> base_class;
167 ensure_functor( Func f )
171 void operator ()( bool bNew, node_type& node, node_type& )
173 base_class::get()( bNew, node.m_Data );
177 template <typename Func>
178 class find_functor: protected cds::details::functor_wrapper<Func>
180 typedef cds::details::functor_wrapper<Func> base_class;
182 find_functor( Func f )
186 template <typename Q>
187 void operator ()( node_type& node, Q& )
189 base_class::get()( node.m_Data );
193 struct empty_find_functor
195 template <typename Q>
196 void operator ()( node_type& node, Q& val ) const
200 template <typename Func>
205 erase_functor( Func f )
209 void operator ()( node_type const & node )
211 cds::unref(m_func)( const_cast<value_type&>(node.m_Data) );
214 # endif // ifndef CDS_CXX11_LAMBDA_SUPPORT
219 template <typename K>
220 static node_type * alloc_node(const K& key)
222 return cxx_allocator().New( key );
225 template <typename K, typename V>
226 static node_type * alloc_node( const K& key, const V& val )
228 return cxx_allocator().New( key, val );
231 template <typename K, typename... Args>
232 static node_type * alloc_node( K&& key, Args&&... args )
234 return cxx_allocator().MoveNew( std::forward<K>(key), std::forward<Args>(args)...);
237 static void free_node( node_type * pNode )
239 cxx_allocator().Delete( pNode );
242 struct node_disposer {
243 void operator()( node_type * pNode )
248 typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
252 return base_class::m_pHead;
255 head_type& head() const
257 return const_cast<head_type&>( base_class::m_pHead );
263 template <bool IsConst>
264 class iterator_type: protected base_class::template iterator_type<IsConst>
266 typedef typename base_class::template iterator_type<IsConst> iterator_base;
268 iterator_type( head_type const& pNode )
269 : iterator_base( pNode )
272 friend class MichaelKVList;
275 typedef typename cds::details::make_const_type<mapped_type, IsConst>::reference value_ref;
276 typedef typename cds::details::make_const_type<mapped_type, IsConst>::pointer value_ptr;
278 typedef typename cds::details::make_const_type<value_type, IsConst>::reference pair_ref;
279 typedef typename cds::details::make_const_type<value_type, IsConst>::pointer pair_ptr;
284 iterator_type( iterator_type const& src )
285 : iterator_base( src )
288 key_type const& key() const
290 typename iterator_base::value_ptr p = iterator_base::operator ->();
291 assert( p != nullptr );
292 return p->m_Data.first;
295 pair_ptr operator ->() const
297 typename iterator_base::value_ptr p = iterator_base::operator ->();
298 return p ? &(p->m_Data) : nullptr;
301 pair_ref operator *() const
303 typename iterator_base::value_ref p = iterator_base::operator *();
307 value_ref val() const
309 typename iterator_base::value_ptr p = iterator_base::operator ->();
310 assert( p != nullptr );
311 return p->m_Data.second;
315 iterator_type& operator ++()
317 iterator_base::operator ++();
322 bool operator ==(iterator_type<C> const& i ) const
324 return iterator_base::operator ==(i);
327 bool operator !=(iterator_type<C> const& i ) const
329 return iterator_base::operator !=(i);
336 typedef iterator_type<false> iterator;
338 /// Const forward iterator
339 typedef iterator_type<true> const_iterator;
341 /// Returns a forward iterator addressing the first element in a list
343 For empty list \code begin() == end() \endcode
347 return iterator( head() );
350 /// Returns an iterator that addresses the location succeeding the last element in a list
352 Do not use the value returned by <tt>end</tt> function to access any item.
353 Internally, <tt>end</tt> returning value equals to \p nullptr.
355 The returned value can be used only to control reaching the end of the list.
356 For empty list \code begin() == end() \endcode
363 /// Returns a forward const iterator addressing the first element in a list
365 const_iterator begin() const
367 return const_iterator( head() );
369 const_iterator cbegin()
371 return const_iterator( head() );
375 /// Returns an const iterator that addresses the location succeeding the last element in a list
377 const_iterator end() const
379 return const_iterator();
381 const_iterator cend()
383 return const_iterator();
388 /// Default constructor
390 Initializes empty list
404 /// Inserts new node with key and default value
406 The function creates a node with \p key and default value, and then inserts the node created into the list.
409 - The \ref key_type should be constructible from value of type \p K.
410 In trivial case, \p K is equal to \ref key_type.
411 - The \ref mapped_type should be default-constructible.
413 The function makes RCU lock internally.
415 Returns \p true if inserting successful, \p false otherwise.
417 template <typename K>
418 bool insert( const K& key )
420 return insert_at( head(), key );
423 /// Inserts new node with a key and a value
425 The function creates a node with \p key and value \p val, and then inserts the node created into the list.
428 - The \ref key_type should be constructible from \p key of type \p K.
429 - The \ref mapped_type should be constructible from \p val of type \p V.
431 The function makes RCU lock internally.
433 Returns \p true if inserting successful, \p false otherwise.
435 template <typename K, typename V>
436 bool insert( const K& key, const V& val )
438 return insert_at( head(), key, val );
441 /// Inserts new node and initialize it by a functor
443 This function inserts new node with key \p key and if inserting is successful then it calls
444 \p func functor with signature
447 void operator()( value_type& item );
451 The argument \p item of user-defined functor \p func is the reference
452 to the list's item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
453 User-defined functor \p func should guarantee that during changing item's value no any other changes
454 could be made on this list's item by concurrent threads.
455 The user-defined functor can be passed by reference using <tt>boost::ref</tt>
456 and it is called only if inserting is successful.
458 The key_type should be constructible from value of type \p K.
460 The function allows to split creating of new item into two part:
461 - create item from \p key;
462 - insert new item into the list;
463 - if inserting is successful, initialize the value of item by calling \p func functor
465 This can be useful if complete initialization of object of \p mapped_type is heavyweight and
466 it is preferable that the initialization should be completed only if inserting is successful.
468 The function makes RCU lock internally.
470 template <typename K, typename Func>
471 bool insert_key( const K& key, Func func )
473 return insert_key_at( head(), key, func );
476 /// Ensures that the \p key exists in the list
478 The operation performs inserting or changing data with lock-free manner.
480 If the \p key not found in the list, then the new item created from \p key
481 is inserted into the list (note that in this case the \ref key_type should be
482 copy-constructible from type \p K).
483 Otherwise, the functor \p func is called with item found.
484 The functor \p Func may be a function with signature:
486 void func( bool bNew, value_type& item );
491 void operator()( bool bNew, value_type& item );
496 - \p bNew - \p true if the item has been inserted, \p false otherwise
497 - \p item - item of the list
499 The functor may change any fields of the \p item.second that is \ref mapped_type;
500 however, \p func must guarantee that during changing no any other modifications
501 could be made on this item by concurrent threads.
503 You may pass \p func argument by reference using <tt>boost::ref</tt>.
505 The function makes RCU lock internally.
507 Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
508 \p second is true if new item has been added or \p false if the item with \p key
509 already is in the list.
511 template <typename K, typename Func>
512 std::pair<bool, bool> ensure( const K& key, Func f )
514 return ensure_at( head(), key, f );
517 /// Inserts data of type \ref mapped_type constructed with <tt>std::forward<Args>(args)...</tt>
519 Returns \p true if inserting successful, \p false otherwise.
521 The function makes RCU lock internally.
523 template <typename K, typename... Args>
524 bool emplace( K&& key, Args&&... args )
526 return emplace_at( head(), std::forward<K>(key), std::forward<Args>(args)... );
529 /// Deletes \p key from the list
530 /** \anchor cds_nonintrusive_MichaelKVList_rcu_erase
532 RCU \p synchronize method can be called. RCU should not be locked.
534 Returns \p true if \p key is found and has been deleted, \p false otherwise
536 template <typename K>
537 bool erase( K const& key )
539 return erase_at( head(), key, intrusive_key_comparator() );
542 /// Deletes the item from the list using \p pred predicate for searching
544 The function is an analog of \ref cds_nonintrusive_MichaelKVList_rcu_erase "erase(K const&)"
545 but \p pred is used for key comparing.
546 \p Less functor has the interface like \p std::less.
547 \p pred must imply the same element order as the comparator used for building the list.
549 template <typename K, typename Less>
550 bool erase_with( K const& key, Less pred )
552 return erase_at( head(), key, typename options::template less_wrapper<Less>::type() );
555 /// Deletes \p key from the list
556 /** \anchor cds_nonintrusive_MichaelKVList_rcu_erase_func
557 The function searches an item with key \p key, calls \p f functor
558 and deletes the item. If \p key is not found, the functor is not called.
560 The functor \p Func interface:
563 void operator()(value_type& val) { ... }
566 The functor may be passed by reference with <tt>boost:ref</tt>
568 RCU \p synchronize method can be called. RCU should not be locked.
570 Return \p true if key is found and deleted, \p false otherwise
574 template <typename K, typename Func>
575 bool erase( K const& key, Func f )
577 return erase_at( head(), key, intrusive_key_comparator(), f );
580 /// Deletes the item from the list using \p pred predicate for searching
582 The function is an analog of \ref cds_nonintrusive_MichaelKVList_rcu_erase_func "erase(K const&, Func)"
583 but \p pred is used for key comparing.
584 \p Less functor has the interface like \p std::less.
585 \p pred must imply the same element order as the comparator used for building the list.
587 template <typename K, typename Less, typename Func>
588 bool erase_with( K const& key, Less pred, Func f )
590 return erase_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
593 /// Extracts an item from the list
595 @anchor cds_nonintrusive_MichaelKVList_rcu_extract
596 The function searches an item with key equal to \p key in the list,
597 unlinks it from the list, and returns pointer to an item found in \p dest argument.
598 If \p key is not found the function returns \p false.
600 @note The function does NOT call RCU read-side lock or synchronization,
601 and does NOT dispose the item found. It just excludes the item from the list
602 and returns a pointer to item found.
603 You should lock RCU before calling this function.
606 #include <cds/urcu/general_buffered.h>
607 #include <cds/container/michael_kvlist_rcu.h>
609 typedef cds::urcu::gc< general_buffered<> > rcu;
610 typedef cds::container::MichaelKVList< rcu, int, Foo > rcu_michael_list;
612 rcu_michael_list theList;
615 rcu_michael_list::exempt_ptr p;
617 // first, we should lock RCU
618 rcu_michael_list::rcu_lock sl;
620 // Now, you can apply extract function
621 // Note that you must not delete the item found inside the RCU lock
622 if ( theList.extract( p, 10 )) {
623 // do something with p
627 // Outside RCU lock section we may safely release extracted pointer.
628 // release() passes the pointer to RCU reclamation cycle.
632 template <typename K>
633 bool extract( exempt_ptr& dest, K const& key )
635 dest = extract_at( head(), key, intrusive_key_comparator() );
636 return !dest.empty();
639 /// Extracts an item from the list using \p pred predicate for searching
641 This function is the analog for \ref cds_nonintrusive_MichaelKVList_rcu_extract "extract(exempt_ptr&, K const&)".
642 The \p pred is a predicate used for key comparing.
643 \p Less has the interface like \p std::less.
644 \p pred must imply the same element order as \ref key_comparator.
646 template <typename K, typename Less>
647 bool extract_with( exempt_ptr& dest, K const& key, Less pred )
649 dest = extract_at( head(), key, typename options::template less_wrapper<Less>::type() );
650 return !dest.empty();
653 /// Finds the key \p key
654 /** \anchor cds_nonintrusive_MichaelKVList_rcu_find_val
656 The function searches the item with key equal to \p key
657 and returns \p true if it is found, and \p false otherwise
659 The function makes RCU lock internally.
661 template <typename Q>
662 bool find( Q const& key ) const
664 return find_at( head(), key, intrusive_key_comparator() );
667 /// Finds the key \p val using \p pred predicate for searching
669 The function is an analog of \ref cds_nonintrusive_MichaelKVList_rcu_find_val "find(Q const&)"
670 but \p pred is used for key comparing.
671 \p Less functor has the interface like \p std::less.
672 \p pred must imply the same element order as the comparator used for building the list.
674 template <typename Q, typename Less>
675 bool find_with( Q const& key, Less pred ) const
677 return find_at( head(), key, typename options::template less_wrapper<Less>::type() );
680 /// Finds the key \p key and performs an action with it
681 /** \anchor cds_nonintrusive_MichaelKVList_rcu_find_func
682 The function searches an item with key equal to \p key and calls the functor \p f for the item found.
683 The interface of \p Func functor is:
686 void operator()( value_type& item );
689 where \p item is the item found.
691 You may pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
693 The functor may change <tt>item.second</tt> that is reference to value of node.
694 Note that the function is only guarantee that \p item cannot be deleted during functor is executing.
695 The function does not serialize simultaneous access to the list \p item. If such access is
696 possible you must provide your own synchronization schema to exclude unsafe item modifications.
698 The function makes RCU lock internally.
700 The function returns \p true if \p key is found, \p false otherwise.
702 template <typename Q, typename Func>
703 bool find( Q const& key, Func f ) const
705 return find_at( head(), key, intrusive_key_comparator(), f );
708 /// Finds the key \p val using \p pred predicate for searching
710 The function is an analog of \ref cds_nonintrusive_MichaelKVList_rcu_find_func "find(Q const&, Func)"
711 but \p pred is used for key comparing.
712 \p Less functor has the interface like \p std::less.
713 \p pred must imply the same element order as the comparator used for building the list.
715 template <typename Q, typename Less, typename Func>
716 bool find_with( Q const& key, Less pred, Func f ) const
718 return find_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
721 /// Finds \p key and return the item found
722 /** \anchor cds_nonintrusive_MichaelKVList_rcu_get
723 The function searches the item with \p key and returns the pointer to item found.
724 If \p key is not found it returns \p nullptr.
726 Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
728 RCU should be locked before call of this function.
729 Returned item is valid only while RCU is locked:
731 typedef cds::container::MichaelKVList< cds::urcu::gc< cds::urcu::general_buffered<> >, int, foo, my_traits > ord_list;
736 ord_list::rcu_lock lock;
738 ord_list::value_type * pVal = theList.get( 5 );
743 // Unlock RCU by rcu_lock destructor
744 // pVal can be freed at any time after RCU has been unlocked
748 template <typename K>
749 value_type * get( K const& key ) const
751 return get_at( head(), key, intrusive_key_comparator());
754 /// Finds \p key and return the item found
756 The function is an analog of \ref cds_nonintrusive_MichaelKVList_rcu_get "get(K const&)"
757 but \p pred is used for comparing the keys.
759 \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
761 \p pred must imply the same element order as the comparator used for building the list.
763 template <typename K, typename Less>
764 value_type * get_with( K const& key, Less pred ) const
766 return get_at( head(), key, typename options::template less_wrapper<Less>::type());
769 /// Checks if the list is empty
772 return base_class::empty();
775 /// Returns list's item count
777 The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
778 this function always returns 0.
780 <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
781 is empty. To check list emptyness use \ref empty() method.
785 return base_class::size();
790 Post-condition: the list is empty
799 bool insert_node_at( head_type& refHead, node_type * pNode )
801 assert( pNode != nullptr );
802 scoped_node_ptr p( pNode );
803 if ( base_class::insert_at( refHead, *pNode )) {
810 template <typename K>
811 bool insert_at( head_type& refHead, const K& key )
813 return insert_node_at( refHead, alloc_node( key ));
816 template <typename K, typename V>
817 bool insert_at( head_type& refHead, const K& key, const V& val )
819 return insert_node_at( refHead, alloc_node( key, val ));
822 template <typename K, typename Func>
823 bool insert_key_at( head_type& refHead, const K& key, Func f )
825 scoped_node_ptr pNode( alloc_node( key ));
827 # ifdef CDS_CXX11_LAMBDA_SUPPORT
828 if ( base_class::insert_at( refHead, *pNode, [&f](node_type& node){ cds::unref(f)( node.m_Data ); }))
830 insert_functor<Func> wrapper( f );
831 if ( base_class::insert_at( refHead, *pNode, cds::ref(wrapper) ))
840 template <typename K, typename... Args>
841 bool emplace_at( head_type& refHead, K&& key, Args&&... args )
843 return insert_node_at( refHead, alloc_node( std::forward<K>(key), std::forward<Args>(args)... ));
846 template <typename K, typename Func>
847 std::pair<bool, bool> ensure_at( head_type& refHead, const K& key, Func f )
849 scoped_node_ptr pNode( alloc_node( key ));
851 # ifdef CDS_CXX11_LAMBDA_SUPPORT
852 std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode,
853 [&f]( bool bNew, node_type& node, node_type& ){ cds::unref(f)( bNew, node.m_Data ); });
855 ensure_functor<Func> wrapper( f );
856 std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode, cds::ref(wrapper));
858 if ( ret.first && ret.second )
864 template <typename K, typename Compare>
865 bool erase_at( head_type& refHead, K const& key, Compare cmp )
867 return base_class::erase_at( refHead, key, cmp );
870 template <typename K, typename Compare, typename Func>
871 bool erase_at( head_type& refHead, K const& key, Compare cmp, Func f )
873 # ifdef CDS_CXX11_LAMBDA_SUPPORT
874 return base_class::erase_at( refHead, key, cmp, [&f]( node_type const & node ){ cds::unref(f)( const_cast<value_type&>(node.m_Data)); });
876 erase_functor<Func> wrapper( f );
877 return base_class::erase_at( refHead, key, cmp, cds::ref(wrapper) );
881 template <typename K, typename Compare>
882 node_type * extract_at( head_type& refHead, K const& key, Compare cmp )
884 return base_class::extract_at( refHead, key, cmp );
887 template <typename K, typename Compare>
888 bool find_at( head_type& refHead, K const& key, Compare cmp ) const
890 # ifdef CDS_CXX11_LAMBDA_SUPPORT
891 return base_class::find_at( refHead, key, cmp, [](node_type&, K const&) {} );
893 return base_class::find_at( refHead, key, cmp, empty_find_functor() );
897 template <typename K, typename Compare, typename Func>
898 bool find_at( head_type& refHead, K& key, Compare cmp, Func f ) const
900 # ifdef CDS_CXX11_LAMBDA_SUPPORT
901 return base_class::find_at( refHead, key, cmp, [&f](node_type& node, K const&){ cds::unref(f)( node.m_Data ); });
903 find_functor<Func> wrapper( f );
904 return base_class::find_at( refHead, key, cmp, cds::ref(wrapper) );
908 template <typename K, typename Compare>
909 value_type * get_at( head_type& refHead, K const& val, Compare cmp ) const
911 node_type * pNode = base_class::get_at( refHead, val, cmp );
912 return pNode ? &pNode->m_Data : nullptr;
918 }} // namespace cds::container
920 #endif // #ifndef __CDS_CONTAINER_MICHAEL_KVLIST_RCU_H