3dc503f9b49568f17eea35bed40fdf969142f811
[libcds.git] / cds / container / impl / michael_list.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8     
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
29 */
30
31 #ifndef CDSLIB_CONTAINER_IMPL_MICHAEL_LIST_H
32 #define CDSLIB_CONTAINER_IMPL_MICHAEL_LIST_H
33
34 #include <memory>
35 #include <cds/container/details/guarded_ptr_cast.h>
36
37 namespace cds { namespace container {
38
39     /// Michael's ordered list
40     /** @ingroup cds_nonintrusive_list
41         \anchor cds_nonintrusive_MichaelList_gc
42
43         Usually, ordered single-linked list is used as a building block for the hash table implementation.
44         The complexity of searching is <tt>O(N)</tt>, where \p N is the item count in the list, not in the
45         hash table.
46
47         Source:
48         - [2002] Maged Michael "High performance dynamic lock-free hash tables and list-based sets"
49
50         This class is non-intrusive version of cds::intrusive::MichaelList class
51
52         Template arguments:
53         - \p GC - garbage collector used
54         - \p T - type stored in the list. The type must be default- and copy-constructible.
55         - \p Traits - type traits, default is \p michael_list::traits
56
57         Unlike standard container, this implementation does not divide type \p T into key and value part and
58         may be used as a main building block for hash set algorithms.
59         The key is a function (or a part) of type \p T, and this function is specified by <tt>Traits::compare</tt> functor
60         or <tt>Traits::less</tt> predicate
61
62         MichaelKVList is a key-value version of Michael's non-intrusive list that is closer to the C++ std library approach.
63
64         It is possible to declare option-based list with cds::container::michael_list::make_traits metafunction istead of \p Traits template
65         argument. For example, the following traits-based declaration of gc::HP Michael's list
66         \code
67         #include <cds/container/michael_list_hp.h>
68         // Declare comparator for the item
69         struct my_compare {
70             int operator ()( int i1, int i2 )
71             {
72                 return i1 - i2;
73             }
74         };
75
76         // Declare traits
77         struct my_traits: public cds::container::michael_list::traits
78         {
79             typedef my_compare compare;
80         };
81
82         // Declare traits-based list
83         typedef cds::container::MichaelList< cds::gc::HP, int, my_traits >     traits_based_list;
84         \endcode
85
86         is equivalent for the following option-based list
87         \code
88         #include <cds/container/michael_list_hp.h>
89
90         // my_compare is the same
91
92         // Declare option-based list
93         typedef cds::container::MichaelList< cds::gc::HP, int,
94             typename cds::container::michael_list::make_traits<
95                 cds::container::opt::compare< my_compare >     // item comparator option
96             >::type
97         >     option_based_list;
98         \endcode
99
100         \par Usage
101         There are different specializations of this template for each garbage collecting schema used.
102         You should include appropriate .h-file depending on GC you are using:
103         - for gc::HP: \code #include <cds/container/michael_list_hp.h> \endcode
104         - for gc::DHP: \code #include <cds/container/michael_list_dhp.h> \endcode
105         - for \ref cds_urcu_desc "RCU": \code #include <cds/container/michael_list_rcu.h> \endcode
106         - for gc::nogc: \code #include <cds/container/michael_list_nogc.h> \endcode
107     */
108     template <
109         typename GC,
110         typename T,
111 #ifdef CDS_DOXYGEN_INVOKED
112         typename Traits = michael_list::traits
113 #else
114         typename Traits
115 #endif
116     >
117     class MichaelList:
118 #ifdef CDS_DOXYGEN_INVOKED
119         protected intrusive::MichaelList< GC, T, Traits >
120 #else
121         protected details::make_michael_list< GC, T, Traits >::type
122 #endif
123     {
124         //@cond
125         typedef details::make_michael_list< GC, T, Traits > maker;
126         typedef typename maker::type base_class;
127         //@endcond
128
129     public:
130         typedef T value_type;   ///< Type of value stored in the list
131         typedef Traits traits;  ///< List traits
132
133         typedef typename base_class::gc             gc;             ///< Garbage collector used
134         typedef typename base_class::back_off       back_off;       ///< Back-off strategy used
135         typedef typename maker::allocator_type      allocator_type; ///< Allocator type used for allocate/deallocate the nodes
136         typedef typename base_class::item_counter   item_counter;   ///< Item counting policy used
137         typedef typename maker::key_comparator      key_comparator; ///< key comparison functor
138         typedef typename base_class::memory_model   memory_model;   ///< Memory ordering. See \p cds::opt::memory_model option
139
140         static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
141
142     protected:
143         //@cond
144         typedef typename base_class::value_type      node_type;
145         typedef typename maker::cxx_allocator        cxx_allocator;
146         typedef typename maker::node_deallocator     node_deallocator;
147         typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
148
149         typedef typename base_class::atomic_node_ptr head_type;
150         //@endcond
151
152     public:
153         /// Guarded pointer
154         typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
155
156     private:
157         //@cond
158         static value_type& node_to_value( node_type& n )
159         {
160             return n.m_Value;
161         }
162         static value_type const& node_to_value( node_type const& n )
163         {
164             return n.m_Value;
165         }
166         //@endcond
167
168     protected:
169         //@cond
170         template <typename Q>
171         static node_type * alloc_node( Q const& v )
172         {
173             return cxx_allocator().New( v );
174         }
175
176         template <typename... Args>
177         static node_type * alloc_node( Args&&... args )
178         {
179             return cxx_allocator().MoveNew( std::forward<Args>(args)... );
180         }
181
182         static void free_node( node_type * pNode )
183         {
184             cxx_allocator().Delete( pNode );
185         }
186
187         struct node_disposer {
188             void operator()( node_type * pNode )
189             {
190                 free_node( pNode );
191             }
192         };
193         typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
194
195         head_type& head()
196         {
197             return base_class::m_pHead;
198         }
199
200         head_type const& head() const
201         {
202             return base_class::m_pHead;
203         }
204         //@endcond
205
206     protected:
207         //@cond
208         template <bool IsConst>
209         class iterator_type: protected base_class::template iterator_type<IsConst>
210         {
211             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
212
213             iterator_type( head_type const& pNode )
214                 : iterator_base( pNode )
215             {}
216
217             friend class MichaelList;
218
219         public:
220             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
221             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
222
223             iterator_type()
224             {}
225
226             iterator_type( iterator_type const& src )
227                 : iterator_base( src )
228             {}
229
230             value_ptr operator ->() const
231             {
232                 typename iterator_base::value_ptr p = iterator_base::operator ->();
233                 return p ? &(p->m_Value) : nullptr;
234             }
235
236             value_ref operator *() const
237             {
238                 return (iterator_base::operator *()).m_Value;
239             }
240
241             /// Pre-increment
242             iterator_type& operator ++()
243             {
244                 iterator_base::operator ++();
245                 return *this;
246             }
247
248             template <bool C>
249             bool operator ==(iterator_type<C> const& i ) const
250             {
251                 return iterator_base::operator ==(i);
252             }
253             template <bool C>
254             bool operator !=(iterator_type<C> const& i ) const
255             {
256                 return iterator_base::operator !=(i);
257             }
258         };
259         //@endcond
260
261     public:
262     ///@name Forward iterators (only for debugging purpose)
263     //@{
264         /// Forward iterator
265         /**
266             The forward iterator for Michael's list has some features:
267             - it has no post-increment operator
268             - to protect the value, the iterator contains a GC-specific guard + another guard is required locally for increment operator.
269               For some GC (\p gc::HP), a guard is limited resource per thread, so an exception (or assertion) "no free guard"
270               may be thrown if a limit of guard count per thread is exceeded.
271             - The iterator cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
272             - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
273               deleting operations it is no guarantee that you iterate all item in the list.
274               Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
275
276             @warning Use this iterator on the concurrent container for debugging purpose only.
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         const_iterator begin() const
310         {
311             return const_iterator( head() );
312         }
313
314         /// Returns a forward const iterator addressing the first element in a list
315         const_iterator cbegin() const
316         {
317             return const_iterator( head() );
318         }
319
320         /// Returns an const iterator that addresses the location succeeding the last element in a list
321         const_iterator end() const
322         {
323             return const_iterator();
324         }
325
326         /// Returns an const iterator that addresses the location succeeding the last element in a list
327         const_iterator cend() const
328         {
329             return const_iterator();
330         }
331     //@}
332
333     public:
334         /// Default constructor
335         /**
336             Initialize empty list
337         */
338         MichaelList()
339         {}
340
341         /// List destructor
342         /**
343             Clears the list
344         */
345         ~MichaelList()
346         {
347             clear();
348         }
349
350         /// Inserts new node
351         /**
352             The function creates a node with copy of \p val value
353             and then inserts the node created into the list.
354
355             The type \p Q should contain least the complete key of the node.
356             The object of \ref value_type should be constructible from \p val of type \p Q.
357             In trivial case, \p Q is equal to \ref value_type.
358
359             Returns \p true if inserting successful, \p false otherwise.
360         */
361         template <typename Q>
362         bool insert( Q const& val )
363         {
364             return insert_at( head(), val );
365         }
366
367         /// Inserts new node
368         /**
369             This function inserts new node with default-constructed value and then it calls
370             \p func functor with signature
371             \code void func( value_type& itemValue ) ;\endcode
372
373             The argument \p itemValue of user-defined functor \p func is the reference
374             to the list's item inserted. User-defined functor \p func should guarantee that during changing
375             item's value no any other changes could be made on this list's item by concurrent threads.
376             The user-defined functor is called only if inserting is success.
377
378             The type \p Q should contain the complete key of the node.
379             The object of \p value_type should be constructible from \p key of type \p Q.
380
381             The function allows to split creating of new item into two part:
382             - create item from \p key with initializing key-fields only;
383             - insert new item into the list;
384             - if inserting is successful, initialize non-key fields of item by calling \p func functor
385
386             The method can be useful if complete initialization of object of \p value_type is heavyweight and
387             it is preferable that the initialization should be completed only if inserting is successful.
388
389             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
390         */
391         template <typename Q, typename Func>
392         bool insert( Q const& key, Func func )
393         {
394             return insert_at( head(), key, func );
395         }
396
397         /// Updates data by \p key
398         /**
399             The operation performs inserting or replacing the element with lock-free manner.
400
401             If the \p key not found in the list, then the new item created from \p key
402             will be inserted iff \p bAllowInsert is \p true.
403             Otherwise, if \p key is found, the functor \p func is called with item found.
404
405             The functor \p Func signature is:
406             \code
407                 struct my_functor {
408                     void operator()( bool bNew, value_type& item, Q const& val );
409                 };
410             \endcode
411
412             with arguments:
413             - \p bNew - \p true if the item has been inserted, \p false otherwise
414             - \p item - item of the list
415             - \p val - argument \p key passed into the \p %update() function
416
417             The functor may change non-key fields of the \p item; however, \p func must guarantee
418             that during changing no any other modifications could be made on this item by concurrent threads.
419
420             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
421             \p second is true if new item has been added or \p false if the item with \p key
422             already exists.
423
424             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
425         */
426         template <typename Q, typename Func>
427         std::pair<bool, bool> update( Q const& key, Func func, bool bAllowInsert = true )
428         {
429             return update_at( head(), key, func, bAllowInsert );
430         }
431         //@cond
432         template <typename Q, typename Func>
433         CDS_DEPRECATED("ensure() is deprecated, use update()")
434         std::pair<bool, bool> ensure( Q const& key, Func func )
435         {
436             return update( key, func );
437         }
438         //@endcond
439
440         /// Inserts data of type \p value_type constructed with <tt>std::forward<Args>(args)...</tt>
441         /**
442             Returns \p true if inserting successful, \p false otherwise.
443         */
444         template <typename... Args>
445         bool emplace( Args&&... args )
446         {
447             return emplace_at( head(), std::forward<Args>(args)... );
448         }
449
450         /// Delete \p key from the list
451         /** \anchor cds_nonintrusive_MichealList_hp_erase_val
452             Since the key of MichaelList's item type \p value_type is not explicitly specified,
453             template parameter \p Q sould contain the complete key to search in the list.
454             The list item comparator should be able to compare the type \p value_type
455             and the type \p Q.
456
457             Return \p true if key is found and deleted, \p false otherwise
458         */
459         template <typename Q>
460         bool erase( Q const& key )
461         {
462             return erase_at( head(), key, intrusive_key_comparator(), [](value_type const&){} );
463         }
464
465         /// Deletes the item from the list using \p pred predicate for searching
466         /**
467             The function is an analog of \ref cds_nonintrusive_MichealList_hp_erase_val "erase(Q const&)"
468             but \p pred is used for key comparing.
469             \p Less functor has the interface like \p std::less.
470             \p pred must imply the same element order as the comparator used for building the list.
471         */
472         template <typename Q, typename Less>
473         bool erase_with( Q const& key, Less pred )
474         {
475             CDS_UNUSED( pred );
476             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), [](value_type const&){} );
477         }
478
479         /// Deletes \p key from the list
480         /** \anchor cds_nonintrusive_MichaelList_hp_erase_func
481             The function searches an item with key \p key, calls \p f functor with item found
482             and deletes it. If \p key is not found, the functor is not called.
483
484             The functor \p Func interface:
485             \code
486             struct extractor {
487                 void operator()(const value_type& val) { ... }
488             };
489             \endcode
490
491             Since the key of MichaelList's item type \p value_type is not explicitly specified,
492             template parameter \p Q should contain the complete key to search in the list.
493             The list item comparator should be able to compare the type \p value_type of list item
494             and the type \p Q.
495
496             Return \p true if key is found and deleted, \p false otherwise
497         */
498         template <typename Q, typename Func>
499         bool erase( Q const& key, Func f )
500         {
501             return erase_at( head(), key, intrusive_key_comparator(), f );
502         }
503
504         /// Deletes the item from the list using \p pred predicate for searching
505         /**
506             The function is an analog of \ref cds_nonintrusive_MichaelList_hp_erase_func "erase(Q const&, Func)"
507             but \p pred is used for key comparing.
508             \p Less functor has the interface like \p std::less.
509             \p pred must imply the same element order as the comparator used for building the list.
510         */
511         template <typename Q, typename Less, typename Func>
512         bool erase_with( Q const& key, Less pred, Func f )
513         {
514             CDS_UNUSED( pred );
515             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
516         }
517
518         /// Extracts the item from the list with specified \p key
519         /** \anchor cds_nonintrusive_MichaelList_hp_extract
520             The function searches an item with key equal to \p key,
521             unlinks it from the list, and returns it as \p guarded_ptr.
522             If \p key is not found the function returns an empty guarded pointer.
523
524             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
525
526             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
527
528             Usage:
529             \code
530             typedef cds::container::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
531             ord_list theList;
532             // ...
533             {
534                 ord_list::guarded_ptr gp(theList.extract( 5 ));
535                 if ( gp ) {
536                     // Deal with gp
537                     // ...
538                 }
539                 // Destructor of gp releases internal HP guard and frees the item
540             }
541             \endcode
542         */
543         template <typename Q>
544         guarded_ptr extract( Q const& key )
545         {
546             guarded_ptr gp;
547             extract_at( head(), gp.guard(), key, intrusive_key_comparator() );
548             return gp;
549         }
550
551         /// Extracts the item from the list with comparing functor \p pred
552         /**
553             The function is an analog of \ref cds_nonintrusive_MichaelList_hp_extract "extract(Q const&)"
554             but \p pred predicate is used for key comparing.
555
556             \p Less functor has the semantics like \p std::less but it should accept arguments of type \p value_type and \p Q
557             in any order.
558             \p pred must imply the same element order as the comparator used for building the list.
559         */
560         template <typename Q, typename Less>
561         guarded_ptr extract_with( Q const& key, Less pred )
562         {
563             CDS_UNUSED( pred );
564             guarded_ptr gp;
565             extract_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
566             return gp;
567         }
568
569         /// Checks whether the list contains \p key
570         /**
571             The function searches the item with key equal to \p key
572             and returns \p true if it is found, and \p false otherwise.
573         */
574         template <typename Q>
575         bool contains( Q const& key )
576         {
577             return find_at( head(), key, intrusive_key_comparator() );
578         }
579         //@cond
580         template <typename Q>
581         CDS_DEPRECATED("deprecated, use contains()")
582         bool find( Q const& key )
583         {
584             return contains( key );
585         }
586         //@endcond
587
588         /// Checks whether the list contains \p key using \p pred predicate for searching
589         /**
590             The function is an analog of <tt>contains( key )</tt> 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 contains( Q const& key, Less pred )
596         {
597             CDS_UNUSED( pred );
598             return find_at( head(), key, typename maker::template less_wrapper<Less>::type() );
599         }
600         //@cond
601         template <typename Q, typename Less>
602         CDS_DEPRECATED("deprecated, use contains()")
603         bool find_with( Q const& key, Less pred )
604         {
605             return contains( key, pred );
606         }
607         //@endcond
608
609         /// Finds \p key and perform an action with it
610         /** \anchor cds_nonintrusive_MichaelList_hp_find_func
611             The function searches an item with key equal to \p key and calls the functor \p f for the item found.
612             The interface of \p Func functor is:
613             \code
614             struct functor {
615                 void operator()( value_type& item, Q& key );
616             };
617             \endcode
618             where \p item is the item found, \p key is the <tt>find</tt> function argument.
619
620             The functor may change non-key fields of \p item. Note that the function is only guarantee
621             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& key, Func f )
629         {
630             return find_at( head(), key, intrusive_key_comparator(), f );
631         }
632         //@cond
633         template <typename Q, typename Func>
634         bool find( Q const& key, Func f )
635         {
636             return find_at( head(), key, intrusive_key_comparator(), f );
637         }
638         //@endcond
639
640         /// Finds \p key using \p pred predicate for searching
641         /**
642             The function is an analog of \ref cds_nonintrusive_MichaelList_hp_find_func "find(Q&, Func)"
643             but \p pred is used for key comparing.
644             \p Less functor has the interface like \p std::less.
645             \p pred must imply the same element order as the comparator used for building the list.
646         */
647         template <typename Q, typename Less, typename Func>
648         bool find_with( Q& key, Less pred, Func f )
649         {
650             CDS_UNUSED( pred );
651             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
652         }
653         //@cond
654         template <typename Q, typename Less, typename Func>
655         bool find_with( Q const& key, Less pred, Func f )
656         {
657             CDS_UNUSED( pred );
658             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
659         }
660         //@endcond
661
662         /// Finds \p key and return the item found
663         /** \anchor cds_nonintrusive_MichaelList_hp_get
664             The function searches the item with key equal to \p key
665             and returns it as \p guarded_ptr.
666             If \p key is not found the function returns an empty guarded pointer.
667
668             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
669
670             Usage:
671             \code
672             typedef cds::container::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
673             ord_list theList;
674             // ...
675             {
676                 ord_list::guarded_ptr gp(theList.get( 5 ));
677                 if ( gp ) {
678                     // Deal with gp
679                     //...
680                 }
681                 // Destructor of guarded_ptr releases internal HP guard and frees the item
682             }
683             \endcode
684
685             Note the compare functor specified for class \p Traits template parameter
686             should accept a parameter of type \p Q that can be not the same as \p value_type.
687         */
688         template <typename Q>
689         guarded_ptr get( Q const& key )
690         {
691             guarded_ptr gp;
692             get_at( head(), gp.guard(), key, intrusive_key_comparator() );
693             return gp;
694         }
695
696         /// Finds \p key and return the item found
697         /**
698             The function is an analog of \ref cds_nonintrusive_MichaelList_hp_get "get( Q const&)"
699             but \p pred is used for comparing the keys.
700
701             \p Less functor has the semantics like \p std::less but should accept arguments of type \p value_type and \p Q
702             in any order.
703             \p pred must imply the same element order as the comparator used for building the list.
704         */
705         template <typename Q, typename Less>
706         guarded_ptr get_with( Q const& key, Less pred )
707         {
708             CDS_UNUSED( pred );
709             guarded_ptr gp;
710             get_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
711             return gp;
712         }
713
714         /// Check if the list is empty
715         bool empty() const
716         {
717             return base_class::empty();
718         }
719
720         /// Returns list's item count
721         /**
722             The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
723             this function always returns 0.
724
725             @note Even if you use real item counter and it returns 0, this fact is not mean that the list
726             is empty. To check list emptyness use \p empty() method.
727         */
728         size_t size() const
729         {
730             return base_class::size();
731         }
732
733         /// Clears the list
734         void clear()
735         {
736             base_class::clear();
737         }
738
739     protected:
740         //@cond
741         bool insert_node_at( head_type& refHead, node_type * pNode )
742         {
743             assert( pNode );
744             scoped_node_ptr p(pNode);
745             if ( base_class::insert_at( refHead, *pNode )) {
746                 p.release();
747                 return true;
748             }
749
750             return false;
751         }
752
753         template <typename Q>
754         bool insert_at( head_type& refHead, Q const& val )
755         {
756             return insert_node_at( refHead, alloc_node( val ));
757         }
758
759         template <typename Q, typename Func>
760         bool insert_at( head_type& refHead, Q const& key, Func f )
761         {
762             scoped_node_ptr pNode( alloc_node( key ));
763
764             if ( base_class::insert_at( refHead, *pNode, [&f]( node_type& node ) { f( node_to_value(node) ); } )) {
765                 pNode.release();
766                 return true;
767             }
768             return false;
769         }
770
771         template <typename... Args>
772         bool emplace_at( head_type& refHead, Args&&... args )
773         {
774             return insert_node_at( refHead, alloc_node( std::forward<Args>(args) ... ));
775         }
776
777         template <typename Q, typename Compare, typename Func>
778         bool erase_at( head_type& refHead, Q const& key, Compare cmp, Func f )
779         {
780             return base_class::erase_at( refHead, key, cmp, [&f](node_type const& node){ f( node_to_value(node) ); } );
781         }
782
783         template <typename Q, typename Compare>
784         bool extract_at( head_type& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp )
785         {
786             return base_class::extract_at( refHead, guard, key, cmp );
787         }
788
789         template <typename Q, typename Func>
790         std::pair<bool, bool> update_at( head_type& refHead, Q const& key, Func f, bool bAllowInsert )
791         {
792             scoped_node_ptr pNode( alloc_node( key ));
793
794             std::pair<bool, bool> ret = base_class::update_at( refHead, *pNode,
795                 [&f, &key](bool bNew, node_type& node, node_type&){ f( bNew, node_to_value(node), key );},
796                 bAllowInsert );
797             if ( ret.first && ret.second )
798                 pNode.release();
799
800             return ret;
801         }
802
803         template <typename Q, typename Compare>
804         bool find_at( head_type& refHead, Q const& key, Compare cmp )
805         {
806             return base_class::find_at( refHead, key, cmp );
807         }
808
809         template <typename Q, typename Compare, typename Func>
810         bool find_at( head_type& refHead, Q& val, Compare cmp, Func f )
811         {
812             return base_class::find_at( refHead, val, cmp, [&f](node_type& node, Q& v){ f( node_to_value(node), v ); });
813         }
814
815         template <typename Q, typename Compare>
816         bool get_at( head_type& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp )
817         {
818             return base_class::get_at( refHead, guard, key, cmp );
819         }
820
821         //@endcond
822     };
823
824 }}  // namespace cds::container
825
826 #endif  // #ifndef CDSLIB_CONTAINER_IMPL_MICHAEL_LIST_H