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