3 #ifndef CDSLIB_INTRUSIVE_STRIPED_SET_H
4 #define CDSLIB_INTRUSIVE_STRIPED_SET_H
6 #include <cds/intrusive/details/base.h>
7 #include <cds/intrusive/striped_set/adapter.h>
8 #include <cds/intrusive/striped_set/striping_policy.h>
10 namespace cds { namespace intrusive {
11 /// StripedSet related definitions
12 namespace striped_set {
14 /** @defgroup cds_striped_resizing_policy Resizing policy for striped/refinable set/map
16 Resizing policy for \p intrusive::StripedSet, \p container::StripedSet and \p container::StripedMap.
19 } // namespace striped_set
22 /** @ingroup cds_intrusive_map
25 - [2008] Maurice Herlihy, Nir Shavit "The Art of Multiprocessor Programming"
27 Lock striping is very simple technique.
28 The set consists of the bucket table and the array of locks.
29 Initially, the capacity of lock array and bucket table is the same.
30 When set is resized, bucket table capacity will be doubled but lock array will not.
31 The lock \p i protects each bucket \p j, where <tt> j = i mod L </tt>,
32 where \p L - the size of lock array.
35 - \p Container - the container class that is used as bucket table entry. The \p Container class should support
36 an uniform interface described below.
37 - \p Options - options
39 The \p %StripedSet class does not exactly dictate the type of container that should be used as a \p Container bucket.
40 Instead, the class supports different intrusive container type for the bucket, for exampe,
41 \p boost::intrusive::list, \p boost::intrusive::set and others.
43 Remember that \p %StripedSet class algorithm ensures sequential blocking access to its bucket through the mutex type you specify
44 among \p Options template arguments.
47 - \p opt::mutex_policy - concurrent access policy.
48 Available policies: \p striped_set::striping, \p striped_set::refinable.
49 Default is \p %striped_set::striping.
50 - \p cds::opt::hash - hash functor. Default option value see <tt>opt::v::hash_selector <opt::none></tt>
51 which selects default hash functor for your compiler.
52 - \p cds::opt::compare - key comparison functor. No default functor is provided.
53 If the option is not specified, the \p opt::less is used.
54 - \p cds::opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
55 - \p cds::opt::item_counter - item counter type. Default is \p atomicity::item_counter since some operation on the counter is performed
56 without locks. Note that item counting is an essential part of the set algorithm, so dummy counter like \p atomicity::empty_item_counter
58 - \p cds::opt::allocator - the allocator type using for memory allocation of bucket table and lock array. Default is \ref CDS_DEFAULT_ALLOCATOR.
59 - \p cds::opt::resizing_policy - the resizing policy - a functor that decides when to resize the hash set.
60 Default option value depends on bucket container type:
61 for sequential containers like \p boost::intrusive::list the resizing policy is <tt>cds::container::striped_set::load_factor_resizing<4> </tt>;
62 for other type of containers like \p boost::intrusive::set the resizing policy is cds::container::striped_set::no_resizing.
63 See \ref cds_striped_resizing_policy "available resizing policy".
64 Note that the choose of resizing policy depends of \p Container type:
65 for sequential containers like \p boost::intrusive::list the right policy can significantly improve performance.
66 For other, non-sequential types of \p Container (like a \p boost::intrusive::set) the resizing policy is not so important.
67 - \p cds::opt::buffer - a buffer type used only for \p boost::intrusive::unordered_set.
68 Default is <tt>cds::opt::v::static_buffer< cds::any_type, 256 > </tt>.
70 \p opt::compare or \p opt::less options are used in some \p Container class for ordering.
71 \p %opt::compare option has the highest priority: if \p %opt::compare is specified, \p %opt::less is not used.
73 You can pass other option that would be passed to \p adapt metafunction, see below.
75 <b>Internal details</b>
77 The \p %StripedSet class cannot utilize the \p Container specified directly, but only its adapted variant which
78 supports an unified interface. Internally, the adaptation is made via \p intrusive::striped_set::adapt metafunction that wraps bucket container
79 and provides the unified bucket interface suitable for \p %StripedSet. Such adaptation is completely transparent for you -
80 you don't need to call \p adapt metafunction directly, \p %StripedSet class's internal machinery itself invokes appropriate
81 \p adapt metafunction specialization to adjust your \p Container container class to \p %StripedSet bucket's internal interface.
82 All you need is to include a right header before <tt>striped_set.h</tt>.
84 By default, <tt>intrusive::striped_set::adapt<AnyContainer, OptionPack> </tt> metafunction does not make any wrapping to \p AnyContainer,
85 so, the result <tt>intrusive::striped_set::adapt<AnyContainer, OptionPack>::type </tt> is the same as \p AnyContainer.
86 However, there are a lot of specializations of \p %intrusive::striped_set::adapt for \p boost::intrusive containers, see table below.
87 Any of this specialization wraps corresponding container making it suitable for the set's bucket.
88 Remember, you should include the proper header file for \p adapt <b>before</b> including <tt>striped_set.h</tt>.
90 \note It is important to specify <tt>boost::intrusive::constant_time_size<true></tt> option
91 for all \p boost::intrusive container that supports this option. Fast item counting feature is essential part of
92 \p %StripedSet resizing algorithm.
97 <th>.h-file for \p adapt</th>
102 <td> \p boost::intrusive::list</td>
103 <td><tt><cds/intrusive/striped_set/boost_list.h></tt></td>
105 #include <cds/intrusive/striped_set/boost_list.h>
106 #include <cds/intrusive/striped_set.h>
107 typedef cds::intrusive::StripedSet<
108 boost::intrusive::list<T, boost::intrusive::constant_time_size<true> >,
109 cds::opt::less< std::less<T> >
115 Template argument pack \p Options <b>must</b> contain cds::opt::less or cds::opt::compare for type \p T stored in the list
119 <td> \p boost::intrusive::slist</td>
120 <td><tt><cds/intrusive/striped_set/boost_slist.h></tt></td>
122 #include <cds/intrusive/striped_set/boost_slist.h>
123 #include <cds/intrusive/striped_set.h>
124 typedef cds::intrusive::StripedSet<
125 boost::intrusive::slist<T, boost::intrusive::constant_time_size<true> >,
126 cds::opt::less< std::less<T> >
132 Template argument pack \p Options <b>must</b> contain \p cds::opt::less or \p cds::opt::compare for type \p T stored in the list
136 <td> \p boost::intrusive::set</td>
137 <td><tt><cds/intrusive/striped_set/boost_set.h></tt></td>
139 #include <cds/intrusive/striped_set/boost_set.h>
140 #include <cds/intrusive/striped_set.h>
141 typedef cds::intrusive::StripedSet<
142 boost::intrusive::set<T, boost::intrusive::constant_time_size<true> >
147 Note that \p boost::intrusive::compare option using in \p boost::intrusive::set
148 should support \p T type stored in the set and any type \p Q that you can use
149 in \p erase() and \p find() member functions.
153 <td> \p boost::intrusive::unordered_set</td>
154 <td><tt><cds/intrusive/striped_set/boost_unordered_set.h></tt></td>
156 #include <cds/intrusive/striped_set/boost_unordered_set.h>
157 #include <cds/intrusive/striped_set.h>
158 typedef cds::intrusive::StripedSet<
159 boost::intrusive::unordered_set<T
160 ,boost::intrusive::constant_time_size<true>
161 ,boost::intrusive::hash< user_provided_hash_functor >
167 You should provide two different hash function \p h1 and \p h2 - one for \p boost::intrusive::unordered_set
168 and other for \p %StripedSet. For the best result, \p h1 and \p h2 must be orthogonal i.e. <tt>h1(X) != h2(X)</tt> for any value \p X
170 The option \p opt::buffer is used for \p boost::intrusive::bucket_traits. Default is <tt> cds::opt::v::static_buffer< cds::any_type, 256 > </tt>.
171 The resizing policy should correlate with the buffer capacity.
172 The default resizing policy is <tt>cds::container::striped_set::load_factor_resizing<256> </tt> what gives load factor 1 for
173 default bucket buffer that is the best for \p boost::intrusive::unordered_set.
177 <td> \p boost::intrusive::avl_set</td>
178 <td><tt><cds/intrusive/striped_set/boost_avl_set.h></tt></td>
180 #include <cds/intrusive/striped_set/boost_avl_set.h>
181 #include <cds/intrusive/striped_set.h>
182 typedef cds::intrusive::StripedSet<
183 boost::intrusive::avl_set<T, boost::intrusive::constant_time_size<true> >
188 Note that \p boost::intrusive::compare option using in \p boost::intrusive::avl_set
189 should support \p T type stored in the set and any type \p Q that you can use
190 in \p erase() and \p find() member functions.
194 <td> \p boost::intrusive::sg_set</td>
195 <td><tt><cds/intrusive/striped_set/boost_sg_set.h></tt></td>
197 #include <cds/intrusive/striped_set/boost_sg_set.h>
198 #include <cds/intrusive/striped_set.h>
199 typedef cds::intrusive::StripedSet<
200 boost::intrusive::sg_set<T, boost::intrusive::constant_time_size<true> >
205 Note that \p boost::intrusive::compare option using in \p boost::intrusive::sg_set
206 should support \p T type stored in the set and any type \p Q that you can use
207 in \p erase() and \p find() member functions.
211 <td> \p boost::intrusive::splay_set</td>
212 <td><tt><cds/intrusive/striped_set/boost_splay_set.h></tt></td>
214 #include <cds/intrusive/striped_set/boost_splay_set.h>
215 #include <cds/intrusive/striped_set.h>
216 typedef cds::intrusive::StripedSet<
217 boost::intrusive::splay_set<T, boost::intrusive::constant_time_size<true> >
222 Note that \p boost::intrusive::compare option using in \p boost::intrusive::splay_set
223 should support \p T type stored in the set and any type \p Q that you can use
224 in \p erase() and \p find() member functions.
228 <td> \p boost::intrusive::treap_set</td>
229 <td><tt><cds/intrusive/striped_set/boost_treap_set.h></tt></td>
231 #include <cds/intrusive/striped_set/boost_treap_set.h>
232 #include <cds/intrusive/striped_set.h>
233 typedef cds::intrusive::StripedSet<
234 boost::intrusive::treap_set<T, boost::intrusive::constant_time_size<true> >
239 Note that \p boost::intrusive::compare option using in \p boost::intrusive::treap_set
240 should support \p T type stored in the set and any type \p Q that you can use
241 in \p erase() and \p find() member functions.
246 You can use another intrusive container type as striped set's bucket.
247 Suppose, you have a container class \p MyBestContainer and you want to integrate it with \p StripedSet as bucket type.
248 There are two possibility:
249 - either your \p MyBestContainer class has native support of bucket's interface;
250 in this case, you can use default \p intrusive::striped_set::adapt metafunction;
251 - or your \p MyBestContainer class does not support bucket's interface, which means, that you should create a specialization of
252 <tt>cds::intrusive::striped_set::adapt<MyBestContainer> </tt> metafunction providing necessary interface.
254 The <tt>intrusive::striped_set::adapt< Container, OptionPack ></tt> metafunction has two template argument:
255 - \p Container is the class that should be used as the bucket, for example, <tt>boost::intrusive::list< T ></tt>.
256 - \p OptionPack is the packed options from \p %StripedSet declaration. The \p adapt metafunction can use
257 any option from \p OptionPack for its internal use. For example, a \p compare option can be passed to \p adapt
258 metafunction via \p OptionPack argument of \p %StripedSet declaration.
260 See \p intrusive::striped_set::adapt metafunction for the description of interface that the bucket container must provide
261 to be \p %StripedSet compatible.
263 template <class Container, typename... Options>
268 struct default_options {
269 typedef striped_set::striping<> mutex_policy;
270 typedef typename cds::opt::v::hash_selector< cds::opt::none >::type hash;
271 typedef cds::atomicity::item_counter item_counter;
272 typedef CDS_DEFAULT_ALLOCATOR allocator;
273 typedef cds::opt::none resizing_policy;
274 typedef cds::opt::none compare;
275 typedef cds::opt::none less;
278 typedef typename cds::opt::make_options<
279 typename cds::opt::find_type_traits< default_options, Options... >::type
284 typedef Container underlying_container_type ; ///< original intrusive container type for the bucket
285 typedef typename cds::intrusive::striped_set::adapt< underlying_container_type, Options... >::type bucket_type ; ///< container type adapted for hash set
286 typedef typename bucket_type::value_type value_type ; ///< value type stored in the set
288 typedef typename options::hash hash ; ///< Hash functor
289 typedef typename options::item_counter item_counter ; ///< Item counter
290 typedef typename cds::opt::select_default<
291 typename options::resizing_policy,
292 typename bucket_type::default_resizing_policy
293 >::type resizing_policy ; ///< Resizing policy
294 typedef typename options::allocator allocator_type ; ///< allocator type specified in options.
295 typedef typename options::mutex_policy mutex_policy ; ///< Mutex policy
297 typedef cds::details::Allocator< bucket_type, allocator_type > bucket_allocator; ///< bucket allocator type based on allocator_type
300 typedef cds::intrusive::striped_set::implementation_tag implementation_tag;
304 bucket_type * m_Buckets ; ///< Bucket table
305 size_t m_nBucketMask ; ///< Bucket table size - 1. m_nBucketMask + 1 should be power of two.
306 item_counter m_ItemCounter ; ///< Item counter
307 hash m_Hash ; ///< Hash functor
309 mutex_policy m_MutexPolicy ; ///< Mutex policy
310 resizing_policy m_ResizingPolicy; ///< Resizing policy
312 static const size_t c_nMinimalCapacity = 16 ; ///< Minimal capacity
316 typedef typename mutex_policy::scoped_cell_lock scoped_cell_lock;
317 typedef typename mutex_policy::scoped_full_lock scoped_full_lock;
318 typedef typename mutex_policy::scoped_resize_lock scoped_resize_lock;
323 static size_t calc_init_capacity( size_t nCapacity )
325 nCapacity = cds::beans::ceil2( nCapacity );
326 return nCapacity < c_nMinimalCapacity ? c_nMinimalCapacity : nCapacity;
329 void alloc_bucket_table( size_t nSize )
331 assert( cds::beans::is_power2( nSize ));
332 m_nBucketMask = nSize - 1;
333 m_Buckets = bucket_allocator().NewArray( nSize );
336 static void free_bucket_table( bucket_type * pBuckets, size_t nSize )
338 bucket_allocator().Delete( pBuckets, nSize );
341 template <typename Q>
342 size_t hashing( Q const& v ) const
347 bucket_type * bucket( size_t nHash ) const CDS_NOEXCEPT
349 return m_Buckets + (nHash & m_nBucketMask);
352 template <typename Q, typename Func>
353 bool find_( Q& val, Func f )
355 size_t nHash = hashing( val );
357 scoped_cell_lock sl( m_MutexPolicy, nHash );
358 return bucket( nHash )->find( val, f );
361 template <typename Q, typename Less, typename Func>
362 bool find_with_( Q& val, Less pred, Func f )
364 size_t nHash = hashing( val );
365 scoped_cell_lock sl( m_MutexPolicy, nHash );
366 return bucket( nHash )->find( val, pred, f );
369 void internal_resize( size_t nNewCapacity )
371 // All locks are already locked!
372 m_MutexPolicy.resize( nNewCapacity );
374 size_t nOldCapacity = bucket_count();
375 bucket_type * pOldBuckets = m_Buckets;
377 alloc_bucket_table( nNewCapacity );
379 typedef typename bucket_type::iterator bucket_iterator;
380 bucket_type * pEnd = pOldBuckets + nOldCapacity;
381 for ( bucket_type * pCur = pOldBuckets; pCur != pEnd; ++pCur ) {
382 bucket_iterator itEnd = pCur->end();
383 bucket_iterator itNext;
384 for ( bucket_iterator it = pCur->begin(); it != itEnd; it = itNext ) {
387 bucket( m_Hash( *it ) )->move_item( *pCur, it );
392 free_bucket_table( pOldBuckets, nOldCapacity );
394 m_ResizingPolicy.reset();
399 size_t nOldCapacity = bucket_count();
400 size_t volatile& refBucketMask = m_nBucketMask;
402 scoped_resize_lock al( m_MutexPolicy );
403 if ( al.success() ) {
404 if ( nOldCapacity != refBucketMask + 1 ) {
405 // someone resized already
409 internal_resize( nOldCapacity * 2 );
416 /// Default ctor. The initial capacity is 16.
418 : m_Buckets( nullptr )
419 , m_nBucketMask( c_nMinimalCapacity - 1 )
420 , m_MutexPolicy( c_nMinimalCapacity )
422 alloc_bucket_table( m_nBucketMask + 1 );
425 /// Ctor with initial capacity specified
427 size_t nCapacity ///< Initial size of bucket table and lock array. Must be power of two, the minimum is 16.
429 : m_Buckets( nullptr )
430 , m_nBucketMask( calc_init_capacity(nCapacity) - 1 )
431 , m_MutexPolicy( m_nBucketMask + 1 )
433 alloc_bucket_table( m_nBucketMask + 1 );
436 /// Ctor with resizing policy (copy semantics)
438 This constructor initializes m_ResizingPolicy member with copy of \p resizingPolicy parameter
441 size_t nCapacity ///< Initial size of bucket table and lock array. Must be power of two, the minimum is 16.
442 ,resizing_policy const& resizingPolicy ///< Resizing policy
444 : m_Buckets( nullptr )
445 , m_nBucketMask( ( nCapacity ? calc_init_capacity(nCapacity) : c_nMinimalCapacity ) - 1 )
446 , m_MutexPolicy( m_nBucketMask + 1 )
447 , m_ResizingPolicy( resizingPolicy )
449 alloc_bucket_table( m_nBucketMask + 1 );
452 /// Ctor with resizing policy (move semantics)
454 This constructor initializes m_ResizingPolicy member moving \p resizingPolicy parameter
455 Move semantics is used.
458 size_t nCapacity ///< Initial size of bucket table and lock array. Must be power of two, the minimum is 16.
459 ,resizing_policy&& resizingPolicy ///< Resizing policy
461 : m_Buckets( nullptr )
462 , m_nBucketMask( ( nCapacity ? calc_init_capacity(nCapacity) : c_nMinimalCapacity ) - 1 )
463 , m_MutexPolicy( m_nBucketMask + 1 )
464 , m_ResizingPolicy( std::forward<resizing_policy>( resizingPolicy ) )
466 alloc_bucket_table( m_nBucketMask + 1 );
469 /// Destructor destroys internal data
472 free_bucket_table( m_Buckets, m_nBucketMask + 1 );
478 The function inserts \p val in the set if it does not contain
479 an item with key equal to \p val.
481 Returns \p true if \p val is placed into the set, \p false otherwise.
483 bool insert( value_type& val )
485 return insert( val, []( value_type& ) {} );
490 The function allows to split creating of new item into two part:
491 - create item with key only
492 - insert new item into the set
493 - if inserting is success, calls \p f functor to initialize value-field of \p val.
495 The functor signature is:
497 void func( value_type& val );
499 where \p val is the item inserted.
501 template <typename Func>
502 bool insert( value_type& val, Func f )
506 size_t nHash = hashing( val );
507 bucket_type * pBucket;
509 scoped_cell_lock sl( m_MutexPolicy, nHash );
510 pBucket = bucket( nHash );
511 bOk = pBucket->insert( val, f );
512 bResize = bOk && m_ResizingPolicy( ++m_ItemCounter, *this, *pBucket );
522 The operation performs inserting or changing data with lock-free manner.
524 If the item \p val is not found in the set, then \p val is inserted
525 iff \p bAllowInsert is \p true.
526 Otherwise, the functor \p func is called with item found.
527 The functor signature is:
529 void func( bool bNew, value_type& item, value_type& val );
532 - \p bNew - \p true if the item has been inserted, \p false otherwise
533 - \p item - item of the set
534 - \p val - argument \p val passed into the \p update() function
535 If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
536 refers to the same thing.
538 The functor may change non-key fields of the \p item.
540 Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
541 \p second is \p true if new item has been added or \p false if the item with \p val
542 already is in the set.
544 template <typename Func>
545 std::pair<bool, bool> update( value_type& val, Func func, bool bAllowInsert = true )
547 std::pair<bool, bool> result;
549 size_t nHash = hashing( val );
550 bucket_type * pBucket;
552 scoped_cell_lock sl( m_MutexPolicy, nHash );
553 pBucket = bucket( nHash );
555 result = pBucket->update( val, func, bAllowInsert );
556 bResize = result.first && result.second && m_ResizingPolicy( ++m_ItemCounter, *this, *pBucket );
564 template <typename Func>
565 std::pair<bool, bool> ensure( value_type& val, Func func )
567 return update( val, func, true );
571 /// Unlink the item \p val from the set
573 The function searches the item \p val in the set and unlink it
574 if it is found and is equal to \p val (here, the equality means that
575 \p val belongs to the set: if \p item is an item found then
576 unlink is successful iif <tt>&val == &item</tt>)
578 The function returns \p true if success and \p false otherwise.
580 bool unlink( value_type& val )
583 size_t nHash = hashing( val );
585 scoped_cell_lock sl( m_MutexPolicy, nHash );
586 bOk = bucket( nHash )->unlink( val );
594 /// Deletes the item from the set
595 /** \anchor cds_intrusive_StripedSet_erase
596 The function searches an item with key equal to \p val in the set,
597 unlinks it from the set, and returns a pointer to unlinked item.
599 If the item with key equal to \p val is not found the function return \p nullptr.
601 Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
603 template <typename Q>
604 value_type * erase( Q const& val )
606 return erase( val, [](value_type const&) {} );
609 /// Deletes the item from the set using \p pred predicate for searching
611 The function is an analog of \ref cds_intrusive_StripedSet_erase "erase(Q const&)"
612 but \p pred is used for key comparing
613 \p Less has the interface like \p std::less.
614 \p pred must imply the same element order as the comparator used for building the set.
616 template <typename Q, typename Less>
617 value_type * erase_with( Q const& val, Less pred )
619 return erase_with( val, pred, [](value_type const&) {} );
622 /// Deletes the item from the set
623 /** \anchor cds_intrusive_StripedSet_erase_func
625 The function searches an item with key equal to \p val in the set,
626 call \p f functor with item found, unlinks it from the set, and returns a pointer to unlinked item.
628 The \p Func interface is
631 void operator()( value_type const& item );
635 If the item with key equal to \p val is not found the function return \p false.
637 Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
639 template <typename Q, typename Func>
640 value_type * erase( Q const& val, Func f )
642 size_t nHash = hashing( val );
645 scoped_cell_lock sl( m_MutexPolicy, nHash );
646 pVal = bucket( nHash )->erase( val, f );
654 /// Deletes the item from the set using \p pred predicate for searching
656 The function is an analog of \ref cds_intrusive_StripedSet_erase_func "erase(Q const&, Func)"
657 but \p pred is used for key comparing
658 \p Less has the interface like \p std::less.
659 \p pred must imply the same element order as the comparator used for building the set.
661 template <typename Q, typename Less, typename Func>
662 value_type * erase_with( Q const& val, Less pred, Func f )
664 size_t nHash = hashing( val );
667 scoped_cell_lock sl( m_MutexPolicy, nHash );
668 pVal = bucket( nHash )->erase( val, pred, f );
676 /// Find the key \p val
677 /** \anchor cds_intrusive_StripedSet_find_func
678 The function searches the item with key equal to \p val and calls the functor \p f for item found.
679 The interface of \p Func functor is:
682 void operator()( value_type& item, Q& val );
685 where \p item is the item found, \p val is the <tt>find</tt> function argument.
687 The functor may change non-key fields of \p item.
689 The \p val argument is non-const since it can be used as \p f functor destination i.e., the functor
690 may modify both arguments.
692 Note the hash functor specified for class \p Traits template parameter
693 should accept a parameter of type \p Q that can be not the same as \p value_type.
695 The function returns \p true if \p val is found, \p false otherwise.
697 template <typename Q, typename Func>
698 bool find( Q& val, Func f )
700 return find_( val, f );
703 /// Find the key \p val using \p pred predicate
705 The function is an analog of \ref cds_intrusive_StripedSet_find_func "find(Q&, Func)"
706 but \p pred is used for key comparing
707 \p Less has the interface like \p std::less.
708 \p pred must imply the same element order as the comparator used for building the set.
710 template <typename Q, typename Less, typename Func>
711 bool find_with( Q& val, Less pred, Func f )
713 return find_with_( val, pred, f );
716 /// Find the key \p val
717 /** \anchor cds_intrusive_StripedSet_find_cfunc
718 The function searches the item with key equal to \p val and calls the functor \p f for item found.
719 The interface of \p Func functor is:
722 void operator()( value_type& item, Q const& val );
725 where \p item is the item found, \p val is the <tt>find</tt> function argument.
727 The functor may change non-key fields of \p item.
729 The \p val argument is non-const since it can be used as \p f functor destination i.e., the functor
730 may modify both arguments.
732 The function returns \p true if \p val is found, \p false otherwise.
734 template <typename Q, typename Func>
735 bool find( Q const& val, Func f )
737 return find_( val, f );
740 /// Find the key \p val using \p pred predicate
742 The function is an analog of \ref cds_intrusive_StripedSet_find_cfunc "find(Q const&, Func)"
743 but \p pred is used for key comparing
744 \p Less has the interface like \p std::less.
745 \p pred must imply the same element order as the comparator used for building the set.
747 template <typename Q, typename Less, typename Func>
748 bool find_with( Q const& val, Less pred, Func f )
750 return find_with_( val, pred, f );
753 /// Checks whether the set contains \p key
755 The function searches the item with key equal to \p key
756 and returns \p true if it is found, and \p false otherwise.
758 Note the hash functor specified for class \p Traits template parameter
759 should accept a parameter of type \p Q that can be not the same as \p value_type.
760 Otherwise, you may use \p contains( Q const&, Less pred ) functions with explicit predicate for key comparing.
762 template <typename Q>
763 bool contains( Q const& key )
765 return find( key, [](value_type&, Q const& ) {} );
768 template <typename Q>
769 CDS_DEPRECATED("use contains()")
770 bool find( Q const& val )
772 return contains( val ;)
776 /// Checks whether the set contains \p key using \p pred predicate for searching
778 The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
779 \p Less functor has the interface like \p std::less.
780 \p Less must imply the same element order as the comparator used for building the set.
782 template <typename Q, typename Less>
783 bool contains( Q const& key, Less pred )
785 return find_with( key, pred, [](value_type& , Q const& ) {} );
788 template <typename Q, typename Less>
789 CDS_DEPRECATED("use contains()")
790 bool find_with( Q const& val, Less pred )
792 return contains( val, pred );
798 The function unlinks all items from the set.
802 // locks entire array
803 scoped_full_lock sl( m_MutexPolicy );
805 size_t nBucketCount = bucket_count();
806 bucket_type * pBucket = m_Buckets;
807 for ( size_t i = 0; i < nBucketCount; ++i, ++pBucket )
809 m_ItemCounter.reset();
812 /// Clears the set and calls \p disposer for each item
814 The function unlinks all items from the set calling \p disposer for each item.
815 \p Disposer functor interface is:
818 void operator()( value_type * p );
822 template <typename Disposer>
823 void clear_and_dispose( Disposer disposer )
825 // locks entire array
826 scoped_full_lock sl( m_MutexPolicy );
828 size_t nBucketCount = bucket_count();
829 bucket_type * pBucket = m_Buckets;
830 for ( size_t i = 0; i < nBucketCount; ++i, ++pBucket )
831 pBucket->clear( disposer );
832 m_ItemCounter.reset();
835 /// Checks if the set is empty
837 Emptiness is checked by item counting: if item count is zero then the set is empty.
844 /// Returns item count in the set
847 return m_ItemCounter;
850 /// Returns the size of hash table
852 The hash table size is non-constant and can be increased via resizing.
854 size_t bucket_count() const
856 return m_nBucketMask + 1;
859 /// Returns lock array size
860 size_t lock_count() const
862 return m_MutexPolicy.lock_count();
865 /// Returns resizing policy object
866 resizing_policy& get_resizing_policy()
868 return m_ResizingPolicy;
871 /// Returns resizing policy (const version)
872 resizing_policy const& get_resizing_policy() const
874 return m_ResizingPolicy;
877 }} // namespace cds::itrusive
879 #endif // #ifndef CDSLIB_INTRUSIVE_STRIPED_SET_H