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