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