remove CDS_CONSTEXPR_CONST macro
[libcds.git] / cds / container / michael_set_rcu.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_CONTAINER_MICHAEL_SET_RCU_H
4 #define __CDS_CONTAINER_MICHAEL_SET_RCU_H
5
6 #include <cds/container/details/michael_set_base.h>
7 #include <cds/details/allocator.h>
8
9 namespace cds { namespace container {
10
11     /// Michael's hash set (template specialization for \ref cds_urcu_desc "RCU")
12     /** @ingroup cds_nonintrusive_set
13         \anchor cds_nonintrusive_MichaelHashSet_rcu
14
15         Source:
16             - [2002] Maged Michael "High performance dynamic lock-free hash tables and list-based sets"
17
18         Michael's hash table algorithm is based on lock-free ordered list and it is very simple.
19         The main structure is an array \p T of size \p M. Each element in \p T is basically a pointer
20         to a hash bucket, implemented as a singly linked list. The array of buckets cannot be dynamically expanded.
21         However, each bucket may contain unbounded number of items.
22
23         Template parameters are:
24         - \p RCU - one of \ref cds_urcu_gc "RCU type"
25         - \p OrderedList - ordered list implementation used as bucket for hash set, for example, MichaelList.
26             The ordered list implementation specifies the type \p T stored in the hash-set,
27             the comparison functor for the type \p T and other features specific for
28             the ordered list.
29         - \p Traits - type traits. See michael_set::type_traits for explanation.
30
31         Instead of defining \p Traits struct you may use option-based syntax with michael_set::make_traits metafunction.
32         For michael_set::make_traits the following option may be used:
33         - opt::hash - mandatory option, specifies hash functor.
34         - opt::item_counter - optional, specifies item counting policy. See michael_set::type_traits for explanation.
35         - opt::allocator - optional, bucket table allocator. Default is \ref CDS_DEFAULT_ALLOCATOR.
36
37         \note About hash functor see \ref cds_nonintrusive_MichaelHashSet_hash_functor "MichaelSet".
38
39         <b>How to use</b>
40
41         Suppose, we have the following type \p Foo that we want to store in our MichaelHashSet:
42         \code
43         struct Foo {
44             int     nKey    ;   // key field
45             int     nVal    ;   // value field
46         };
47         \endcode
48
49         To use \p %MichaelHashSet for \p Foo values, you should first choose suitable ordered list class
50         that will be used as a bucket for the set. We will cds::urcu::general_buffered<> RCU type and
51         MichaelList as a bucket type.
52         You should include RCU-related header file (<tt>cds/urcu/general_buffered.h</tt> in this example)
53         before including <tt>cds/container/michael_set_rcu.h</tt>.
54         Also, for ordered list we should develop a comparator for our \p Foo struct.
55         \code
56         #include <cds/urcu/general_buffered.h>
57         #include <cds/container/michael_list_rcu.h>
58         #include <cds/container/michael_set_rcu.h>
59
60         namespace cc = cds::container;
61
62         // Foo comparator
63         struct Foo_cmp {
64             int operator ()(Foo const& v1, Foo const& v2 ) const
65             {
66                 if ( std::less( v1.nKey, v2.nKey ))
67                     return -1;
68                 return std::less(v2.nKey, v1.nKey) ? 1 : 0;
69             }
70         };
71
72         // Our ordered list
73         typedef cc::MichaelList< cds::urcu::gc< cds::urcu::general_buffered<> >, Foo,
74             typename cc::michael_list::make_traits<
75                 cc::opt::compare< Foo_cmp >     // item comparator option
76             >::type
77         > bucket_list;
78
79         // Hash functor for Foo
80         struct foo_hash {
81             size_t operator ()( int i ) const
82             {
83                 return std::hash( i );
84             }
85             size_t operator()( Foo const& i ) const
86             {
87                 return std::hash( i.nKey );
88             }
89         };
90
91         // Declare set type.
92         // Note that \p RCU template parameter of ordered list must be equal \p RCU for the set.
93         typedef cc::MichaelHashSet< cds::urcu::gc< cds::urcu::general_buffered<> >, bucket_list,
94             cc::michael_set::make_traits<
95                 cc::opt::hash< foo_hash >
96             >::type
97         > foo_set;
98
99         // Set variable
100         foo_set fooSet;
101         \endcode
102     */
103     template <
104         class RCU,
105         class OrderedList,
106 #ifdef CDS_DOXYGEN_INVOKED
107         class Traits = michael_set::type_traits
108 #else
109         class Traits
110 #endif
111     >
112     class MichaelHashSet< cds::urcu::gc< RCU >, OrderedList, Traits >
113     {
114     public:
115         typedef OrderedList bucket_type     ;   ///< type of ordered list used as a bucket implementation
116         typedef Traits      options         ;   ///< Traits template parameters
117
118         typedef typename bucket_type::value_type        value_type      ;   ///< type of value stored in the list
119         typedef cds::urcu::gc< RCU >                    gc              ;   ///< RCU used as garbage collector
120         typedef typename bucket_type::key_comparator    key_comparator  ;   ///< key comparing functor
121
122         /// Hash functor for \ref value_type and all its derivatives that you use
123         typedef typename cds::opt::v::hash_selector< typename options::hash >::type   hash;
124         typedef typename options::item_counter          item_counter    ;   ///< Item counter type
125
126         /// Bucket table allocator
127         typedef cds::details::Allocator< bucket_type, typename options::allocator >  bucket_table_allocator;
128
129         typedef typename bucket_type::rcu_lock      rcu_lock   ; ///< RCU scoped lock
130         typedef typename bucket_type::exempt_ptr    exempt_ptr ; ///< pointer to extracted node
131         /// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
132         static CDS_CONSTEXPR const bool c_bExtractLockExternal = bucket_type::c_bExtractLockExternal;
133
134     protected:
135         item_counter    m_ItemCounter   ;   ///< Item counter
136         hash            m_HashFunctor   ;   ///< Hash functor
137
138         bucket_type *   m_Buckets       ;   ///< bucket table
139
140     private:
141         //@cond
142         const size_t    m_nHashBitmask;
143         //@endcond
144
145     protected:
146         /// Calculates hash value of \p key
147         template <typename Q>
148         size_t hash_value( Q const& key ) const
149         {
150             return m_HashFunctor( key ) & m_nHashBitmask;
151         }
152
153         /// Returns the bucket (ordered list) for \p key
154         //@{
155         template <typename Q>
156         bucket_type&    bucket( Q const& key )
157         {
158             return m_Buckets[ hash_value( key ) ];
159         }
160         template <typename Q>
161         bucket_type const&    bucket( Q const& key ) const
162         {
163             return m_Buckets[ hash_value( key ) ];
164         }
165         //@}
166     public:
167         /// Forward iterator
168         /**
169             The forward iterator for Michael's set is based on \p OrderedList forward iterator and has some features:
170             - it has no post-increment operator
171             - it iterates items in unordered fashion
172             - The iterator cannot be moved across thread boundary since it may contain GC's guard that is thread-private GC data.
173             - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
174               deleting operations it is no guarantee that you iterate all item in the set.
175
176             Therefore, the use of iterators in concurrent environment is not good idea. Use the iterator for the concurrent container
177             for debug purpose only.
178         */
179         typedef michael_set::details::iterator< bucket_type, false >    iterator;
180
181         /// Const forward iterator
182         typedef michael_set::details::iterator< bucket_type, true >     const_iterator;
183
184         /// Returns a forward iterator addressing the first element in a set
185         /**
186             For empty set \code begin() == end() \endcode
187         */
188         iterator begin()
189         {
190             return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count() );
191         }
192
193         /// Returns an iterator that addresses the location succeeding the last element in a set
194         /**
195             Do not use the value returned by <tt>end</tt> function to access any item.
196             The returned value can be used only to control reaching the end of the set.
197             For empty set \code begin() == end() \endcode
198         */
199         iterator end()
200         {
201             return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
202         }
203
204         /// Returns a forward const iterator addressing the first element in a set
205         //@{
206         const_iterator begin() const
207         {
208             return get_const_begin();
209         }
210         const_iterator cbegin()
211         {
212             return get_const_begin();
213         }
214         //@}
215
216         /// Returns an const iterator that addresses the location succeeding the last element in a set
217         //@{
218         const_iterator end() const
219         {
220             return get_const_end();
221         }
222         const_iterator cend()
223         {
224             return get_const_end();
225         }
226         //@}
227
228     private:
229         //@cond
230         const_iterator get_const_begin() const
231         {
232             return const_iterator( const_cast<bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
233         }
234         const_iterator get_const_end() const
235         {
236             return const_iterator( const_cast<bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
237         }
238         //@endcond
239
240     public:
241         /// Initialize hash set
242         /**
243             The Michael's hash set is non-expandable container. You should point the average count of items \p nMaxItemCount
244             when you create an object.
245             \p nLoadFactor parameter defines average count of items per bucket and it should be small number between 1 and 10.
246             Remember, since the bucket implementation is an ordered list, searching in the bucket is linear [<tt>O(nLoadFactor)</tt>].
247             Note, that many popular STL hash map implementation uses load factor 1.
248
249             The ctor defines hash table size as rounding <tt>nMacItemCount / nLoadFactor</tt> up to nearest power of two.
250         */
251         MichaelHashSet(
252             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
253             size_t nLoadFactor      ///< load factor: estimation of max number of items in the bucket
254         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
255         {
256             // GC and OrderedList::gc must be the same
257             static_assert(( std::is_same<gc, typename bucket_type::gc>::value ), "GC and OrderedList::gc must be the same");
258
259             // atomicity::empty_item_counter is not allowed as a item counter
260             static_assert(( !std::is_same<item_counter, atomicity::empty_item_counter>::value ), "atomicity::empty_item_counter is not allowed as a item counter");
261
262             m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
263         }
264
265         /// Clear hash set and destroy it
266         ~MichaelHashSet()
267         {
268             clear();
269             bucket_table_allocator().Delete( m_Buckets, bucket_count() );
270         }
271
272         /// Inserts new node
273         /**
274             The function creates a node with copy of \p val value
275             and then inserts the node created into the set.
276
277             The type \p Q should contain as minimum the complete key for the node.
278             The object of \ref value_type should be constructible from a value of type \p Q.
279             In trivial case, \p Q is equal to \ref value_type.
280
281             The function applies RCU lock internally.
282
283             Returns \p true if \p val is inserted into the set, \p false otherwise.
284         */
285         template <typename Q>
286         bool insert( Q const& val )
287         {
288             const bool bRet = bucket( val ).insert( val );
289             if ( bRet )
290                 ++m_ItemCounter;
291             return bRet;
292         }
293
294         /// Inserts new node
295         /**
296             The function allows to split creating of new item into two part:
297             - create item with key only
298             - insert new item into the set
299             - if inserting is success, calls  \p f functor to initialize value-fields of \p val.
300
301             The functor signature is:
302             \code
303                 void func( value_type& val );
304             \endcode
305             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
306             \p val no any other changes could be made on this set's item by concurrent threads.
307             The user-defined functor is called only if the inserting is success. It may be passed by reference
308             using \p std::ref
309
310             The function applies RCU lock internally.
311         */
312         template <typename Q, typename Func>
313         bool insert( Q const& val, Func f )
314         {
315             const bool bRet = bucket( val ).insert( val, f );
316             if ( bRet )
317                 ++m_ItemCounter;
318             return bRet;
319         }
320
321         /// Ensures that the item exists in the set
322         /**
323             The operation performs inserting or changing data with lock-free manner.
324
325             If the \p val key not found in the set, then the new item created from \p val
326             is inserted into the set. Otherwise, the functor \p func is called with the item found.
327             The functor \p Func should be a function with signature:
328             \code
329                 void func( bool bNew, value_type& item, const Q& val );
330             \endcode
331             or a functor:
332             \code
333                 struct my_functor {
334                     void operator()( bool bNew, value_type& item, const Q& val );
335                 };
336             \endcode
337
338             with arguments:
339             - \p bNew - \p true if the item has been inserted, \p false otherwise
340             - \p item - item of the set
341             - \p val - argument \p key passed into the \p ensure function
342
343             The functor may change non-key fields of the \p item; however, \p func must guarantee
344             that during changing no any other modifications could be made on this item by concurrent threads.
345
346             You may pass \p func argument by reference using \p std::ref
347
348             The function applies RCU lock internally.
349
350             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
351             \p second is true if new item has been added or \p false if the item with \p key
352             already is in the set.
353         */
354         template <typename Q, typename Func>
355         std::pair<bool, bool> ensure( const Q& val, Func func )
356         {
357             std::pair<bool, bool> bRet = bucket( val ).ensure( val, func );
358             if ( bRet.first && bRet.second )
359                 ++m_ItemCounter;
360             return bRet;
361         }
362
363         /// Inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
364         /**
365             Returns \p true if inserting successful, \p false otherwise.
366
367             The function applies RCU lock internally.
368         */
369         template <typename... Args>
370         bool emplace( Args&&... args )
371         {
372             bool bRet = bucket( value_type(std::forward<Args>(args)...) ).emplace( std::forward<Args>(args)... );
373             if ( bRet )
374                 ++m_ItemCounter;
375             return bRet;
376         }
377
378         /// Deletes \p key from the set
379         /** \anchor cds_nonintrusive_MichealSet_rcu_erase_val
380
381             Since the key of MichaelHashSet's item type \ref value_type is not explicitly specified,
382             template parameter \p Q defines the key type searching in the list.
383             The set item comparator should be able to compare the type \p value_type
384             and the type \p Q.
385
386             RCU \p synchronize method can be called. RCU should not be locked.
387
388             Return \p true if key is found and deleted, \p false otherwise
389         */
390         template <typename Q>
391         bool erase( Q const& key )
392         {
393             const bool bRet = bucket( key ).erase( key );
394             if ( bRet )
395                 --m_ItemCounter;
396             return bRet;
397         }
398
399         /// Deletes the item from the set using \p pred predicate for searching
400         /**
401             The function is an analog of \ref cds_nonintrusive_MichealSet_rcu_erase_val "erase(Q const&)"
402             but \p pred is used for key comparing.
403             \p Less functor has the interface like \p std::less.
404             \p Less must imply the same element order as the comparator used for building the set.
405         */
406         template <typename Q, typename Less>
407         bool erase_with( Q const& key, Less pred )
408         {
409             const bool bRet = bucket( key ).erase_with( key, pred );
410             if ( bRet )
411                 --m_ItemCounter;
412             return bRet;
413         }
414
415         /// Deletes \p key from the set
416         /** \anchor cds_nonintrusive_MichealSet_rcu_erase_func
417
418             The function searches an item with key \p key, calls \p f functor
419             and deletes the item. If \p key is not found, the functor is not called.
420
421             The functor \p Func interface:
422             \code
423             struct extractor {
424                 void operator()(value_type const& val);
425             };
426             \endcode
427             The functor may be passed by reference using <tt>boost:ref</tt>
428
429             Since the key of %MichaelHashSet's \p value_type is not explicitly specified,
430             template parameter \p Q defines the key type searching in the list.
431             The list item comparator should be able to compare the type \p T of list item
432             and the type \p Q.
433
434             RCU \p synchronize method can be called. RCU should not be locked.
435
436             Return \p true if key is found and deleted, \p false otherwise
437         */
438         template <typename Q, typename Func>
439         bool erase( Q const& key, Func f )
440         {
441             const bool bRet = bucket( key ).erase( key, f );
442             if ( bRet )
443                 --m_ItemCounter;
444             return bRet;
445         }
446
447         /// Deletes the item from the set using \p pred predicate for searching
448         /**
449             The function is an analog of \ref cds_nonintrusive_MichealSet_rcu_erase_func "erase(Q const&, Func)"
450             but \p pred is used for key comparing.
451             \p Less functor has the interface like \p std::less.
452             \p Less must imply the same element order as the comparator used for building the set.
453         */
454         template <typename Q, typename Less, typename Func>
455         bool erase_with( Q const& key, Less pred, Func f )
456         {
457             const bool bRet = bucket( key ).erase_with( key, pred, f );
458             if ( bRet )
459                 --m_ItemCounter;
460             return bRet;
461         }
462
463         /// Extracts an item from the set
464         /** \anchor cds_nonintrusive_MichaelHashSet_rcu_extract
465             The function searches an item with key equal to \p val in the set,
466             unlinks it from the set, places item pointer into \p dest argument, and returns \p true.
467             If the item with the key equal to \p val is not found the function return \p false.
468
469             @note The function does NOT call RCU read-side lock or synchronization,
470             and does NOT dispose the item found. It just excludes the item from the set
471             and returns a pointer to item found.
472             You should lock RCU before calling of the function, and you should synchronize RCU
473             outside the RCU lock to free extracted item
474
475             \code
476             #include <cds/urcu/general_buffered.h>
477             #include <cds/container/michael_list_rcu.h>
478             #include <cds/container/michael_set_rcu.h>
479
480             typedef cds::urcu::gc< general_buffered<> > rcu;
481             typedef cds::container::MichaelList< rcu, Foo > rcu_michael_list;
482             typedef cds::container::MichaelHashSet< rcu, rcu_michael_list, foo_traits > rcu_michael_set;
483
484             rcu_michael_set theSet;
485             // ...
486
487             rcu_michael_set::exempt_ptr p;
488             {
489                 // first, we should lock RCU
490                 rcu_michael_set::rcu_lock lock;
491
492                 // Now, you can apply extract function
493                 // Note that you must not delete the item found inside the RCU lock
494                 if ( theSet.extract( p, 10 )) {
495                     // do something with p
496                     ...
497                 }
498             }
499
500             // We may safely release p here
501             // release() passes the pointer to RCU reclamation cycle
502             p.release();
503             \endcode
504         */
505         template <typename Q>
506         bool extract( exempt_ptr& dest, Q const& val )
507         {
508             if ( bucket( val ).extract( dest, val )) {
509                 --m_ItemCounter;
510                 return true;
511             }
512             return false;
513         }
514
515         /// Extracts an item from the set using \p pred predicate for searching
516         /**
517             The function is an analog of \ref cds_nonintrusive_MichaelHashSet_rcu_extract "extract(exempt_ptr&, Q const&)"
518             but \p pred is used for key comparing.
519             \p Less functor has the interface like \p std::less.
520             \p pred must imply the same element order as the comparator used for building the set.
521         */
522         template <typename Q, typename Less>
523         bool extract_with( exempt_ptr& dest, Q const& val, Less pred )
524         {
525             if ( bucket( val ).extract_with( dest, val, pred )) {
526                 --m_ItemCounter;
527                 return true;
528             }
529             return false;
530         }
531
532         /// Finds the key \p val
533         /** \anchor cds_nonintrusive_MichealSet_rcu_find_func
534
535             The function searches the item with key equal to \p val and calls the functor \p f for item found.
536             The interface of \p Func functor is:
537             \code
538             struct functor {
539                 void operator()( value_type& item, Q& val );
540             };
541             \endcode
542             where \p item is the item found, \p val is the <tt>find</tt> function argument.
543
544             You may pass \p f argument by reference using \p std::ref.
545
546             The functor may change non-key fields of \p item. Note that the functor is only guarantee
547             that \p item cannot be disposed during functor is executing.
548             The functor does not serialize simultaneous access to the set's \p item. If such access is
549             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
550
551             The \p val argument is non-const since it can be used as \p f functor destination i.e., the functor
552             can modify both arguments.
553
554             Note the hash functor specified for class \p Traits template parameter
555             should accept a parameter of type \p Q that may be not the same as \p value_type.
556
557             The function applies RCU lock internally.
558
559             The function returns \p true if \p val is found, \p false otherwise.
560         */
561         template <typename Q, typename Func>
562         bool find( Q& val, Func f ) const
563         {
564             return bucket( val ).find( val, f );
565         }
566
567         /// Finds the key \p val using \p pred predicate for searching
568         /**
569             The function is an analog of \ref cds_nonintrusive_MichealSet_rcu_find_func "find(Q&, Func)"
570             but \p pred is used for key comparing.
571             \p Less functor has the interface like \p std::less.
572             \p Less must imply the same element order as the comparator used for building the set.
573         */
574         template <typename Q, typename Less, typename Func>
575         bool find_with( Q& val, Less pred, Func f ) const
576         {
577             return bucket( val ).find_with( val, pred, f );
578         }
579
580         /// Finds the key \p val
581         /** \anchor cds_nonintrusive_MichealSet_rcu_find_cfunc
582
583             The function searches the item with key equal to \p val and calls the functor \p f for item found.
584             The interface of \p Func functor is:
585             \code
586             struct functor {
587                 void operator()( value_type& item, Q const& val );
588             };
589             \endcode
590             where \p item is the item found, \p val is the <tt>find</tt> function argument.
591
592             You may pass \p f argument by reference using \p std::ref.
593
594             The functor may change non-key fields of \p item. Note that the functor is only guarantee
595             that \p item cannot be disposed during functor is executing.
596             The functor does not serialize simultaneous access to the set's \p item. If such access is
597             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
598
599             Note the hash functor specified for class \p Traits template parameter
600             should accept a parameter of type \p Q that may be not the same as \p value_type.
601
602             The function applies RCU lock internally.
603
604             The function returns \p true if \p val is found, \p false otherwise.
605         */
606         template <typename Q, typename Func>
607         bool find( Q const& val, Func f ) const
608         {
609             return bucket( val ).find( val, f );
610         }
611
612         /// Finds the key \p val using \p pred predicate for searching
613         /**
614             The function is an analog of \ref cds_nonintrusive_MichealSet_rcu_find_cfunc "find(Q const&, Func)"
615             but \p pred is used for key comparing.
616             \p Less functor has the interface like \p std::less.
617             \p Less must imply the same element order as the comparator used for building the set.
618         */
619         template <typename Q, typename Less, typename Func>
620         bool find_with( Q const& val, Less pred, Func f ) const
621         {
622             return bucket( val ).find_with( val, pred, f );
623         }
624
625         /// Finds the key \p val
626         /** \anchor cds_nonintrusive_MichealSet_rcu_find_val
627
628             The function searches the item with key equal to \p val
629             and returns \p true if it is found, and \p false otherwise.
630
631             Note the hash functor specified for class \p Traits template parameter
632             should accept a parameter of type \p Q that may be not the same as \ref value_type.
633         */
634         template <typename Q>
635         bool find( Q const & val ) const
636         {
637             return bucket( val ).find( val );
638         }
639
640         /// Finds the key \p val using \p pred predicate for searching
641         /**
642             The function is an analog of \ref cds_nonintrusive_MichealSet_rcu_find_val "find(Q const&)"
643             but \p pred is used for key comparing.
644             \p Less functor has the interface like \p std::less.
645             \p Less must imply the same element order as the comparator used for building the set.
646         */
647         template <typename Q, typename Less>
648         bool find_with( Q const & val, Less pred ) const
649         {
650             return bucket( val ).find_with( val, pred );
651         }
652
653         /// Finds the key \p val and return the item found
654         /** \anchor cds_nonintrusive_MichaelHashSet_rcu_get
655             The function searches the item with key equal to \p val and returns the pointer to item found.
656             If \p val is not found it returns \p nullptr.
657
658             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
659
660             RCU should be locked before call of this function.
661             Returned item is valid only while RCU is locked:
662             \code
663             typedef cds::container::MichaelHashSet< your_template_parameters > hash_set;
664             hash_set theSet;
665             // ...
666             {
667                 // Lock RCU
668                 hash_set::rcu_lock lock;
669
670                 foo * pVal = theSet.get( 5 );
671                 if ( pVal ) {
672                     // Deal with pVal
673                     //...
674                 }
675                 // Unlock RCU by rcu_lock destructor
676                 // pVal can be freed at any time after RCU has been unlocked
677             }
678             \endcode
679         */
680         template <typename Q>
681         value_type * get( Q const& val ) const
682         {
683             return bucket( val ).get( val );
684         }
685
686         /// Finds the key \p val and return the item found
687         /**
688             The function is an analog of \ref cds_nonintrusive_MichaelHashSet_rcu_get "get(Q const&)"
689             but \p pred is used for comparing the keys.
690
691             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
692             in any order.
693             \p pred must imply the same element order as the comparator used for building the set.
694         */
695         template <typename Q, typename Less>
696         value_type * get_with( Q const& val, Less pred ) const
697         {
698             return bucket( val ).get_with( val, pred );
699         }
700
701         /// Clears the set (non-atomic)
702         /**
703             The function erases all items from the set.
704
705             The function is not atomic. It cleans up each bucket and then resets the item counter to zero.
706             If there are a thread that performs insertion while \p clear is working the result is undefined in general case:
707             <tt> empty() </tt> may return \p true but the set may contain item(s).
708             Therefore, \p clear may be used only for debugging purposes.
709
710             RCU \p synchronize method can be called. RCU should not be locked.
711         */
712         void clear()
713         {
714             for ( size_t i = 0; i < bucket_count(); ++i )
715                 m_Buckets[i].clear();
716             m_ItemCounter.reset();
717         }
718
719         /// Checks if the set is empty
720         /**
721             Emptiness is checked by item counting: if item count is zero then the set is empty.
722             Thus, the correct item counting feature is an important part of Michael's set implementation.
723         */
724         bool empty() const
725         {
726             return size() == 0;
727         }
728
729         /// Returns item count in the set
730         size_t size() const
731         {
732             return m_ItemCounter;
733         }
734
735         /// Returns the size of hash table
736         /**
737             Since MichaelHashSet cannot dynamically extend the hash table size,
738             the value returned is an constant depending on object initialization parameters;
739             see MichaelHashSet::MichaelHashSet for explanation.
740         */
741         size_t bucket_count() const
742         {
743             return m_nHashBitmask + 1;
744         }
745     };
746
747 }} // namespace cds::container
748
749 #endif // ifndef __CDS_CONTAINER_MICHAEL_SET_H