2b1a5aad0210de40b859bbdb6fec514fc656c467
[libcds.git] / cds / container / split_list_set_rcu.h
1 //$$CDS-header$$
2
3 #ifndef CDSLIB_CONTAINER_SPLIT_LIST_SET_RCU_H
4 #define CDSLIB_CONTAINER_SPLIT_LIST_SET_RCU_H
5
6 #include <cds/intrusive/split_list_rcu.h>
7 #include <cds/container/details/make_split_list_set.h>
8 #include <cds/urcu/exempt_ptr.h>
9
10 namespace cds { namespace container {
11
12     //@cond
13     namespace split_list { namespace details {
14
15         template <
16             typename T,
17             class OrdList,
18             typename OrdListTag
19         >
20         class make_raw_ptr;
21
22 #ifdef CDSLIB_CONTAINER_DETAILS_MICHAEL_LIST_BASE_H
23         template <typename T, class RawPtr>
24         class make_raw_ptr< T, RawPtr, cds::container::michael_list_tag >
25         {
26             typedef RawPtr intrusive_raw_ptr;
27             typedef typename intrusive_raw_ptr::value_type node_type;
28             typedef T value_type;
29
30             struct raw_ptr_converter
31             {
32                 value_type * operator()( node_type * p ) const
33                 {
34                    return p ? &p->m_Value : nullptr;
35                 }
36
37                 value_type& operator()( node_type& n ) const
38                 {
39                     return n.m_Value;
40                 }
41
42                 value_type const& operator()( node_type const& n ) const
43                 {
44                     return n.m_Value;
45                 }
46             };
47         public:
48             typedef cds::urcu::raw_ptr_adaptor< value_type, intrusive_raw_ptr, raw_ptr_converter > raw_ptr;
49
50             static raw_ptr make( intrusive_raw_ptr&& p )
51             {
52                 return raw_ptr(std::move( p ));
53             }
54         };
55 #endif
56
57 #ifdef CDSLIB_CONTAINER_DETAILS_LAZY_LIST_BASE_H
58         template <typename T, typename RawPtr>
59         class make_raw_ptr< T, RawPtr, cds::container::lazy_list_tag >
60         {
61             typedef RawPtr node_type_pointer;
62             typedef T value_type;
63
64         public:
65             typedef value_type * raw_ptr;
66
67             static raw_ptr make( node_type_pointer p )
68             {
69                 return p ? &p->m_Value : nullptr;
70             }
71         };
72 #endif
73     }} //namespace split_list::details
74     //@endcond
75
76     /// Split-ordered list set (template specialization for \ref cds_urcu_desc "RCU")
77     /** @ingroup cds_nonintrusive_set
78         \anchor cds_nonintrusive_SplitListSet_rcu
79
80         Hash table implementation based on split-ordered list algorithm discovered by Ori Shalev and Nir Shavit, see
81         - [2003] Ori Shalev, Nir Shavit "Split-Ordered Lists - Lock-free Resizable Hash Tables"
82         - [2008] Nir Shavit "The Art of Multiprocessor Programming"
83
84         See \p intrusive::SplitListSet for a brief description of the split-list algorithm.
85
86         Template parameters:
87         - \p RCU - one of \ref cds_urcu_gc "RCU type"
88         - \p T - type of the value to be stored in the split-list.
89         - \p Traits - type traits, default is \p split_list::traits. Instead of declaring \p split_list::traits -based
90             struct you can apply option-based notation with \p split_list::make_traits metafunction.
91
92         <b>Iterators</b>
93
94         The class supports a forward iterator (\ref iterator and \ref const_iterator).
95         The iteration is unordered.
96
97         You may iterate over split-list set items only under RCU lock.
98         Only in this case the iterator is thread-safe since
99         while RCU is locked any set's item cannot be reclaimed.
100
101         @warning The iterator object cannot be passed between threads
102
103         \warning Due to concurrent nature of skip-list set it is not guarantee that you can iterate
104         all elements in the set: any concurrent deletion can exclude the element
105         pointed by the iterator from the set, and your iteration can be terminated
106         before end of the set. Therefore, such iteration is more suitable for debugging purposes
107
108         The iterator class supports the following minimalistic interface:
109         \code
110         struct iterator {
111             // Default ctor
112             iterator();
113
114             // Copy ctor
115             iterator( iterator const& s);
116
117             value_type * operator ->() const;
118             value_type& operator *() const;
119
120             // Pre-increment
121             iterator& operator ++();
122
123             // Copy assignment
124             iterator& operator = (const iterator& src);
125
126             bool operator ==(iterator const& i ) const;
127             bool operator !=(iterator const& i ) const;
128         };
129         \endcode
130         Note, the iterator object returned by \p end(), \p cend() member functions points to \p nullptr and should not be dereferenced.
131
132         \par Usage
133
134         You should decide what garbage collector you want, and what ordered list you want to use. Split-ordered list
135         is an original data structure based on an ordered list. Suppose, you want construct split-list set based on \p cds::urcu::general_buffered<> GC
136         and \p LazyList as ordered list implementation. So, you beginning your program with following include:
137         \code
138         #include <cds/urcu/general_buffered.h>
139         #include <cds/container/lazy_list_rcu.h>
140         #include <cds/container/split_list_set_rcu.h>
141
142         namespace cc = cds::container;
143
144         // The data belonged to split-ordered list
145         sturuct foo {
146             int     nKey;   // key field
147             std::string strValue    ;   // value field
148         };
149         \endcode
150         The inclusion order is important:
151         - first, include one of \ref cds_urcu_gc "RCU implementation" (<tt>cds/urcu/general_buffered.h</tt> in our case)
152         - second, include file for ordered-list implementation (for this example, <tt>cds/container/lazy_list_rcu.h</tt>),
153         - then, the header for RCU-based split-list set <tt>cds/container/split_list_set_rcu.h</tt>.
154
155         Now, you should declare traits for split-list set. The main parts of traits are a hash functor for the set and a comparing functor for ordered list.
156         Note that we define several function in \p foo_hash and \p foo_less functors for different argument types since we want call our \p %SplitListSet
157         object by the key of type \p int and by the value of type \p foo.
158
159         The second attention: instead of using \p %LazyList in \p %SplitListSet traits we use \p cds::contaner::lazy_list_tag tag for the lazy list.
160         The split-list requires significant support from underlying ordered list class and it is not good idea to dive you
161         into deep implementation details of split-list and ordered list interrelations. The tag paradigm simplifies split-list interface.
162
163         \code
164         // foo hash functor
165         struct foo_hash {
166             size_t operator()( int key ) const { return std::hash( key ) ; }
167             size_t operator()( foo const& item ) const { return std::hash( item.nKey ) ; }
168         };
169
170         // foo comparator
171         struct foo_less {
172             bool operator()(int i, foo const& f ) const { return i < f.nKey ; }
173             bool operator()(foo const& f, int i ) const { return f.nKey < i ; }
174             bool operator()(foo const& f1, foo const& f2) const { return f1.nKey < f2.nKey; }
175         };
176
177         // SplitListSet traits
178         struct foo_set_traits: public cc::split_list::traits
179         {
180             typedef cc::lazy_list_tag   ordered_list    ;   // what type of ordered list we want to use
181             typedef foo_hash            hash            ;   // hash functor for our data stored in split-list set
182
183             // Type traits for our LazyList class
184             struct ordered_list_traits: public cc::lazy_list::traits
185             {
186                 typedef foo_less less   ;   // use our foo_less as comparator to order list nodes
187             };
188         };
189         \endcode
190
191         Now you are ready to declare our set class based on \p %SplitListSet:
192         \code
193         typedef cc::SplitListSet< cds::urcu::gc<cds::urcu::general_buffered<> >, foo, foo_set_traits > foo_set;
194         \endcode
195
196         You may use the modern option-based declaration instead of classic type-traits-based one:
197         \code
198         typedef cc::SplitListSet<
199             cds::urcu::gc<cds::urcu::general_buffered<> >   // RCU type used
200             ,foo                                            // type of data stored
201             ,cc::split_list::make_traits<      // metafunction to build split-list traits
202                 cc::split_list::ordered_list<cc::lazy_list_tag>     // tag for underlying ordered list implementation
203                 ,cc::opt::hash< foo_hash >              // hash functor
204                 ,cc::split_list::ordered_list_traits<   // ordered list traits
205                     cc::lazy_list::make_traits<         // metafunction to build lazy list traits
206                         cc::opt::less< foo_less >       // less-based compare functor
207                     >::type
208                 >
209             >::type
210         >  foo_set;
211         \endcode
212         In case of option-based declaration using \p split_list::make_traits metafunction
213         the struct \p foo_set_traits is not required.
214
215         Now, the set of type \p foo_set is ready to use in your program.
216
217         Note that in this example we show only mandatory \p traits parts, optional ones is the default and they are inherited
218         from \p container::split_list::traits.
219         There are many other options for deep tuning of the split-list and ordered-list containers.
220     */
221     template <
222         class RCU,
223         class T,
224 #ifdef CDS_DOXYGEN_INVOKED
225         class Traits = split_list::traits
226 #else
227         class Traits
228 #endif
229     >
230     class SplitListSet< cds::urcu::gc< RCU >, T, Traits >:
231 #ifdef CDS_DOXYGEN_INVOKED
232         protected intrusive::SplitListSet< cds::urcu::gc< RCU >, T, typename Traits::ordered_list, Traits >
233 #else
234         protected details::make_split_list_set< cds::urcu::gc< RCU >, T, typename Traits::ordered_list, split_list::details::wrap_set_traits<T, Traits> >::type
235 #endif
236     {
237     protected:
238         //@cond
239         typedef details::make_split_list_set< cds::urcu::gc< RCU >, T, typename Traits::ordered_list, split_list::details::wrap_set_traits<T, Traits> > maker;
240         typedef typename maker::type  base_class;
241         //@endcond
242
243     public:
244         typedef cds::urcu::gc< RCU >  gc; ///< RCU-based garbage collector
245         typedef T       value_type; ///< Type of value to be storedin the set
246         typedef Traits  traits;    ///< \p Traits template argument
247
248         // Note: ordered_list is not real ordered list type. Actual type is base_class::ordered_list
249         typedef typename maker::ordered_list        ordered_list;   ///< Underlying ordered list class
250         typedef typename base_class::key_comparator key_comparator; ///< key compare functor
251
252         /// Hash functor for \ref value_type and all its derivatives that you use
253         typedef typename base_class::hash           hash;
254         typedef typename base_class::item_counter   item_counter; ///< Item counter type
255         typedef typename base_class::stat           stat; ///< Internal statistics
256
257         typedef typename base_class::rcu_lock      rcu_lock   ; ///< RCU scoped lock
258         /// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
259         static CDS_CONSTEXPR const bool c_bExtractLockExternal = base_class::c_bExtractLockExternal;
260
261         //@cond
262         typedef cds::container::split_list::implementation_tag implementation_tag;
263         //@endcond
264
265     protected:
266         //@cond
267         typedef typename maker::cxx_node_allocator    cxx_node_allocator;
268         typedef typename maker::node_type             node_type;
269         //@endcond
270
271     public:
272         /// pointer to extracted node
273         using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::ordered_list_traits::disposer >;
274 #   ifdef CDS_DOXYGEN_INVOKED
275         /// pointer to the node for \p get() function
276         /**
277             For \p LazyList, \p %raw_ptr is just pointer to \p value_type.
278
279             For \p MichaelList, \p %raw_ptr is \p cds::urcu::raw_ptr object giving access to \p value_type.
280         */
281         typedef implementation_defined raw_ptr;
282 #   else
283     private:
284         typedef split_list::details::make_raw_ptr< value_type, typename base_class::ordered_list::raw_ptr, typename traits::ordered_list > raw_ptr_maker;
285     public:
286         typedef typename raw_ptr_maker::raw_ptr raw_ptr;
287 #endif
288
289     protected:
290         //@cond
291         template <typename Q, typename Func>
292         bool find_( Q& val, Func f )
293         {
294             return base_class::find( val, [&f]( node_type& item, Q& val ) { f(item.m_Value, val) ; } );
295         }
296
297         template <typename Q, typename Less, typename Func>
298         bool find_with_( Q& val, Less pred, Func f )
299         {
300             CDS_UNUSED( pred );
301             return base_class::find_with( val, typename maker::template predicate_wrapper<Less>::type(),
302                 [&f]( node_type& item, Q& val ) { f(item.m_Value, val) ; } );
303         }
304
305         template <typename Q>
306         static node_type * alloc_node( Q const& v )
307         {
308             return cxx_node_allocator().New( v );
309         }
310
311         template <typename... Args>
312         static node_type * alloc_node( Args&&... args )
313         {
314             return cxx_node_allocator().MoveNew( std::forward<Args>(args)...);
315         }
316
317         static void free_node( node_type * pNode )
318         {
319             cxx_node_allocator().Delete( pNode );
320         }
321
322         struct node_disposer {
323             void operator()( node_type * pNode )
324             {
325                 free_node( pNode );
326             }
327         };
328         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
329
330         bool insert_node( node_type * pNode )
331         {
332             assert( pNode != nullptr );
333             scoped_node_ptr p(pNode);
334
335             if ( base_class::insert( *pNode ) ) {
336                 p.release();
337                 return true;
338             }
339
340             return false;
341         }
342         //@endcond
343
344     protected:
345         /// Forward iterator
346         /**
347             \p IsConst - constness boolean flag
348
349             The forward iterator for a split-list has the following features:
350             - it has no post-increment operator
351             - it depends on underlying ordered list iterator
352             - it is safe to iterate only inside RCU critical section
353             - deleting an item pointed by the iterator can cause to deadlock
354
355             Therefore, the use of iterators in concurrent environment is not good idea.
356             Use it for debug purpose only.
357         */
358         template <bool IsConst>
359         class iterator_type: protected base_class::template iterator_type<IsConst>
360         {
361             //@cond
362             typedef typename base_class::template iterator_type<IsConst> iterator_base_class;
363             friend class SplitListSet;
364             //@endcond
365         public:
366             /// Value pointer type (const for const iterator)
367             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
368             /// Value reference type (const for const iterator)
369             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
370
371         public:
372             /// Default ctor
373             iterator_type()
374             {}
375
376             /// Copy ctor
377             iterator_type( iterator_type const& src )
378                 : iterator_base_class( src )
379             {}
380
381         protected:
382             //@cond
383             explicit iterator_type( iterator_base_class const& src )
384                 : iterator_base_class( src )
385             {}
386             //@endcond
387
388         public:
389             /// Dereference operator
390             value_ptr operator ->() const
391             {
392                 return &(iterator_base_class::operator->()->m_Value);
393             }
394
395             /// Dereference operator
396             value_ref operator *() const
397             {
398                 return iterator_base_class::operator*().m_Value;
399             }
400
401             /// Pre-increment
402             iterator_type& operator ++()
403             {
404                 iterator_base_class::operator++();
405                 return *this;
406             }
407
408             /// Assignment operator
409             iterator_type& operator = (iterator_type const& src)
410             {
411                 iterator_base_class::operator=(src);
412                 return *this;
413             }
414
415             /// Equality operator
416             template <bool C>
417             bool operator ==(iterator_type<C> const& i ) const
418             {
419                 return iterator_base_class::operator==(i);
420             }
421
422             /// Equality operator
423             template <bool C>
424             bool operator !=(iterator_type<C> const& i ) const
425             {
426                 return iterator_base_class::operator!=(i);
427             }
428         };
429
430     public:
431         /// Initializes split-ordered list of default capacity
432         /**
433             The default capacity is defined in bucket table constructor.
434             See \p intrusive::split_list::expandable_bucket_table, \p intrusive::split_list::static_bucket_table
435             which selects by \p container::split_list::dynamic_bucket_table option.
436         */
437         SplitListSet()
438             : base_class()
439         {}
440
441         /// Initializes split-ordered list
442         SplitListSet(
443             size_t nItemCount           ///< estimated average of item count
444             , size_t nLoadFactor = 1    ///< load factor - average item count per bucket. Small integer up to 8, default is 1.
445             )
446             : base_class( nItemCount, nLoadFactor )
447         {}
448
449     public:
450         typedef iterator_type<false>  iterator        ; ///< Forward iterator
451         typedef iterator_type<true>   const_iterator  ; ///< Forward const iterator
452
453         /// Returns a forward iterator addressing the first element in a set
454         /**
455             For empty set \code begin() == end() \endcode
456         */
457         iterator begin()
458         {
459             return iterator( base_class::begin() );
460         }
461
462         /// Returns an iterator that addresses the location succeeding the last element in a set
463         /**
464             Do not use the value returned by <tt>end</tt> function to access any item.
465             The returned value can be used only to control reaching the end of the set.
466             For empty set \code begin() == end() \endcode
467         */
468         iterator end()
469         {
470             return iterator( base_class::end() );
471         }
472
473         /// Returns a forward const iterator addressing the first element in a set
474         const_iterator begin() const
475         {
476             return cbegin();
477         }
478         /// Returns a forward const iterator addressing the first element in a set
479         const_iterator cbegin() const
480         {
481             return const_iterator( base_class::cbegin() );
482         }
483
484         /// Returns an const iterator that addresses the location succeeding the last element in a set
485         const_iterator end() const
486         {
487             return cend();
488         }
489         /// Returns an const iterator that addresses the location succeeding the last element in a set
490         const_iterator cend() const
491         {
492             return const_iterator( base_class::cend() );
493         }
494
495     public:
496         /// Inserts new node
497         /**
498             The function creates a node with copy of \p val value
499             and then inserts the node created into the set.
500
501             The type \p Q should contain as minimum the complete key for the node.
502             The object of \p value_type should be constructible from a value of type \p Q.
503             In trivial case, \p Q is equal to \p value_type.
504
505             The function applies RCU lock internally.
506
507             Returns \p true if \p val is inserted into the set, \p false otherwise.
508         */
509         template <typename Q>
510         bool insert( Q const& val )
511         {
512             return insert_node( alloc_node( val ) );
513         }
514
515         /// Inserts new node
516         /**
517             The function allows to split creating of new item into two part:
518             - create item with key only
519             - insert new item into the set
520             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
521
522             The functor signature is:
523             \code
524                 void func( value_type& val );
525             \endcode
526             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
527             \p val no any other changes could be made on this set's item by concurrent threads.
528             The user-defined functor is called only if the inserting is success.
529
530             The function applies RCU lock internally.
531         */
532         template <typename Q, typename Func>
533         bool insert( Q const& key, Func f )
534         {
535             scoped_node_ptr pNode( alloc_node( key ));
536
537             if ( base_class::insert( *pNode, [&f](node_type& node) { f( node.m_Value ) ; } )) {
538                 pNode.release();
539                 return true;
540             }
541             return false;
542         }
543
544         /// Inserts data of type \p value_type created from \p args
545         /**
546             Returns \p true if inserting successful, \p false otherwise.
547
548             The function applies RCU lock internally.
549         */
550         template <typename... Args>
551         bool emplace( Args&&... args )
552         {
553             return insert_node( alloc_node( std::forward<Args>(args)...));
554         }
555
556         /// Ensures that the \p val exists in the set
557         /**
558             The operation performs inserting or changing data with lock-free manner.
559
560             If the \p val key not found in the set, then the new item created from \p val
561             is inserted into the set. Otherwise, the functor \p func is called with the item found.
562             The functor \p Func signature is:
563             \code
564                 struct my_functor {
565                     void operator()( bool bNew, value_type& item, const Q& val );
566                 };
567             \endcode
568
569             with arguments:
570             - \p bNew - \p true if the item has been inserted, \p false otherwise
571             - \p item - item of the set
572             - \p val - argument \p val passed into the \p %ensure() function
573
574             The functor may change non-key fields of the \p item; however, \p func must guarantee
575             that during changing no any other modifications could be made on this item by concurrent threads.
576
577             The function applies RCU lock internally.
578
579             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
580             \p second is true if new item has been added or \p false if the item with \p key
581             already is in the set.
582         */
583         /// Updates the node
584         /**
585             The operation performs inserting or changing data with lock-free manner.
586
587             If \p key is not found in the set, then \p key is inserted iff \p bAllowInsert is \p true.
588             Otherwise, the functor \p func is called with item found.
589
590             The functor signature is:
591             \code
592                 struct my_functor {
593                     void operator()( bool bNew, value_type& item, const Q& val );
594                 };
595             \endcode
596
597             with arguments:
598             - \p bNew - \p true if the item has been inserted, \p false otherwise
599             - \p item - item of the set
600             - \p val - argument \p val passed into the \p %update() function
601
602             The functor may change non-key fields of the \p item.
603
604             The function applies RCU lock internally.
605
606             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
607             \p second is true if new item has been added or \p false if the item with \p key
608             already is in the map.
609
610             @warning For \ref cds_intrusive_MichaelList_rcu "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
611             \ref cds_intrusive_LazyList_rcu "LazyList" provides exclusive access to inserted item and does not require any node-level
612             synchronization.
613         */
614         template <typename Q, typename Func>
615         std::pair<bool, bool> update( Q const& val, Func func, bool bAllowInsert = true )
616         {
617             scoped_node_ptr pNode( alloc_node( val ));
618
619             std::pair<bool, bool> bRet = base_class::update( *pNode,
620                 [&func, &val]( bool bNew, node_type& item,  node_type const& /*val*/ ) {
621                     func( bNew, item.m_Value, val );
622                 }, bAllowInsert );
623             if ( bRet.first && bRet.second )
624                 pNode.release();
625             return bRet;
626         }
627         //@cond
628         // Dprecated, use update()
629         template <typename Q, typename Func>
630         std::pair<bool, bool> ensure( Q const& val, Func func )
631         {
632             return update( val, func, true );
633         }
634         //@endcond
635
636         /// Deletes \p key from the set
637         /** \anchor cds_nonintrusive_SplitListSet_rcu_erase_val
638
639             Template parameter of type \p Q defines the key type searching in the list.
640             The set item comparator should be able to compare the values of type \p value_type
641             and the type \p Q.
642
643             RCU \p synchronize method can be called. RCU should not be locked.
644
645             Return \p true if key is found and deleted, \p false otherwise
646         */
647         template <typename Q>
648         bool erase( Q const& key )
649         {
650             return base_class::erase( key );
651         }
652
653         /// Deletes the item from the set using \p pred predicate for searching
654         /**
655             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_erase_val "erase(Q const&)"
656             but \p pred is used for key comparing.
657             \p Less functor has the interface like \p std::less.
658             \p Less must imply the same element order as the comparator used for building the set.
659         */
660         template <typename Q, typename Less>
661         bool erase_with( Q const& key, Less pred )
662         {
663             CDS_UNUSED( pred );
664              return base_class::erase_with( key, typename maker::template predicate_wrapper<Less>::type() );
665         }
666
667         /// Deletes \p key from the set
668         /** \anchor cds_nonintrusive_SplitListSet_rcu_erase_func
669
670             The function searches an item with key \p key, calls \p f functor
671             and deletes the item. If \p key is not found, the functor is not called.
672
673             The functor \p Func interface:
674             \code
675             struct extractor {
676                 void operator()(value_type const& val);
677             };
678             \endcode
679
680             Template parameter of type \p Q defines the key type searching in the list.
681             The list item comparator should be able to compare the values of the type \p value_type
682             and the type \p Q.
683
684             RCU \p synchronize method can be called. RCU should not be locked.
685
686             Return \p true if key is found and deleted, \p false otherwise
687         */
688         template <typename Q, typename Func>
689         bool erase( Q const& key, Func f )
690         {
691             return base_class::erase( key, [&f](node_type& node) { f( node.m_Value ); } );
692         }
693
694         /// Deletes the item from the set using \p pred predicate for searching
695         /**
696             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_erase_func "erase(Q const&, Func)"
697             but \p pred is used for key comparing.
698             \p Less functor has the interface like \p std::less.
699             \p Less must imply the same element order as the comparator used for building the set.
700         */
701         template <typename Q, typename Less, typename Func>
702         bool erase_with( Q const& key, Less pred, Func f )
703         {
704             CDS_UNUSED( pred );
705             return base_class::erase_with( key, typename maker::template predicate_wrapper<Less>::type(),
706                 [&f](node_type& node) { f( node.m_Value ); } );
707         }
708
709         /// Extracts an item from the set
710         /** \anchor cds_nonintrusive_SplitListSet_rcu_extract
711             The function searches an item with key equal to \p key in the set,
712             unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
713             If the item with the key equal to \p key is not found the function returns an empty \p exempt_ptr.
714
715             Depends on \p bucket_type you should or should not lock RCU before calling of this function:
716             - for the set based on \ref cds_intrusive_MichaelList_rcu "MichaelList" RCU should not be locked
717             - for the set based on \ref cds_intrusive_LazyList_rcu "LazyList" RCU should be locked
718             See ordered list implementation for details.
719
720             \code
721             typedef cds::urcu::gc< general_buffered<> > rcu;
722
723             // Split-list set based on MichaelList by default
724             typedef cds::container::SplitListSet< rcu, Foo > splitlist_set;
725
726             splitlist_set theSet;
727             // ...
728
729             splitlist_set::exempt_ptr p;
730
731             // For MichaelList we should not lock RCU
732
733             // Now, you can apply extract function
734             p = theSet.extract( 10 );
735             if ( p ) {
736                 // do something with p
737                 ...
738             }
739
740             // We may safely release p here
741             // release() passes the pointer to RCU reclamation cycle
742             p.release();
743             \endcode
744         */
745         template <typename Q>
746         exempt_ptr extract( Q const& key )
747         {
748             return exempt_ptr( base_class::extract_( key, key_comparator() ));
749         }
750
751         /// Extracts an item from the set using \p pred predicate for searching
752         /**
753             The function is an analog of \p extract(Q const&) but \p pred is used for key comparing.
754             \p Less functor has the interface like \p std::less.
755             \p pred must imply the same element order as the comparator used for building the set.
756         */
757         template <typename Q, typename Less>
758         exempt_ptr extract_with( Q const& key, Less pred )
759         {
760             CDS_UNUSED( pred );
761             return exempt_ptr( base_class::extract_with_( key, typename maker::template predicate_wrapper<Less>::type()));
762         }
763
764         /// Finds the key \p key
765         /** \anchor cds_nonintrusive_SplitListSet_rcu_find_func
766
767             The function searches the item with key equal to \p key and calls the functor \p f for item found.
768             The interface of \p Func functor is:
769             \code
770             struct functor {
771                 void operator()( value_type& item, Q& key );
772             };
773             \endcode
774             where \p item is the item found, \p key is the <tt>find</tt> function argument.
775
776             The functor may change non-key fields of \p item. Note that the functor is only guarantee
777             that \p item cannot be disposed during functor is executing.
778             The functor does not serialize simultaneous access to the set's \p item. If such access is
779             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
780
781             Note the hash functor specified for class \p Traits template parameter
782             should accept a parameter of type \p Q that can be not the same as \p value_type.
783
784             The function makes RCU lock internally.
785
786             The function returns \p true if \p key is found, \p false otherwise.
787         */
788         template <typename Q, typename Func>
789         bool find( Q& key, Func f )
790         {
791             return find_( key, f );
792         }
793         //@cond
794         template <typename Q, typename Func>
795         bool find( Q const& key, Func f )
796         {
797             return find_( key, f );
798         }
799         //@endcond
800
801         /// Finds the key \p key using \p pred predicate for searching
802         /**
803             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_find_func "find(Q&, Func)"
804             but \p pred is used for key comparing.
805             \p Less functor has the interface like \p std::less.
806             \p Less must imply the same element order as the comparator used for building the set.
807         */
808         template <typename Q, typename Less, typename Func>
809         bool find_with( Q& key, Less pred, Func f )
810         {
811             return find_with_( key, pred, f );
812         }
813         //@cond
814         template <typename Q, typename Less, typename Func>
815         bool find_with( Q const& key, Less pred, Func f )
816         {
817             return find_with_( key, pred, f );
818         }
819         //@endcond
820
821         /// Checks whether the set contains \p key
822         /**
823             The function searches the item with key equal to \p key
824             and returns \p true if it is found, and \p false otherwise.
825
826             Note the hash functor specified for class \p Traits template parameter
827             should accept a parameter of type \p Q that can be not the same as \p value_type.
828             Otherwise, you may use \p contains( Q const&, Less pred ) functions with explicit predicate for key comparing.
829
830             The function applies RCU lock internally.
831         */
832         template <typename Q>
833         bool contains( Q const& key )
834         {
835             return base_class::contains( key );
836         }
837         //@cond
838         // Deprecated, use contains()
839         template <typename Q>
840         bool find( Q const& key )
841         {
842             return contains( key );
843         }
844         //@endcond
845
846         /// Checks whether the map contains \p key using \p pred predicate for searching
847         /**
848             The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
849             \p Less functor has the interface like \p std::less.
850             \p Less must imply the same element order as the comparator used for building the map.
851         */
852         template <typename Q, typename Less>
853         bool contains( Q const& key, Less pred )
854         {
855             CDS_UNUSED( pred );
856             return base_class::contains( key, typename maker::template predicate_wrapper<Less>::type() );
857         }
858         //@cond
859         // Deprecated, use contains()
860         template <typename Q, typename Less>
861         bool find_with( Q const& key, Less pred )
862         {
863             return contains( key, pred );
864         }
865         //@endcond
866
867         /// Finds the key \p key and return the item found
868         /** \anchor cds_nonintrusive_SplitListSet_rcu_get
869             The function searches the item with key equal to \p key and returns the pointer to item found.
870             If \p key is not found it returns \p nullptr.
871
872             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
873
874             RCU should be locked before call of this function.
875             Returned item is valid only while RCU is locked:
876             \code
877             typedef cds::urcu::gc< general_buffered<> > rcu;
878             typedef cds::container::SplitListSet< rcu, Foo > splitlist_set;
879             splitlist_set theSet;
880             // ...
881             {
882                 // Lock RCU
883                 splitlist_set::rcu_lock lock;
884
885                 foo * pVal = theSet.get( 5 );
886                 if ( pVal ) {
887                     // Deal with pVal
888                     //...
889                 }
890                 // Unlock RCU by rcu_lock destructor
891                 // pVal can be retired by disposer at any time after RCU has been unlocked
892             }
893             \endcode
894         */
895         template <typename Q>
896         raw_ptr get( Q const& key )
897         {
898             return raw_ptr_maker::make( base_class::get( key ));
899         }
900
901         /// Finds the key \p key and return the item found
902         /**
903             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_get "get(Q const&)"
904             but \p pred is used for comparing the keys.
905
906             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
907             in any order.
908             \p pred must imply the same element order as the comparator used for building the set.
909         */
910         template <typename Q, typename Less>
911         raw_ptr get_with( Q const& key, Less pred )
912         {
913             CDS_UNUSED( pred );
914             return raw_ptr_maker::make( base_class::get_with( key, typename maker::template predicate_wrapper<Less>::type()));
915         }
916
917         /// Clears the set (not atomic)
918         void clear()
919         {
920             base_class::clear();
921         }
922
923         /// Checks if the set is empty
924         /**
925             Emptiness is checked by item counting: if item count is zero then assume that the set is empty.
926             Thus, the correct item counting feature is an important part of split-list set implementation.
927         */
928         bool empty() const
929         {
930             return base_class::empty();
931         }
932
933         /// Returns item count in the set
934         size_t size() const
935         {
936             return base_class::size();
937         }
938
939         /// Returns internal statistics
940         stat const& statistics() const
941         {
942             return base_class::statistics();
943         }
944     };
945 }}  // namespace cds::container
946
947 #endif // #ifndef CDSLIB_CONTAINER_SPLIT_LIST_SET_RCU_H