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