* SkipListMap, SkipListSet:
[libcds.git] / cds / container / skip_list_set_rcu.h
1 //$$CDS-header$$
2
3 #ifndef CDSLIB_CONTAINER_SKIP_LIST_SET_RCU_H
4 #define CDSLIB_CONTAINER_SKIP_LIST_SET_RCU_H
5
6 #include <cds/intrusive/skip_list_rcu.h>
7 #include <cds/container/details/make_skip_list_set.h>
8
9 namespace cds { namespace container {
10
11     /// Lock-free skip-list set (template specialization for \ref cds_urcu_desc "RCU")
12     /** @ingroup cds_nonintrusive_set
13         \anchor cds_nonintrusive_SkipListSet_rcu
14
15         The implementation of well-known probabilistic data structure called skip-list
16         invented by W.Pugh in his papers:
17             - [1989] W.Pugh Skip Lists: A Probabilistic Alternative to Balanced Trees
18             - [1990] W.Pugh A Skip List Cookbook
19
20         A skip-list is a probabilistic data structure that provides expected logarithmic
21         time search without the need of rebalance. The skip-list is a collection of sorted
22         linked list. Nodes are ordered by key. Each node is linked into a subset of the lists.
23         Each list has a level, ranging from 0 to 32. The bottom-level list contains
24         all the nodes, and each higher-level list is a sublist of the lower-level lists.
25         Each node is created with a random top level (with a random height), and belongs
26         to all lists up to that level. The probability that a node has the height 1 is 1/2.
27         The probability that a node has the height N is 1/2 ** N (more precisely,
28         the distribution depends on an random generator provided, but our generators
29         have this property).
30
31         The lock-free variant of skip-list is implemented according to book
32             - [2008] M.Herlihy, N.Shavit "The Art of Multiprocessor Programming",
33                 chapter 14.4 "A Lock-Free Concurrent Skiplist"
34
35         Template arguments:
36         - \p RCU - one of \ref cds_urcu_gc "RCU type".
37         - \p T - type to be stored in the list.
38         - \p Traits - set traits, default is skip_list::traits for explanation.
39
40         It is possible to declare option-based list with cds::container::skip_list::make_traits metafunction istead of \p Traits template
41         argument.
42         Template argument list \p Options of cds::container::skip_list::make_traits metafunction are:
43         - opt::compare - key comparison functor. No default functor is provided.
44             If the option is not specified, the opt::less is used.
45         - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
46         - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that is no item counting.
47         - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
48             or opt::v::sequential_consistent (sequentially consisnent memory model).
49         - skip_list::random_level_generator - random level generator. Can be skip_list::xorshift, skip_list::turbo_pascal or
50             user-provided one. See skip_list::random_level_generator option description for explanation.
51             Default is \p %skip_list::turbo_pascal.
52         - opt::allocator - allocator for skip-list node. Default is \ref CDS_DEFAULT_ALLOCATOR.
53         - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::Default is used.
54         - opt::stat - internal statistics. Available types: skip_list::stat, skip_list::empty_stat (the default)
55         - opt::rcu_check_deadlock - a deadlock checking policy. Default is opt::v::rcu_throw_deadlock
56
57         @note Before including <tt><cds/container/skip_list_set_rcu.h></tt> you should include appropriate RCU header file,
58         see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
59
60         <b>Iterators</b>
61
62         The class supports a forward iterator (\ref iterator and \ref const_iterator).
63         The iteration is ordered.
64
65         You may iterate over skip-list set items only under RCU lock.
66         Only in this case the iterator is thread-safe since
67         while RCU is locked any set's item cannot be reclaimed.
68
69         The requirement of RCU lock during iterating means that deletion of the elements (i.e. \ref erase)
70         is not possible.
71
72         @warning The iterator object cannot be passed between threads
73
74         Example how to use skip-list set iterators:
75         \code
76         // First, you should include the header for RCU type you have chosen
77         #include <cds/urcu/general_buffered.h>
78         #include <cds/container/skip_list_set_rcu.h>
79
80         typedef cds::urcu::gc< cds::urcu::general_buffered<> > rcu_type;
81
82         struct Foo {
83             // ...
84         };
85
86         // Traits for your skip-list.
87         // At least, you should define cds::opt::less or cds::opt::compare for Foo struct
88         struct my_traits: public cds::continer::skip_list::traits
89         {
90             // ...
91         };
92         typedef cds::container::SkipListSet< rcu_type, Foo, my_traits > my_skiplist_set;
93
94         my_skiplist_set theSet;
95
96         // ...
97
98         // Begin iteration
99         {
100             // Apply RCU locking manually
101             typename rcu_type::scoped_lock sl;
102
103             for ( auto it = theList.begin(); it != theList.end(); ++it ) {
104                 // ...
105             }
106
107             // rcu_type::scoped_lock destructor releases RCU lock implicitly
108         }
109         \endcode
110
111         \warning Due to concurrent nature of skip-list set it is not guarantee that you can iterate
112         all elements in the set: any concurrent deletion can exclude the element
113         pointed by the iterator from the set, and your iteration can be terminated
114         before end of the set. Therefore, such iteration is more suitable for debugging purposes
115
116         The iterator class supports the following minimalistic interface:
117         \code
118         struct iterator {
119             // Default ctor
120             iterator();
121
122             // Copy ctor
123             iterator( iterator const& s);
124
125             value_type * operator ->() const;
126             value_type& operator *() const;
127
128             // Pre-increment
129             iterator& operator ++();
130
131             // Copy assignment
132             iterator& operator = (const iterator& src);
133
134             bool operator ==(iterator const& i ) const;
135             bool operator !=(iterator const& i ) const;
136         };
137         \endcode
138         Note, the iterator object returned by \ref end, \p cend member functions points to \p nullptr and should not be dereferenced.
139     */
140     template <
141         typename RCU,
142         typename T,
143 #ifdef CDS_DOXYGEN_INVOKED
144         typename Traits = skip_list::traits
145 #else
146         typename Traits
147 #endif
148     >
149     class SkipListSet< cds::urcu::gc< RCU >, T, Traits >:
150 #ifdef CDS_DOXYGEN_INVOKED
151         protected intrusive::SkipListSet< cds::urcu::gc< RCU >, T, Traits >
152 #else
153         protected details::make_skip_list_set< cds::urcu::gc< RCU >, T, Traits >::type
154 #endif
155     {
156         //@cond
157         typedef details::make_skip_list_set< cds::urcu::gc< RCU >, T, Traits >    maker;
158         typedef typename maker::type base_class;
159         //@endcond
160     public:
161         typedef typename base_class::gc gc  ; ///< Garbage collector used
162         typedef T       value_type  ;   ///< Value type stored in the set
163         typedef Traits  traits     ;   ///< Options specified
164
165         typedef typename base_class::back_off       back_off        ;   ///< Back-off strategy used
166         typedef typename traits::allocator         allocator_type  ;   ///< Allocator type used for allocate/deallocate the skip-list nodes
167         typedef typename base_class::item_counter   item_counter    ;   ///< Item counting policy used
168         typedef typename maker::key_comparator      key_comparator  ;   ///< key compare functor
169         typedef typename base_class::memory_model   memory_model    ;   ///< Memory ordering. See cds::opt::memory_model option
170         typedef typename traits::random_level_generator random_level_generator ; ///< random level generator
171         typedef typename traits::stat              stat            ;   ///< internal statistics type
172         typedef typename traits::rcu_check_deadlock    rcu_check_deadlock ; ///< Deadlock checking policy
173
174         //@cond
175         typedef cds::container::skip_list::implementation_tag implementation_tag;
176         //@endcond
177
178     protected:
179         //@cond
180         typedef typename maker::node_type           node_type;
181         typedef typename maker::node_allocator      node_allocator;
182
183         typedef std::unique_ptr< node_type, typename maker::node_deallocator >    scoped_node_ptr;
184         //@endcond
185
186     public:
187         typedef typename base_class::rcu_lock  rcu_lock;   ///< RCU scoped lock
188         /// Group of \p extract_xxx functions do not require external locking
189         static CDS_CONSTEXPR const bool c_bExtractLockExternal = base_class::c_bExtractLockExternal;
190
191         /// pointer to extracted node
192         using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_traits::disposer >;
193
194     private:
195         //@cond
196         struct raw_ptr_converter
197         {
198             value_type * operator()( node_type * p ) const
199             {
200                return p ? &p->m_Value : nullptr;
201             }
202
203             value_type& operator()( node_type& n ) const
204             {
205                 return n.m_Value;
206             }
207
208             value_type const& operator()( node_type const& n ) const
209             {
210                 return n.m_Value;
211             }
212         };
213         //@endcond
214
215     public:
216         /// Result of \p get(), \p get_with() functions - pointer to the node found
217         typedef cds::urcu::raw_ptr_adaptor< value_type, typename base_class::raw_ptr, raw_ptr_converter > raw_ptr;
218
219     protected:
220         //@cond
221         unsigned int random_level()
222         {
223             return base_class::random_level();
224         }
225         //@endcond
226
227     public:
228         /// Default ctor
229         SkipListSet()
230             : base_class()
231         {}
232
233         /// Destructor destroys the set object
234         ~SkipListSet()
235         {}
236
237     public:
238         /// Iterator type
239         typedef skip_list::details::iterator< typename base_class::iterator >  iterator;
240
241         /// Const iterator type
242         typedef skip_list::details::iterator< typename base_class::const_iterator >   const_iterator;
243
244         /// Returns a forward iterator addressing the first element in a set
245         iterator begin()
246         {
247             return iterator( base_class::begin() );
248         }
249
250         /// Returns a forward const iterator addressing the first element in a set
251         //@{
252         const_iterator begin() const
253         {
254             return const_iterator( base_class::begin() );
255         }
256         const_iterator cbegin() const
257         {
258             return const_iterator( base_class::cbegin() );
259         }
260         //@}
261
262         /// Returns a forward iterator that addresses the location succeeding the last element in a set.
263         iterator end()
264         {
265             return iterator( base_class::end() );
266         }
267
268         /// Returns a forward const iterator that addresses the location succeeding the last element in a set.
269         //@{
270         const_iterator end() const
271         {
272             return const_iterator( base_class::end() );
273         }
274         const_iterator cend() const
275         {
276             return const_iterator( base_class::cend() );
277         }
278         //@}
279
280     public:
281         /// Inserts new node
282         /**
283             The function creates a node with copy of \p val value
284             and then inserts the node created into the set.
285
286             The type \p Q should contain as minimum the complete key for the node.
287             The object of \ref value_type should be constructible from a value of type \p Q.
288             In trivial case, \p Q is equal to \ref value_type.
289
290             RCU \p synchronize method can be called. RCU should not be locked.
291
292             Returns \p true if \p val is inserted into the set, \p false otherwise.
293         */
294         template <typename Q>
295         bool insert( Q const& val )
296         {
297             scoped_node_ptr sp( node_allocator().New( random_level(), val ));
298             if ( base_class::insert( *sp.get() )) {
299                 sp.release();
300                 return true;
301             }
302             return false;
303         }
304
305         /// Inserts new node
306         /**
307             The function allows to split creating of new item into two part:
308             - create item with key only
309             - insert new item into the set
310             - if inserting is success, calls  \p f functor to initialize value-fields of \p val.
311
312             The functor signature is:
313             \code
314                 void func( value_type& val );
315             \endcode
316             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
317             \p val no any other changes could be made on this set's item by concurrent threads.
318             The user-defined functor is called only if the inserting is success.
319
320             RCU \p synchronize method can be called. RCU should not be locked.
321         */
322         template <typename Q, typename Func>
323         bool insert( Q const& val, Func f )
324         {
325             scoped_node_ptr sp( node_allocator().New( random_level(), val ));
326             if ( base_class::insert( *sp.get(), [&f]( node_type& val ) { f( val.m_Value ); } )) {
327                 sp.release();
328                 return true;
329             }
330             return false;
331         }
332
333         /// Updates the item
334         /**
335             The operation performs inserting or changing data with lock-free manner.
336
337             If \p val not found in the set, then the new item created from \p val
338             is inserted into the set iff \p bInsert is \p true.
339             Otherwise, the functor \p func is called with the item found.
340             The functor \p Func signature:
341             \code
342                 struct my_functor {
343                     void operator()( bool bNew, value_type& item, const Q& val );
344                 };
345             \endcode
346             where:
347             - \p bNew - \p true if the item has been inserted, \p false otherwise
348             - \p item - an item of the set
349             - \p val - argument \p val passed into the \p %update() function
350
351             The functor may change non-key fields of the \p item; however, \p func must guarantee
352             that during changing no any other modifications could be made on this item by concurrent threads.
353
354             RCU \p synchronize method can be called. RCU should not be locked.
355
356             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
357             \p second is true if new item has been added or \p false if the item with \p key
358             already exists.
359         */
360         template <typename Q, typename Func>
361         std::pair<bool, bool> update( const Q& val, Func func, bool bInsert = true )
362         {
363             scoped_node_ptr sp( node_allocator().New( random_level(), val ));
364             std::pair<bool, bool> bRes = base_class::update( *sp,
365                 [&func, &val](bool bNew, node_type& node, node_type&){ func( bNew, node.m_Value, val );}, bInsert );
366             if ( bRes.first && bRes.second )
367                 sp.release();
368             return bRes;
369         }
370         //@cond
371         // Deprecated, use update()
372         template <typename Q, typename Func>
373         std::pair<bool, bool> ensure( const Q& val, Func func )
374         {
375             return update( val, func, true );
376         }
377         //@endcond
378
379         /// Inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
380         /**
381             Returns \p true if inserting successful, \p false otherwise.
382
383             RCU \p synchronize method can be called. RCU should not be locked.
384         */
385         template <typename... Args>
386         bool emplace( Args&&... args )
387         {
388             scoped_node_ptr sp( node_allocator().New( random_level(), std::forward<Args>(args)... ));
389             if ( base_class::insert( *sp.get() )) {
390                 sp.release();
391                 return true;
392             }
393             return false;
394         }
395
396         /// Delete \p key from the set
397         /** \anchor cds_nonintrusive_SkipListSet_rcu_erase_val
398
399             The item comparator should be able to compare the type \p value_type
400             and the type \p Q.
401
402             RCU \p synchronize method can be called. RCU should not be locked.
403
404             Return \p true if key is found and deleted, \p false otherwise
405         */
406         template <typename Q>
407         bool erase( Q const& key )
408         {
409             return base_class::erase( key );
410         }
411
412         /// Deletes the item from the set using \p pred predicate for searching
413         /**
414             The function is an analog of \ref cds_nonintrusive_SkipListSet_rcu_erase_val "erase(Q const&)"
415             but \p pred is used for key comparing.
416             \p Less functor has the interface like \p std::less.
417             \p Less must imply the same element order as the comparator used for building the set.
418         */
419         template <typename Q, typename Less>
420         bool erase_with( Q const& key, Less pred )
421         {
422             CDS_UNUSED( pred );
423             return base_class::erase_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor >());
424         }
425
426         /// Delete \p key from the set
427         /** \anchor cds_nonintrusive_SkipListSet_rcu_erase_func
428
429             The function searches an item with key \p key, calls \p f functor
430             and deletes the item. If \p key is not found, the functor is not called.
431
432             The functor \p Func interface:
433             \code
434             struct extractor {
435                 void operator()(value_type const& val);
436             };
437             \endcode
438
439             Since the key of MichaelHashSet's \p value_type is not explicitly specified,
440             template parameter \p Q defines the key type searching in the list.
441             The list item comparator should be able to compare the type \p T of list item
442             and the type \p Q.
443
444             RCU \p synchronize method can be called. RCU should not be locked.
445
446             Return \p true if key is found and deleted, \p false otherwise
447
448             See also: \ref erase
449         */
450         template <typename Q, typename Func>
451         bool erase( Q const& key, Func f )
452         {
453             return base_class::erase( key, [&f]( node_type const& node) { f( node.m_Value ); } );
454         }
455
456         /// Deletes the item from the set using \p pred predicate for searching
457         /**
458             The function is an analog of \ref cds_nonintrusive_SkipListSet_rcu_erase_func "erase(Q const&, Func)"
459             but \p pred is used for key comparing.
460             \p Less functor has the interface like \p std::less.
461             \p Less must imply the same element order as the comparator used for building the set.
462         */
463         template <typename Q, typename Less, typename Func>
464         bool erase_with( Q const& key, Less pred, Func f )
465         {
466             CDS_UNUSED( pred );
467             return base_class::erase_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor >(),
468                 [&f]( node_type const& node) { f( node.m_Value ); } );
469         }
470
471         /// Extracts the item from the set with specified \p key
472         /** \anchor cds_nonintrusive_SkipListSet_rcu_extract
473             The function searches an item with key equal to \p key in the set,
474             unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
475             If the item is not found the function returns an empty \p exempt_ptr
476
477             Note the compare functor from \p Traits class' template argument
478             should accept a parameter of type \p Q that can be not the same as \p value_type.
479
480             RCU \p synchronize method can be called. RCU should NOT be locked.
481
482             The function does not free the item found.
483             The item will be implicitly freed when the returned object is destroyed or when
484             its \p release() member function is called.
485         */
486         template <typename Q>
487         exempt_ptr extract( Q const& key )
488         {
489             return exempt_ptr( base_class::do_extract( key ));
490         }
491
492         /// Extracts the item from the set with comparing functor \p pred
493         /**
494             The function is an analog of \p extract(Q const&) but \p pred predicate is used for key comparing.
495             \p Less has the semantics like \p std::less.
496             \p pred must imply the same element order as the comparator used for building the set.
497         */
498         template <typename Q, typename Less>
499         exempt_ptr extract_with( Q const& key, Less pred )
500         {
501             CDS_UNUSED( pred );
502             return exempt_ptr( base_class::do_extract_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor >()));
503         }
504
505         /// Extracts an item with minimal key from the set
506         /**
507             The function searches an item with minimal key, unlinks it,
508             and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item.
509             If the skip-list is empty the function returns an empty \p exempt_ptr.
510
511             RCU \p synchronize method can be called. RCU should NOT be locked.
512
513             The function does not free the item found.
514             The item will be implicitly freed when the returned object is destroyed or when
515             its \p release() member function is called.
516         */
517         exempt_ptr extract_min()
518         {
519             return exempt_ptr( base_class::do_extract_min());
520         }
521
522         /// Extracts an item with maximal key from the set
523         /**
524             The function searches an item with maximal key, unlinks it from the set,
525             and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item.
526             If the skip-list is empty the function returns an empty \p exempt_ptr.
527
528             RCU \p synchronize method can be called. RCU should NOT be locked.
529
530             The function does not free the item found.
531             The item will be implicitly freed when the returned object is destroyed or when
532             its \p release() member function is called.
533         */
534         exempt_ptr extract_max()
535         {
536             return exempt_ptr( base_class::do_extract_max());
537         }
538
539         /// Find the key \p val
540         /**
541             @anchor cds_nonintrusive_SkipListSet_rcu_find_func
542
543             The function searches the item with key equal to \p val and calls the functor \p f for item found.
544             The interface of \p Func functor is:
545             \code
546             struct functor {
547                 void operator()( value_type& item, Q& val );
548             };
549             \endcode
550             where \p item is the item found, \p val is the <tt>find</tt> function argument.
551
552             The functor may change non-key fields of \p item. Note that the functor is only guarantee
553             that \p item cannot be disposed during functor is executing.
554             The functor does not serialize simultaneous access to the set's \p item. If such access is
555             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
556
557             The \p val argument is non-const since it can be used as \p f functor destination i.e., the functor
558             can modify both arguments.
559
560             Note the hash functor specified for class \p Traits template parameter
561             should accept a parameter of type \p Q that may be not the same as \p value_type.
562
563             The function applies RCU lock internally.
564
565             The function returns \p true if \p val is found, \p false otherwise.
566         */
567         template <typename Q, typename Func>
568         bool find( Q& val, Func f )
569         {
570             return base_class::find( val, [&f]( node_type& node, Q& v ) { f( node.m_Value, v ); });
571         }
572         //@cond
573         template <typename Q, typename Func>
574         bool find( Q const& val, Func f )
575         {
576             return base_class::find( val, [&f]( node_type& node, Q& v ) { f( node.m_Value, v ); } );
577         }
578         //@endcond
579
580         /// Finds the key \p val using \p pred predicate for searching
581         /**
582             The function is an analog of \ref cds_nonintrusive_SkipListSet_rcu_find_func "find(Q&, Func)"
583             but \p pred is used for key comparing.
584             \p Less functor has the interface like \p std::less.
585             \p Less must imply the same element order as the comparator used for building the set.
586         */
587         template <typename Q, typename Less, typename Func>
588         bool find_with( Q& val, Less pred, Func f )
589         {
590             CDS_UNUSED( pred );
591             return base_class::find_with( val, cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor >(),
592                 [&f]( node_type& node, Q& v ) { f( node.m_Value, v ); } );
593         }
594         //@cond
595         template <typename Q, typename Less, typename Func>
596         bool find_with( Q const& val, Less pred, Func f )
597         {
598             CDS_UNUSED( pred );
599             return base_class::find_with( val, cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor >(),
600                                           [&f]( node_type& node, Q& v ) { f( node.m_Value, v ); } );
601         }
602         //@endcond
603
604         /// Checks whether the set contains \p key
605         /**
606             The function searches the item with key equal to \p key
607             and returns \p true if it is found, and \p false otherwise.
608
609             The function applies RCU lock internally.
610         */
611         template <typename Q>
612         bool contains( Q const & key )
613         {
614             return base_class::contains( key );
615         }
616         //@cond
617         // Deprecated, use contains()
618         template <typename Q>
619         bool find( Q const & key )
620         {
621             return contains( key );
622         }
623         //@endcond
624
625         /// Checks whether the set contains \p key using \p pred predicate for searching
626         /**
627             The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
628             \p Less functor has the interface like \p std::less.
629             \p Less must imply the same element order as the comparator used for building the set.
630         */
631         template <typename Q, typename Less>
632         bool contains( Q const& key, Less pred )
633         {
634             CDS_UNUSED( pred );
635             return base_class::contains( key, cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor >());
636         }
637         //@cond
638         // Deprecated, use contains()
639         template <typename Q, typename Less>
640         bool find_with( Q const& key, Less pred )
641         {
642             return contains( key, pred );
643         }
644         //@endcond
645
646         /// Finds \p key and return the item found
647         /** \anchor cds_nonintrusive_SkipListSet_rcu_get
648             The function searches the item with key equal to \p key and returns a \p raw_ptr object pointed to item found.
649             If \p key is not found it returns empty \p raw_ptr.
650
651             Note the compare functor in \p Traits class' template argument
652             should accept a parameter of type \p Q that can be not the same as \p value_type.
653
654             RCU should be locked before call of this function.
655             Returned item is valid only while RCU is locked:
656             \code
657             typedef cds::container::SkipListSet< cds::urcu::gc< cds::urcu::general_buffered<> >, foo, my_traits > skip_list;
658             skip_list theList;
659             // ...
660             typename skip_list::raw_ptr pVal;
661             {
662                 // Lock RCU
663                 skip_list::rcu_lock lock;
664
665                 pVal = theList.get( 5 );
666                 if ( pVal ) {
667                     // Deal with pVal
668                     //...
669                 }
670             }
671             // You can manually release pVal after RCU-locked section
672             pVal.release();
673             \endcode
674         */
675         template <typename Q>
676         raw_ptr get( Q const& key )
677         {
678             return raw_ptr( base_class::get( key ));
679         }
680
681         /// Finds the key \p val and return the item found
682         /**
683             The function is an analog of \ref cds_nonintrusive_SkipListSet_rcu_get "get(Q const&)"
684             but \p pred is used for comparing the keys.
685
686             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
687             in any order.
688             \p pred must imply the same element order as the comparator used for building the set.
689         */
690         template <typename Q, typename Less>
691         raw_ptr get_with( Q const& val, Less pred )
692         {
693             CDS_UNUSED( pred );
694             return raw_ptr( base_class::get_with( val, cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor >() ));
695         }
696
697         /// Clears the set (non-atomic).
698         /**
699             The function deletes all items from the set.
700             The function is not atomic, thus, in multi-threaded environment with parallel insertions
701             this sequence
702             \code
703             set.clear();
704             assert( set.empty() );
705             \endcode
706             the assertion could be raised.
707
708             For each item the \ref disposer provided by \p Traits template parameter will be called.
709         */
710         void clear()
711         {
712             base_class::clear();
713         }
714
715         /// Checks if the set is empty
716         bool empty() const
717         {
718             return base_class::empty();
719         }
720
721         /// Returns item count in the set
722         /**
723             The value returned depends on item counter type provided by \p Traits template parameter.
724             If it is atomicity::empty_item_counter this function always returns 0.
725             Therefore, the function is not suitable for checking the set emptiness, use \ref empty
726             member function for this purpose.
727         */
728         size_t size() const
729         {
730             return base_class::size();
731         }
732
733         /// Returns const reference to internal statistics
734         stat const& statistics() const
735         {
736             return base_class::statistics();
737         }
738     };
739
740 }} // namespace cds::container
741
742 #endif // #ifndef CDSLIB_CONTAINER_SKIP_LIST_SET_RCU_H