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