420d367c78d105f604002cd7f97c597a087931f4
[libcds.git] / cds / container / michael_kvlist_rcu.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_CONTAINER_MICHAEL_KVLIST_RCU_H
4 #define __CDS_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 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         typedef 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         > exempt_ptr;
133
134     protected:
135         //@cond
136         template <typename K>
137         static node_type * alloc_node(const K& key)
138         {
139             return cxx_allocator().New( key );
140         }
141
142         template <typename K, typename V>
143         static node_type * alloc_node( const K& key, const V& val )
144         {
145             return cxx_allocator().New( key, val );
146         }
147
148         template <typename K, typename... Args>
149         static node_type * alloc_node( K&& key, Args&&... args )
150         {
151             return cxx_allocator().MoveNew( std::forward<K>(key), std::forward<Args>(args)...);
152         }
153
154         static void free_node( node_type * pNode )
155         {
156             cxx_allocator().Delete( pNode );
157         }
158
159         struct node_disposer {
160             void operator()( node_type * pNode )
161             {
162                 free_node( pNode );
163             }
164         };
165         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
166
167         head_type& head()
168         {
169             return base_class::m_pHead;
170         }
171
172         head_type& head() const
173         {
174             return const_cast<head_type&>( base_class::m_pHead );
175         }
176         //@endcond
177
178     protected:
179         //@cond
180         template <bool IsConst>
181         class iterator_type: protected base_class::template iterator_type<IsConst>
182         {
183             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
184
185             iterator_type( head_type const& pNode )
186                 : iterator_base( pNode )
187             {}
188
189             friend class MichaelKVList;
190
191         public:
192             typedef typename cds::details::make_const_type<mapped_type, IsConst>::reference  value_ref;
193             typedef typename cds::details::make_const_type<mapped_type, IsConst>::pointer    value_ptr;
194
195             typedef typename cds::details::make_const_type<value_type,  IsConst>::reference  pair_ref;
196             typedef typename cds::details::make_const_type<value_type,  IsConst>::pointer    pair_ptr;
197
198             iterator_type()
199             {}
200
201             iterator_type( iterator_type const& src )
202                 : iterator_base( src )
203             {}
204
205             key_type const& key() const
206             {
207                 typename iterator_base::value_ptr p = iterator_base::operator ->();
208                 assert( p != nullptr );
209                 return p->m_Data.first;
210             }
211
212             pair_ptr operator ->() const
213             {
214                 typename iterator_base::value_ptr p = iterator_base::operator ->();
215                 return p ? &(p->m_Data) : nullptr;
216             }
217
218             pair_ref operator *() const
219             {
220                 typename iterator_base::value_ref p = iterator_base::operator *();
221                 return p.m_Data;
222             }
223
224             value_ref val() const
225             {
226                 typename iterator_base::value_ptr p = iterator_base::operator ->();
227                 assert( p != nullptr );
228                 return p->m_Data.second;
229             }
230
231             /// Pre-increment
232             iterator_type& operator ++()
233             {
234                 iterator_base::operator ++();
235                 return *this;
236             }
237
238             template <bool C>
239             bool operator ==(iterator_type<C> const& i ) const
240             {
241                 return iterator_base::operator ==(i);
242             }
243             template <bool C>
244             bool operator !=(iterator_type<C> const& i ) const
245             {
246                 return iterator_base::operator !=(i);
247             }
248         };
249         //@endcond
250
251     public:
252         /// Forward iterator
253         typedef iterator_type<false>    iterator;
254
255         /// Const forward iterator
256         typedef iterator_type<true>     const_iterator;
257
258         /// Returns a forward iterator addressing the first element in a list
259         /**
260             For empty list \code begin() == end() \endcode
261         */
262         iterator begin()
263         {
264             return iterator( head() );
265         }
266
267         /// Returns an iterator that addresses the location succeeding the last element in a list
268         /**
269             Do not use the value returned by <tt>end</tt> function to access any item.
270             Internally, <tt>end</tt> returning value equals to \p nullptr.
271
272             The returned value can be used only to control reaching the end of the list.
273             For empty list \code begin() == end() \endcode
274         */
275         iterator end()
276         {
277             return iterator();
278         }
279
280         /// Returns a forward const iterator addressing the first element in a list
281         //@{
282         const_iterator begin() const
283         {
284             return const_iterator( head() );
285         }
286         const_iterator cbegin() const
287         {
288             return const_iterator( head() );
289         }
290         //@}
291
292         /// Returns an const iterator that addresses the location succeeding the last element in a list
293         //@{
294         const_iterator end() const
295         {
296             return const_iterator();
297         }
298         const_iterator cend() const
299         {
300             return const_iterator();
301         }
302         //@}
303
304     public:
305         /// Default constructor
306         /**
307             Initializes empty list
308         */
309         MichaelKVList()
310         {}
311
312         /// List desctructor
313         /**
314             Clears the list
315         */
316         ~MichaelKVList()
317         {
318             clear();
319         }
320
321         /// Inserts new node with key and default value
322         /**
323             The function creates a node with \p key and default value, and then inserts the node created into the list.
324
325             Preconditions:
326             - The \ref key_type should be constructible from value of type \p K.
327                 In trivial case, \p K is equal to \ref key_type.
328             - The \ref mapped_type should be default-constructible.
329
330             The function makes RCU lock internally.
331
332             Returns \p true if inserting successful, \p false otherwise.
333         */
334         template <typename K>
335         bool insert( const K& key )
336         {
337             return insert_at( head(), key );
338         }
339
340         /// Inserts new node with a key and a value
341         /**
342             The function creates a node with \p key and value \p val, and then inserts the node created into the list.
343
344             Preconditions:
345             - The \ref key_type should be constructible from \p key of type \p K.
346             - The \ref mapped_type should be constructible from \p val of type \p V.
347
348             The function makes RCU lock internally.
349
350             Returns \p true if inserting successful, \p false otherwise.
351         */
352         template <typename K, typename V>
353         bool insert( const K& key, const V& val )
354         {
355             return insert_at( head(), key, val );
356         }
357
358         /// Inserts new node and initialize it by a functor
359         /**
360             This function inserts new node with key \p key and if inserting is successful then it calls
361             \p func functor with signature
362             \code
363                 struct functor {
364                     void operator()( value_type& item );
365                 };
366             \endcode
367
368             The argument \p item of user-defined functor \p func is the reference
369             to the list's item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
370             User-defined functor \p func should guarantee that during changing item's value no any other changes
371             could be made on this list's item by concurrent threads.
372             The user-defined functor can be passed by reference using \p std::ref
373             and it is called only if inserting is successful.
374
375             The key_type should be constructible from value of type \p K.
376
377             The function allows to split creating of new item into two part:
378             - create item from \p key;
379             - insert new item into the list;
380             - if inserting is successful, initialize the value of item by calling \p func functor
381
382             This can be useful if complete initialization of object of \p mapped_type is heavyweight and
383             it is preferable that the initialization should be completed only if inserting is successful.
384
385             The function makes RCU lock internally.
386
387             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
388         */
389         template <typename K, typename Func>
390         bool insert_key( const K& key, Func func )
391         {
392             return insert_key_at( head(), key, func );
393         }
394
395         /// Ensures that the \p key exists in the list
396         /**
397             The operation performs inserting or changing data with lock-free manner.
398
399             If the \p key not found in the list, then the new item created from \p key
400             is inserted into the list (note that in this case the \ref key_type should be
401             copy-constructible from type \p K).
402             Otherwise, the functor \p func is called with item found.
403             The functor \p Func may be a function with signature:
404             \code
405                 void func( bool bNew, value_type& item );
406             \endcode
407             or a functor:
408             \code
409                 struct my_functor {
410                     void operator()( bool bNew, value_type& item );
411                 };
412             \endcode
413
414             with arguments:
415             - \p bNew - \p true if the item has been inserted, \p false otherwise
416             - \p item - item of the list
417
418             The functor may change any fields of the \p item.second that is \ref mapped_type;
419             however, \p func must guarantee that during changing no any other modifications
420             could be made on this item by concurrent threads.
421
422             You may pass \p func argument by reference using \p std::ref
423
424             The function makes RCU lock internally.
425
426             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
427             \p second is true if new item has been added or \p false if the item with \p key
428             already is in the list.
429
430             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
431         */
432         template <typename K, typename Func>
433         std::pair<bool, bool> ensure( const K& key, Func f )
434         {
435             return ensure_at( head(), key, f );
436         }
437
438         /// Inserts data of type \ref mapped_type constructed with <tt>std::forward<Args>(args)...</tt>
439         /**
440             Returns \p true if inserting successful, \p false otherwise.
441
442             The function makes RCU lock internally.
443         */
444         template <typename K, typename... Args>
445         bool emplace( K&& key, Args&&... args )
446         {
447             return emplace_at( head(), std::forward<K>(key), std::forward<Args>(args)... );
448         }
449
450         /// Deletes \p key from the list
451         /** \anchor cds_nonintrusive_MichaelKVList_rcu_erase
452
453             RCU \p synchronize method can be called. RCU should not be locked.
454
455             Returns \p true if \p key is found and has been deleted, \p false otherwise
456         */
457         template <typename K>
458         bool erase( K const& key )
459         {
460             return erase_at( head(), key, intrusive_key_comparator() );
461         }
462
463         /// Deletes the item from the list using \p pred predicate for searching
464         /**
465             The function is an analog of \ref cds_nonintrusive_MichaelKVList_rcu_erase "erase(K const&)"
466             but \p pred is used for key comparing.
467             \p Less functor has the interface like \p std::less.
468             \p pred must imply the same element order as the comparator used for building the list.
469         */
470         template <typename K, typename Less>
471         bool erase_with( K const& key, Less pred )
472         {
473             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type() );
474         }
475
476         /// Deletes \p key from the list
477         /** \anchor cds_nonintrusive_MichaelKVList_rcu_erase_func
478             The function searches an item with key \p key, calls \p f functor
479             and deletes the item. If \p key is not found, the functor is not called.
480
481             The functor \p Func interface:
482             \code
483             struct extractor {
484                 void operator()(value_type& val) { ... }
485             };
486             \endcode
487             The functor may be passed by reference with <tt>boost:ref</tt>
488
489             RCU \p synchronize method can be called. RCU should not be locked.
490
491             Return \p true if key is found and deleted, \p false otherwise
492
493             See also: \ref erase
494         */
495         template <typename K, typename Func>
496         bool erase( K const& key, Func f )
497         {
498             return erase_at( head(), key, intrusive_key_comparator(), f );
499         }
500
501         /// Deletes the item from the list using \p pred predicate for searching
502         /**
503             The function is an analog of \ref cds_nonintrusive_MichaelKVList_rcu_erase_func "erase(K const&, Func)"
504             but \p pred is used for key comparing.
505             \p Less functor has the interface like \p std::less.
506             \p pred must imply the same element order as the comparator used for building the list.
507         */
508         template <typename K, typename Less, typename Func>
509         bool erase_with( K const& key, Less pred, Func f )
510         {
511             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
512         }
513
514         /// Extracts an item from the list
515         /**
516         @anchor cds_nonintrusive_MichaelKVList_rcu_extract
517             The function searches an item with key equal to \p key in the list,
518             unlinks it from the list, and returns pointer to an item found in \p dest argument.
519             If \p key is not found the function returns \p false.
520
521             @note The function does NOT call RCU read-side lock or synchronization,
522             and does NOT dispose the item found. It just excludes the item from the list
523             and returns a pointer to item found.
524             You should lock RCU before calling this function.
525
526             \code
527             #include <cds/urcu/general_buffered.h>
528             #include <cds/container/michael_kvlist_rcu.h>
529
530             typedef cds::urcu::gc< general_buffered<> > rcu;
531             typedef cds::container::MichaelKVList< rcu, int, Foo > rcu_michael_list;
532
533             rcu_michael_list theList;
534             // ...
535
536             rcu_michael_list::exempt_ptr p;
537             {
538                 // first, we should lock RCU
539                 rcu_michael_list::rcu_lock sl;
540
541                 // Now, you can apply extract function
542                 // Note that you must not delete the item found inside the RCU lock
543                 if ( theList.extract( p, 10 )) {
544                     // do something with p
545                     ...
546                 }
547             }
548             // Outside RCU lock section we may safely release extracted pointer.
549             // release() passes the pointer to RCU reclamation cycle.
550             p.release();
551             \endcode
552         */
553         template <typename K>
554         bool extract( exempt_ptr& dest, K const& key )
555         {
556             dest = extract_at( head(), key, intrusive_key_comparator() );
557             return !dest.empty();
558         }
559
560         /// Extracts an item from the list using \p pred predicate for searching
561         /**
562             This function is the analog for \ref cds_nonintrusive_MichaelKVList_rcu_extract "extract(exempt_ptr&, K const&)".
563             The \p pred is a predicate used for key comparing.
564             \p Less has the interface like \p std::less.
565             \p pred must imply the same element order as \ref key_comparator.
566         */
567         template <typename K, typename Less>
568         bool extract_with( exempt_ptr& dest, K const& key, Less pred )
569         {
570             dest = extract_at( head(), key, typename maker::template less_wrapper<Less>::type() );
571             return !dest.empty();
572         }
573
574         /// Finds the key \p key
575         /** \anchor cds_nonintrusive_MichaelKVList_rcu_find_val
576
577             The function searches the item with key equal to \p key
578             and returns \p true if it is found, and \p false otherwise
579
580             The function makes RCU lock internally.
581         */
582         template <typename Q>
583         bool find( Q const& key ) const
584         {
585             return find_at( head(), key, intrusive_key_comparator() );
586         }
587
588         /// Finds the key \p key using \p pred predicate for searching
589         /**
590             The function is an analog of \ref cds_nonintrusive_MichaelKVList_rcu_find_val "find(Q const&)"
591             but \p pred is used for key comparing.
592             \p Less functor has the interface like \p std::less.
593             \p pred must imply the same element order as the comparator used for building the list.
594         */
595         template <typename Q, typename Less>
596         bool find_with( Q const& key, Less pred ) const
597         {
598             return find_at( head(), key, typename maker::template less_wrapper<Less>::type() );
599         }
600
601         /// Finds \p key and performs an action with it
602         /** \anchor cds_nonintrusive_MichaelKVList_rcu_find_func
603             The function searches an item with key equal to \p key and calls the functor \p f for the item found.
604             The interface of \p Func functor is:
605             \code
606             struct functor {
607                 void operator()( value_type& item );
608             };
609             \endcode
610             where \p item is the item found.
611
612             The functor may change <tt>item.second</tt> that is reference to value of node.
613             Note that the function is only guarantee that \p item cannot be deleted during functor is executing.
614             The function does not serialize simultaneous access to the list \p item. If such access is
615             possible you must provide your own synchronization schema to exclude unsafe item modifications.
616
617             The function makes RCU lock internally.
618
619             The function returns \p true if \p key is found, \p false otherwise.
620         */
621         template <typename Q, typename Func>
622         bool find( Q const& key, Func f ) const
623         {
624             return find_at( head(), key, intrusive_key_comparator(), f );
625         }
626
627         /// Finds the key \p val using \p pred predicate for searching
628         /**
629             The function is an analog of \ref cds_nonintrusive_MichaelKVList_rcu_find_func "find(Q const&, Func)"
630             but \p pred is used for key comparing.
631             \p Less functor has the interface like \p std::less.
632             \p pred must imply the same element order as the comparator used for building the list.
633         */
634         template <typename Q, typename Less, typename Func>
635         bool find_with( Q const& key, Less pred, Func f ) const
636         {
637             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
638         }
639
640         /// Finds \p key and return the item found
641         /** \anchor cds_nonintrusive_MichaelKVList_rcu_get
642             The function searches the item with \p key and returns the pointer to item found.
643             If \p key is not found it returns \p nullptr.
644
645             Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
646
647             RCU should be locked before call of this function.
648             Returned item is valid only while RCU is locked:
649             \code
650             typedef cds::container::MichaelKVList< cds::urcu::gc< cds::urcu::general_buffered<> >, int, foo, my_traits > ord_list;
651             ord_list theList;
652             // ...
653             {
654                 // Lock RCU
655                 ord_list::rcu_lock lock;
656
657                 ord_list::value_type * pVal = theList.get( 5 );
658                 if ( pVal ) {
659                     // Deal with pVal
660                     //...
661                 }
662                 // Unlock RCU by rcu_lock destructor
663                 // pVal can be freed at any time after RCU has been unlocked
664             }
665             \endcode
666         */
667         template <typename K>
668         value_type * get( K const& key ) const
669         {
670             return get_at( head(), key, intrusive_key_comparator());
671         }
672
673         /// Finds \p key and return the item found
674         /**
675             The function is an analog of \ref cds_nonintrusive_MichaelKVList_rcu_get "get(K const&)"
676             but \p pred is used for comparing the keys.
677
678             \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
679             in any order.
680             \p pred must imply the same element order as the comparator used for building the list.
681         */
682         template <typename K, typename Less>
683         value_type * get_with( K const& key, Less pred ) const
684         {
685             return get_at( head(), key, typename maker::template less_wrapper<Less>::type() );
686         }
687
688         /// Checks if the list is empty
689         bool empty() const
690         {
691             return base_class::empty();
692         }
693
694         /// Returns list's item count
695         /**
696             The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
697             this function always returns 0.
698
699             @note Even if you use real item counter and it returns 0, this fact does not mean that the list
700             is empty. To check list emptyness use \p empty() method.
701         */
702         size_t size() const
703         {
704             return base_class::size();
705         }
706
707         /// Clears the list
708         /**
709             Post-condition: the list is empty
710         */
711         void clear()
712         {
713             base_class::clear();
714         }
715
716     protected:
717         //@cond
718         bool insert_node_at( head_type& refHead, node_type * pNode )
719         {
720             assert( pNode != nullptr );
721             scoped_node_ptr p( pNode );
722             if ( base_class::insert_at( refHead, *pNode )) {
723                 p.release();
724                 return true;
725             }
726             return false;
727         }
728
729         template <typename K>
730         bool insert_at( head_type& refHead, const K& key )
731         {
732             return insert_node_at( refHead, alloc_node( key ));
733         }
734
735         template <typename K, typename V>
736         bool insert_at( head_type& refHead, const K& key, const V& val )
737         {
738             return insert_node_at( refHead, alloc_node( key, val ));
739         }
740
741         template <typename K, typename Func>
742         bool insert_key_at( head_type& refHead, const K& key, Func f )
743         {
744             scoped_node_ptr pNode( alloc_node( key ));
745
746             if ( base_class::insert_at( refHead, *pNode, [&f](node_type& node){ f( node.m_Data ); })) {
747                 pNode.release();
748                 return true;
749             }
750             return false;
751         }
752
753         template <typename K, typename... Args>
754         bool emplace_at( head_type& refHead, K&& key, Args&&... args )
755         {
756             return insert_node_at( refHead, alloc_node( std::forward<K>(key), std::forward<Args>(args)... ));
757         }
758
759         template <typename K, typename Func>
760         std::pair<bool, bool> ensure_at( head_type& refHead, const K& key, Func f )
761         {
762             scoped_node_ptr pNode( alloc_node( key ));
763
764             std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode,
765                 [&f]( bool bNew, node_type& node, node_type& ){ f( bNew, node.m_Data ); });
766             if ( ret.first && ret.second )
767                 pNode.release();
768
769             return ret;
770         }
771
772         template <typename K, typename Compare>
773         bool erase_at( head_type& refHead, K const& key, Compare cmp )
774         {
775             return base_class::erase_at( refHead, key, cmp );
776         }
777
778         template <typename K, typename Compare, typename Func>
779         bool erase_at( head_type& refHead, K const& key, Compare cmp, Func f )
780         {
781             return base_class::erase_at( refHead, key, cmp, [&f]( node_type const & node ){ f( const_cast<value_type&>(node.m_Data)); });
782         }
783
784         template <typename K, typename Compare>
785         node_type * extract_at( head_type& refHead, K const& key, Compare cmp )
786         {
787             return base_class::extract_at( refHead, key, cmp );
788         }
789
790         template <typename K, typename Compare>
791         bool find_at( head_type& refHead, K const& key, Compare cmp ) const
792         {
793             return base_class::find_at( refHead, key, cmp, [](node_type&, K const&) {} );
794         }
795
796         template <typename K, typename Compare, typename Func>
797         bool find_at( head_type& refHead, K& key, Compare cmp, Func f ) const
798         {
799             return base_class::find_at( refHead, key, cmp, [&f](node_type& node, K const&){ f( node.m_Data ); });
800         }
801
802         template <typename K, typename Compare>
803         value_type * get_at( head_type& refHead, K const& val, Compare cmp ) const
804         {
805             node_type * pNode = base_class::get_at( refHead, val, cmp );
806             return pNode ? &pNode->m_Data : nullptr;
807         }
808
809         //@endcond
810     };
811
812 }}  // namespace cds::container
813
814 #endif  // #ifndef __CDS_CONTAINER_MICHAEL_KVLIST_RCU_H