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