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