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