3 #ifndef __CDS_CONTAINER_LAZY_KVLIST_RCU_H
4 #define __CDS_CONTAINER_LAZY_KVLIST_RCU_H
7 #include <cds/container/lazy_list_base.h>
8 #include <cds/intrusive/lazy_list_rcu.h>
9 #include <cds/container/details/make_lazy_kvlist.h>
11 #include <cds/details/functor_wrapper.h>
13 namespace cds { namespace container {
15 /// Lazy ordered list (key-value pair), template specialization for \ref cds_urcu_desc "RCU"
16 /** @ingroup cds_nonintrusive_list
17 \anchor cds_nonintrusive_LazyKVList_rcu
19 This is key-value variation of non-intrusive LazyList.
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 the list
30 - \p Traits - type traits, default is lazy_list::type_traits
32 It is possible to declare option-based list with cds::container::lazy_list::make_traits metafunction istead of \p Traits template
33 argument. For example, the following traits-based declaration of gc::HP lazy list
34 @note Before including <tt><cds/container/lazy_kvlist_rcu.h></tt> you should include appropriate RCU header file,
35 see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
37 #include <cds/urcu/general_threaded.h>
38 #include <cds/container/lazy_kvlist_rcu.h>
39 // Declare comparator for the item
41 int operator ()( int i1, int i2 )
47 // Declare type_traits
48 struct my_traits: public cds::container::lazy_list::type_traits
50 typedef my_compare compare;
53 // Declare traits-based list
54 typedef cds::container::LazyKVList< cds::urcu::gc< cds::urcu::general_threaded<> >, int, int, my_traits > traits_based_list;
57 is equivalent for the following option-based list
59 #include <cds/urcu/general_threaded.h>
60 #include <cds/container/lazy_kvlist_rcu.h>
62 // my_compare is the same
64 // Declare option-based list
65 typedef cds::container::LazyKVList< cds::urcu::gc< cds::urcu::general_threaded<> >, int, int,
66 typename cds::container::lazy_list::make_traits<
67 cds::container::opt::compare< my_compare > // item comparator option
72 Template argument list \p Options of cds::container::lazy_list::make_traits metafunction are:
73 - opt::compare - key comparison functor. No default functor is provided.
74 If the option is not specified, the opt::less is used.
75 - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
76 - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used.
77 - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that is no item counting.
78 - opt::allocator - the allocator used for creating and freeing list's item. Default is \ref CDS_DEFAULT_ALLOCATOR macro.
79 - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
80 or opt::v::sequential_consistent (sequentially consisnent memory model).
81 - opt::rcu_check_deadlock - a deadlock checking policy. Default is opt::v::rcu_throw_deadlock
87 #ifdef CDS_DOXYGEN_INVOKED
88 typename Traits = lazy_list::type_traits
93 class LazyKVList< cds::urcu::gc<RCU>, Key, Value, Traits >:
94 #ifdef CDS_DOXYGEN_INVOKED
95 protected intrusive::LazyList< cds::urcu::gc<RCU>, implementation_defined, Traits >
97 protected details::make_lazy_kvlist< cds::urcu::gc<RCU>, Key, Value, Traits >::type
101 typedef details::make_lazy_kvlist< cds::urcu::gc<RCU>, Key, Value, Traits > options;
102 typedef typename options::type base_class;
106 #ifdef CDS_DOXYGEN_INVOKED
107 typedef Key key_type ; ///< Key type
108 typedef Value mapped_type ; ///< Type of value stored in the list
109 typedef std::pair<key_type const, mapped_type> value_type ; ///< key/value pair stored in the list
111 typedef typename options::key_type key_type;
112 typedef typename options::value_type mapped_type;
113 typedef typename options::pair_type value_type;
116 typedef typename base_class::gc gc ; ///< Garbage collector used
117 typedef typename base_class::back_off back_off ; ///< Back-off strategy used
118 typedef typename options::allocator_type allocator_type ; ///< Allocator type used for allocate/deallocate the nodes
119 typedef typename base_class::item_counter item_counter ; ///< Item counting policy used
120 typedef typename options::key_comparator key_comparator ; ///< key comparison functor
121 typedef typename base_class::memory_model memory_model ; ///< Memory ordering. See cds::opt::memory_model option
122 typedef typename base_class::rcu_check_deadlock rcu_check_deadlock ; ///< RCU deadlock checking policy
124 typedef typename gc::scoped_lock rcu_lock ; ///< RCU scoped lock
125 static CDS_CONSTEXPR_CONST bool c_bExtractLockExternal = base_class::c_bExtractLockExternal; ///< Group of \p extract_xxx functions require external locking
129 typedef typename base_class::value_type node_type;
130 typedef typename options::cxx_allocator cxx_allocator;
131 typedef typename options::node_deallocator node_deallocator;
132 typedef typename options::type_traits::compare intrusive_key_comparator;
134 typedef typename base_class::node_type head_type;
138 /// pointer to extracted node
139 typedef cds::urcu::exempt_ptr< gc, node_type, value_type, typename options::type_traits::disposer,
140 cds::urcu::details::conventional_exempt_pair_cast<node_type, value_type>
145 # ifndef CDS_CXX11_LAMBDA_SUPPORT
146 template <typename Func>
147 class insert_functor: protected cds::details::functor_wrapper<Func>
149 typedef cds::details::functor_wrapper<Func> base_class;
151 insert_functor ( Func f )
155 void operator()( node_type& node )
157 base_class::get()( node.m_Data );
161 template <typename Func>
162 class ensure_functor: protected cds::details::functor_wrapper<Func>
164 typedef cds::details::functor_wrapper<Func> base_class;
166 ensure_functor( Func f )
170 void operator ()( bool bNew, node_type& node, node_type& )
172 base_class::get()( bNew, node.m_Data );
176 template <typename Func>
177 class find_functor: protected cds::details::functor_wrapper<Func>
179 typedef cds::details::functor_wrapper<Func> base_class;
181 find_functor( Func f )
185 template <typename Q>
186 void operator ()( node_type& node, Q& )
188 base_class::get()( node.m_Data );
192 struct empty_find_functor
194 template <typename Q>
195 void operator ()( node_type& node, Q& val ) const
199 template <typename Func>
204 erase_functor( Func f )
208 void operator ()( node_type const & node )
210 cds::unref(m_func)( const_cast<value_type&>(node.m_Data) );
213 # endif // ifndef CDS_CXX11_LAMBDA_SUPPORT
218 template <typename K>
219 static node_type * alloc_node(const K& key)
221 return cxx_allocator().New( key );
224 template <typename K, typename V>
225 static node_type * alloc_node( const K& key, const V& val )
227 return cxx_allocator().New( key, val );
230 template <typename... Args>
231 static node_type * alloc_node( Args&&... args )
233 return cxx_allocator().MoveNew( std::forward<Args>(args)... );
236 static void free_node( node_type * pNode )
238 cxx_allocator().Delete( pNode );
241 struct node_disposer {
242 void operator()( node_type * pNode )
247 typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
251 return base_class::m_Head;
254 head_type& head() const
256 return const_cast<head_type&>( base_class::m_Head );
261 return base_class::m_Tail;
264 head_type& tail() const
266 return const_cast<head_type&>( base_class::m_Tail );
273 template <bool IsConst>
274 class iterator_type: protected base_class::template iterator_type<IsConst>
276 typedef typename base_class::template iterator_type<IsConst> iterator_base;
278 iterator_type( head_type const& pNode )
279 : iterator_base( const_cast<head_type *>(&pNode) )
281 iterator_type( head_type const * pNode )
282 : iterator_base( const_cast<head_type *>(pNode) )
285 friend class LazyKVList;
288 typedef typename cds::details::make_const_type<mapped_type, IsConst>::reference value_ref;
289 typedef typename cds::details::make_const_type<mapped_type, IsConst>::pointer value_ptr;
291 typedef typename cds::details::make_const_type<value_type, IsConst>::reference pair_ref;
292 typedef typename cds::details::make_const_type<value_type, IsConst>::pointer pair_ptr;
297 iterator_type( iterator_type const& src )
298 : iterator_base( src )
301 key_type const& key() const
303 typename iterator_base::value_ptr p = iterator_base::operator ->();
304 assert( p != nullptr );
305 return p->m_Data.first;
308 value_ref val() const
310 typename iterator_base::value_ptr p = iterator_base::operator ->();
311 assert( p != nullptr );
312 return p->m_Data.second;
315 pair_ptr operator ->() const
317 typename iterator_base::value_ptr p = iterator_base::operator ->();
318 return p ? &(p->m_Data) : nullptr;
321 pair_ref operator *() const
323 typename iterator_base::value_ref p = iterator_base::operator *();
328 iterator_type& operator ++()
330 iterator_base::operator ++();
335 bool operator ==(iterator_type<C> const& i ) const
337 return iterator_base::operator ==(i);
340 bool operator !=(iterator_type<C> const& i ) const
342 return iterator_base::operator !=(i);
349 typedef iterator_type<false> iterator;
351 /// Const forward iterator
352 typedef iterator_type<true> const_iterator;
354 /// Returns a forward iterator addressing the first element in a list
356 For empty list \code begin() == end() \endcode
360 iterator it( head() );
361 ++it ; // skip dummy head
365 /// Returns an iterator that addresses the location succeeding the last element in a list
367 Do not use the value returned by <tt>end</tt> function to access any item.
368 Internally, <tt>end</tt> returning value pointing to dummy tail node.
370 The returned value can be used only to control reaching the end of the list.
371 For empty list \code begin() == end() \endcode
375 return iterator( tail() );
378 /// Returns a forward const iterator addressing the first element in a list
380 const_iterator begin() const
382 const_iterator it( head() );
383 ++it; // skip dummy head
386 const_iterator cbegin()
388 const_iterator it( head() );
389 ++it; // skip dummy head
394 /// Returns an const iterator that addresses the location succeeding the last element in a list
396 const_iterator end() const
398 return const_iterator( tail());
400 const_iterator cend()
402 return const_iterator( tail());
407 /// Default constructor
409 Initializes empty list
423 /// Inserts new node with key and default value
425 The function creates a node with \p key and default value, and then inserts the node created into the list.
428 - The \ref key_type should be constructible from value of type \p K.
429 In trivial case, \p K is equal to \ref key_type.
430 - The \ref mapped_type should be default-constructible.
432 The function makes RCU lock internally.
434 Returns \p true if inserting successful, \p false otherwise.
436 template <typename K>
437 bool insert( const K& key )
439 return insert_at( head(), key );
442 /// Inserts new node with a key and a value
444 The function creates a node with \p key and value \p val, and then inserts the node created into the list.
447 - The \ref key_type should be constructible from \p key of type \p K.
448 - The \ref mapped_type should be constructible from \p val of type \p V.
450 The function makes RCU lock internally.
452 Returns \p true if inserting successful, \p false otherwise.
454 template <typename K, typename V>
455 bool insert( const K& key, const V& val )
457 return insert_at( head(), key, val );
460 /// Inserts new node and initializes it by a functor
462 This function inserts new node with key \p key and if inserting is successful then it calls
463 \p func functor with signature
466 void operator()( value_type& item );
470 The argument \p item of user-defined functor \p func is the reference
471 to the list's item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
472 User-defined functor \p func should guarantee that during changing item's value no any other changes
473 could be made on this list's item by concurrent threads.
474 The user-defined functor can be passed by reference using <tt>boost::ref</tt>
475 and it is called only if inserting is successful.
477 The key_type should be constructible from value of type \p K.
479 The function allows to split creating of new item into two part:
480 - create item from \p key;
481 - insert new item into the list;
482 - if inserting is successful, initialize the value of item by calling \p func functor
484 This can be useful if complete initialization of object of \p mapped_type is heavyweight and
485 it is preferable that the initialization should be completed only if inserting is successful.
487 The function makes RCU lock internally.
489 template <typename K, typename Func>
490 bool insert_key( const K& key, Func func )
492 return insert_key_at( head(), key, func );
495 /// Inserts data of type \ref mapped_type constructed with <tt>std::forward<Args>(args)...</tt>
497 Returns \p true if inserting successful, \p false otherwise.
499 The function makes RCU lock internally.
501 template <typename... Args>
502 bool emplace( Args&&... args )
504 return emplace_at( head(), std::forward<Args>(args)... );
507 /// Ensures that the \p key exists in the list
509 The operation performs inserting or changing data with lock-free manner.
511 If the \p key not found in the list, then the new item created from \p key
512 is inserted into the list (note that in this case the \ref key_type should be
513 copy-constructible from type \p K).
514 Otherwise, the functor \p func is called with item found.
515 The functor \p Func may be a function with signature:
517 void func( bool bNew, value_type& item );
522 void operator()( bool bNew, value_type& item );
527 - \p bNew - \p true if the item has been inserted, \p false otherwise
528 - \p item - item of the list
530 The functor may change any fields of the \p item.second that is \ref mapped_type;
531 however, \p func must guarantee that during changing no any other modifications
532 could be made on this item by concurrent threads.
534 You may pass \p func argument by reference using <tt>boost::ref</tt>.
536 The function makes RCU lock internally.
538 Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
539 \p second is true if new item has been added or \p false if the item with \p key
540 already is in the list.
542 template <typename K, typename Func>
543 std::pair<bool, bool> ensure( const K& key, Func f )
545 return ensure_at( head(), key, f );
548 /// Deletes \p key from the list
549 /** \anchor cds_nonintrusive_LazyKVList_rcu_erase
551 RCU \p synchronize method can be called. RCU should not be locked.
553 Returns \p true if \p key is found and has been deleted, \p false otherwise
555 template <typename K>
556 bool erase( K const& key )
558 return erase_at( head(), key, intrusive_key_comparator() );
561 /// Deletes the item from the list using \p pred predicate for searching
563 The function is an analog of \ref cds_nonintrusive_LazyKVList_rcu_erase "erase(K const&)"
564 but \p pred is used for key comparing.
565 \p Less functor has the interface like \p std::less.
566 \p pred must imply the same element order as the comparator used for building the list.
568 template <typename K, typename Less>
569 bool erase_with( K const& key, Less pred )
571 return erase_at( head(), key, typename options::template less_wrapper<Less>::type() );
574 /// Deletes \p key from the list
575 /** \anchor cds_nonintrusive_LazyKVList_rcu_erase_func
576 The function searches an item with key \p key, calls \p f functor
577 and deletes the item. If \p key is not found, the functor is not called.
579 The functor \p Func interface:
582 void operator()(value_type& val) { ... }
585 The functor may be passed by reference with <tt>boost:ref</tt>
587 RCU \p synchronize method can be called. RCU should not be locked.
589 Returns \p true if key is found and deleted, \p false otherwise
591 template <typename K, typename Func>
592 bool erase( K const& key, Func f )
594 return erase_at( head(), key, intrusive_key_comparator(), f );
597 /// Deletes the item from the list using \p pred predicate for searching
599 The function is an analog of \ref cds_nonintrusive_LazyKVList_rcu_erase_func "erase(K const&, Func)"
600 but \p pred is used for key comparing.
601 \p Less functor has the interface like \p std::less.
602 \p pred must imply the same element order as the comparator used for building the list.
604 template <typename K, typename Less, typename Func>
605 bool erase_with( K const& key, Less pred, Func f )
607 return erase_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
610 /// Extracts an item from the list
612 @anchor cds_nonintrusive_LazyKVList_rcu_extract
613 The function searches an item with key equal to \p key in the list,
614 unlinks it from the list, and returns pointer to an item found in \p dest argument.
615 If \p key is not found the function returns \p false.
617 @note The function does NOT call RCU read-side lock or synchronization,
618 and does NOT dispose the item found. It just excludes the item from the list
619 and returns a pointer to item found.
620 You should lock RCU before calling this function.
623 #include <cds/urcu/general_buffered.h>
624 #include <cds/container/lazy_kvlist_rcu.h>
626 typedef cds::urcu::gc< general_buffered<> > rcu;
627 typedef cds::container::LazyKVList< rcu, int, Foo > rcu_lazy_list;
629 rcu_lazy_list theList;
632 rcu_lazy_list::exempt_ptr p;
634 // first, we should lock RCU
635 rcu_lazy_list::rcu_lock sl;
637 // Now, you can apply extract function
638 // Note that you must not delete the item found inside the RCU lock
639 if ( theList.extract( p, 10 )) {
640 // do something with p
644 // Outside RCU lock section we may safely release extracted pointer.
645 // release() passes the pointer to RCU reclamation cycle.
649 template <typename K>
650 bool extract( exempt_ptr& dest, K const& key )
652 dest = extract_at( head(), key, intrusive_key_comparator() );
653 return !dest.empty();
656 /// Extracts an item from the list using \p pred predicate for searching
658 This function is the analog for \ref cds_nonintrusive_LazyKVList_rcu_extract "extract(exempt_ptr&, K const&)".
659 The \p pred is a predicate used for key comparing.
660 \p Less has the interface like \p std::less.
661 \p pred must imply the same element order as \ref key_comparator.
663 template <typename K, typename Less>
664 bool extract_with( exempt_ptr& dest, K const& key, Less pred )
666 dest = extract_at( head(), key, typename options::template less_wrapper<Less>::type() );
667 return !dest.empty();
670 /// Finds the key \p key
671 /** \anchor cds_nonintrusive_LazyKVList_rcu_find_val
672 The function searches the item with key equal to \p key
673 and returns \p true if it is found, and \p false otherwise
675 The function applies RCU lock internally.
677 template <typename Q>
678 bool find( Q const& key ) const
680 return find_at( head(), key, intrusive_key_comparator() );
683 /// Finds the key \p val using \p pred predicate for searching
685 The function is an analog of \ref cds_nonintrusive_LazyKVList_rcu_find_val "find(Q const&)"
686 but \p pred is used for key comparing.
687 \p Less functor has the interface like \p std::less.
688 \p pred must imply the same element order as the comparator used for building the list.
690 template <typename Q, typename Less>
691 bool find_with( Q const& key, Less pred ) const
693 return find_at( head(), key, typename options::template less_wrapper<Less>::type() );
696 /// Finds the key \p key and performs an action with it
697 /** \anchor cds_nonintrusive_LazyKVList_rcu_find_func
698 The function searches an item with key equal to \p key and calls the functor \p f for the item found.
699 The interface of \p Func functor is:
702 void operator()( value_type& item );
705 where \p item is the item found.
707 You may pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
709 The functor may change <tt>item.second</tt> that is reference to value of node.
710 Note that the function is only guarantee that \p item cannot be deleted during functor is executing.
711 The function does not serialize simultaneous access to the list \p item. If such access is
712 possible you must provide your own synchronization schema to exclude unsafe item modifications.
714 The function applies RCU lock internally.
716 The function returns \p true if \p key is found, \p false otherwise.
718 template <typename Q, typename Func>
719 bool find( Q const& key, Func f ) const
721 return find_at( head(), key, intrusive_key_comparator(), f );
724 /// Finds the key \p val using \p pred predicate for searching
726 The function is an analog of \ref cds_nonintrusive_LazyKVList_rcu_find_func "find(Q const&, Func)"
727 but \p pred is used for key comparing.
728 \p Less functor has the interface like \p std::less.
729 \p pred must imply the same element order as the comparator used for building the list.
731 template <typename Q, typename Less, typename Func>
732 bool find_with( Q const& key, Less pred, Func f ) const
734 return find_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
737 /// Finds \p key and return the item found
738 /** \anchor cds_nonintrusive_LazyKVList_rcu_get
739 The function searches the item with \p key and returns the pointer to item found.
740 If \p key is not found it returns \p nullptr.
742 Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
744 RCU should be locked before call of this function.
745 Returned item is valid only while RCU is locked:
747 typedef cds::container::LazyKVList< cds::urcu::gc< cds::urcu::general_buffered<> >, int, foo, my_traits > ord_list;
752 ord_list::rcu_lock lock;
754 ord_list::value_type * pVal = theList.get( 5 );
759 // Unlock RCU by rcu_lock destructor
760 // pVal can be freed at any time after RCU has been unlocked
764 template <typename K>
765 value_type * get( K const& key ) const
767 return get_at( head(), key, intrusive_key_comparator());
770 /// Finds \p key and return the item found
772 The function is an analog of \ref cds_nonintrusive_LazyKVList_rcu_get "get(K const&)"
773 but \p pred is used for comparing the keys.
775 \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
777 \p pred must imply the same element order as the comparator used for building the list.
779 template <typename K, typename Less>
780 value_type * get_with( K const& key, Less pred ) const
782 return get_at( head(), key, typename options::template less_wrapper<Less>::type());
785 /// Checks if the list is empty
788 return base_class::empty();
791 /// Returns list's item count
793 The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
794 this function always returns 0.
796 <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
797 is empty. To check list emptyness use \ref empty() method.
801 return base_class::size();
806 Post-condition: the list is empty
815 bool insert_node_at( head_type& refHead, node_type * pNode )
817 assert( pNode != nullptr );
818 scoped_node_ptr p( pNode );
820 if ( base_class::insert_at( &refHead, *p )) {
828 template <typename K>
829 bool insert_at( head_type& refHead, const K& key )
831 return insert_node_at( refHead, alloc_node( key ));
834 template <typename K, typename V>
835 bool insert_at( head_type& refHead, const K& key, const V& val )
837 return insert_node_at( refHead, alloc_node( key, val ));
840 template <typename K, typename Func>
841 bool insert_key_at( head_type& refHead, const K& key, Func f )
843 scoped_node_ptr pNode( alloc_node( key ));
845 # ifdef CDS_CXX11_LAMBDA_SUPPORT
846 if ( base_class::insert_at( &refHead, *pNode, [&f](node_type& node){ cds::unref(f)( node.m_Data ); } ))
848 insert_functor<Func> wrapper( f );
849 if ( base_class::insert_at( &refHead, *pNode, cds::ref(wrapper) ))
858 template <typename... Args>
859 bool emplace_at( head_type& refHead, Args&&... args )
861 return insert_node_at( refHead, alloc_node( std::forward<Args>(args)... ));
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 Func>
882 std::pair<bool, bool> ensure_at( head_type& refHead, const K& key, Func f )
884 scoped_node_ptr pNode( alloc_node( key ));
886 # ifdef CDS_CXX11_LAMBDA_SUPPORT
887 std::pair<bool, bool> ret = base_class::ensure_at( &refHead, *pNode,
888 [&f]( bool bNew, node_type& node, node_type& ){ cds::unref(f)( bNew, node.m_Data ); });
890 ensure_functor<Func> wrapper( f );
891 std::pair<bool, bool> ret = base_class::ensure_at( &refHead, *pNode, cds::ref(wrapper));
893 if ( ret.first && ret.second )
899 template <typename K, typename Compare>
900 node_type * extract_at( head_type& refHead, K const& key, Compare cmp )
902 return base_class::extract_at( &refHead, key, cmp );
905 template <typename K, typename Compare>
906 bool find_at( head_type& refHead, K const& key, Compare cmp ) const
908 # ifdef CDS_CXX11_LAMBDA_SUPPORT
909 return base_class::find_at( &refHead, key, cmp, [](node_type&, K const&) {} );
911 return base_class::find_at( &refHead, key, cmp, empty_find_functor() );
915 template <typename K, typename Compare, typename Func>
916 bool find_at( head_type& refHead, K& key, Compare cmp, Func f ) const
918 # ifdef CDS_CXX11_LAMBDA_SUPPORT
919 return base_class::find_at( &refHead, key, cmp, [&f]( node_type& node, K& ){ cds::unref(f)( node.m_Data ); });
921 find_functor<Func> wrapper( f );
922 return base_class::find_at( &refHead, key, cmp, cds::ref(wrapper) );
926 template <typename K, typename Compare>
927 value_type * get_at( head_type& refHead, K const& val, Compare cmp ) const
929 node_type * pNode = base_class::get_at( &refHead, val, cmp );
930 return pNode ? &pNode->m_Data : nullptr;
936 }} // namespace cds::container
938 #endif // #ifndef __CDS_CONTAINER_LAZY_KVLIST_RCU_H