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