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