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