3 #ifndef CDSLIB_CONTAINER_SPLIT_LIST_SET_RCU_H
4 #define CDSLIB_CONTAINER_SPLIT_LIST_SET_RCU_H
6 #include <cds/intrusive/split_list_rcu.h>
7 #include <cds/container/details/make_split_list_set.h>
8 #include <cds/urcu/exempt_ptr.h>
10 namespace cds { namespace container {
13 namespace split_list { namespace details {
22 #ifdef CDSLIB_CONTAINER_DETAILS_MICHAEL_LIST_BASE_H
23 template <typename T, class RawPtr>
24 class make_raw_ptr< T, RawPtr, cds::container::michael_list_tag >
26 typedef RawPtr intrusive_raw_ptr;
27 typedef typename intrusive_raw_ptr::value_type node_type;
30 struct raw_ptr_converter
32 value_type * operator()( node_type * p ) const
34 return p ? &p->m_Value : nullptr;
37 value_type& operator()( node_type& n ) const
42 value_type const& operator()( node_type const& n ) const
48 typedef cds::urcu::raw_ptr_adaptor< value_type, intrusive_raw_ptr, raw_ptr_converter > raw_ptr;
50 static raw_ptr make( typename intrusive_raw_ptr&& p )
52 return raw_ptr(std::move( p ));
57 #ifdef CDSLIB_CONTAINER_DETAILS_LAZY_LIST_BASE_H
58 template <typename T, typename RawPtr>
59 class make_raw_ptr< T, RawPtr, cds::container::lazy_list_tag >
61 typedef RawPtr node_type_pointer;
65 typedef value_type * raw_ptr;
67 static raw_ptr make( node_type_pointer p )
69 return p ? &p->m_Value : nullptr;
73 }} //namespace split_list::details
76 /// Split-ordered list set (template specialization for \ref cds_urcu_desc "RCU")
77 /** @ingroup cds_nonintrusive_set
78 \anchor cds_nonintrusive_SplitListSet_rcu
80 Hash table implementation based on split-ordered list algorithm discovered by Ori Shalev and Nir Shavit, see
81 - [2003] Ori Shalev, Nir Shavit "Split-Ordered Lists - Lock-free Resizable Hash Tables"
82 - [2008] Nir Shavit "The Art of Multiprocessor Programming"
84 See \p intrusive::SplitListSet for a brief description of the split-list algorithm.
87 - \p RCU - one of \ref cds_urcu_gc "RCU type"
88 - \p T - type of the value to be stored in the split-list.
89 - \p Traits - type traits, default is \p split_list::traits. Instead of declaring \p split_list::traits -based
90 struct you can apply option-based notation with \p split_list::make_traits metafunction.
94 The class supports a forward iterator (\ref iterator and \ref const_iterator).
95 The iteration is unordered.
97 You may iterate over split-list set items only under RCU lock.
98 Only in this case the iterator is thread-safe since
99 while RCU is locked any set's item cannot be reclaimed.
101 @warning The iterator object cannot be passed between threads
103 \warning Due to concurrent nature of skip-list set it is not guarantee that you can iterate
104 all elements in the set: any concurrent deletion can exclude the element
105 pointed by the iterator from the set, and your iteration can be terminated
106 before end of the set. Therefore, such iteration is more suitable for debugging purposes
108 The iterator class supports the following minimalistic interface:
115 iterator( iterator const& s);
117 value_type * operator ->() const;
118 value_type& operator *() const;
121 iterator& operator ++();
124 iterator& operator = (const iterator& src);
126 bool operator ==(iterator const& i ) const;
127 bool operator !=(iterator const& i ) const;
130 Note, the iterator object returned by \p end(), \p cend() member functions points to \p nullptr and should not be dereferenced.
134 You should decide what garbage collector you want, and what ordered list you want to use. Split-ordered list
135 is an original data structure based on an ordered list. Suppose, you want construct split-list set based on \p cds::urcu::general_buffered<> GC
136 and \p LazyList as ordered list implementation. So, you beginning your program with following include:
138 #include <cds/urcu/general_buffered.h>
139 #include <cds/container/lazy_list_rcu.h>
140 #include <cds/container/split_list_set_rcu.h>
142 namespace cc = cds::container;
144 // The data belonged to split-ordered list
146 int nKey; // key field
147 std::string strValue ; // value field
150 The inclusion order is important:
151 - first, include one of \ref cds_urcu_gc "RCU implementation" (<tt>cds/urcu/general_buffered.h</tt> in our case)
152 - second, include file for ordered-list implementation (for this example, <tt>cds/container/lazy_list_rcu.h</tt>),
153 - then, the header for RCU-based split-list set <tt>cds/container/split_list_set_rcu.h</tt>.
155 Now, you should declare traits for split-list set. The main parts of traits are a hash functor for the set and a comparing functor for ordered list.
156 Note that we define several function in \p foo_hash and \p foo_less functors for different argument types since we want call our \p %SplitListSet
157 object by the key of type \p int and by the value of type \p foo.
159 The second attention: instead of using \p %LazyList in \p %SplitListSet traits we use \p cds::contaner::lazy_list_tag tag for the lazy list.
160 The split-list requires significant support from underlying ordered list class and it is not good idea to dive you
161 into deep implementation details of split-list and ordered list interrelations. The tag paradigm simplifies split-list interface.
166 size_t operator()( int key ) const { return std::hash( key ) ; }
167 size_t operator()( foo const& item ) const { return std::hash( item.nKey ) ; }
172 bool operator()(int i, foo const& f ) const { return i < f.nKey ; }
173 bool operator()(foo const& f, int i ) const { return f.nKey < i ; }
174 bool operator()(foo const& f1, foo const& f2) const { return f1.nKey < f2.nKey; }
177 // SplitListSet traits
178 struct foo_set_traits: public cc::split_list::traits
180 typedef cc::lazy_list_tag ordered_list ; // what type of ordered list we want to use
181 typedef foo_hash hash ; // hash functor for our data stored in split-list set
183 // Type traits for our LazyList class
184 struct ordered_list_traits: public cc::lazy_list::traits
186 typedef foo_less less ; // use our foo_less as comparator to order list nodes
191 Now you are ready to declare our set class based on \p %SplitListSet:
193 typedef cc::SplitListSet< cds::urcu::gc<cds::urcu::general_buffered<> >, foo, foo_set_traits > foo_set;
196 You may use the modern option-based declaration instead of classic type-traits-based one:
198 typedef cc:SplitListSet<
199 cds::urcu::gc<cds::urcu::general_buffered<> > // RCU type used
200 ,foo // type of data stored
201 ,cc::split_list::make_traits< // metafunction to build split-list traits
202 cc::split_list::ordered_list<cc::lazy_list_tag> // tag for underlying ordered list implementation
203 ,cc::opt::hash< foo_hash > // hash functor
204 ,cc::split_list::ordered_list_traits< // ordered list traits
205 cc::lazy_list::make_traits< // metafunction to build lazy list traits
206 cc::opt::less< foo_less > // less-based compare functor
212 In case of option-based declaration using \p split_list::make_traits metafunction
213 the struct \p foo_set_traits is not required.
215 Now, the set of type \p foo_set is ready to use in your program.
217 Note that in this example we show only mandatory \p traits parts, optional ones is the default and they are inherited
218 from \p container::split_list::traits.
219 There are many other options for deep tuning of the split-list and ordered-list containers.
224 #ifdef CDS_DOXYGEN_INVOKED
225 class Traits = split_list::traits
230 class SplitListSet< cds::urcu::gc< RCU >, T, Traits >:
231 #ifdef CDS_DOXYGEN_INVOKED
232 protected intrusive::SplitListSet< cds::urcu::gc< RCU >, T, typename Traits::ordered_list, Traits >
234 protected details::make_split_list_set< cds::urcu::gc< RCU >, T, typename Traits::ordered_list, split_list::details::wrap_set_traits<T, Traits> >::type
239 typedef details::make_split_list_set< cds::urcu::gc< RCU >, T, typename Traits::ordered_list, split_list::details::wrap_set_traits<T, Traits> > maker;
240 typedef typename maker::type base_class;
244 typedef cds::urcu::gc< RCU > gc; ///< RCU-based garbage collector
245 typedef T value_type; ///< Type of value to be storedin the set
246 typedef Traits traits; ///< \p Traits template argument
248 // Note: ordered_list is not real ordered list type. Actual type is base_class::ordered_list
249 typedef typename maker::ordered_list ordered_list; ///< Underlying ordered list class
250 typedef typename base_class::key_comparator key_comparator; ///< key compare functor
252 /// Hash functor for \ref value_type and all its derivatives that you use
253 typedef typename base_class::hash hash;
254 typedef typename base_class::item_counter item_counter; ///< Item counter type
255 typedef typename base_class::stat stat; ///< Internal statistics
257 typedef typename base_class::rcu_lock rcu_lock ; ///< RCU scoped lock
258 /// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
259 static CDS_CONSTEXPR const bool c_bExtractLockExternal = base_class::c_bExtractLockExternal;
262 typedef cds::container::split_list::implementation_tag implementation_tag;
267 typedef typename maker::cxx_node_allocator cxx_node_allocator;
268 typedef typename maker::node_type node_type;
272 /// pointer to extracted node
273 using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::ordered_list_traits::disposer >;
274 # ifdef CDS_DOXYGEN_INVOKED
275 /// pointer to the node for \p get() function
277 For \p LazyList, \p %raw_ptr is just pointer to \p value_type.
279 For \p MichaelList, \p %raw_ptr is \p cds::urcu::raw_ptr object giving access to \p value_type.
281 typedef implementation_defined raw_ptr;
284 typedef split_list::details::make_raw_ptr< value_type, typename base_class::ordered_list::raw_ptr, typename traits::ordered_list > raw_ptr_maker;
286 typedef typename raw_ptr_maker::raw_ptr raw_ptr;
291 template <typename Q, typename Func>
292 bool find_( Q& val, Func f )
294 return base_class::find( val, [&f]( node_type& item, Q& val ) { f(item.m_Value, val) ; } );
297 template <typename Q, typename Less, typename Func>
298 bool find_with_( Q& val, Less pred, Func f )
301 return base_class::find_with( val, typename maker::template predicate_wrapper<Less>::type(),
302 [&f]( node_type& item, Q& val ) { f(item.m_Value, val) ; } );
305 template <typename Q>
306 static node_type * alloc_node( Q const& v )
308 return cxx_node_allocator().New( v );
311 template <typename... Args>
312 static node_type * alloc_node( Args&&... args )
314 return cxx_node_allocator().MoveNew( std::forward<Args>(args)...);
317 static void free_node( node_type * pNode )
319 cxx_node_allocator().Delete( pNode );
322 struct node_disposer {
323 void operator()( node_type * pNode )
328 typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
330 bool insert_node( node_type * pNode )
332 assert( pNode != nullptr );
333 scoped_node_ptr p(pNode);
335 if ( base_class::insert( *pNode ) ) {
347 \p IsConst - constness boolean flag
349 The forward iterator for a split-list has the following features:
350 - it has no post-increment operator
351 - it depends on underlying ordered list iterator
352 - it is safe to iterate only inside RCU critical section
353 - deleting an item pointed by the iterator can cause to deadlock
355 Therefore, the use of iterators in concurrent environment is not good idea.
356 Use it for debug purpose only.
358 template <bool IsConst>
359 class iterator_type: protected base_class::template iterator_type<IsConst>
362 typedef typename base_class::template iterator_type<IsConst> iterator_base_class;
363 friend class SplitListSet;
366 /// Value pointer type (const for const iterator)
367 typedef typename cds::details::make_const_type<value_type, IsConst>::pointer value_ptr;
368 /// Value reference type (const for const iterator)
369 typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
377 iterator_type( iterator_type const& src )
378 : iterator_base_class( src )
383 explicit iterator_type( iterator_base_class const& src )
384 : iterator_base_class( src )
389 /// Dereference operator
390 value_ptr operator ->() const
392 return &(iterator_base_class::operator->()->m_Value);
395 /// Dereference operator
396 value_ref operator *() const
398 return iterator_base_class::operator*().m_Value;
402 iterator_type& operator ++()
404 iterator_base_class::operator++();
408 /// Assignment operator
409 iterator_type& operator = (iterator_type const& src)
411 iterator_base_class::operator=(src);
415 /// Equality operator
417 bool operator ==(iterator_type<C> const& i ) const
419 return iterator_base_class::operator==(i);
422 /// Equality operator
424 bool operator !=(iterator_type<C> const& i ) const
426 return iterator_base_class::operator!=(i);
431 /// Initializes split-ordered list of default capacity
433 The default capacity is defined in bucket table constructor.
434 See \p intrusive::split_list::expandable_bucket_table, \p intrusive::split_list::static_bucket_table
435 which selects by \p container::split_list::dynamic_bucket_table option.
441 /// Initializes split-ordered list
443 size_t nItemCount ///< estimated average of item count
444 , size_t nLoadFactor = 1 ///< load factor - average item count per bucket. Small integer up to 8, default is 1.
446 : base_class( nItemCount, nLoadFactor )
450 typedef iterator_type<false> iterator ; ///< Forward iterator
451 typedef iterator_type<true> const_iterator ; ///< Forward const iterator
453 /// Returns a forward iterator addressing the first element in a set
455 For empty set \code begin() == end() \endcode
459 return iterator( base_class::begin() );
462 /// Returns an iterator that addresses the location succeeding the last element in a set
464 Do not use the value returned by <tt>end</tt> function to access any item.
465 The returned value can be used only to control reaching the end of the set.
466 For empty set \code begin() == end() \endcode
470 return iterator( base_class::end() );
473 /// Returns a forward const iterator addressing the first element in a set
474 const_iterator begin() const
478 /// Returns a forward const iterator addressing the first element in a set
479 const_iterator cbegin() const
481 return const_iterator( base_class::cbegin() );
484 /// Returns an const iterator that addresses the location succeeding the last element in a set
485 const_iterator end() const
489 /// Returns an const iterator that addresses the location succeeding the last element in a set
490 const_iterator cend() const
492 return const_iterator( base_class::cend() );
498 The function creates a node with copy of \p val value
499 and then inserts the node created into the set.
501 The type \p Q should contain as minimum the complete key for the node.
502 The object of \p value_type should be constructible from a value of type \p Q.
503 In trivial case, \p Q is equal to \p value_type.
505 The function applies RCU lock internally.
507 Returns \p true if \p val is inserted into the set, \p false otherwise.
509 template <typename Q>
510 bool insert( Q const& val )
512 return insert_node( alloc_node( val ) );
517 The function allows to split creating of new item into two part:
518 - create item with key only
519 - insert new item into the set
520 - if inserting is success, calls \p f functor to initialize value-field of \p val.
522 The functor signature is:
524 void func( value_type& val );
526 where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
527 \p val no any other changes could be made on this set's item by concurrent threads.
528 The user-defined functor is called only if the inserting is success.
530 The function applies RCU lock internally.
532 template <typename Q, typename Func>
533 bool insert( Q const& key, Func f )
535 scoped_node_ptr pNode( alloc_node( key ));
537 if ( base_class::insert( *pNode, [&f](node_type& node) { f( node.m_Value ) ; } )) {
544 /// Inserts data of type \p value_type created from \p args
546 Returns \p true if inserting successful, \p false otherwise.
548 The function applies RCU lock internally.
550 template <typename... Args>
551 bool emplace( Args&&... args )
553 return insert_node( alloc_node( std::forward<Args>(args)...));
556 /// Ensures that the \p val exists in the set
558 The operation performs inserting or changing data with lock-free manner.
560 If the \p val key not found in the set, then the new item created from \p val
561 is inserted into the set. Otherwise, the functor \p func is called with the item found.
562 The functor \p Func signature is:
565 void operator()( bool bNew, value_type& item, const Q& val );
570 - \p bNew - \p true if the item has been inserted, \p false otherwise
571 - \p item - item of the set
572 - \p val - argument \p val passed into the \p %ensure() function
574 The functor may change non-key fields of the \p item; however, \p func must guarantee
575 that during changing no any other modifications could be made on this item by concurrent threads.
577 The function applies RCU lock internally.
579 Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
580 \p second is true if new item has been added or \p false if the item with \p key
581 already is in the set.
583 template <typename Q, typename Func>
584 std::pair<bool, bool> ensure( Q const& val, Func func )
586 scoped_node_ptr pNode( alloc_node( val ));
588 std::pair<bool, bool> bRet = base_class::ensure( *pNode,
589 [&func, &val]( bool bNew, node_type& item, node_type const& /*val*/ ) {
590 func( bNew, item.m_Value, val );
592 if ( bRet.first && bRet.second )
597 /// Deletes \p key from the set
598 /** \anchor cds_nonintrusive_SplitListSet_rcu_erase_val
600 Template parameter of type \p Q defines the key type searching in the list.
601 The set item comparator should be able to compare the values of type \p value_type
604 RCU \p synchronize method can be called. RCU should not be locked.
606 Return \p true if key is found and deleted, \p false otherwise
608 template <typename Q>
609 bool erase( Q const& key )
611 return base_class::erase( key );
614 /// Deletes the item from the set using \p pred predicate for searching
616 The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_erase_val "erase(Q const&)"
617 but \p pred is used for key comparing.
618 \p Less functor has the interface like \p std::less.
619 \p Less must imply the same element order as the comparator used for building the set.
621 template <typename Q, typename Less>
622 bool erase_with( Q const& key, Less pred )
625 return base_class::erase_with( key, typename maker::template predicate_wrapper<Less>::type() );
628 /// Deletes \p key from the set
629 /** \anchor cds_nonintrusive_SplitListSet_rcu_erase_func
631 The function searches an item with key \p key, calls \p f functor
632 and deletes the item. If \p key is not found, the functor is not called.
634 The functor \p Func interface:
637 void operator()(value_type const& val);
641 Template parameter of type \p Q defines the key type searching in the list.
642 The list item comparator should be able to compare the values of the type \p value_type
645 RCU \p synchronize method can be called. RCU should not be locked.
647 Return \p true if key is found and deleted, \p false otherwise
649 template <typename Q, typename Func>
650 bool erase( Q const& key, Func f )
652 return base_class::erase( key, [&f](node_type& node) { f( node.m_Value ); } );
655 /// Deletes the item from the set using \p pred predicate for searching
657 The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_erase_func "erase(Q const&, Func)"
658 but \p pred is used for key comparing.
659 \p Less functor has the interface like \p std::less.
660 \p Less must imply the same element order as the comparator used for building the set.
662 template <typename Q, typename Less, typename Func>
663 bool erase_with( Q const& key, Less pred, Func f )
666 return base_class::erase_with( key, typename maker::template predicate_wrapper<Less>::type(),
667 [&f](node_type& node) { f( node.m_Value ); } );
670 /// Extracts an item from the set
671 /** \anchor cds_nonintrusive_SplitListSet_rcu_extract
672 The function searches an item with key equal to \p key in the set,
673 unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
674 If the item with the key equal to \p key is not found the function returns an empty \p exempt_ptr.
676 Depends on \p bucket_type you should or should not lock RCU before calling of this function:
677 - for the set based on \ref cds_intrusive_MichaelList_rcu "MichaelList" RCU should not be locked
678 - for the set based on \ref cds_intrusive_LazyList_rcu "LazyList" RCU should be locked
679 See ordered list implementation for details.
682 typedef cds::urcu::gc< general_buffered<> > rcu;
684 // Split-list set based on MichaelList by default
685 typedef cds::container::SplitListSet< rcu, Foo > splitlist_set;
687 splitlist_set theSet;
690 splitlist_set::exempt_ptr p;
692 // For MichaelList we should not lock RCU
694 // Now, you can apply extract function
695 p = theSet.extract( 10 );
697 // do something with p
701 // We may safely release p here
702 // release() passes the pointer to RCU reclamation cycle
706 template <typename Q>
707 exempt_ptr extract( Q const& key )
709 return exempt_ptr( base_class::extract_( key, key_comparator() ));
712 /// Extracts an item from the set using \p pred predicate for searching
714 The function is an analog of \p extract(Q const&) but \p pred is used for key comparing.
715 \p Less functor has the interface like \p std::less.
716 \p pred must imply the same element order as the comparator used for building the set.
718 template <typename Q, typename Less>
719 exempt_ptr extract_with( Q const& key, Less pred )
722 return exempt_ptr( base_class::extract_with_( key, typename maker::template predicate_wrapper<Less>::type()));
725 /// Finds the key \p key
726 /** \anchor cds_nonintrusive_SplitListSet_rcu_find_func
728 The function searches the item with key equal to \p key and calls the functor \p f for item found.
729 The interface of \p Func functor is:
732 void operator()( value_type& item, Q& key );
735 where \p item is the item found, \p key is the <tt>find</tt> function argument.
737 The functor may change non-key fields of \p item. Note that the functor is only guarantee
738 that \p item cannot be disposed during functor is executing.
739 The functor does not serialize simultaneous access to the set's \p item. If such access is
740 possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
742 Note the hash functor specified for class \p Traits template parameter
743 should accept a parameter of type \p Q that can be not the same as \p value_type.
745 The function makes RCU lock internally.
747 The function returns \p true if \p key is found, \p false otherwise.
749 template <typename Q, typename Func>
750 bool find( Q& key, Func f )
752 return find_( key, f );
755 template <typename Q, typename Func>
756 bool find( Q const& key, Func f )
758 return find_( key, f );
762 /// Finds the key \p key using \p pred predicate for searching
764 The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_find_func "find(Q&, Func)"
765 but \p pred is used for key comparing.
766 \p Less functor has the interface like \p std::less.
767 \p Less must imply the same element order as the comparator used for building the set.
769 template <typename Q, typename Less, typename Func>
770 bool find_with( Q& key, Less pred, Func f )
772 return find_with_( key, pred, f );
775 template <typename Q, typename Less, typename Func>
776 bool find_with( Q const& key, Less pred, Func f )
778 return find_with_( key, pred, f );
782 /// Finds the key \p key
783 /** \anchor cds_nonintrusive_SplitListSet_rcu_find_val
785 The function searches the item with key equal to \p key
786 and returns \p true if it is found, and \p false otherwise.
788 Note the hash functor specified for class \p Traits template parameter
789 should accept a parameter of type \p Q that can be not the same as \p value_type.
791 The function makes RCU lock internally.
793 template <typename Q>
794 bool find( Q const& key )
796 return base_class::find( key );
799 /// Finds the key \p key using \p pred predicate for searching
801 The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_find_val "find(Q const&)"
802 but \p pred is used for key comparing.
803 \p Less functor has the interface like \p std::less.
804 \p Less must imply the same element order as the comparator used for building the set.
806 template <typename Q, typename Less>
807 bool find_with( Q const& key, Less pred )
810 return base_class::find_with( key, typename maker::template predicate_wrapper<Less>::type() );
813 /// Finds the key \p key and return the item found
814 /** \anchor cds_nonintrusive_SplitListSet_rcu_get
815 The function searches the item with key equal to \p key and returns the pointer to item found.
816 If \p key is not found it returns \p nullptr.
818 Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
820 RCU should be locked before call of this function.
821 Returned item is valid only while RCU is locked:
823 typedef cds::urcu::gc< general_buffered<> > rcu;
824 typedef cds::container::SplitListSet< rcu, Foo > splitlist_set;
825 splitlist_set theSet;
829 splitlist_set::rcu_lock lock;
831 foo * pVal = theSet.get( 5 );
836 // Unlock RCU by rcu_lock destructor
837 // pVal can be retired by disposer at any time after RCU has been unlocked
841 template <typename Q>
842 raw_ptr get( Q const& key )
844 return raw_ptr_maker::make( base_class::get( key ));
847 /// Finds the key \p key and return the item found
849 The function is an analog of \ref cds_nonintrusive_SplitListSet_rcu_get "get(Q const&)"
850 but \p pred is used for comparing the keys.
852 \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
854 \p pred must imply the same element order as the comparator used for building the set.
856 template <typename Q, typename Less>
857 raw_ptr get_with( Q const& key, Less pred )
860 return raw_ptr_maker::make( base_class::get_with( key, typename maker::template predicate_wrapper<Less>::type()));
863 /// Clears the set (not atomic)
869 /// Checks if the set is empty
871 Emptiness is checked by item counting: if item count is zero then assume that the set is empty.
872 Thus, the correct item counting feature is an important part of split-list set implementation.
876 return base_class::empty();
879 /// Returns item count in the set
882 return base_class::size();
885 /// Returns internal statistics
886 stat const& statistics() const
888 return base_class::statistics();
891 }} // namespace cds::container
893 #endif // #ifndef CDSLIB_CONTAINER_SPLIT_LIST_SET_RCU_H