514dbfd8c348f79c135b58e0070844208d802cc0
[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     protected:
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
167         template <typename Q>
168         static node_type * alloc_node( Q const& v )
169         {
170             return cxx_allocator().New( v );
171         }
172
173         template <typename... Args>
174         static node_type * alloc_node( Args&&... args )
175         {
176             return cxx_allocator().MoveNew( std::forward<Args>(args)... );
177         }
178
179         static void free_node( node_type * pNode )
180         {
181             cxx_allocator().Delete( pNode );
182         }
183
184         struct node_disposer {
185             void operator()( node_type * pNode )
186             {
187                 free_node( pNode );
188             }
189         };
190         typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
191
192         head_type& head()
193         {
194             return base_class::m_pHead;
195         }
196
197         head_type const& head() const
198         {
199             return base_class::m_pHead;
200         }
201         //@endcond
202
203     protected:
204         //@cond
205         template <bool IsConst>
206         class iterator_type: protected base_class::template iterator_type<IsConst>
207         {
208             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
209
210             iterator_type( head_type const& pNode )
211                 : iterator_base( pNode )
212             {}
213
214             friend class MichaelList;
215
216         public:
217             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
218             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
219
220             iterator_type()
221             {}
222
223             iterator_type( iterator_type const& src )
224                 : iterator_base( src )
225             {}
226
227             value_ptr operator ->() const
228             {
229                 typename iterator_base::value_ptr p = iterator_base::operator ->();
230                 return p ? &(p->m_Value) : nullptr;
231             }
232
233             value_ref operator *() const
234             {
235                 return (iterator_base::operator *()).m_Value;
236             }
237
238             /// Pre-increment
239             iterator_type& operator ++()
240             {
241                 iterator_base::operator ++();
242                 return *this;
243             }
244
245             template <bool C>
246             bool operator ==(iterator_type<C> const& i ) const
247             {
248                 return iterator_base::operator ==(i);
249             }
250             template <bool C>
251             bool operator !=(iterator_type<C> const& i ) const
252             {
253                 return iterator_base::operator !=(i);
254             }
255         };
256         //@endcond
257
258     public:
259     ///@name Forward iterators (only for debugging purpose)
260     //@{
261         /// Forward iterator
262         /**
263             The forward iterator for Michael's list has some features:
264             - it has no post-increment operator
265             - to protect the value, the iterator contains a GC-specific guard + another guard is required locally for increment operator.
266               For some GC (\p gc::HP), a guard is limited resource per thread, so an exception (or assertion) "no free guard"
267               may be thrown if a limit of guard count per thread is exceeded.
268             - The iterator cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
269             - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
270               deleting operations it is no guarantee that you iterate all item in the list.
271               Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
272
273             @warning Use this iterator on the concurrent container for debugging purpose only.
274         */
275         typedef iterator_type<false>    iterator;
276
277         /// Const forward iterator
278         /**
279             For iterator's features and requirements see \ref iterator
280         */
281         typedef iterator_type<true>     const_iterator;
282
283         /// Returns a forward iterator addressing the first element in a list
284         /**
285             For empty list \code begin() == end() \endcode
286         */
287         iterator begin()
288         {
289             return iterator( head() );
290         }
291
292         /// Returns an iterator that addresses the location succeeding the last element in a list
293         /**
294             Do not use the value returned by <tt>end</tt> function to access any item.
295             Internally, <tt>end</tt> returning value equals to \p nullptr.
296
297             The returned value can be used only to control reaching the end of the list.
298             For empty list \code begin() == end() \endcode
299         */
300         iterator end()
301         {
302             return iterator();
303         }
304
305         /// Returns a forward const iterator addressing the first element in a list
306         const_iterator begin() const
307         {
308             return const_iterator( head() );
309         }
310
311         /// Returns a forward const iterator addressing the first element in a list
312         const_iterator cbegin() const
313         {
314             return const_iterator( head() );
315         }
316
317         /// Returns an const iterator that addresses the location succeeding the last element in a list
318         const_iterator end() const
319         {
320             return const_iterator();
321         }
322
323         /// Returns an const iterator that addresses the location succeeding the last element in a list
324         const_iterator cend() const
325         {
326             return const_iterator();
327         }
328     //@}
329
330     public:
331         /// Default constructor
332         /**
333             Initialize empty list
334         */
335         MichaelList()
336         {}
337
338         /// List destructor
339         /**
340             Clears the list
341         */
342         ~MichaelList()
343         {
344             clear();
345         }
346
347         /// Inserts new node
348         /**
349             The function creates a node with copy of \p val value
350             and then inserts the node created into the list.
351
352             The type \p Q should contain least the complete key of the node.
353             The object of \ref value_type should be constructible from \p val of type \p Q.
354             In trivial case, \p Q is equal to \ref value_type.
355
356             Returns \p true if inserting successful, \p false otherwise.
357         */
358         template <typename Q>
359         bool insert( Q const& val )
360         {
361             return insert_at( head(), val );
362         }
363
364         /// Inserts new node
365         /**
366             This function inserts new node with default-constructed value and then it calls
367             \p func functor with signature
368             \code void func( value_type& itemValue ) ;\endcode
369
370             The argument \p itemValue of user-defined functor \p func is the reference
371             to the list's item inserted. User-defined functor \p func should guarantee that during changing
372             item's value no any other changes could be made on this list's item by concurrent threads.
373             The user-defined functor is called only if inserting is success.
374
375             The type \p Q should contain the complete key of the node.
376             The object of \p value_type should be constructible from \p key of type \p Q.
377
378             The function allows to split creating of new item into two part:
379             - create item from \p key with initializing key-fields only;
380             - insert new item into the list;
381             - if inserting is successful, initialize non-key fields of item by calling \p func functor
382
383             The method can be useful if complete initialization of object of \p value_type is heavyweight and
384             it is preferable that the initialization should be completed only if inserting is successful.
385
386             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
387         */
388         template <typename Q, typename Func>
389         bool insert( Q const& key, Func func )
390         {
391             return insert_at( head(), key, func );
392         }
393
394         /// Updates data by \p key
395         /**
396             The operation performs inserting or replacing the element with lock-free manner.
397
398             If the \p key not found in the list, then the new item created from \p key
399             will be inserted iff \p bAllowInsert is \p true.
400             Otherwise, if \p key is found, the functor \p func is called with item found.
401
402             The functor \p Func signature is:
403             \code
404                 struct my_functor {
405                     void operator()( bool bNew, value_type& item, Q const& val );
406                 };
407             \endcode
408
409             with arguments:
410             - \p bNew - \p true if the item has been inserted, \p false otherwise
411             - \p item - item of the list
412             - \p val - argument \p key passed into the \p %update() function
413
414             The functor may change non-key fields of the \p item; however, \p func must guarantee
415             that during changing no any other modifications could be made on this item by concurrent threads.
416
417             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
418             \p second is true if new item has been added or \p false if the item with \p key
419             already exists.
420
421             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
422         */
423         template <typename Q, typename Func>
424         std::pair<bool, bool> update( Q const& key, Func func, bool bAllowInsert = true )
425         {
426             return update_at( head(), key, func, bAllowInsert );
427         }
428         //@cond
429         template <typename Q, typename Func>
430         CDS_DEPRECATED("ensure() is deprecated, use update()")
431         std::pair<bool, bool> ensure( Q const& key, Func func )
432         {
433             return update( key, func );
434         }
435         //@endcond
436
437         /// Inserts data of type \p value_type constructed with <tt>std::forward<Args>(args)...</tt>
438         /**
439             Returns \p true if inserting successful, \p false otherwise.
440         */
441         template <typename... Args>
442         bool emplace( Args&&... args )
443         {
444             return emplace_at( head(), std::forward<Args>(args)... );
445         }
446
447         /// Delete \p key from the list
448         /** \anchor cds_nonintrusive_MichealList_hp_erase_val
449             Since the key of MichaelList's item type \p value_type is not explicitly specified,
450             template parameter \p Q sould contain the complete key to search in the list.
451             The list item comparator should be able to compare the type \p value_type
452             and the type \p Q.
453
454             Return \p true if key is found and deleted, \p false otherwise
455         */
456         template <typename Q>
457         bool erase( Q const& key )
458         {
459             return erase_at( head(), key, intrusive_key_comparator(), [](value_type const&){} );
460         }
461
462         /// Deletes the item from the list using \p pred predicate for searching
463         /**
464             The function is an analog of \ref cds_nonintrusive_MichealList_hp_erase_val "erase(Q const&)"
465             but \p pred is used for key comparing.
466             \p Less functor has the interface like \p std::less.
467             \p pred must imply the same element order as the comparator used for building the list.
468         */
469         template <typename Q, typename Less>
470         bool erase_with( Q const& key, Less pred )
471         {
472             CDS_UNUSED( pred );
473             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), [](value_type const&){} );
474         }
475
476         /// Deletes \p key from the list
477         /** \anchor cds_nonintrusive_MichaelList_hp_erase_func
478             The function searches an item with key \p key, calls \p f functor with item found
479             and deletes it. If \p key is not found, the functor is not called.
480
481             The functor \p Func interface:
482             \code
483             struct extractor {
484                 void operator()(const value_type& val) { ... }
485             };
486             \endcode
487
488             Since the key of MichaelList's item type \p value_type is not explicitly specified,
489             template parameter \p Q should contain the complete key to search in the list.
490             The list item comparator should be able to compare the type \p value_type of list item
491             and the type \p Q.
492
493             Return \p true if key is found and deleted, \p false otherwise
494         */
495         template <typename Q, typename Func>
496         bool erase( Q const& key, Func f )
497         {
498             return erase_at( head(), key, intrusive_key_comparator(), f );
499         }
500
501         /// Deletes the item from the list using \p pred predicate for searching
502         /**
503             The function is an analog of \ref cds_nonintrusive_MichaelList_hp_erase_func "erase(Q const&, Func)"
504             but \p pred is used for key comparing.
505             \p Less functor has the interface like \p std::less.
506             \p pred must imply the same element order as the comparator used for building the list.
507         */
508         template <typename Q, typename Less, typename Func>
509         bool erase_with( Q const& key, Less pred, Func f )
510         {
511             CDS_UNUSED( pred );
512             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
513         }
514
515         /// Extracts the item from the list with specified \p key
516         /** \anchor cds_nonintrusive_MichaelList_hp_extract
517             The function searches an item with key equal to \p key,
518             unlinks it from the list, and returns it as \p guarded_ptr.
519             If \p key is not found the function returns an empty guarded pointer.
520
521             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
522
523             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
524
525             Usage:
526             \code
527             typedef cds::container::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
528             ord_list theList;
529             // ...
530             {
531                 ord_list::guarded_ptr gp(theList.extract( 5 ));
532                 if ( gp ) {
533                     // Deal with gp
534                     // ...
535                 }
536                 // Destructor of gp releases internal HP guard and frees the item
537             }
538             \endcode
539         */
540         template <typename Q>
541         guarded_ptr extract( Q const& key )
542         {
543             guarded_ptr gp;
544             extract_at( head(), gp.guard(), key, intrusive_key_comparator() );
545             return gp;
546         }
547
548         /// Extracts the item from the list with comparing functor \p pred
549         /**
550             The function is an analog of \ref cds_nonintrusive_MichaelList_hp_extract "extract(Q const&)"
551             but \p pred predicate is used for key comparing.
552
553             \p Less functor has the semantics like \p std::less but it should accept arguments of type \p value_type and \p Q
554             in any order.
555             \p pred must imply the same element order as the comparator used for building the list.
556         */
557         template <typename Q, typename Less>
558         guarded_ptr extract_with( Q const& key, Less pred )
559         {
560             CDS_UNUSED( pred );
561             guarded_ptr gp;
562             extract_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
563             return gp;
564         }
565
566         /// Checks whether the list contains \p key
567         /**
568             The function searches the item with key equal to \p key
569             and returns \p true if it is found, and \p false otherwise.
570         */
571         template <typename Q>
572         bool contains( Q const& key )
573         {
574             return find_at( head(), key, intrusive_key_comparator() );
575         }
576         //@cond
577         template <typename Q>
578         CDS_DEPRECATED("deprecated, use contains()")
579         bool find( Q const& key )
580         {
581             return contains( key );
582         }
583         //@endcond
584
585         /// Checks whether the list contains \p key using \p pred predicate for searching
586         /**
587             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
588             \p Less functor has the interface like \p std::less.
589             \p pred must imply the same element order as the comparator used for building the list.
590         */
591         template <typename Q, typename Less>
592         bool contains( Q const& key, Less pred )
593         {
594             CDS_UNUSED( pred );
595             return find_at( head(), key, typename maker::template less_wrapper<Less>::type() );
596         }
597         //@cond
598         template <typename Q, typename Less>
599         CDS_DEPRECATED("deprecated, use contains()")
600         bool find_with( Q const& key, Less pred )
601         {
602             return contains( key, pred );
603         }
604         //@endcond
605
606         /// Finds \p key and perform an action with it
607         /** \anchor cds_nonintrusive_MichaelList_hp_find_func
608             The function searches an item with key equal to \p key and calls the functor \p f for the item found.
609             The interface of \p Func functor is:
610             \code
611             struct functor {
612                 void operator()( value_type& item, Q& key );
613             };
614             \endcode
615             where \p item is the item found, \p key is the <tt>find</tt> function argument.
616
617             The functor may change non-key fields of \p item. Note that the function is only guarantee
618             that \p item cannot be deleted during functor is executing.
619             The function does not serialize simultaneous access to the list \p item. If such access is
620             possible you must provide your own synchronization schema to exclude unsafe item modifications.
621
622             The function returns \p true if \p key is found, \p false otherwise.
623         */
624         template <typename Q, typename Func>
625         bool find( Q& key, Func f )
626         {
627             return find_at( head(), key, intrusive_key_comparator(), f );
628         }
629         //@cond
630         template <typename Q, typename Func>
631         bool find( Q const& key, Func f )
632         {
633             return find_at( head(), key, intrusive_key_comparator(), f );
634         }
635         //@endcond
636
637         /// Finds \p key using \p pred predicate for searching
638         /**
639             The function is an analog of \ref cds_nonintrusive_MichaelList_hp_find_func "find(Q&, Func)"
640             but \p pred is used for key comparing.
641             \p Less functor has the interface like \p std::less.
642             \p pred must imply the same element order as the comparator used for building the list.
643         */
644         template <typename Q, typename Less, typename Func>
645         bool find_with( Q& key, Less pred, Func f )
646         {
647             CDS_UNUSED( pred );
648             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
649         }
650         //@cond
651         template <typename Q, typename Less, typename Func>
652         bool find_with( Q const& key, Less pred, Func f )
653         {
654             CDS_UNUSED( pred );
655             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
656         }
657         //@endcond
658
659         /// Finds \p key and return the item found
660         /** \anchor cds_nonintrusive_MichaelList_hp_get
661             The function searches the item with key equal to \p key
662             and returns it as \p guarded_ptr.
663             If \p key is not found the function returns an empty guarded pointer.
664
665             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
666
667             Usage:
668             \code
669             typedef cds::container::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
670             ord_list theList;
671             // ...
672             {
673                 ord_list::guarded_ptr gp(theList.get( 5 ));
674                 if ( gp ) {
675                     // Deal with gp
676                     //...
677                 }
678                 // Destructor of guarded_ptr releases internal HP guard and frees the item
679             }
680             \endcode
681
682             Note the compare functor specified for class \p Traits template parameter
683             should accept a parameter of type \p Q that can be not the same as \p value_type.
684         */
685         template <typename Q>
686         guarded_ptr get( Q const& key )
687         {
688             guarded_ptr gp;
689             get_at( head(), gp.guard(), key, intrusive_key_comparator() );
690             return gp;
691         }
692
693         /// Finds \p key and return the item found
694         /**
695             The function is an analog of \ref cds_nonintrusive_MichaelList_hp_get "get( Q const&)"
696             but \p pred is used for comparing the keys.
697
698             \p Less functor has the semantics like \p std::less but should accept arguments of type \p value_type and \p Q
699             in any order.
700             \p pred must imply the same element order as the comparator used for building the list.
701         */
702         template <typename Q, typename Less>
703         guarded_ptr get_with( Q const& key, Less pred )
704         {
705             CDS_UNUSED( pred );
706             guarded_ptr gp;
707             get_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
708             return gp;
709         }
710
711         /// Check if the list is empty
712         bool empty() const
713         {
714             return base_class::empty();
715         }
716
717         /// Returns list's item count
718         /**
719             The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
720             this function always returns 0.
721
722             @note Even if you use real item counter and it returns 0, this fact is not mean that the list
723             is empty. To check list emptyness use \p empty() method.
724         */
725         size_t size() const
726         {
727             return base_class::size();
728         }
729
730         /// Clears the list
731         void clear()
732         {
733             base_class::clear();
734         }
735
736     protected:
737         //@cond
738         bool insert_node( node_type * pNode )
739         {
740             return insert_node_at( head(), pNode );
741         }
742
743         bool insert_node_at( head_type& refHead, node_type * pNode )
744         {
745             assert( pNode );
746             scoped_node_ptr p(pNode);
747             if ( base_class::insert_at( refHead, *pNode )) {
748                 p.release();
749                 return true;
750             }
751
752             return false;
753         }
754
755         template <typename Q>
756         bool insert_at( head_type& refHead, Q const& val )
757         {
758             return insert_node_at( refHead, alloc_node( val ));
759         }
760
761         template <typename Q, typename Func>
762         bool insert_at( head_type& refHead, Q const& key, Func f )
763         {
764             scoped_node_ptr pNode( alloc_node( key ));
765
766             if ( base_class::insert_at( refHead, *pNode, [&f]( node_type& node ) { f( node_to_value(node) ); } )) {
767                 pNode.release();
768                 return true;
769             }
770             return false;
771         }
772
773         template <typename... Args>
774         bool emplace_at( head_type& refHead, Args&&... args )
775         {
776             return insert_node_at( refHead, alloc_node( std::forward<Args>(args) ... ));
777         }
778
779         template <typename Q, typename Compare, typename Func>
780         bool erase_at( head_type& refHead, Q const& key, Compare cmp, Func f )
781         {
782             return base_class::erase_at( refHead, key, cmp, [&f](node_type const& node){ f( node_to_value(node) ); } );
783         }
784
785         template <typename Q, typename Compare>
786         bool extract_at( head_type& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp )
787         {
788             return base_class::extract_at( refHead, guard, key, cmp );
789         }
790
791         template <typename Q, typename Func>
792         std::pair<bool, bool> update_at( head_type& refHead, Q const& key, Func f, bool bAllowInsert )
793         {
794             scoped_node_ptr pNode( alloc_node( key ));
795
796             std::pair<bool, bool> ret = base_class::update_at( refHead, *pNode,
797                 [&f, &key](bool bNew, node_type& node, node_type&){ f( bNew, node_to_value(node), key );},
798                 bAllowInsert );
799             if ( ret.first && ret.second )
800                 pNode.release();
801
802             return ret;
803         }
804
805         template <typename Q, typename Compare>
806         bool find_at( head_type& refHead, Q const& key, Compare cmp )
807         {
808             return base_class::find_at( refHead, key, cmp );
809         }
810
811         template <typename Q, typename Compare, typename Func>
812         bool find_at( head_type& refHead, Q& val, Compare cmp, Func f )
813         {
814             return base_class::find_at( refHead, val, cmp, [&f](node_type& node, Q& v){ f( node_to_value(node), v ); });
815         }
816
817         template <typename Q, typename Compare>
818         bool get_at( head_type& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp )
819         {
820             return base_class::get_at( refHead, guard, key, cmp );
821         }
822
823         //@endcond
824     };
825
826 }}  // namespace cds::container
827
828 #endif  // #ifndef CDSLIB_CONTAINER_IMPL_MICHAEL_LIST_H