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