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