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