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