Improved management of SkipList auxiliary nodes: now aux nodes are allocated from...
[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         //@cond
370         template <bool IsConst>
371         class iterator_type: protected base_class::template iterator_type<IsConst>
372         {
373             typedef typename base_class::template iterator_type<IsConst> iterator_base_class;
374             friend class SplitListSet;
375
376         public:
377             /// Value pointer type (const for const iterator)
378             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
379             /// Value reference type (const for const iterator)
380             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
381
382         public:
383             /// Default ctor
384             iterator_type()
385             {}
386
387             /// Copy ctor
388             iterator_type( iterator_type const& src )
389                 : iterator_base_class( src )
390             {}
391
392         protected:
393             explicit iterator_type( iterator_base_class const& src )
394                 : iterator_base_class( src )
395             {}
396
397         public:
398             /// Dereference operator
399             value_ptr operator ->() const
400             {
401                 return &(iterator_base_class::operator->()->m_Value);
402             }
403
404             /// Dereference operator
405             value_ref operator *() const
406             {
407                 return iterator_base_class::operator*().m_Value;
408             }
409
410             /// Pre-increment
411             iterator_type& operator ++()
412             {
413                 iterator_base_class::operator++();
414                 return *this;
415             }
416
417             /// Assignment operator
418             iterator_type& operator = (iterator_type const& src)
419             {
420                 iterator_base_class::operator=(src);
421                 return *this;
422             }
423
424             /// Equality operator
425             template <bool C>
426             bool operator ==(iterator_type<C> const& i ) const
427             {
428                 return iterator_base_class::operator==(i);
429             }
430
431             /// Equality operator
432             template <bool C>
433             bool operator !=(iterator_type<C> const& i ) const
434             {
435                 return iterator_base_class::operator!=(i);
436             }
437         };
438         //@endcond
439
440     public:
441         /// Initializes split-ordered list of default capacity
442         /**
443             The default capacity is defined in bucket table constructor.
444             See \p intrusive::split_list::expandable_bucket_table, \p intrusive::split_list::static_bucket_table
445             which selects by \p container::split_list::dynamic_bucket_table option.
446         */
447         SplitListSet()
448             : base_class()
449         {}
450
451         /// Initializes split-ordered list
452         SplitListSet(
453             size_t nItemCount           ///< estimated average of item count
454             , size_t nLoadFactor = 1    ///< load factor - average item count per bucket. Small integer up to 8, default is 1.
455             )
456             : base_class( nItemCount, nLoadFactor )
457         {}
458
459     public:
460     ///@name Forward iterators (thread-safe under RCU lock)
461     //@{
462         /// Forward iterator
463         /**
464             The forward iterator for Michael's set is based on \p OrderedList forward iterator and has some features:
465             - it has no post-increment operator
466             - it iterates items in unordered fashion
467
468             You may safely use iterators in multi-threaded environment only under RCU lock.
469             Otherwise, a crash is possible if another thread deletes the element the iterator points to.
470
471             The iterator interface:
472             \code
473             class iterator {
474             public:
475                 // Default constructor
476                 iterator();
477
478                 // Copy construtor
479                 iterator( iterator const& src );
480
481                 // Dereference operator
482                 value_type * operator ->() const;
483
484                 // Dereference operator
485                 value_type& operator *() const;
486
487                 // Preincrement operator
488                 iterator& operator ++();
489
490                 // Assignment operator
491                 iterator& operator = (iterator const& src);
492
493                 // Equality operators
494                 bool operator ==(iterator const& i ) const;
495                 bool operator !=(iterator const& i ) const;
496             };
497             \endcode
498         */
499         typedef iterator_type<false>  iterator;
500
501         /// Forward const iterator
502         typedef iterator_type<true>   const_iterator;
503
504         /// Returns a forward iterator addressing the first element in a set
505         /**
506             For empty set \code begin() == end() \endcode
507         */
508         iterator begin()
509         {
510             return iterator( base_class::begin() );
511         }
512
513         /// Returns an iterator that addresses the location succeeding the last element in a set
514         /**
515             Do not use the value returned by <tt>end</tt> function to access any item.
516             The returned value can be used only to control reaching the end of the set.
517             For empty set \code begin() == end() \endcode
518         */
519         iterator end()
520         {
521             return iterator( base_class::end() );
522         }
523
524         /// Returns a forward const iterator addressing the first element in a set
525         const_iterator begin() const
526         {
527             return cbegin();
528         }
529         /// Returns a forward const iterator addressing the first element in a set
530         const_iterator cbegin() const
531         {
532             return const_iterator( base_class::cbegin() );
533         }
534
535         /// Returns an const iterator that addresses the location succeeding the last element in a set
536         const_iterator end() const
537         {
538             return cend();
539         }
540         /// Returns an const iterator that addresses the location succeeding the last element in a set
541         const_iterator cend() const
542         {
543             return const_iterator( base_class::cend() );
544         }
545     //@}
546
547     public:
548         /// Inserts new node
549         /**
550             The function creates a node with copy of \p val value
551             and then inserts the node created into the set.
552
553             The type \p Q should contain as minimum the complete key for the node.
554             The object of \p value_type should be constructible from a value of type \p Q.
555             In trivial case, \p Q is equal to \p value_type.
556
557             The function applies RCU lock internally.
558
559             Returns \p true if \p val is inserted into the set, \p false otherwise.
560         */
561         template <typename Q>
562         bool insert( Q const& val )
563         {
564             return insert_node( alloc_node( val ) );
565         }
566
567         /// Inserts new node
568         /**
569             The function allows to split creating of new item into two part:
570             - create item with key only
571             - insert new item into the set
572             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
573
574             The functor signature is:
575             \code
576                 void func( value_type& val );
577             \endcode
578             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
579             \p val no any other changes could be made on this set's item by concurrent threads.
580             The user-defined functor is called only if the inserting is success.
581
582             The function applies RCU lock internally.
583         */
584         template <typename Q, typename Func>
585         bool insert( Q const& key, Func f )
586         {
587             scoped_node_ptr pNode( alloc_node( key ));
588
589             if ( base_class::insert( *pNode, [&f](node_type& node) { f( node.m_Value ) ; } )) {
590                 pNode.release();
591                 return true;
592             }
593             return false;
594         }
595
596         /// Inserts data of type \p value_type created from \p args
597         /**
598             Returns \p true if inserting successful, \p false otherwise.
599
600             The function applies RCU lock internally.
601         */
602         template <typename... Args>
603         bool emplace( Args&&... args )
604         {
605             return insert_node( alloc_node( std::forward<Args>(args)...));
606         }
607
608         /// Updates an element with given \p val
609         /**
610             The operation performs inserting or changing data with lock-free manner.
611
612             If the \p val key not found in the set, then the new item created from \p val
613             is inserted into the set. Otherwise, the functor \p func is called with the item found.
614             The functor \p Func 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 %ensure() function
625
626             The functor may change non-key fields of the \p item; however, \p func must guarantee
627             that during changing no any other modifications could be made on this item by concurrent threads.
628
629             The function applies RCU lock internally.
630
631             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
632             \p second is true if new item has been added or \p false if the item with \p key
633             already is in the set.
634         */
635         /// Updates the node
636         /**
637             The operation performs inserting or changing data with lock-free manner.
638
639             If \p key is not found in the set, then \p key is inserted iff \p bAllowInsert is \p true.
640             Otherwise, the functor \p func is called with item found.
641
642             The functor signature is:
643             \code
644                 struct my_functor {
645                     void operator()( bool bNew, value_type& item, const Q& val );
646                 };
647             \endcode
648
649             with arguments:
650             - \p bNew - \p true if the item has been inserted, \p false otherwise
651             - \p item - item of the set
652             - \p val - argument \p val passed into the \p %update() function
653
654             The functor may change non-key fields of the \p item.
655
656             The function applies RCU lock internally.
657
658             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
659             \p second is true if new item has been added or \p false if the item with \p key
660             already is in the map.
661
662             @warning For \ref cds_intrusive_MichaelList_rcu "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
663             \ref cds_intrusive_LazyList_rcu "LazyList" provides exclusive access to inserted item and does not require any node-level
664             synchronization.
665         */
666         template <typename Q, typename Func>
667         std::pair<bool, bool> update( Q const& val, Func func, bool bAllowInsert = true )
668         {
669             scoped_node_ptr pNode( alloc_node( val ));
670
671             std::pair<bool, bool> bRet = base_class::update( *pNode,
672                 [&func, &val]( bool bNew, node_type& item,  node_type const& /*val*/ ) {
673                     func( bNew, item.m_Value, val );
674                 }, bAllowInsert );
675             if ( bRet.first && bRet.second )
676                 pNode.release();
677             return bRet;
678         }
679         //@cond
680         // Dprecated, use update()
681         template <typename Q, typename Func>
682         std::pair<bool, bool> ensure( Q const& val, Func func )
683         {
684             return update( val, func, true );
685         }
686         //@endcond
687
688         /// Deletes \p key from the set
689         /** \anchor cds_nonintrusive_SplitListSet_rcu_erase_val
690
691             Template parameter of type \p Q defines the key type searching in the list.
692             The set item comparator should be able to compare the values of type \p value_type
693             and the type \p Q.
694
695             RCU \p synchronize method can be called. RCU should not be locked.
696
697             Return \p true if key is found and deleted, \p false otherwise
698         */
699         template <typename Q>
700         bool erase( Q const& key )
701         {
702             return base_class::erase( key );
703         }
704
705         /// Deletes the item from the set using \p pred predicate for searching
706         /**
707             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_erase_val "erase(Q const&)"
708             but \p pred is used for key comparing.
709             \p Less functor has the interface like \p std::less.
710             \p Less must imply the same element order as the comparator used for building the set.
711         */
712         template <typename Q, typename Less>
713         bool erase_with( Q const& key, Less pred )
714         {
715             CDS_UNUSED( pred );
716              return base_class::erase_with( key, typename maker::template predicate_wrapper<Less>::type() );
717         }
718
719         /// Deletes \p key from the set
720         /** \anchor cds_nonintrusive_SplitListSet_rcu_erase_func
721
722             The function searches an item with key \p key, calls \p f functor
723             and deletes the item. If \p key is not found, the functor is not called.
724
725             The functor \p Func interface:
726             \code
727             struct extractor {
728                 void operator()(value_type const& val);
729             };
730             \endcode
731
732             Template parameter of type \p Q defines the key type searching in the list.
733             The list item comparator should be able to compare the values of the type \p value_type
734             and the type \p Q.
735
736             RCU \p synchronize method can be called. RCU should not be locked.
737
738             Return \p true if key is found and deleted, \p false otherwise
739         */
740         template <typename Q, typename Func>
741         bool erase( Q const& key, Func f )
742         {
743             return base_class::erase( key, [&f](node_type& node) { f( node.m_Value ); } );
744         }
745
746         /// Deletes the item from the set using \p pred predicate for searching
747         /**
748             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_erase_func "erase(Q const&, Func)"
749             but \p pred is used for key comparing.
750             \p Less functor has the interface like \p std::less.
751             \p Less must imply the same element order as the comparator used for building the set.
752         */
753         template <typename Q, typename Less, typename Func>
754         bool erase_with( Q const& key, Less pred, Func f )
755         {
756             CDS_UNUSED( pred );
757             return base_class::erase_with( key, typename maker::template predicate_wrapper<Less>::type(),
758                 [&f](node_type& node) { f( node.m_Value ); } );
759         }
760
761         /// Extracts an item from the set
762         /** \anchor cds_nonintrusive_SplitListSet_rcu_extract
763             The function searches an item with key equal to \p key in the set,
764             unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
765             If the item with the key equal to \p key is not found the function returns an empty \p exempt_ptr.
766
767             Depends on \p bucket_type you should or should not lock RCU before calling of this function:
768             - for the set based on \ref cds_intrusive_MichaelList_rcu "MichaelList" RCU should not be locked
769             - for the set based on \ref cds_intrusive_LazyList_rcu "LazyList" RCU should be locked
770             See ordered list implementation for details.
771
772             \code
773             typedef cds::urcu::gc< general_buffered<> > rcu;
774
775             // Split-list set based on MichaelList by default
776             typedef cds::container::SplitListSet< rcu, Foo > splitlist_set;
777
778             splitlist_set theSet;
779             // ...
780
781             splitlist_set::exempt_ptr p;
782
783             // For MichaelList we should not lock RCU
784
785             // Now, you can apply extract function
786             p = theSet.extract( 10 );
787             if ( p ) {
788                 // do something with p
789                 ...
790             }
791
792             // We may safely release p here
793             // release() passes the pointer to RCU reclamation cycle
794             p.release();
795             \endcode
796         */
797         template <typename Q>
798         exempt_ptr extract( Q const& key )
799         {
800             return exempt_ptr( base_class::extract_( key, key_comparator() ));
801         }
802
803         /// Extracts an item from the set using \p pred predicate for searching
804         /**
805             The function is an analog of \p extract(Q const&) but \p pred is used for key comparing.
806             \p Less functor has the interface like \p std::less.
807             \p pred must imply the same element order as the comparator used for building the set.
808         */
809         template <typename Q, typename Less>
810         exempt_ptr extract_with( Q const& key, Less pred )
811         {
812             CDS_UNUSED( pred );
813             return exempt_ptr( base_class::extract_with_( key, typename maker::template predicate_wrapper<Less>::type()));
814         }
815
816         /// Finds the key \p key
817         /** \anchor cds_nonintrusive_SplitListSet_rcu_find_func
818
819             The function searches the item with key equal to \p key and calls the functor \p f for item found.
820             The interface of \p Func functor is:
821             \code
822             struct functor {
823                 void operator()( value_type& item, Q& key );
824             };
825             \endcode
826             where \p item is the item found, \p key is the <tt>find</tt> function argument.
827
828             The functor may change non-key fields of \p item. Note that the functor is only guarantee
829             that \p item cannot be disposed during functor is executing.
830             The functor does not serialize simultaneous access to the set's \p item. If such access is
831             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
832
833             Note the hash functor specified for class \p Traits template parameter
834             should accept a parameter of type \p Q that can be not the same as \p value_type.
835
836             The function makes RCU lock internally.
837
838             The function returns \p true if \p key is found, \p false otherwise.
839         */
840         template <typename Q, typename Func>
841         bool find( Q& key, Func f )
842         {
843             return find_( key, f );
844         }
845         //@cond
846         template <typename Q, typename Func>
847         bool find( Q const& key, Func f )
848         {
849             return find_( key, f );
850         }
851         //@endcond
852
853         /// Finds the key \p key using \p pred predicate for searching
854         /**
855             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_find_func "find(Q&, Func)"
856             but \p pred is used for key comparing.
857             \p Less functor has the interface like \p std::less.
858             \p Less must imply the same element order as the comparator used for building the set.
859         */
860         template <typename Q, typename Less, typename Func>
861         bool find_with( Q& key, Less pred, Func f )
862         {
863             return find_with_( key, pred, f );
864         }
865         //@cond
866         template <typename Q, typename Less, typename Func>
867         bool find_with( Q const& key, Less pred, Func f )
868         {
869             return find_with_( key, pred, f );
870         }
871         //@endcond
872
873         /// Checks whether the set contains \p key
874         /**
875             The function searches the item with key equal to \p key
876             and returns \p true if it is found, and \p false otherwise.
877
878             Note the hash functor specified for class \p Traits template parameter
879             should accept a parameter of type \p Q that can be not the same as \p value_type.
880             Otherwise, you may use \p contains( Q const&, Less pred ) functions with explicit predicate for key comparing.
881
882             The function applies RCU lock internally.
883         */
884         template <typename Q>
885         bool contains( Q const& key )
886         {
887             return base_class::contains( key );
888         }
889         //@cond
890         template <typename Q>
891         CDS_DEPRECATED("deprecated, use contains()")
892         bool find( Q const& key )
893         {
894             return contains( key );
895         }
896         //@endcond
897
898         /// Checks whether the map contains \p key using \p pred predicate for searching
899         /**
900             The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
901             \p Less functor has the interface like \p std::less.
902             \p Less must imply the same element order as the comparator used for building the map.
903         */
904         template <typename Q, typename Less>
905         bool contains( Q const& key, Less pred )
906         {
907             CDS_UNUSED( pred );
908             return base_class::contains( key, typename maker::template predicate_wrapper<Less>::type() );
909         }
910         //@cond
911         template <typename Q, typename Less>
912         CDS_DEPRECATED("deprecated, use contains()")
913         bool find_with( Q const& key, Less pred )
914         {
915             return contains( key, pred );
916         }
917         //@endcond
918
919         /// Finds the key \p key and return the item found
920         /** \anchor cds_nonintrusive_SplitListSet_rcu_get
921             The function searches the item with key equal to \p key and returns the pointer to item found.
922             If \p key is not found it returns \p nullptr.
923
924             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
925
926             RCU should be locked before call of this function.
927             Returned item is valid only while RCU is locked:
928             \code
929             typedef cds::urcu::gc< general_buffered<> > rcu;
930             typedef cds::container::SplitListSet< rcu, Foo > splitlist_set;
931             splitlist_set theSet;
932             // ...
933             {
934                 // Lock RCU
935                 splitlist_set::rcu_lock lock;
936
937                 foo * pVal = theSet.get( 5 );
938                 if ( pVal ) {
939                     // Deal with pVal
940                     //...
941                 }
942                 // Unlock RCU by rcu_lock destructor
943                 // pVal can be retired by disposer at any time after RCU has been unlocked
944             }
945             \endcode
946         */
947         template <typename Q>
948         raw_ptr get( Q const& key )
949         {
950             return raw_ptr_maker::make( base_class::get( key ));
951         }
952
953         /// Finds the key \p key and return the item found
954         /**
955             The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_get "get(Q const&)"
956             but \p pred is used for comparing the keys.
957
958             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
959             in any order.
960             \p pred must imply the same element order as the comparator used for building the set.
961         */
962         template <typename Q, typename Less>
963         raw_ptr get_with( Q const& key, Less pred )
964         {
965             CDS_UNUSED( pred );
966             return raw_ptr_maker::make( base_class::get_with( key, typename maker::template predicate_wrapper<Less>::type()));
967         }
968
969         /// Clears the set (not atomic)
970         void clear()
971         {
972             base_class::clear();
973         }
974
975         /// Checks if the set is empty
976         /**
977             Emptiness is checked by item counting: if item count is zero then assume that the set is empty.
978             Thus, the correct item counting feature is an important part of split-list set implementation.
979         */
980         bool empty() const
981         {
982             return base_class::empty();
983         }
984
985         /// Returns item count in the set
986         size_t size() const
987         {
988             return base_class::size();
989         }
990
991         /// Returns internal statistics
992         stat const& statistics() const
993         {
994             return base_class::statistics();
995         }
996     };
997 }}  // namespace cds::container
998
999 #endif // #ifndef CDSLIB_CONTAINER_SPLIT_LIST_SET_RCU_H