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