6d8ba10286a6ab4f33a60860376bef53f3bb4796
[libcds.git] / cds / container / michael_list_rcu.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_CONTAINER_MICHAEL_LIST_RCU_H
4 #define __CDS_CONTAINER_MICHAEL_LIST_RCU_H
5
6 #include <memory>
7 #include <cds/container/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::type_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 type_traits
57         struct my_traits: public cds::container::michael_list::type_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::type_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 > options;
110         typedef typename options::type  base_class;
111         //@endcond
112
113     public:
114         typedef T                                   value_type      ;   ///< Type of value stored in the list
115         typedef typename base_class::gc             gc              ;   ///< RCU schema used
116         typedef typename base_class::back_off       back_off        ;   ///< Back-off strategy used
117         typedef typename options::allocator_type    allocator_type  ;   ///< Allocator type used for allocate/deallocate the nodes
118         typedef typename base_class::item_counter   item_counter    ;   ///< Item counting policy used
119         typedef typename options::key_comparator    key_comparator  ;   ///< key comparison functor
120         typedef typename base_class::memory_model   memory_model    ;   ///< Memory ordering. See cds::opt::memory_model option
121         typedef typename base_class::rcu_check_deadlock rcu_check_deadlock ; ///< RCU deadlock checking policy
122
123         typedef typename gc::scoped_lock    rcu_lock ;  ///< RCU scoped lock
124         static CDS_CONSTEXPR_CONST bool c_bExtractLockExternal = base_class::c_bExtractLockExternal; ///< Group of \p extract_xxx functions require external locking
125
126     protected:
127         //@cond
128         typedef typename base_class::value_type     node_type;
129         typedef typename options::cxx_allocator     cxx_allocator;
130         typedef typename options::node_deallocator  node_deallocator;
131         typedef typename options::type_traits::compare  intrusive_key_comparator;
132
133         typedef typename base_class::atomic_node_ptr      head_type;
134 #   ifndef CDS_CXX11_LAMBDA_SUPPORT
135         typedef typename base_class::empty_erase_functor    empty_erase_functor;
136 #   endif
137         //@endcond
138
139     public:
140         typedef cds::urcu::exempt_ptr< gc, node_type, value_type, typename options::type_traits::disposer > exempt_ptr; ///< pointer to extracted node
141
142     private:
143         //@cond
144         static value_type& node_to_value( node_type& n )
145         {
146             return n.m_Value;
147         }
148         static value_type const& node_to_value( node_type const& n )
149         {
150             return n.m_Value;
151         }
152
153 #   ifndef CDS_CXX11_LAMBDA_SUPPORT
154         template <typename Func>
155         struct insert_functor
156         {
157             Func        m_func;
158
159             insert_functor ( Func f )
160                 : m_func(f)
161             {}
162
163             void operator()( node_type& node )
164             {
165                 cds::unref(m_func)( node_to_value(node) );
166             }
167         };
168
169         template <typename Q, typename Func>
170         struct ensure_functor
171         {
172             Func        m_func;
173             Q const&    m_arg;
174
175             ensure_functor( Q const& arg, Func f )
176                 : m_func(f)
177                 , m_arg( arg )
178             {}
179
180             void operator ()( bool bNew, node_type& node, node_type& )
181             {
182                 cds::unref(m_func)( bNew, node_to_value(node), m_arg );
183             }
184         };
185
186         template <typename Func>
187         struct find_functor
188         {
189             Func    m_func;
190
191             find_functor( Func f )
192                 : m_func(f)
193             {}
194
195             template <typename Q>
196             void operator ()( node_type& node, Q& val )
197             {
198                 cds::unref(m_func)( node_to_value(node), val );
199             }
200         };
201
202         struct empty_find_functor
203         {
204             template <typename Q>
205             void operator ()( node_type& node, Q& val ) const
206             {}
207         };
208
209         template <typename Func>
210         struct erase_functor
211         {
212             Func        m_func;
213
214             erase_functor( Func f )
215                 : m_func(f)
216             {}
217
218             void operator()( node_type const& node )
219             {
220                 cds::unref(m_func)( node_to_value(node) );
221             }
222         };
223 #endif  // ifndef CDS_CXX11_LAMBDA_SUPPORT
224         //@endcond
225
226     protected:
227         //@cond
228         template <typename Q>
229         static node_type * alloc_node( Q const& v )
230         {
231             return cxx_allocator().New( v );
232         }
233
234         template <typename... Args>
235         static node_type * alloc_node( Args&&... args )
236         {
237             return cxx_allocator().MoveNew( std::forward<Args>(args)... );
238         }
239
240         static void free_node( node_type * pNode )
241         {
242             cxx_allocator().Delete( pNode );
243         }
244
245         struct node_disposer {
246             void operator()( node_type * pNode )
247             {
248                 free_node( pNode );
249             }
250         };
251         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
252
253         head_type& head()
254         {
255             return base_class::m_pHead;
256         }
257
258         head_type& head() const
259         {
260             return const_cast<head_type&>( base_class::m_pHead );
261         }
262         //@endcond
263
264     protected:
265                 //@cond
266         template <bool IsConst>
267         class iterator_type: protected base_class::template iterator_type<IsConst>
268         {
269             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
270
271             iterator_type( head_type const& pNode )
272                 : iterator_base( pNode )
273             {}
274
275             friend class MichaelList;
276
277         public:
278             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
279             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
280
281             iterator_type()
282             {}
283
284             iterator_type( iterator_type const& src )
285                 : iterator_base( src )
286             {}
287
288             value_ptr operator ->() const
289             {
290                 typename iterator_base::value_ptr p = iterator_base::operator ->();
291                 return p ? &(p->m_Value) : nullptr;
292             }
293
294             value_ref operator *() const
295             {
296                 return (iterator_base::operator *()).m_Value;
297             }
298
299             /// Pre-increment
300             iterator_type& operator ++()
301             {
302                 iterator_base::operator ++();
303                 return *this;
304             }
305
306             template <bool C>
307             bool operator ==(iterator_type<C> const& i ) const
308             {
309                 return iterator_base::operator ==(i);
310             }
311             template <bool C>
312             bool operator !=(iterator_type<C> const& i ) const
313             {
314                 return iterator_base::operator !=(i);
315             }
316         };
317         //@endcond
318
319     public:
320         /// Forward iterator
321         typedef iterator_type<false>    iterator;
322
323         /// Const forward iterator
324         typedef iterator_type<true>     const_iterator;
325
326         /// Returns a forward iterator addressing the first element in a list
327         /**
328             For empty list \code begin() == end() \endcode
329         */
330         iterator begin()
331         {
332             return iterator( head() );
333         }
334
335         /// Returns an iterator that addresses the location succeeding the last element in a list
336         /**
337             Do not use the value returned by <tt>end</tt> function to access any item.
338             Internally, <tt>end</tt> returning value equals to \p nullptr.
339
340             The returned value can be used only to control reaching the end of the list.
341             For empty list \code begin() == end() \endcode
342         */
343         iterator end()
344         {
345             return iterator();
346         }
347
348         /// Returns a forward const iterator addressing the first element in a list
349         //@{
350         const_iterator begin() const
351         {
352             return const_iterator( head() );
353         }
354         const_iterator cbegin()
355         {
356             return const_iterator( head() );
357         }
358         //@}
359
360         /// Returns an const iterator that addresses the location succeeding the last element in a list
361         //@{
362         const_iterator end() const
363         {
364             return const_iterator();
365         }
366         const_iterator cend()
367         {
368             return const_iterator();
369         }
370         //@}
371
372     public:
373         /// Default constructor
374         /**
375             Initialize empty list
376         */
377         MichaelList()
378         {}
379
380         /// List destructor
381         /**
382             Clears the list
383         */
384         ~MichaelList()
385         {
386             clear();
387         }
388
389         /// Inserts new node
390         /**
391             The function creates a node with copy of \p val value
392             and then inserts the node created into the list.
393
394             The type \p Q should contain as minimum the complete key of the node.
395             The object of \ref value_type should be constructible from \p val of type \p Q.
396             In trivial case, \p Q is equal to \ref value_type.
397
398             The function makes RCU lock internally.
399
400             Returns \p true if inserting successful, \p false otherwise.
401         */
402         template <typename Q>
403         bool insert( Q const& val )
404         {
405             return insert_at( head(), val );
406         }
407
408         /// Inserts new node
409         /**
410             This function inserts new node with default-constructed value and then it calls
411             \p func functor with signature
412             \code void func( value_type& itemValue ) ;\endcode
413
414             The argument \p itemValue of user-defined functor \p func is the reference
415             to the list's item inserted. User-defined functor \p func should guarantee that during changing
416             item's value no any other changes could be made on this list's item by concurrent threads.
417             The user-defined functor can be passed by reference using <tt>boost::ref</tt>
418             and it is called only if the inserting is success.
419
420             The type \p Q should contain the complete key of the node.
421             The object of \ref value_type should be constructible from \p key of type \p Q.
422
423             The function allows to split creating of new item into two part:
424             - create item from \p key with initializing key-fields only;
425             - insert new item into the list;
426             - if inserting is successful, initialize non-key fields of item by calling \p f functor
427
428             This can be useful if complete initialization of object of \p value_type is heavyweight and
429             it is preferable that the initialization should be completed only if inserting is successful.
430
431             The function makes RCU lock internally.
432         */
433         template <typename Q, typename Func>
434         bool insert( Q const& key, Func func )
435         {
436             return insert_at( head(), key, func );
437         }
438
439         /// Ensures that the \p key exists in the list
440         /**
441             The operation performs inserting or changing data with lock-free manner.
442
443             If the \p key not found in the list, then the new item created from \p key
444             is inserted into the list. Otherwise, the functor \p func is called with the item found.
445             The functor \p Func should be a function with signature:
446             \code
447                 void func( bool bNew, value_type& item, const Q& val );
448             \endcode
449             or a functor:
450             \code
451                 struct my_functor {
452                     void operator()( bool bNew, value_type& item, const Q& val );
453                 };
454             \endcode
455
456             with arguments:
457             - \p bNew - \p true if the item has been inserted, \p false otherwise
458             - \p item - item of the list
459             - \p val - argument \p key passed into the \p ensure function
460
461             The functor may change non-key fields of the \p item; however, \p func must guarantee
462             that during changing no any other modifications could be made on this item by concurrent threads.
463
464             You may pass \p func argument by reference using <tt>boost::ref</tt>.
465
466             The function makes RCU lock internally.
467
468             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
469             \p second is true if new item has been added or \p false if the item with \p key
470             already is in the list.
471         */
472         template <typename Q, typename Func>
473         std::pair<bool, bool> ensure( Q const& key, Func f )
474         {
475             return ensure_at( head(), key, f );
476         }
477
478         /// Inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
479         /**
480             Returns \p true if inserting successful, \p false otherwise.
481
482             The function makes RCU lock internally.
483         */
484         template <typename... Args>
485         bool emplace( Args&&... args )
486         {
487             return emplace_at( head(), std::forward<Args>(args)... );
488         }
489
490         /// Deletes \p key from the list
491         /** \anchor cds_nonintrusive_MichealList_rcu_erase_val
492             Since the key of MichaelList's item type \p T is not explicitly specified,
493             template parameter \p Q defines the key type searching in the list.
494             The list item comparator should be able to compare the type \p T of list item
495             and the value \p key of type \p Q.
496
497             RCU \p synchronize method can be called. RCU should not be locked.
498
499             Return \p true if key is found and deleted, \p false otherwise
500         */
501         template <typename Q>
502         bool erase( Q const& key )
503         {
504 #       ifdef CDS_CXX11_LAMBDA_SUPPORT
505             return erase_at( head(), key, intrusive_key_comparator(),  [](value_type const&){} );
506 #       else
507             return erase_at( head(), key, intrusive_key_comparator(), empty_erase_functor() );
508 #       endif
509         }
510
511         /// Deletes the item from the list using \p pred predicate for searching
512         /**
513             The function is an analog of \ref cds_nonintrusive_MichealList_rcu_erase_val "erase(Q const&)"
514             but \p pred is used for key comparing.
515             \p Less functor has the interface like \p std::less.
516             \p pred must imply the same element order as the comparator used for building the list.
517         */
518         template <typename Q, typename Less>
519         bool erase_with( Q const& key, Less pred )
520         {
521 #       ifdef CDS_CXX11_LAMBDA_SUPPORT
522             return erase_at( head(), key, typename options::template less_wrapper<Less>::type(), [](value_type const&){} );
523 #       else
524             return erase_at( head(), key, typename options::template less_wrapper<Less>::type(), empty_erase_functor() );
525 #       endif
526         }
527
528         /// Deletes \p key from the list
529         /** \anchor cds_nonintrusive_MichaelList_rcu_erase_func
530             The function searches an item with key \p key, calls \p f functor with item found
531             and deletes it. If \p key is not found, the functor is not called.
532
533             The functor \p Func interface:
534             \code
535             struct extractor {
536                 void operator()(const value_type& val) { ... }
537             };
538             \endcode
539             The functor may be passed by reference with <tt>boost:ref</tt>
540
541             Since the key of MichaelList's item type \p T is not explicitly specified,
542             template parameter \p Q defines the key type searching in the list.
543             The list item comparator should be able to compare the type \p T of list item
544             and the type \p Q.
545
546             RCU \p synchronize method can be called. RCU should not be locked.
547
548             Return \p true if key is found and deleted, \p false otherwise
549         */
550         template <typename Q, typename Func>
551         bool erase( Q const& key, Func f )
552         {
553             return erase_at( head(), key, intrusive_key_comparator(), f );
554         }
555
556         /// Deletes the item from the list using \p pred predicate for searching
557         /**
558             The function is an analog of \ref cds_nonintrusive_MichaelList_rcu_erase_func "erase(Q const&, Func)"
559             but \p pred is used for key comparing.
560             \p Less functor has the interface like \p std::less.
561             \p pred must imply the same element order as the comparator used for building the list.
562         */
563         template <typename Q, typename Less, typename Func>
564         bool erase_with( Q const& key, Less pred, Func f )
565         {
566             return erase_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
567         }
568
569         /// Extracts an item from the list
570         /**
571         @anchor cds_nonintrusive_MichaelList_rcu_extract
572             The function searches an item with key equal to \p val in the list,
573             unlinks it from the list, and returns pointer to an item found in \p dest argument.
574             If the item with the key equal to \p val is not found the function returns \p false.
575
576             @note The function does NOT call RCU read-side lock or synchronization,
577             and does NOT dispose the item found. It just excludes the item from the list
578             and returns a pointer to item found.
579             You should lock RCU before calling this function.
580
581             \code
582             #include <cds/urcu/general_buffered.h>
583             #include <cds/container/michael_list_rcu.h>
584
585             typedef cds::urcu::gc< general_buffered<> > rcu;
586             typedef cds::container::MichaelList< rcu, Foo > rcu_michael_list;
587
588             rcu_michael_list theList;
589             // ...
590
591             rcu_michael_list::exempt_ptr p;
592             {
593                 // first, we should lock RCU
594                 rcu::scoped_lock sl;
595
596                 // Now, you can apply extract function
597                 // Note that you must not delete the item found inside the RCU lock
598                 if ( theList.extract( p, 10 )) {
599                     // do something with p
600                     ...
601                 }
602             }
603             // Outside RCU lock section we may safely release extracted pointer.
604             // release() passes the pointer to RCU reclamation cycle.
605             p.release();
606             \endcode
607         */
608         template <typename Q>
609         bool extract( exempt_ptr& dest, Q const& val )
610         {
611             dest = extract_at( head(), val, intrusive_key_comparator() );
612             return !dest.empty();
613         }
614
615         /// Extracts an item from the list using \p pred predicate for searching
616         /**
617             This function is the analog for \ref cds_nonintrusive_MichaelList_rcu_extract "extract(exempt_ptr&, Q const&)".
618
619             The \p pred is a predicate used for key comparing.
620             \p Less has the interface like \p std::less.
621             \p pred must imply the same element order as \ref key_comparator.
622         */
623         template <typename Q, typename Less>
624         bool extract_with( exempt_ptr& dest, Q const& val, Less pred )
625         {
626             dest = extract_at( head(), val, typename options::template less_wrapper<Less>::type() );
627             return !dest.empty();
628         }
629
630         /// Finds the key \p key
631         /** \anchor cds_nonintrusive_MichaelList_rcu_find_val
632             The function searches the item with key equal to \p key
633             and returns \p true if it is found, and \p false otherwise.
634
635             The function makes RCU lock internally.
636         */
637         template <typename Q>
638         bool find( Q const& key ) const
639         {
640             return find_at( head(), key, intrusive_key_comparator() );
641         }
642
643         /// Finds the key \p val using \p pred predicate for searching
644         /**
645             The function is an analog of \ref cds_nonintrusive_MichaelList_rcu_find_val "find(Q const&)"
646             but \p pred is used for key comparing.
647             \p Less functor has the interface like \p std::less.
648             \p pred must imply the same element order as the comparator used for building the list.
649         */
650         template <typename Q, typename Less>
651         bool find_with( Q const& key, Less pred ) const
652         {
653             return find_at( head(), key, typename options::template less_wrapper<Less>::type() );
654         }
655
656         /// Finds the key \p val and performs an action with it
657         /** \anchor cds_nonintrusive_MichaelList_rcu_find_func
658             The function searches an item with key equal to \p val and calls the functor \p f for the item found.
659             The interface of \p Func functor is:
660             \code
661             struct functor {
662                 void operator()( value_type& item, Q& val );
663             };
664             \endcode
665             where \p item is the item found, \p val is the <tt>find</tt> function argument.
666
667             You may pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
668
669             The functor may change non-key fields of \p item. Note that the function is only guarantee
670             that \p item cannot be deleted during functor is executing.
671             The function does not serialize simultaneous access to the list \p item. If such access is
672             possible you must provide your own synchronization schema to exclude unsafe item modifications.
673
674             The \p val argument is non-const since it can be used as \p f functor destination i.e., the functor
675             may modify both arguments.
676
677             The function makes RCU lock internally.
678
679             The function returns \p true if \p val is found, \p false otherwise.
680         */
681         template <typename Q, typename Func>
682         bool find( Q& val, Func f ) const
683         {
684             return find_at( head(), val, intrusive_key_comparator(), f );
685         }
686
687         /// Finds the key \p val using \p pred predicate for searching
688         /**
689             The function is an analog of \ref cds_nonintrusive_MichaelList_rcu_find_func "find(Q&, Func)"
690             but \p pred is used for key comparing.
691             \p Less functor has the interface like \p std::less.
692             \p pred must imply the same element order as the comparator used for building the list.
693         */
694         template <typename Q, typename Less, typename Func>
695         bool find_with( Q& val, Less pred, Func f ) const
696         {
697             return find_at( head(), val, typename options::template less_wrapper<Less>::type(), f );
698         }
699
700         /// Finds the key \p val and performs an action with it
701         /** \anchor cds_nonintrusive_MichaelList_rcu_find_cfunc
702             The function searches an item with key equal to \p val and calls the functor \p f for the item found.
703             The interface of \p Func functor is:
704             \code
705             struct functor {
706                 void operator()( value_type& item, Q const& val );
707             };
708             \endcode
709             where \p item is the item found, \p val is the <tt>find</tt> function argument.
710
711             You may pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
712
713             The functor may change non-key fields of \p item. Note that the function is only guarantee
714             that \p item cannot be deleted during functor is executing.
715             The function does not serialize simultaneous access to the list \p item. If such access is
716             possible you must provide your own synchronization schema to exclude unsafe item modifications.
717
718             The function makes RCU lock internally.
719
720             The function returns \p true if \p val is found, \p false otherwise.
721         */
722         template <typename Q, typename Func>
723         bool find( Q const& val, Func f ) const
724         {
725             return find_at( head(), val, intrusive_key_comparator(), f );
726         }
727
728         /// Finds the key \p val using \p pred predicate for searching
729         /**
730             The function is an analog of \ref cds_nonintrusive_MichaelList_rcu_find_cfunc "find(Q&, Func)"
731             but \p pred is used for key comparing.
732             \p Less functor has the interface like \p std::less.
733             \p pred must imply the same element order as the comparator used for building the list.
734         */
735         template <typename Q, typename Less, typename Func>
736         bool find_with( Q const& val, Less pred, Func f ) const
737         {
738             return find_at( head(), val, typename options::template less_wrapper<Less>::type(), f );
739         }
740
741         /// Finds the key \p val and return the item found
742         /** \anchor cds_nonintrusive_MichaelList_rcu_get
743             The function searches the item with key equal to \p val and returns the pointer to item found.
744             If \p val is not found it returns \p nullptr.
745
746             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
747
748             RCU should be locked before call of this function.
749             Returned item is valid only while RCU is locked:
750             \code
751             typedef cds::container::MichaelList< cds::urcu::gc< cds::urcu::general_buffered<> >, foo, my_traits > ord_list;
752             ord_list theList;
753             // ...
754             {
755                 // Lock RCU
756                 ord_list::rcu_lock lock;
757
758                 foo * pVal = theList.get( 5 );
759                 if ( pVal ) {
760                     // Deal with pVal
761                     //...
762                 }
763                 // Unlock RCU by rcu_lock destructor
764                 // pVal can be freed at any time after RCU has been unlocked
765             }
766             \endcode
767         */
768         template <typename Q>
769         value_type * get( Q const& val ) const
770         {
771             return get_at( head(), val, intrusive_key_comparator());
772         }
773
774         /// Finds the key \p val and return the item found
775         /**
776             The function is an analog of \ref cds_nonintrusive_MichaelList_rcu_get "get(Q const&)"
777             but \p pred is used for comparing the keys.
778
779             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
780             in any order.
781             \p pred must imply the same element order as the comparator used for building the list.
782         */
783         template <typename Q, typename Less>
784         value_type * get_with( Q const& val, Less pred ) const
785         {
786             return get_at( head(), val, typename options::template less_wrapper<Less>::type());
787         }
788
789         /// Checks if the list is empty
790         bool empty() const
791         {
792             return base_class::empty();
793         }
794
795         /// Returns list's item count
796         /**
797             The value returned depends on opt::item_counter option. For atomics::empty_item_counter,
798             this function always returns 0.
799
800             <b>Warning</b>: even if you use a real item counter and it returns 0, this fact is not mean that the list
801             is empty. To check list emptyness use \ref empty() method.
802         */
803         size_t size() const
804         {
805             return base_class::size();
806         }
807
808         /// Clears the list
809         /**
810             Post-condition: the list is empty
811         */
812         void clear()
813         {
814             base_class::clear();
815         }
816
817     protected:
818         //@cond
819         bool insert_node_at( head_type& refHead, node_type * pNode )
820         {
821             assert( pNode );
822             scoped_node_ptr p(pNode);
823             if ( base_class::insert_at( refHead, *pNode )) {
824                 p.release();
825                 return true;
826             }
827
828             return false;
829         }
830
831         template <typename Q>
832         bool insert_at( head_type& refHead, Q const& val )
833         {
834             return insert_node_at( refHead, alloc_node( val ));
835         }
836
837         template <typename Q, typename Func>
838         bool insert_at( head_type& refHead, Q const& key, Func f )
839         {
840             scoped_node_ptr pNode( alloc_node( key ));
841
842 #   ifdef CDS_CXX11_LAMBDA_SUPPORT
843 #       ifdef CDS_BUG_STATIC_MEMBER_IN_LAMBDA
844             // GCC 4.5,4.6,4.7: node_to_value is unaccessible from lambda,
845             // like as MichaelList::node_to_value that requires to capture *this* despite on node_to_value is static function
846             value_type& (* n2v)( node_type& ) = node_to_value;
847             if ( base_class::insert_at( refHead, *pNode, [&f, n2v]( node_type& node ) { cds::unref(f)( n2v(node) ); } ))
848 #       else
849             if ( base_class::insert_at( refHead, *pNode, [&f]( node_type& node ) { cds::unref(f)( node_to_value(node) ); } ))
850 #       endif
851 #   else
852             insert_functor<Func>  wrapper( f );
853             if ( base_class::insert_at( refHead, *pNode, cds::ref(wrapper) ))
854 #   endif
855             {
856                 pNode.release();
857                 return true;
858             }
859             return false;
860         }
861
862         template <typename... Args>
863         bool emplace_at( head_type& refHead, Args&&... args )
864         {
865             return insert_node_at( refHead, alloc_node( std::forward<Args>(args) ... ));
866         }
867
868         template <typename Q, typename Compare, typename Func>
869         bool erase_at( head_type& refHead, Q const& key, Compare cmp, Func f )
870         {
871 #   ifdef CDS_CXX11_LAMBDA_SUPPORT
872 #       ifdef CDS_BUG_STATIC_MEMBER_IN_LAMBDA
873             // GCC 4.5-4.7: node_to_value is unaccessible from lambda,
874             // like as MichaelList::node_to_value that requires to capture *this* despite on node_to_value is static function
875             value_type const& (* n2v)( node_type const& ) = node_to_value;
876             return base_class::erase_at( refHead, key, cmp, [&f,n2v](node_type const& node){ cds::unref(f)( n2v(node) ); } );
877 #       else
878             return base_class::erase_at( refHead, key, cmp, [&f](node_type const& node){ cds::unref(f)( node_to_value(node) ); } );
879 #       endif
880 #   else
881             erase_functor<Func> wrapper( f );
882             return base_class::erase_at( refHead, key, cmp, cds::ref(wrapper) );
883 #   endif
884         }
885
886         template <typename Q, typename Func>
887         std::pair<bool, bool> ensure_at( head_type& refHead, Q const& key, Func f )
888         {
889             scoped_node_ptr pNode( alloc_node( key ));
890
891 #   ifdef CDS_CXX11_LAMBDA_SUPPORT
892 #       ifdef CDS_BUG_STATIC_MEMBER_IN_LAMBDA
893             // GCC 4.5-4.7: node_to_value is unaccessible from lambda,
894             // like as MichaelList::node_to_value that requires to capture *this* despite on node_to_value is static function
895             value_type& (* n2v)( node_type& ) = node_to_value;
896             std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode,
897                 [&f, &key, n2v](bool bNew, node_type& node, node_type&){ cds::unref(f)( bNew, n2v(node), key ); });
898 #       else
899             std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode,
900                 [&f, &key](bool bNew, node_type& node, node_type&){ cds::unref(f)( bNew, node_to_value(node), key ); });
901 #       endif
902 #   else
903             ensure_functor<Q, Func> wrapper( key, f );
904             std::pair<bool, bool> ret = base_class::ensure_at( refHead, *pNode, cds::ref(wrapper));
905 #   endif
906             if ( ret.first && ret.second )
907                 pNode.release();
908
909             return ret;
910         }
911
912         template <typename Q, typename Compare>
913         node_type * extract_at( head_type& refHead, Q const& key, Compare cmp )
914         {
915             return base_class::extract_at( refHead, key, cmp );
916         }
917
918         template <typename Q, typename Compare>
919         bool find_at( head_type& refHead, Q const& key, Compare cmp ) const
920         {
921 #       ifdef CDS_CXX11_LAMBDA_SUPPORT
922             return base_class::find_at( refHead, key, cmp, [](node_type&, Q const &) {} );
923 #       else
924             return base_class::find_at( refHead, key, cmp, empty_find_functor() );
925 #       endif
926         }
927
928         template <typename Q, typename Compare, typename Func>
929         bool find_at( head_type& refHead, Q& val, Compare cmp, Func f ) const
930         {
931 #   ifdef CDS_CXX11_LAMBDA_SUPPORT
932 #       ifdef CDS_BUG_STATIC_MEMBER_IN_LAMBDA
933             // GCC 4.5-4.7: node_to_value is unaccessible from lambda,
934             // like as MichaelList::node_to_value that requires to capture *this* despite on node_to_value is static function
935             value_type& (* n2v)( node_type& ) = node_to_value;
936             return base_class::find_at( refHead, val, cmp, [&f, n2v](node_type& node, Q& v){ cds::unref(f)( n2v(node), v ); });
937 #       else
938             return base_class::find_at( refHead, val, cmp, [&f](node_type& node, Q& v){ cds::unref(f)( node_to_value(node), v ); });
939 #       endif
940 #   else
941             find_functor<Func>  wrapper( f );
942             return base_class::find_at( refHead, val, cmp, cds::ref(wrapper) );
943 #   endif
944         }
945
946         template <typename Q, typename Compare>
947         value_type * get_at( head_type& refHead, Q const& val, Compare cmp ) const
948         {
949             node_type * pNode = base_class::get_at( refHead, val, cmp );
950             return pNode ? &pNode->m_Value : nullptr;
951         }
952
953         //@endcond
954     };
955
956 }}  // namespace cds::container
957
958 #endif  // #ifndef __CDS_CONTAINER_MICHAEL_LIST_RCU_H