Remove unused vars
[libcds.git] / cds / container / michael_list_rcu.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_CONTAINER_MICHAEL_LIST_RCU_H
4 #define __CDS_CONTAINER_MICHAEL_LIST_RCU_H
5
6 #include <memory>
7 #include <cds/container/details/michael_list_base.h>
8 #include <cds/intrusive/michael_list_rcu.h>
9 #include <cds/container/details/make_michael_list.h>
10 #include <cds/details/binary_functor_wrapper.h>
11
12 namespace cds { namespace container {
13
14     /// Michael's ordered list (template specialization for \ref cds_urcu_desc "RCU")
15     /** @ingroup cds_nonintrusive_list
16         \anchor cds_nonintrusive_MichaelList_rcu
17
18         Usually, ordered single-linked list is used as a building block for the hash table implementation.
19         The complexity of searching is <tt>O(N)</tt>.
20
21         Source:
22         - [2002] Maged Michael "High performance dynamic lock-free hash tables and list-based sets"
23
24         This class is non-intrusive version of \ref cds_intrusive_MichaelList_rcu "cds::intrusive::MichaelList" RCU specialization.
25
26         Template arguments:
27         - \p RCU - one of \ref cds_urcu_gc "RCU type"
28         - \p T - type stored in the list. The type must be default- and copy-constructible.
29         - \p Traits - type traits, default is michael_list::traits
30
31         The implementation does not divide type \p T into key and value part and
32         may be used as a main building block for hash set containers.
33         The key is a function (or a part) of type \p T, and this function is specified by <tt>Traits::compare</tt> functor
34         or <tt>Traits::less</tt> predicate.
35
36         \ref cds_nonintrusive_MichaelKVList_rcu "MichaelKVList" is a key-value version of Michael's
37         non-intrusive list that is closer to the C++ std library approach.
38
39         @note Before including <tt><cds/container/michael_list_rcu.h></tt> you should include appropriate RCU header file,
40         see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
41
42         It is possible to declare option-based list with cds::container::michael_list::make_traits metafunction istead of \p Traits template
43         argument. For example, the following traits-based declaration of Michael's list
44
45         \code
46         #include <cds/urcu/general_buffered.h>
47         #include <cds/container/michael_list_rcu.h>
48         // Declare comparator for the item
49         struct my_compare {
50             int operator ()( int i1, int i2 )
51             {
52                 return i1 - i2;
53             }
54         };
55
56         // Declare traits
57         struct my_traits: public cds::container::michael_list::traits
58         {
59             typedef my_compare compare;
60         };
61
62         // Declare traits-based list
63         typedef cds::container::MichaelList< cds::urcu::gc< cds::urcu::general_buffered<> >, int, my_traits >     traits_based_list;
64         \endcode
65
66         is equivalent for the following option-based list
67         \code
68         #include <cds/urcu/general_buffered.h>
69         #include <cds/container/michael_list_rcu.h>
70
71         // my_compare is the same
72
73         // Declare option-based list
74         typedef cds::container::MichaelList< cds::urcu::gc< cds::urcu::general_buffered<> >, int,
75             typename cds::container::michael_list::make_traits<
76                 cds::container::opt::compare< my_compare >     // item comparator option
77             >::type
78         >     option_based_list;
79         \endcode
80
81         Template argument list \p Options of cds::container::michael_list::make_traits metafunction are:
82         - opt::compare - key comparison functor. No default functor is provided.
83             If the option is not specified, the opt::less is used.
84         - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
85         - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used.
86         - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that is no item counting.
87         - opt::allocator - the allocator used for creating and freeing list's item. Default is \ref CDS_DEFAULT_ALLOCATOR macro.
88         - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
89             or opt::v::sequential_consistent (sequentially consisnent memory model).
90         - opt::rcu_check_deadlock - a deadlock checking policy. Default is opt::v::rcu_throw_deadlock
91     */
92     template <
93         typename RCU,
94         typename T,
95 #ifdef CDS_DOXYGEN_INVOKED
96         typename Traits = michael_list::traits
97 #else
98         typename Traits
99 #endif
100     >
101     class MichaelList< cds::urcu::gc<RCU>, T, Traits > :
102 #ifdef CDS_DOXYGEN_INVOKED
103         protected intrusive::MichaelList< cds::urcu::gc<RCU>, T, Traits >
104 #else
105         protected details::make_michael_list< cds::urcu::gc<RCU>, T, Traits >::type
106 #endif
107     {
108         //@cond
109         typedef details::make_michael_list< cds::urcu::gc<RCU>, T, Traits > maker;
110         typedef typename maker::type  base_class;
111         //@endcond
112
113     public:
114         typedef cds::urcu::gc<RCU> gc;          ///< RCU
115         typedef T                  value_type;  ///< Type of value stored in the list
116         typedef Traits             traits;      ///< List traits
117
118         typedef typename base_class::back_off     back_off;       ///< Back-off strategy used
119         typedef typename maker::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 maker::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
124
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
127
128     protected:
129         //@cond
130         typedef typename base_class::value_type   node_type;
131         typedef typename maker::cxx_allocator     cxx_allocator;
132         typedef typename maker::node_deallocator  node_deallocator;
133         typedef typename maker::intrusive_traits::compare  intrusive_key_comparator;
134
135         typedef typename base_class::atomic_node_ptr      head_type;
136         //@endcond
137
138     public:
139         using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_traits::disposer >; ///< pointer to extracted node
140
141     private:
142         //@cond
143         static value_type& node_to_value( node_type& n )
144         {
145             return n.m_Value;
146         }
147         static value_type const& node_to_value( node_type const& n )
148         {
149             return n.m_Value;
150         }
151         //@endcond
152
153     protected:
154         //@cond
155         template <typename Q>
156         static node_type * alloc_node( Q const& v )
157         {
158             return cxx_allocator().New( v );
159         }
160
161         template <typename... Args>
162         static node_type * alloc_node( Args&&... args )
163         {
164             return cxx_allocator().MoveNew( std::forward<Args>(args)... );
165         }
166
167         static void free_node( node_type * pNode )
168         {
169             cxx_allocator().Delete( pNode );
170         }
171
172         struct node_disposer {
173             void operator()( node_type * pNode )
174             {
175                 free_node( pNode );
176             }
177         };
178         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
179
180         head_type& head()
181         {
182             return base_class::m_pHead;
183         }
184
185         head_type& head() const
186         {
187             return const_cast<head_type&>( base_class::m_pHead );
188         }
189         //@endcond
190
191     protected:
192                 //@cond
193         template <bool IsConst>
194         class iterator_type: protected base_class::template iterator_type<IsConst>
195         {
196             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
197
198             iterator_type( head_type const& pNode )
199                 : iterator_base( pNode )
200             {}
201
202             friend class MichaelList;
203
204         public:
205             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
206             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
207
208             iterator_type()
209             {}
210
211             iterator_type( iterator_type const& src )
212                 : iterator_base( src )
213             {}
214
215             value_ptr operator ->() const
216             {
217                 typename iterator_base::value_ptr p = iterator_base::operator ->();
218                 return p ? &(p->m_Value) : nullptr;
219             }
220
221             value_ref operator *() const
222             {
223                 return (iterator_base::operator *()).m_Value;
224             }
225
226             /// Pre-increment
227             iterator_type& operator ++()
228             {
229                 iterator_base::operator ++();
230                 return *this;
231             }
232
233             template <bool C>
234             bool operator ==(iterator_type<C> const& i ) const
235             {
236                 return iterator_base::operator ==(i);
237             }
238             template <bool C>
239             bool operator !=(iterator_type<C> const& i ) const
240             {
241                 return iterator_base::operator !=(i);
242             }
243         };
244         //@endcond
245
246     public:
247         /// Forward iterator
248         typedef iterator_type<false>    iterator;
249
250         /// Const forward iterator
251         typedef iterator_type<true>     const_iterator;
252
253         /// Returns a forward iterator addressing the first element in a list
254         /**
255             For empty list \code begin() == end() \endcode
256         */
257         iterator begin()
258         {
259             return iterator( head() );
260         }
261
262         /// Returns an iterator that addresses the location succeeding the last element in a list
263         /**
264             Do not use the value returned by <tt>end</tt> function to access any item.
265             Internally, <tt>end</tt> returning value equals to \p nullptr.
266
267             The returned value can be used only to control reaching the end of the list.
268             For empty list \code begin() == end() \endcode
269         */
270         iterator end()
271         {
272             return iterator();
273         }
274
275         /// Returns a forward const iterator addressing the first element in a list
276         //@{
277         const_iterator begin() const
278         {
279             return const_iterator( head() );
280         }
281         const_iterator cbegin() const
282         {
283             return const_iterator( head() );
284         }
285         //@}
286
287         /// Returns an const iterator that addresses the location succeeding the last element in a list
288         //@{
289         const_iterator end() const
290         {
291             return const_iterator();
292         }
293         const_iterator cend() const
294         {
295             return const_iterator();
296         }
297         //@}
298
299     public:
300         /// Default constructor
301         /**
302             Initialize empty list
303         */
304         MichaelList()
305         {}
306
307         /// List destructor
308         /**
309             Clears the list
310         */
311         ~MichaelList()
312         {
313             clear();
314         }
315
316         /// Inserts new node
317         /**
318             The function creates a node with copy of \p val value
319             and then inserts the node created into the list.
320
321             The type \p Q should contain as minimum the complete key of the node.
322             The object of \ref value_type should be constructible from \p val of type \p Q.
323             In trivial case, \p Q is equal to \ref value_type.
324
325             The function makes RCU lock internally.
326
327             Returns \p true if inserting successful, \p false otherwise.
328         */
329         template <typename Q>
330         bool insert( Q const& val )
331         {
332             return insert_at( head(), val );
333         }
334
335         /// Inserts new node
336         /**
337             This function inserts new node with default-constructed value and then it calls
338             \p func functor with signature
339             \code void func( value_type& itemValue ) ;\endcode
340
341             The argument \p itemValue of user-defined functor \p func is the reference
342             to the list's item inserted. User-defined functor \p func should guarantee that during changing
343             item's value no any other changes could be made on this list's item by concurrent threads.
344
345             The type \p Q should contain the complete key of the node.
346             The object of \ref value_type should be constructible from \p key of type \p Q.
347
348             The function allows to split creating of new item into two part:
349             - create item from \p key with initializing key-fields only;
350             - insert new item into the list;
351             - if inserting is successful, initialize non-key fields of item by calling \p f functor
352
353             This can be useful if complete initialization of object of \p value_type is heavyweight and
354             it is preferable that the initialization should be completed only if inserting is successful.
355
356             The function makes RCU lock internally.
357
358             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
359         */
360         template <typename Q, typename Func>
361         bool insert( Q const& key, Func func )
362         {
363             return insert_at( head(), key, func );
364         }
365
366         /// Ensures that the \p key exists in the list
367         /**
368             The operation performs inserting or changing data with lock-free manner.
369
370             If the \p key not found in the list, then the new item created from \p key
371             is inserted into the list. Otherwise, the functor \p func is called with the item found.
372             The functor \p Func should be a function with signature:
373             \code
374                 void func( bool bNew, value_type& item, const Q& val );
375             \endcode
376             or a functor:
377             \code
378                 struct my_functor {
379                     void operator()( bool bNew, value_type& item, const Q& val );
380                 };
381             \endcode
382
383             with arguments:
384             - \p bNew - \p true if the item has been inserted, \p false otherwise
385             - \p item - item of the list
386             - \p val - argument \p key passed into the \p ensure function
387
388             The functor may change non-key fields of the \p item; however, \p func must guarantee
389             that during changing no any other modifications could be made on this item by concurrent threads.
390
391             The function makes RCU lock internally.
392
393             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
394             \p second is true if new item has been added or \p false if the item with \p key
395             already is in the list.
396
397             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
398         */
399         template <typename Q, typename Func>
400         std::pair<bool, bool> ensure( Q const& key, Func f )
401         {
402             return ensure_at( head(), key, f );
403         }
404
405         /// Inserts data of type \ref value_type constructed from \p args
406         /**
407             Returns \p true if inserting successful, \p false otherwise.
408
409             The function makes RCU lock internally.
410         */
411         template <typename... Args>
412         bool emplace( Args&&... args )
413         {
414             return emplace_at( head(), std::forward<Args>(args)... );
415         }
416
417         /// Deletes \p key from the list
418         /** \anchor cds_nonintrusive_MichealList_rcu_erase_val
419             Since the key of MichaelList's item type \p value_type is not explicitly specified,
420             template parameter \p Q defines the key type searching in the list.
421             The list item comparator should be able to compare values of the type \p value_type
422             and \p Q in any order.
423
424             RCU \p synchronize method can be called. RCU should not be locked.
425
426             Return \p true if key is found and deleted, \p false otherwise
427         */
428         template <typename Q>
429         bool erase( Q const& key )
430         {
431             return erase_at( head(), key, intrusive_key_comparator(),  [](value_type const&){} );
432         }
433
434         /// Deletes the item from the list using \p pred predicate for searching
435         /**
436             The function is an analog of \ref cds_nonintrusive_MichealList_rcu_erase_val "erase(Q const&)"
437             but \p pred is used for key comparing.
438             \p Less functor has the interface like \p std::less.
439             \p pred must imply the same element order as the comparator used for building the list.
440         */
441         template <typename Q, typename Less>
442         bool erase_with( Q const& key, Less pred )
443         {
444             CDS_UNUSED( pred );
445             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), [](value_type const&){} );
446         }
447
448         /// Deletes \p key from the list
449         /** \anchor cds_nonintrusive_MichaelList_rcu_erase_func
450             The function searches an item with key \p key, calls \p f functor with item found
451             and deletes it. If \p key is not found, the functor is not called.
452
453             The functor \p Func interface:
454             \code
455             struct extractor {
456                 void operator()(const value_type& val) { ... }
457             };
458             \endcode
459
460             Since the key of MichaelList's item type \p value_type is not explicitly specified,
461             template parameter \p Q defines the key type searching in the list.
462             The list item comparator should be able to compare the values of type \p value_type
463             and \p Q in any order.
464
465             RCU \p synchronize method can be called. RCU should not be locked.
466
467             Return \p true if key is found and deleted, \p false otherwise
468         */
469         template <typename Q, typename Func>
470         bool erase( Q const& key, Func f )
471         {
472             return erase_at( head(), key, intrusive_key_comparator(), f );
473         }
474
475         /// Deletes the item from the list using \p pred predicate for searching
476         /**
477             The function is an analog of \ref cds_nonintrusive_MichaelList_rcu_erase_func "erase(Q const&, Func)"
478             but \p pred is used for key comparing.
479             \p Less functor has the interface like \p std::less.
480             \p pred must imply the same element order as the comparator used for building the list.
481         */
482         template <typename Q, typename Less, typename Func>
483         bool erase_with( Q const& key, Less pred, Func f )
484         {
485             CDS_UNUSED( pred );
486             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
487         }
488
489         /// Extracts an item from the list
490         /**
491         @anchor cds_nonintrusive_MichaelList_rcu_extract
492             The function searches an item with key equal to \p key in the list,
493             unlinks it from the list, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
494             If the item with the key equal to \p key is not found the function returns an empty \p exempt_ptr.
495
496             @note The function does NOT call RCU read-side lock or synchronization,
497             and does NOT dispose the item found. It just excludes the item from the list
498             and returns a pointer to item found.
499             You should lock RCU before calling this function.
500
501             \code
502             #include <cds/urcu/general_buffered.h>
503             #include <cds/container/michael_list_rcu.h>
504
505             typedef cds::urcu::gc< general_buffered<> > rcu;
506             typedef cds::container::MichaelList< rcu, Foo > rcu_michael_list;
507
508             rcu_michael_list theList;
509             // ...
510
511             rcu_michael_list::exempt_ptr p;
512             {
513                 // first, we should lock RCU
514                 rcu::scoped_lock sl;
515
516                 // Now, you can apply extract function
517                 // Note that you must not delete the item found inside the RCU lock
518                 p = theList.extract( 10 )
519                 if ( p ) {
520                     // do something with p
521                     ...
522                 }
523             }
524             // Outside RCU lock section we may safely release extracted pointer.
525             // release() passes the pointer to RCU reclamation cycle.
526             p.release();
527             \endcode
528         */
529         template <typename Q>
530         exempt_ptr extract( Q const& key )
531         {
532             return exempt_ptr( extract_at( head(), key, intrusive_key_comparator() ));
533         }
534
535         /// Extracts an item from the list using \p pred predicate for searching
536         /**
537             This function is the analog for \ref cds_nonintrusive_MichaelList_rcu_extract "extract(exempt_ptr&, Q const&)".
538
539             The \p pred is a predicate used for key comparing.
540             \p Less has the interface like \p std::less.
541             \p pred must imply the same element order as \ref key_comparator.
542         */
543         template <typename Q, typename Less>
544         exempt_ptr extract_with( Q const& key, Less pred )
545         {
546             CDS_UNUSED( pred );
547             return exempt_ptr( extract_at( head(), key, typename maker::template less_wrapper<Less>::type() ));
548         }
549
550         /// Finds the key \p key
551         /** \anchor cds_nonintrusive_MichaelList_rcu_find_val
552             The function searches the item with key equal to \p key
553             and returns \p true if it is found, and \p false otherwise.
554
555             The function makes RCU lock internally.
556         */
557         template <typename Q>
558         bool find( Q const& key ) const
559         {
560             return find_at( head(), key, intrusive_key_comparator() );
561         }
562
563         /// Finds the key \p val using \p pred predicate for searching
564         /**
565             The function is an analog of \ref cds_nonintrusive_MichaelList_rcu_find_val "find(Q const&)"
566             but \p pred is used for key comparing.
567             \p Less functor has the interface like \p std::less.
568             \p pred must imply the same element order as the comparator used for building the list.
569         */
570         template <typename Q, typename Less>
571         bool find_with( Q const& key, Less pred ) const
572         {
573             CDS_UNUSED( pred );
574             return find_at( head(), key, typename maker::template less_wrapper<Less>::type() );
575         }
576
577         /// Finds the key \p key and performs an action with it
578         /** \anchor cds_nonintrusive_MichaelList_rcu_find_func
579             The function searches an item with key equal to \p key and calls the functor \p f for the item found.
580             The interface of \p Func functor is:
581             \code
582             struct functor {
583                 void operator()( value_type& item, Q& key );
584             };
585             \endcode
586             where \p item is the item found, \p key is the \p %find() function argument.
587
588             The functor may change non-key fields of \p item. Note that the function is only guarantee
589             that \p item cannot be deleted during functor is executing.
590             The function does not serialize simultaneous access to the list \p item. If such access is
591             possible you must provide your own synchronization schema to exclude unsafe item modifications.
592
593             The function makes RCU lock internally.
594
595             The function returns \p true if \p val is found, \p false otherwise.
596         */
597         template <typename Q, typename Func>
598         bool find( Q& key, Func f ) const
599         {
600             return find_at( head(), key, intrusive_key_comparator(), f );
601         }
602         //@cond
603         template <typename Q, typename Func>
604         bool find( Q const& key, Func f ) const
605         {
606             return find_at( head(), key, intrusive_key_comparator(), f );
607         }
608         //@endcond
609
610         /// Finds the key \p key using \p pred predicate for searching
611         /**
612             The function is an analog of \ref cds_nonintrusive_MichaelList_rcu_find_func "find(Q&, Func)"
613             but \p pred is used for key comparing.
614             \p Less functor has the interface like \p std::less.
615             \p pred must imply the same element order as the comparator used for building the list.
616         */
617         template <typename Q, typename Less, typename Func>
618         bool find_with( Q& key, Less pred, Func f ) const
619         {
620             CDS_UNUSED( pred );
621             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
622         }
623         //@cond
624         template <typename Q, typename Less, typename Func>
625         bool find_with( Q const& key, Less pred, Func f ) const
626         {
627             CDS_UNUSED( pred );
628             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
629         }
630         //@endcond
631
632         /// Finds the key \p key and return the item found
633         /** \anchor cds_nonintrusive_MichaelList_rcu_get
634             The function searches the item with key equal to \p key and returns the pointer to item found.
635             If \p key is not found it returns \p nullptr.
636
637             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
638
639             RCU should be locked before call of this function.
640             Returned item is valid only while RCU is locked:
641             \code
642             typedef cds::container::MichaelList< cds::urcu::gc< cds::urcu::general_buffered<> >, foo, my_traits > ord_list;
643             ord_list theList;
644             // ...
645             {
646                 // Lock RCU
647                 ord_list::rcu_lock lock;
648
649                 foo * pVal = theList.get( 5 );
650                 if ( pVal ) {
651                     // Deal with pVal
652                     //...
653                 }
654                 // Unlock RCU by rcu_lock destructor
655                 // pVal can be freed at any time after RCU has been unlocked
656             }
657             \endcode
658         */
659         template <typename Q>
660         value_type * get( Q const& key ) const
661         {
662             return get_at( head(), key, intrusive_key_comparator());
663         }
664
665         /// Finds \p key and return the item found
666         /**
667             The function is an analog of \ref cds_nonintrusive_MichaelList_rcu_get "get(Q const&)"
668             but \p pred is used for comparing the keys.
669
670             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
671             in any order.
672             \p pred must imply the same element order as the comparator used for building the list.
673         */
674         template <typename Q, typename Less>
675         value_type * get_with( Q const& key, Less pred ) const
676         {
677             CDS_UNUSED( pred );
678             return get_at( head(), key, typename maker::template less_wrapper<Less>::type());
679         }
680
681         /// Checks if the list is empty
682         bool empty() const
683         {
684             return base_class::empty();
685         }
686
687         /// Returns list's item count
688         /**
689             The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
690             this function always returns 0.
691
692             @note Even if you use real item counter and it returns 0, this fact does not mean that the list
693             is empty. To check list emptyness use \p empty() method.
694         */
695         size_t size() const
696         {
697             return base_class::size();
698         }
699
700         /// Clears the list
701         void clear()
702         {
703             base_class::clear();
704         }
705
706     protected:
707         //@cond
708         bool insert_node_at( head_type& refHead, node_type * pNode )
709         {
710             assert( pNode );
711             scoped_node_ptr p(pNode);
712             if ( base_class::insert_at( refHead, *pNode )) {
713                 p.release();
714                 return true;
715             }
716
717             return false;
718         }
719
720         template <typename Q>
721         bool insert_at( head_type& refHead, Q const& val )
722         {
723             return insert_node_at( refHead, alloc_node( val ));
724         }
725
726         template <typename Q, typename Func>
727         bool insert_at( head_type& refHead, Q const& key, Func f )
728         {
729             scoped_node_ptr pNode( alloc_node( key ));
730
731             if ( base_class::insert_at( refHead, *pNode, [&f]( node_type& node ) { f( node_to_value(node) ); } )) {
732                 pNode.release();
733                 return true;
734             }
735             return false;
736         }
737
738         template <typename... Args>
739         bool emplace_at( head_type& refHead, Args&&... args )
740         {
741             return insert_node_at( refHead, alloc_node( std::forward<Args>(args) ... ));
742         }
743
744         template <typename Q, typename Compare, typename Func>
745         bool erase_at( head_type& refHead, Q const& key, Compare cmp, Func f )
746         {
747             return base_class::erase_at( refHead, key, cmp, [&f](node_type const& node){ f( node_to_value(node) ); } );
748         }
749
750         template <typename Q, typename Func>
751         std::pair<bool, bool> ensure_at( head_type& refHead, Q const& key, Func f )
752         {
753             scoped_node_ptr pNode( alloc_node( key ));
754
755             std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode,
756                 [&f, &key](bool bNew, node_type& node, node_type&){ f( bNew, node_to_value(node), key ); });
757             if ( ret.first && ret.second )
758                 pNode.release();
759
760             return ret;
761         }
762
763         template <typename Q, typename Compare>
764         node_type * extract_at( head_type& refHead, Q const& key, Compare cmp )
765         {
766             return base_class::extract_at( refHead, key, cmp );
767         }
768
769         template <typename Q, typename Compare>
770         bool find_at( head_type& refHead, Q const& key, Compare cmp ) const
771         {
772             return base_class::find_at( refHead, key, cmp, [](node_type&, Q const &) {} );
773         }
774
775         template <typename Q, typename Compare, typename Func>
776         bool find_at( head_type& refHead, Q& val, Compare cmp, Func f ) const
777         {
778             return base_class::find_at( refHead, val, cmp, [&f](node_type& node, Q& v){ f( node_to_value(node), v ); });
779         }
780
781         template <typename Q, typename Compare>
782         value_type * get_at( head_type& refHead, Q const& val, Compare cmp ) const
783         {
784             node_type * pNode = base_class::get_at( refHead, val, cmp );
785             return pNode ? &pNode->m_Value : nullptr;
786         }
787
788         //@endcond
789     };
790
791 }}  // namespace cds::container
792
793 #endif  // #ifndef __CDS_CONTAINER_MICHAEL_LIST_RCU_H