3 #ifndef __CDS_CONTAINER_MICHAEL_KVLIST_IMPL_H
4 #define __CDS_CONTAINER_MICHAEL_KVLIST_IMPL_H
8 #include <cds/details/functor_wrapper.h>
9 #include <cds/container/details/guarded_ptr_cast.h>
11 namespace cds { namespace container {
13 /// Michael's ordered list (key-value pair)
14 /** @ingroup cds_nonintrusive_list
15 \anchor cds_nonintrusive_MichaelKVList_gc
17 This is key-value variation of non-intrusive MichaelList.
18 Like standard container, this implementation split a value stored into two part -
19 constant key and alterable value.
21 Usually, ordered single-linked list is used as a building block for the hash table implementation.
22 The complexity of searching is <tt>O(N)</tt>.
25 - \p GC - garbage collector used
26 - \p Key - key type of an item stored in the list. It should be copy-constructible
27 - \p Value - value type stored in a list
28 - \p Traits - type traits, default is michael_list::type_traits
30 It is possible to declare option-based list with cds::container::michael_list::make_traits metafunction istead of \p Traits template
31 argument. For example, the following traits-based declaration of gc::HP Michael's list
33 #include <cds/container/michael_kvlist_hp.h>
34 // Declare comparator for the item
36 int operator ()( int i1, int i2 )
42 // Declare type_traits
43 struct my_traits: public cds::container::michael_list::type_traits
45 typedef my_compare compare;
48 // Declare traits-based list
49 typedef cds::container::MichaelKVList< cds::gc::HP, int, int, my_traits > traits_based_list;
52 is equivalent for the following option-based list
54 #include <cds/container/michael_kvlist_hp.h>
56 // my_compare is the same
58 // Declare option-based list
59 typedef cds::container::MichaelKVList< cds::gc::HP, int, int,
60 typename cds::container::michael_list::make_traits<
61 cds::container::opt::compare< my_compare > // item comparator option
66 Template argument list \p Options of cds::container::michael_list::make_traits metafunction are:
67 - opt::compare - key comparison functor. No default functor is provided.
68 If the option is not specified, the opt::less is used.
69 - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
70 - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used.
71 - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that is no item counting.
72 - opt::allocator - the allocator used for creating and freeing list's item. Default is \ref CDS_DEFAULT_ALLOCATOR macro.
73 - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
74 or opt::v::sequential_consistent (sequentially consisnent memory model).
77 There are different specializations of this template for each garbage collecting schema used.
78 You should include appropriate .h-file depending on GC you are using:
79 - for gc::HP: \code #include <cds/container/michael_kvlist_hp.h> \endcode
80 - for gc::PTB: \code #include <cds/container/michael_kvlist_ptb.h> \endcode
81 - for gc::HRC: \code #include <cds/container/michael_kvlist_hrc.h> \endcode
82 - for \ref cds_urcu_desc "RCU": \code #include <cds/container/michael_kvlist_rcu.h> \endcode
83 - for gc::nogc: \code #include <cds/container/michael_kvlist_nogc.h> \endcode
89 #ifdef CDS_DOXYGEN_INVOKED
90 typename Traits = michael_list::type_traits
96 #ifdef CDS_DOXYGEN_INVOKED
97 protected intrusive::MichaelList< GC, implementation_defined, Traits >
99 protected details::make_michael_kvlist< GC, Key, Value, Traits >::type
103 typedef details::make_michael_kvlist< GC, Key, Value, Traits > options;
104 typedef typename options::type base_class;
108 #ifdef CDS_DOXYGEN_INVOKED
109 typedef Key key_type ; ///< Key type
110 typedef Value mapped_type ; ///< Type of value stored in the list
111 typedef std::pair<key_type const, mapped_type> value_type ; ///< key/value pair stored in the list
113 typedef typename options::key_type key_type;
114 typedef typename options::value_type mapped_type;
115 typedef typename options::pair_type value_type;
118 typedef typename base_class::gc gc ; ///< Garbage collector used
119 typedef typename base_class::back_off back_off ; ///< Back-off strategy used
120 typedef typename options::allocator_type allocator_type ; ///< Allocator type used for allocate/deallocate the nodes
121 typedef typename base_class::item_counter item_counter ; ///< Item counting policy used
122 typedef typename options::key_comparator key_comparator ; ///< key comparison functor
123 typedef typename base_class::memory_model memory_model ; ///< Memory ordering. See cds::opt::memory_model option
127 typedef typename base_class::value_type node_type;
128 typedef typename options::cxx_allocator cxx_allocator;
129 typedef typename options::node_deallocator node_deallocator;
130 typedef typename options::type_traits::compare intrusive_key_comparator;
132 typedef typename base_class::atomic_node_ptr head_type;
137 typedef cds::gc::guarded_ptr< gc, node_type, value_type, details::guarded_ptr_cast_map<node_type, value_type> > guarded_ptr;
141 # ifndef CDS_CXX11_LAMBDA_SUPPORT
142 template <typename Func>
143 class insert_functor: protected cds::details::functor_wrapper<Func>
145 typedef cds::details::functor_wrapper<Func> base_class;
147 insert_functor ( Func f )
151 void operator()( node_type& node )
153 base_class::get()( node.m_Data );
157 template <typename Func>
158 class ensure_functor: protected cds::details::functor_wrapper<Func>
160 typedef cds::details::functor_wrapper<Func> base_class;
162 ensure_functor( Func f )
166 void operator ()( bool bNew, node_type& node, node_type& )
168 base_class::get()( bNew, node.m_Data );
172 template <typename Func>
173 class find_functor: protected cds::details::functor_wrapper<Func>
175 typedef cds::details::functor_wrapper<Func> base_class;
177 find_functor( Func f )
181 template <typename Q>
182 void operator ()( node_type& node, Q& )
184 base_class::get()( node.m_Data );
188 template <typename Func>
193 erase_functor( Func f )
197 void operator ()( node_type const & node )
199 cds::unref(m_func)( const_cast<value_type&>(node.m_Data) );
202 # endif // ifndef CDS_CXX11_LAMBDA_SUPPORT
207 template <typename K>
208 static node_type * alloc_node(const K& key)
210 return cxx_allocator().New( key );
213 template <typename K, typename V>
214 static node_type * alloc_node( const K& key, const V& val )
216 return cxx_allocator().New( key, val );
219 template <typename K, typename... Args>
220 static node_type * alloc_node( K&& key, Args&&... args )
222 return cxx_allocator().MoveNew( std::forward<K>(key), std::forward<Args>(args)...);
225 static void free_node( node_type * pNode )
227 cxx_allocator().Delete( pNode );
230 struct node_disposer {
231 void operator()( node_type * pNode )
236 typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
240 return base_class::m_pHead;
243 head_type const& head() const
245 return base_class::m_pHead;
251 template <bool IsConst>
252 class iterator_type: protected base_class::template iterator_type<IsConst>
254 typedef typename base_class::template iterator_type<IsConst> iterator_base;
256 iterator_type( head_type const& pNode )
257 : iterator_base( pNode )
260 friend class MichaelKVList;
263 typedef typename cds::details::make_const_type<mapped_type, IsConst>::reference value_ref;
264 typedef typename cds::details::make_const_type<mapped_type, IsConst>::pointer value_ptr;
266 typedef typename cds::details::make_const_type<value_type, IsConst>::reference pair_ref;
267 typedef typename cds::details::make_const_type<value_type, IsConst>::pointer pair_ptr;
272 iterator_type( iterator_type const& src )
273 : iterator_base( src )
276 key_type const& key() const
278 typename iterator_base::value_ptr p = iterator_base::operator ->();
279 assert( p != nullptr );
280 return p->m_Data.first;
283 pair_ptr operator ->() const
285 typename iterator_base::value_ptr p = iterator_base::operator ->();
286 return p ? &(p->m_Data) : nullptr;
289 pair_ref operator *() const
291 typename iterator_base::value_ref p = iterator_base::operator *();
295 value_ref val() const
297 typename iterator_base::value_ptr p = iterator_base::operator ->();
298 assert( p != nullptr );
299 return p->m_Data.second;
303 iterator_type& operator ++()
305 iterator_base::operator ++();
310 bool operator ==(iterator_type<C> const& i ) const
312 return iterator_base::operator ==(i);
315 bool operator !=(iterator_type<C> const& i ) const
317 return iterator_base::operator !=(i);
325 The forward iterator for Michael's list has some features:
326 - it has no post-increment operator
327 - to protect the value, the iterator contains a GC-specific guard + another guard is required locally for increment operator.
328 For some GC (gc::HP, gc::HRC), a guard is limited resource per thread, so an exception (or assertion) "no free guard"
329 may be thrown if a limit of guard count per thread is exceeded.
330 - The iterator cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
331 - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
332 deleting operations it is no guarantee that you iterate all item in the list.
334 Therefore, the use of iterators in concurrent environment is not good idea. Use the iterator on the concurrent container
335 for debug purpose only.
337 The iterator interface to access item data:
338 - <tt> operator -> </tt> - returns a pointer to \ref value_type for iterator
339 - <tt> operator *</tt> - returns a reference (a const reference for \p const_iterator) to \ref value_type for iterator
340 - <tt> const key_type& key() </tt> - returns a key reference for iterator
341 - <tt> mapped_type& val() </tt> - retuns a value reference for iterator (const reference for \p const_iterator)
343 For both functions the iterator should not be equal to <tt> end() </tt>
345 typedef iterator_type<false> iterator;
347 /// Const forward iterator
349 For iterator's features and requirements see \ref iterator
351 typedef iterator_type<true> const_iterator;
353 /// Returns a forward iterator addressing the first element in a list
355 For empty list \code begin() == end() \endcode
359 return iterator( head() );
362 /// Returns an iterator that addresses the location succeeding the last element in a list
364 Do not use the value returned by <tt>end</tt> function to access any item.
365 Internally, <tt>end</tt> returning value equals to \p nullptr.
367 The returned value can be used only to control reaching the end of the list.
368 For empty list \code begin() == end() \endcode
375 /// Returns a forward const iterator addressing the first element in a list
377 const_iterator begin() const
379 return const_iterator( head() );
381 const_iterator cbegin()
383 return const_iterator( head() );
387 /// Returns an const iterator that addresses the location succeeding the last element in a list
389 const_iterator end() const
391 return const_iterator();
393 const_iterator cend()
395 return const_iterator();
400 /// Default constructor
402 Initializes empty list
416 /// Inserts new node with key and default value
418 The function creates a node with \p key and default value, and then inserts the node created into the list.
421 - The \ref key_type should be constructible from value of type \p K.
422 In trivial case, \p K is equal to \ref key_type.
423 - The \ref mapped_type should be default-constructible.
425 Returns \p true if inserting successful, \p false otherwise.
427 template <typename K>
428 bool insert( const K& key )
430 return insert_at( head(), key );
433 /// Inserts new node with a key and a value
435 The function creates a node with \p key and value \p val, and then inserts the node created into the list.
438 - The \ref key_type should be constructible from \p key of type \p K.
439 - The \ref mapped_type should be constructible from \p val of type \p V.
441 Returns \p true if inserting successful, \p false otherwise.
443 template <typename K, typename V>
444 bool insert( const K& key, const V& val )
446 // We cannot use insert with functor here
447 // because we cannot lock inserted node for updating
448 // Therefore, we use separate function
449 return insert_at( head(), key, val );
452 /// Inserts new node and initialize it by a functor
454 This function inserts new node with key \p key and if inserting is successful then it calls
455 \p func functor with signature
458 void operator()( value_type& item );
462 The argument \p item of user-defined functor \p func is the reference
463 to the list's item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
464 User-defined functor \p func should guarantee that during changing item's value no any other changes
465 could be made on this list's item by concurrent threads.
466 The user-defined functor can be passed by reference using <tt>boost::ref</tt>
467 and it is called only if inserting is successful.
469 The key_type should be constructible from value of type \p K.
471 The function allows to split creating of new item into two part:
472 - create item from \p key;
473 - insert new item into the list;
474 - if inserting is successful, initialize the value of item by calling \p func functor
476 This can be useful if complete initialization of object of \p mapped_type is heavyweight and
477 it is preferable that the initialization should be completed only if inserting is successful.
479 template <typename K, typename Func>
480 bool insert_key( const K& key, Func func )
482 return insert_key_at( head(), key, func );
485 /// Ensures that the \p key exists in the list
487 The operation performs inserting or changing data with lock-free manner.
489 If the \p key not found in the list, then the new item created from \p key
490 is inserted into the list (note that in this case the \ref key_type should be
491 copy-constructible from type \p K).
492 Otherwise, the functor \p func is called with item found.
493 The functor \p Func may be a function with signature:
495 void func( bool bNew, value_type& item );
500 void operator()( bool bNew, value_type& item );
505 - \p bNew - \p true if the item has been inserted, \p false otherwise
506 - \p item - item of the list
508 The functor may change any fields of the \p item.second that is \ref mapped_type;
509 however, \p func must guarantee that during changing no any other modifications
510 could be made on this item by concurrent threads.
512 You may pass \p func argument by reference using <tt>boost::ref</tt>.
514 Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
515 \p second is true if new item has been added or \p false if the item with \p key
516 already is in the list.
518 template <typename K, typename Func>
519 std::pair<bool, bool> ensure( const K& key, Func f )
521 return ensure_at( head(), key, f );
524 /// Inserts data of type \ref mapped_type constructed with <tt>std::forward<Args>(args)...</tt>
526 Returns \p true if inserting successful, \p false otherwise.
528 template <typename K, typename... Args>
529 bool emplace( K&& key, Args&&... args )
531 return emplace_at( head(), std::forward<K>(key), std::forward<Args>(args)... );
534 /// Deletes \p key from the list
535 /** \anchor cds_nonintrusive_MichaelKVList_hp_erase_val
537 Returns \p true if \p key is found and has been deleted, \p false otherwise
539 template <typename K>
540 bool erase( K const& key )
542 return erase_at( head(), key, intrusive_key_comparator() );
545 /// Deletes the item from the list using \p pred predicate for searching
547 The function is an analog of \ref cds_nonintrusive_MichaelKVList_hp_erase_val "erase(K const&)"
548 but \p pred is used for key comparing.
549 \p Less functor has the interface like \p std::less.
550 \p pred must imply the same element order as the comparator used for building the list.
552 template <typename K, typename Less>
553 bool erase_with( K const& key, Less pred )
555 return erase_at( head(), key, typename options::template less_wrapper<Less>::type() );
558 /// Deletes \p key from the list
559 /** \anchor cds_nonintrusive_MichaelKVList_hp_erase_func
560 The function searches an item with key \p key, calls \p f functor
561 and deletes the item. If \p key is not found, the functor is not called.
563 The functor \p Func interface:
566 void operator()(value_type& val) { ... }
569 The functor may be passed by reference with <tt>boost:ref</tt>
571 Return \p true if key is found and deleted, \p false otherwise
575 template <typename K, typename Func>
576 bool erase( K const& key, Func f )
578 return erase_at( head(), key, intrusive_key_comparator(), f );
581 /// Deletes the item from the list using \p pred predicate for searching
583 The function is an analog of \ref cds_nonintrusive_MichaelKVList_hp_erase_func "erase(K const&, Func)"
584 but \p pred is used for key comparing.
585 \p Less functor has the interface like \p std::less.
586 \p pred must imply the same element order as the comparator used for building the list.
588 template <typename K, typename Less, typename Func>
589 bool erase_with( K const& key, Less pred, Func f )
591 return erase_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
594 /// Extracts the item from the list with specified \p key
595 /** \anchor cds_nonintrusive_MichaelKVList_hp_extract
596 The function searches an item with key equal to \p key,
597 unlinks it from the list, and returns it in \p dest parameter.
598 If the item with key equal to \p key is not found the function returns \p false.
600 Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
602 The \ref disposer specified in \p Traits class template parameter is called automatically
603 by garbage collector \p GC specified in class' template parameters when returned \ref guarded_ptr object
604 will be destroyed or released.
605 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
609 typedef cds::container::MichaelKVList< cds::gc::HP, int, foo, my_traits > ord_list;
613 ord_list::guarded_ptr gp;
614 theList.extract( gp, 5 );
618 // Destructor of gp releases internal HP guard
622 template <typename K>
623 bool extract( guarded_ptr& dest, K const& key )
625 return extract_at( head(), dest.guard(), key, intrusive_key_comparator() );
628 /// Extracts the item from the list with comparing functor \p pred
630 The function is an analog of \ref cds_nonintrusive_MichaelKVList_hp_extract "extract(guarded_ptr&, K const&)"
631 but \p pred predicate is used for key comparing.
633 \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
635 \p pred must imply the same element order as the comparator used for building the list.
637 template <typename K, typename Less>
638 bool extract_with( guarded_ptr& dest, K const& key, Less pred )
640 return extract_at( head(), dest.guard(), key, typename options::template less_wrapper<Less>::type() );
643 /// Finds the key \p key
644 /** \anchor cds_nonintrusive_MichaelKVList_hp_find_val
645 The function searches the item with key equal to \p key
646 and returns \p true if it is found, and \p false otherwise
648 template <typename Q>
649 bool find( Q const& key )
651 return find_at( head(), key, intrusive_key_comparator() );
654 /// Finds the key \p val using \p pred predicate for searching
656 The function is an analog of \ref cds_nonintrusive_MichaelKVList_hp_find_val "find(Q const&)"
657 but \p pred is used for key comparing.
658 \p Less functor has the interface like \p std::less.
659 \p pred must imply the same element order as the comparator used for building the list.
661 template <typename Q, typename Less>
662 bool find_with( Q const& key, Less pred )
664 return find_at( head(), key, typename options::template less_wrapper<Less>::type() );
667 /// Finds the key \p key and performs an action with it
668 /** \anchor cds_nonintrusive_MichaelKVList_hp_find_func
669 The function searches an item with key equal to \p key and calls the functor \p f for the item found.
670 The interface of \p Func functor is:
673 void operator()( value_type& item );
676 where \p item is the item found.
678 You may pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
680 The functor may change <tt>item.second</tt> that is reference to value of node.
681 Note that the function is only guarantee that \p item cannot be deleted during functor is executing.
682 The function does not serialize simultaneous access to the list \p item. If such access is
683 possible you must provide your own synchronization schema to exclude unsafe item modifications.
685 The function returns \p true if \p key is found, \p false otherwise.
687 template <typename Q, typename Func>
688 bool find( Q const& key, Func f )
690 return find_at( head(), key, intrusive_key_comparator(), f );
693 /// Finds the key \p val using \p pred predicate for searching
695 The function is an analog of \ref cds_nonintrusive_MichaelKVList_hp_find_func "find(Q&, Func)"
696 but \p pred is used for key comparing.
697 \p Less functor has the interface like \p std::less.
698 \p pred must imply the same element order as the comparator used for building the list.
700 template <typename Q, typename Less, typename Func>
701 bool find_with( Q const& key, Less pred, Func f )
703 return find_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
706 /// Finds the \p key and return the item found
707 /** \anchor cds_nonintrusive_MichaelKVList_hp_get
708 The function searches the item with key equal to \p key
709 and assigns the item found to guarded pointer \p ptr.
710 The function returns \p true if \p key is found, and \p false otherwise.
711 If \p key is not found the \p ptr parameter is not changed.
713 The \ref disposer specified in \p Traits class template parameter is called
714 by garbage collector \p GC automatically when returned \ref guarded_ptr object
715 will be destroyed or released.
716 @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
720 typedef cds::container::MichaelKVList< cds::gc::HP, int, foo, my_traits > ord_list;
724 ord_list::guarded_ptr gp;
725 if ( theList.get( gp, 5 )) {
729 // Destructor of guarded_ptr releases internal HP guard
733 Note the compare functor specified for class \p Traits template parameter
734 should accept a parameter of type \p K that can be not the same as \p key_type.
736 template <typename K>
737 bool get( guarded_ptr& ptr, K const& key )
739 return get_at( head(), ptr.guard(), key, intrusive_key_comparator() );
742 /// Finds the \p key and return the item found
744 The function is an analog of \ref cds_nonintrusive_MichaelKVList_hp_get "get( guarded_ptr& ptr, K const&)"
745 but \p pred is used for comparing the keys.
747 \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
749 \p pred must imply the same element order as the comparator used for building the list.
751 template <typename K, typename Less>
752 bool get_with( guarded_ptr& ptr, K const& key, Less pred )
754 return get_at( head(), ptr.guard(), key, typename options::template less_wrapper<Less>::type() );
757 /// Checks if the list is empty
760 return base_class::empty();
763 /// Returns list's item count
765 The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
766 this function always returns 0.
768 <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
769 is empty. To check list emptyness use \ref empty() method.
773 return base_class::size();
778 Post-condition: the list is empty
787 bool insert_node_at( head_type& refHead, node_type * pNode )
789 assert( pNode != nullptr );
790 scoped_node_ptr p( pNode );
791 if ( base_class::insert_at( refHead, *pNode )) {
798 template <typename K>
799 bool insert_at( head_type& refHead, const K& key )
801 return insert_node_at( refHead, alloc_node( key ));
804 template <typename K, typename V>
805 bool insert_at( head_type& refHead, const K& key, const V& val )
807 return insert_node_at( refHead, alloc_node( key, val ));
810 template <typename K, typename Func>
811 bool insert_key_at( head_type& refHead, const K& key, Func f )
813 scoped_node_ptr pNode( alloc_node( key ));
815 # ifdef CDS_CXX11_LAMBDA_SUPPORT
816 if ( base_class::insert_at( refHead, *pNode, [&f](node_type& node){ cds::unref(f)( node.m_Data ); }))
818 insert_functor<Func> wrapper( f );
819 if ( base_class::insert_at( refHead, *pNode, cds::ref(wrapper) ))
828 template <typename K, typename... Args>
829 bool emplace_at( head_type& refHead, K&& key, Args&&... args )
831 return insert_node_at( refHead, alloc_node( std::forward<K>(key), std::forward<Args>(args)... ));
834 template <typename K, typename Func>
835 std::pair<bool, bool> ensure_at( head_type& refHead, const K& key, Func f )
837 scoped_node_ptr pNode( alloc_node( key ));
839 # ifdef CDS_CXX11_LAMBDA_SUPPORT
840 std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode,
841 [&f]( bool bNew, node_type& node, node_type& ){ cds::unref(f)( bNew, node.m_Data ); });
843 ensure_functor<Func> wrapper( f );
844 std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode, cds::ref(wrapper));
846 if ( ret.first && ret.second )
852 template <typename K, typename Compare>
853 bool erase_at( head_type& refHead, K const& key, Compare cmp )
855 return base_class::erase_at( refHead, key, cmp );
858 template <typename K, typename Compare, typename Func>
859 bool erase_at( head_type& refHead, K const& key, Compare cmp, Func f )
861 # ifdef CDS_CXX11_LAMBDA_SUPPORT
862 return base_class::erase_at( refHead, key, cmp, [&f]( node_type const & node ){ cds::unref(f)( const_cast<value_type&>(node.m_Data)); });
864 erase_functor<Func> wrapper( f );
865 return base_class::erase_at( refHead, key, cmp, cds::ref(wrapper) );
868 template <typename K, typename Compare>
869 bool extract_at( head_type& refHead, typename gc::Guard& dest, K const& key, Compare cmp )
871 return base_class::extract_at( refHead, dest, key, cmp );
874 template <typename K, typename Compare>
875 bool find_at( head_type& refHead, K const& key, Compare cmp )
877 return base_class::find_at( refHead, key, cmp );
880 template <typename K, typename Compare, typename Func>
881 bool find_at( head_type& refHead, K& key, Compare cmp, Func f )
883 # ifdef CDS_CXX11_LAMBDA_SUPPORT
884 return base_class::find_at( refHead, key, cmp, [&f](node_type& node, K const&){ cds::unref(f)( node.m_Data ); });
886 find_functor<Func> wrapper( f );
887 return base_class::find_at( refHead, key, cmp, cds::ref(wrapper) );
891 template <typename K, typename Compare>
892 bool get_at( head_type& refHead, typename gc::Guard& guard, K const& key, Compare cmp )
894 return base_class::get_at( refHead, guard, key, cmp );
900 }} // namespace cds::container
902 #endif // #ifndef __CDS_CONTAINER_MICHAEL_KVLIST_IMPL_H