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