6b7aa3ae81e65ace33b63d33bb9e9ccc180b075b
[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( typename 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         template <typename Q, typename Func>
584         std::pair<bool, bool> ensure( Q const& val, Func func )
585         {
586             scoped_node_ptr pNode( alloc_node( val ));
587
588             std::pair<bool, bool> bRet = base_class::ensure( *pNode,
589                 [&func, &val]( bool bNew, node_type& item,  node_type const& /*val*/ ) {
590                     func( bNew, item.m_Value, val );
591                 } );
592             if ( bRet.first && bRet.second )
593                 pNode.release();
594             return bRet;
595         }
596
597         /// Deletes \p key from the set
598         /** \anchor cds_nonintrusive_SplitListSet_rcu_erase_val
599
600             Template parameter of type \p Q defines the key type searching in the list.
601             The set item comparator should be able to compare the values of type \p value_type
602             and the type \p Q.
603
604             RCU \p synchronize method can be called. RCU should not be locked.
605
606             Return \p true if key is found and deleted, \p false otherwise
607         */
608         template <typename Q>
609         bool erase( Q const& key )
610         {
611             return base_class::erase( key );
612         }
613
614         /// Deletes the item from the set using \p pred predicate for searching
615         /**
616             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_erase_val "erase(Q const&)"
617             but \p pred is used for key comparing.
618             \p Less functor has the interface like \p std::less.
619             \p Less must imply the same element order as the comparator used for building the set.
620         */
621         template <typename Q, typename Less>
622         bool erase_with( Q const& key, Less pred )
623         {
624             CDS_UNUSED( pred );
625              return base_class::erase_with( key, typename maker::template predicate_wrapper<Less>::type() );
626         }
627
628         /// Deletes \p key from the set
629         /** \anchor cds_nonintrusive_SplitListSet_rcu_erase_func
630
631             The function searches an item with key \p key, calls \p f functor
632             and deletes the item. If \p key is not found, the functor is not called.
633
634             The functor \p Func interface:
635             \code
636             struct extractor {
637                 void operator()(value_type const& val);
638             };
639             \endcode
640
641             Template parameter of type \p Q defines the key type searching in the list.
642             The list item comparator should be able to compare the values of the type \p value_type
643             and the type \p Q.
644
645             RCU \p synchronize method can be called. RCU should not be locked.
646
647             Return \p true if key is found and deleted, \p false otherwise
648         */
649         template <typename Q, typename Func>
650         bool erase( Q const& key, Func f )
651         {
652             return base_class::erase( key, [&f](node_type& node) { f( node.m_Value ); } );
653         }
654
655         /// Deletes the item from the set using \p pred predicate for searching
656         /**
657             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_erase_func "erase(Q const&, Func)"
658             but \p pred is used for key comparing.
659             \p Less functor has the interface like \p std::less.
660             \p Less must imply the same element order as the comparator used for building the set.
661         */
662         template <typename Q, typename Less, typename Func>
663         bool erase_with( Q const& key, Less pred, Func f )
664         {
665             CDS_UNUSED( pred );
666             return base_class::erase_with( key, typename maker::template predicate_wrapper<Less>::type(),
667                 [&f](node_type& node) { f( node.m_Value ); } );
668         }
669
670         /// Extracts an item from the set
671         /** \anchor cds_nonintrusive_SplitListSet_rcu_extract
672             The function searches an item with key equal to \p key in the set,
673             unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
674             If the item with the key equal to \p key is not found the function returns an empty \p exempt_ptr.
675
676             Depends on \p bucket_type you should or should not lock RCU before calling of this function:
677             - for the set based on \ref cds_intrusive_MichaelList_rcu "MichaelList" RCU should not be locked
678             - for the set based on \ref cds_intrusive_LazyList_rcu "LazyList" RCU should be locked
679             See ordered list implementation for details.
680
681             \code
682             typedef cds::urcu::gc< general_buffered<> > rcu;
683
684             // Split-list set based on MichaelList by default
685             typedef cds::container::SplitListSet< rcu, Foo > splitlist_set;
686
687             splitlist_set theSet;
688             // ...
689
690             splitlist_set::exempt_ptr p;
691
692             // For MichaelList we should not lock RCU
693
694             // Now, you can apply extract function
695             p = theSet.extract( 10 );
696             if ( p ) {
697                 // do something with p
698                 ...
699             }
700
701             // We may safely release p here
702             // release() passes the pointer to RCU reclamation cycle
703             p.release();
704             \endcode
705         */
706         template <typename Q>
707         exempt_ptr extract( Q const& key )
708         {
709             return exempt_ptr( base_class::extract_( key, key_comparator() ));
710         }
711
712         /// Extracts an item from the set using \p pred predicate for searching
713         /**
714             The function is an analog of \p extract(Q const&) but \p pred is used for key comparing.
715             \p Less functor has the interface like \p std::less.
716             \p pred must imply the same element order as the comparator used for building the set.
717         */
718         template <typename Q, typename Less>
719         exempt_ptr extract_with( Q const& key, Less pred )
720         {
721             CDS_UNUSED( pred );
722             return exempt_ptr( base_class::extract_with_( key, typename maker::template predicate_wrapper<Less>::type()));
723         }
724
725         /// Finds the key \p key
726         /** \anchor cds_nonintrusive_SplitListSet_rcu_find_func
727
728             The function searches the item with key equal to \p key and calls the functor \p f for item found.
729             The interface of \p Func functor is:
730             \code
731             struct functor {
732                 void operator()( value_type& item, Q& key );
733             };
734             \endcode
735             where \p item is the item found, \p key is the <tt>find</tt> function argument.
736
737             The functor may change non-key fields of \p item. Note that the functor is only guarantee
738             that \p item cannot be disposed during functor is executing.
739             The functor does not serialize simultaneous access to the set's \p item. If such access is
740             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
741
742             Note the hash functor specified for class \p Traits template parameter
743             should accept a parameter of type \p Q that can be not the same as \p value_type.
744
745             The function makes RCU lock internally.
746
747             The function returns \p true if \p key is found, \p false otherwise.
748         */
749         template <typename Q, typename Func>
750         bool find( Q& key, Func f )
751         {
752             return find_( key, f );
753         }
754         //@cond
755         template <typename Q, typename Func>
756         bool find( Q const& key, Func f )
757         {
758             return find_( key, f );
759         }
760         //@endcond
761
762         /// Finds the key \p key using \p pred predicate for searching
763         /**
764             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_find_func "find(Q&, Func)"
765             but \p pred is used for key comparing.
766             \p Less functor has the interface like \p std::less.
767             \p Less must imply the same element order as the comparator used for building the set.
768         */
769         template <typename Q, typename Less, typename Func>
770         bool find_with( Q& key, Less pred, Func f )
771         {
772             return find_with_( key, pred, f );
773         }
774         //@cond
775         template <typename Q, typename Less, typename Func>
776         bool find_with( Q const& key, Less pred, Func f )
777         {
778             return find_with_( key, pred, f );
779         }
780         //@endcond
781
782         /// Finds the key \p key
783         /** \anchor cds_nonintrusive_SplitListSet_rcu_find_val
784
785             The function searches the item with key equal to \p key
786             and returns \p true if it is found, and \p false otherwise.
787
788             Note the hash functor specified for class \p Traits template parameter
789             should accept a parameter of type \p Q that can be not the same as \p value_type.
790
791             The function makes RCU lock internally.
792         */
793         template <typename Q>
794         bool find( Q const& key )
795         {
796             return base_class::find( key );
797         }
798
799         /// Finds the key \p key using \p pred predicate for searching
800         /**
801             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_find_val "find(Q const&)"
802             but \p pred is used for key comparing.
803             \p Less functor has the interface like \p std::less.
804             \p Less must imply the same element order as the comparator used for building the set.
805         */
806         template <typename Q, typename Less>
807         bool find_with( Q const& key, Less pred )
808         {
809             CDS_UNUSED( pred );
810             return base_class::find_with( key, typename maker::template predicate_wrapper<Less>::type() );
811         }
812
813         /// Finds the key \p key and return the item found
814         /** \anchor cds_nonintrusive_SplitListSet_rcu_get
815             The function searches the item with key equal to \p key and returns the pointer to item found.
816             If \p key is not found it returns \p nullptr.
817
818             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
819
820             RCU should be locked before call of this function.
821             Returned item is valid only while RCU is locked:
822             \code
823             typedef cds::urcu::gc< general_buffered<> > rcu;
824             typedef cds::container::SplitListSet< rcu, Foo > splitlist_set;
825             splitlist_set theSet;
826             // ...
827             {
828                 // Lock RCU
829                 splitlist_set::rcu_lock lock;
830
831                 foo * pVal = theSet.get( 5 );
832                 if ( pVal ) {
833                     // Deal with pVal
834                     //...
835                 }
836                 // Unlock RCU by rcu_lock destructor
837                 // pVal can be retired by disposer at any time after RCU has been unlocked
838             }
839             \endcode
840         */
841         template <typename Q>
842         raw_ptr get( Q const& key )
843         {
844             return raw_ptr_maker::make( base_class::get( key ));
845         }
846
847         /// Finds the key \p key and return the item found
848         /**
849             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_get "get(Q const&)"
850             but \p pred is used for comparing the keys.
851
852             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
853             in any order.
854             \p pred must imply the same element order as the comparator used for building the set.
855         */
856         template <typename Q, typename Less>
857         raw_ptr get_with( Q const& key, Less pred )
858         {
859             CDS_UNUSED( pred );
860             return raw_ptr_maker::make( base_class::get_with( key, typename maker::template predicate_wrapper<Less>::type()));
861         }
862
863         /// Clears the set (not atomic)
864         void clear()
865         {
866             base_class::clear();
867         }
868
869         /// Checks if the set is empty
870         /**
871             Emptiness is checked by item counting: if item count is zero then assume that the set is empty.
872             Thus, the correct item counting feature is an important part of split-list set implementation.
873         */
874         bool empty() const
875         {
876             return base_class::empty();
877         }
878
879         /// Returns item count in the set
880         size_t size() const
881         {
882             return base_class::size();
883         }
884
885         /// Returns internal statistics
886         stat const& statistics() const
887         {
888             return base_class::statistics();
889         }
890     };
891 }}  // namespace cds::container
892
893 #endif // #ifndef CDSLIB_CONTAINER_SPLIT_LIST_SET_RCU_H