Uses different pass count for different parallel queue test cases
[libcds.git] / cds / intrusive / michael_set_rcu.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_RCU_H
32 #define CDSLIB_INTRUSIVE_MICHAEL_SET_RCU_H
33
34 #include <cds/intrusive/details/michael_set_base.h>
35
36 namespace cds { namespace intrusive {
37
38     /// Michael's hash set, \ref cds_urcu_desc "RCU" specialization
39     /** @ingroup cds_intrusive_map
40         \anchor cds_intrusive_MichaelHashSet_rcu
41
42         Source:
43             - [2002] Maged Michael "High performance dynamic lock-free hash tables and list-based sets"
44
45         Michael's hash table algorithm is based on lock-free ordered list and it is very simple.
46         The main structure is an array \p T of size \p M. Each element in \p T is basically a pointer
47         to a hash bucket, implemented as a singly linked list. The array of buckets cannot be dynamically expanded.
48         However, each bucket may contain unbounded number of items.
49
50         Template parameters are:
51         - \p RCU - one of \ref cds_urcu_gc "RCU type"
52         - \p OrderedList - ordered list implementation used as bucket for hash set, for example, MichaelList, LazyList.
53             The intrusive ordered list implementation specifies the type \p T stored in the hash-set, the reclamation
54             schema \p GC used by hash-set, the comparison functor for the type \p T and other features specific for
55             the ordered list.
56         - \p Traits - type traits, default is \p michael_set::traits.
57             Instead of defining \p Traits struct you can use option-based syntax with \p michael_set::make_traits metafunction.
58
59         \par Usage
60             Before including <tt><cds/intrusive/michael_set_rcu.h></tt> you should include appropriate RCU header file,
61             see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
62             For example, for \ref cds_urcu_general_buffered_gc "general-purpose buffered RCU" you should include:
63             \code
64             #include <cds/urcu/general_buffered.h>
65             #include <cds/intrusive/michael_list_rcu.h>
66             #include <cds/intrusive/michael_set_rcu.h>
67
68             struct Foo { ... };
69             // Hash functor for struct Foo
70             struct foo_hash {
71                 size_t operator()( Foo const& foo ) const { return ... }
72             };
73
74             // Now, you can declare Michael's list for type Foo and default traits:
75             typedef cds::intrusive::MichaelList<cds::urcu::gc< general_buffered<> >, Foo > rcu_michael_list;
76
77             // Declare Michael's set with MichaelList as bucket type
78             typedef cds::intrusive::MichaelSet<
79                 cds::urcu::gc< general_buffered<> >,
80                 rcu_michael_list,
81                 cds::intrusive::michael_set::make_traits<
82                     cds::opt::::hash< foo_hash >
83                 >::type
84             > rcu_michael_set;
85
86             // Declares hash set for 1000000 items with load factor 2
87             rcu_michael_set theSet( 1000000, 2 );
88
89             // Now you can use theSet object in many threads without any synchronization.
90             \endcode
91     */
92     template <
93         class RCU,
94         class OrderedList,
95 #ifdef CDS_DOXYGEN_INVOKED
96         class Traits = michael_set::traits
97 #else
98         class Traits
99 #endif
100     >
101     class MichaelHashSet< cds::urcu::gc< RCU >, OrderedList, Traits >
102     {
103     public:
104         typedef cds::urcu::gc< RCU > gc;            ///< RCU schema
105         typedef OrderedList          ordered_list;  ///< type of ordered list used as a bucket implementation
106         typedef Traits               traits;        ///< Set traits
107
108         typedef typename ordered_list::value_type     value_type;       ///< type of value stored in the list
109         typedef typename ordered_list::key_comparator key_comparator;   ///< key comparing functor
110         typedef typename ordered_list::disposer       disposer;         ///< Node disposer functor
111 #ifdef CDS_DOXYGEN_INVOKED
112         typedef typename ordered_list::stat           stat;             ///< Internal statistics
113 #endif
114
115         /// Hash functor for \ref value_type and all its derivatives that you use
116         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
117         typedef typename traits::item_counter item_counter;   ///< Item counter type
118         typedef typename traits::allocator    allocator;      ///< Bucket table allocator
119
120         typedef typename ordered_list::rcu_lock    rcu_lock;   ///< RCU scoped lock
121         /// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
122         static CDS_CONSTEXPR const bool c_bExtractLockExternal = ordered_list::c_bExtractLockExternal;
123
124         // GC and OrderedList::gc must be the same
125         static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
126
127     protected:
128         //@cond
129         typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
130
131         typedef typename ordered_list::template rebind_traits<
132             cds::opt::item_counter< cds::atomicity::empty_item_counter >
133             , cds::opt::stat< typename bucket_stat::wrapped_stat >
134         >::type internal_bucket_type;
135
136         typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
137         //@endcond
138
139     public:
140         typedef typename internal_bucket_type::exempt_ptr  exempt_ptr; ///< pointer to extracted node
141         typedef typename internal_bucket_type::raw_ptr     raw_ptr;    ///< Return type of \p get() member function and its derivatives
142
143         //@cond
144         typedef typename bucket_stat::stat stat;
145         //@endcond
146
147     private:
148         //@cond
149         hash                    m_HashFunctor;   ///< Hash functor
150         size_t const            m_nHashBitmask;
151         internal_bucket_type*   m_Buckets;       ///< bucket table
152         item_counter            m_ItemCounter;   ///< Item counter
153         stat                    m_Stat;          ///< Internal statistics
154         //@endcond
155
156     public:
157     ///@name Forward iterators (thread-safe under RCU lock)
158     //@{
159         /// Forward iterator
160         /**
161             The forward iterator for Michael's set is based on \p OrderedList forward iterator and has some features:
162             - it has no post-increment operator
163             - it iterates items in unordered fashion
164
165             You may safely use iterators in multi-threaded environment only under RCU lock.
166             Otherwise, a crash is possible if another thread deletes the element the iterator points to.
167
168             The iterator interface:
169             \code
170             class iterator {
171             public:
172                 // Default constructor
173                 iterator();
174
175                 // Copy construtor
176                 iterator( iterator const& src );
177
178                 // Dereference operator
179                 value_type * operator ->() const;
180
181                 // Dereference operator
182                 value_type& operator *() const;
183
184                 // Preincrement operator
185                 iterator& operator ++();
186
187                 // Assignment operator
188                 iterator& operator = (iterator const& src);
189
190                 // Equality operators
191                 bool operator ==(iterator const& i ) const;
192                 bool operator !=(iterator const& i ) const;
193             };
194             \endcode
195         */
196         typedef michael_set::details::iterator< internal_bucket_type, false >    iterator;
197
198         /// Const forward iterator
199         /**
200             For iterator's features and requirements see \ref iterator
201         */
202         typedef michael_set::details::iterator< internal_bucket_type, true >     const_iterator;
203
204         /// Returns a forward iterator addressing the first element in a set
205         /**
206             For empty set \code begin() == end() \endcode
207         */
208         iterator begin()
209         {
210             return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count());
211         }
212
213         /// Returns an iterator that addresses the location succeeding the last element in a set
214         /**
215             Do not use the value returned by <tt>end</tt> function to access any item.
216             The returned value can be used only to control reaching the end of the set.
217             For empty set \code begin() == end() \endcode
218         */
219         iterator end()
220         {
221             return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count());
222         }
223
224         /// Returns a forward const iterator addressing the first element in a set
225         const_iterator begin() const
226         {
227             return cbegin();
228         }
229
230         /// Returns a forward const iterator addressing the first element in a set
231         const_iterator cbegin() const
232         {
233             return const_iterator( m_Buckets[0].cbegin(), m_Buckets, m_Buckets + bucket_count());
234         }
235
236         /// Returns an const iterator that addresses the location succeeding the last element in a set
237         const_iterator end() const
238         {
239             return cend();
240         }
241
242         /// Returns an const iterator that addresses the location succeeding the last element in a set
243         const_iterator cend() const
244         {
245             return const_iterator( m_Buckets[bucket_count() - 1].cend(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count());
246         }
247     //@}
248
249     public:
250         /// Initialize hash set
251         /**
252             The Michael's hash set is an unbounded container, but its hash table is non-expandable.
253             At construction time you should pass estimated maximum item count and a load factor.
254             The load factor is average size of one bucket - a small number between 1 and 10.
255             The bucket is an ordered single-linked list, the complexity of searching in the bucket is linear <tt>O(nLoadFactor)</tt>.
256             The constructor defines hash table size as rounding <tt>nMaxItemCount / nLoadFactor</tt> up to nearest power of two.
257         */
258         MichaelHashSet(
259             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
260             size_t nLoadFactor      ///< load factor: average size of the bucket
261         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
262           , m_Buckets( bucket_table_allocator().allocate( bucket_count()))
263         {
264             for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
265                 construct_bucket<bucket_stat>( it );
266         }
267
268         /// Clear hash set and destroy it
269         ~MichaelHashSet()
270         {
271             clear();
272
273             for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
274                 it->~internal_bucket_type();
275             bucket_table_allocator().deallocate( m_Buckets, bucket_count());
276         }
277
278         /// Inserts new node
279         /**
280             The function inserts \p val in the set if it does not contain
281             an item with key equal to \p val.
282
283             Returns \p true if \p val is placed into the set, \p false otherwise.
284         */
285         bool insert( value_type& val )
286         {
287             bool bRet = bucket( val ).insert( val );
288             if ( bRet )
289                 ++m_ItemCounter;
290             return bRet;
291         }
292
293         /// Inserts new node
294         /**
295             This function is intended for derived non-intrusive containers.
296
297             The function allows to split creating of new item into two part:
298             - create item with key only
299             - insert new item into the set
300             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
301
302             The functor signature is:
303             \code
304                 void func( value_type& val );
305             \endcode
306             where \p val is the item inserted.
307             The user-defined functor is called only if the inserting is success.
308
309             @warning For \ref cds_intrusive_MichaelList_rcu "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
310             \ref cds_intrusive_LazyList_rcu "LazyList" provides exclusive access to inserted item and does not require any node-level
311             synchronization.
312         */
313         template <typename Func>
314         bool insert( value_type& val, Func f )
315         {
316             bool bRet = bucket( val ).insert( val, f );
317             if ( bRet )
318                 ++m_ItemCounter;
319             return bRet;
320         }
321
322         /// Updates the element
323         /**
324             The operation performs inserting or changing data with lock-free manner.
325
326             If the item \p val not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
327             Otherwise, the functor \p func is called with item found.
328             The functor signature is:
329             \code
330                 struct functor {
331                     void operator()( bool bNew, value_type& item, value_type& val );
332                 };
333             \endcode
334             with arguments:
335             - \p bNew - \p true if the item has been inserted, \p false otherwise
336             - \p item - item of the set
337             - \p val - argument \p val passed into the \p %update() function
338             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
339             refers to the same thing.
340
341             The functor may change non-key fields of the \p item.
342
343             Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
344             \p second is \p true if new item has been added or \p false if the item with \p key
345             already is in the set.
346
347             @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
348             \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
349             synchronization.
350         */
351         template <typename Func>
352         std::pair<bool, bool> update( value_type& val, Func func, bool bAllowInsert = true )
353         {
354             std::pair<bool, bool> bRet = bucket( val ).update( val, func, bAllowInsert );
355             if ( bRet.second )
356                 ++m_ItemCounter;
357             return bRet;
358         }
359         //@cond
360         template <typename Func>
361         CDS_DEPRECATED("ensure() is deprecated, use update()")
362         std::pair<bool, bool> ensure( value_type& val, Func func )
363         {
364             return update( val, func, true );
365         }
366         //@endcond
367
368         /// Unlinks the item \p val from the set
369         /**
370             The function searches the item \p val in the set and unlink it from the set
371             if it is found and is equal to \p val.
372
373             The function returns \p true if success and \p false otherwise.
374         */
375         bool unlink( value_type& val )
376         {
377             bool bRet = bucket( val ).unlink( val );
378             if ( bRet )
379                 --m_ItemCounter;
380             return bRet;
381         }
382
383         /// Deletes the item from the set
384         /** \anchor cds_intrusive_MichaelHashSet_rcu_erase
385             The function searches an item with key equal to \p key in the set,
386             unlinks it from the set, and returns \p true.
387             If the item with key equal to \p key is not found the function return \p false.
388
389             Note the hash functor should accept a parameter of type \p Q that may be not the same as \p value_type.
390         */
391         template <typename Q>
392         bool erase( Q const& key )
393         {
394             if ( bucket( key ).erase( key )) {
395                 --m_ItemCounter;
396                 return true;
397             }
398             return false;
399         }
400
401         /// Deletes the item from the set using \p pred predicate for searching
402         /**
403             The function is an analog of \ref cds_intrusive_MichaelHashSet_rcu_erase "erase(Q const&)"
404             but \p pred is used for key comparing.
405             \p Less functor has the interface like \p std::less.
406             \p pred must imply the same element order as the comparator used for building the set.
407         */
408         template <typename Q, typename Less>
409         bool erase_with( Q const& key, Less pred )
410         {
411             if ( bucket( key ).erase_with( key, pred )) {
412                 --m_ItemCounter;
413                 return true;
414             }
415             return false;
416         }
417
418         /// Deletes the item from the set
419         /** \anchor cds_intrusive_MichaelHashSet_rcu_erase_func
420             The function searches an item with key equal to \p key in the set,
421             call \p f functor with item found, and unlinks it from the set.
422             The \ref disposer specified in \p OrderedList class template parameter is called
423             by garbage collector \p GC asynchronously.
424
425             The \p Func interface is
426             \code
427             struct functor {
428                 void operator()( value_type const& item );
429             };
430             \endcode
431
432             If the item with key equal to \p key is not found the function return \p false.
433
434             Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
435         */
436         template <typename Q, typename Func>
437         bool erase( const Q& key, Func f )
438         {
439             if ( bucket( key ).erase( key, f )) {
440                 --m_ItemCounter;
441                 return true;
442             }
443             return false;
444         }
445
446         /// Deletes the item from the set using \p pred predicate for searching
447         /**
448             The function is an analog of \ref cds_intrusive_MichaelHashSet_rcu_erase_func "erase(Q const&)"
449             but \p pred is used for key comparing.
450             \p Less functor has the interface like \p std::less.
451             \p pred must imply the same element order as the comparator used for building the set.
452         */
453         template <typename Q, typename Less, typename Func>
454         bool erase_with( const Q& key, Less pred, Func f )
455         {
456             if ( bucket( key ).erase_with( key, pred, f )) {
457                 --m_ItemCounter;
458                 return true;
459             }
460             return false;
461         }
462
463         /// Extracts an item from the set
464         /** \anchor cds_intrusive_MichaelHashSet_rcu_extract
465             The function searches an item with key equal to \p key in the set,
466             unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
467             If the item with the key equal to \p key is not found the function returns an empty \p exempt_ptr.
468
469             Depends on \p ordered_list you should or should not lock RCU before calling of this function:
470             - for the set based on \ref cds_intrusive_MichaelList_rcu "MichaelList" RCU should not be locked
471             - for the set based on \ref cds_intrusive_LazyList_rcu "LazyList" RCU should be locked
472
473             See ordered list implementation for details.
474
475             \code
476             #include <cds/urcu/general_buffered.h>
477             #include <cds/intrusive/michael_list_rcu.h>
478             #include <cds/intrusive/michael_set_rcu.h>
479
480             typedef cds::urcu::gc< general_buffered<> > rcu;
481             typedef cds::intrusive::MichaelList< rcu, Foo > rcu_michael_list;
482             typedef cds::intrusive::MichaelHashSet< rcu, rcu_michael_list, foo_traits > rcu_michael_set;
483
484             rcu_michael_set theSet;
485             // ...
486
487             typename rcu_michael_set::exempt_ptr p;
488
489             // For MichaelList we should not lock RCU
490
491             // Now, you can apply extract function
492             // Note that you must not delete the item found inside the RCU lock
493             p = theSet.extract( 10 )
494             if ( p ) {
495                 // do something with p
496                 ...
497             }
498
499             // We may safely release p here
500             // release() passes the pointer to RCU reclamation cycle:
501             // it invokes RCU retire_ptr function with the disposer you provided for rcu_michael_list.
502             p.release();
503             \endcode
504         */
505         template <typename Q>
506         exempt_ptr extract( Q const& key )
507         {
508             exempt_ptr p( bucket( key ).extract( key ));
509             if ( p )
510                 --m_ItemCounter;
511             return p;
512         }
513
514         /// Extracts an item from the set using \p pred predicate for searching
515         /**
516             The function is an analog of \p extract(Q const&) but \p pred is used for key comparing.
517             \p Less functor has the interface like \p std::less.
518             \p pred must imply the same element order as the comparator used for building the set.
519         */
520         template <typename Q, typename Less>
521         exempt_ptr extract_with( Q const& key, Less pred )
522         {
523             exempt_ptr p( bucket( key ).extract_with( key, pred ));
524             if ( p )
525                 --m_ItemCounter;
526             return p;
527         }
528
529         /// Checks whether the set contains \p key
530         /**
531
532             The function searches the item with key equal to \p key
533             and returns \p true if the key is found, and \p false otherwise.
534
535             Note the hash functor specified for class \p Traits template parameter
536             should accept a parameter of type \p Q that can be not the same as \p value_type.
537         */
538         template <typename Q>
539         bool contains( Q const& key )
540         {
541             return bucket( key ).contains( key );
542         }
543         //@cond
544         template <typename Q>
545         CDS_DEPRECATED("use contains()")
546         bool find( Q const& key )
547         {
548             return contains( key );
549         }
550         //@endcond
551
552         /// Checks whether the set contains \p key using \p pred predicate for searching
553         /**
554             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
555             \p Less functor has the interface like \p std::less.
556             \p Less must imply the same element order as the comparator used for building the set.
557         */
558         template <typename Q, typename Less>
559         bool contains( Q const& key, Less pred )
560         {
561             return bucket( key ).contains( key, pred );
562         }
563         //@cond
564         template <typename Q, typename Less>
565         CDS_DEPRECATED("use contains()")
566         bool find_with( Q const& key, Less pred )
567         {
568             return contains( key, pred );
569         }
570         //@endcond
571
572         /// Find the key \p key
573         /** \anchor cds_intrusive_MichaelHashSet_rcu_find_func
574             The function searches the item with key equal to \p key and calls the functor \p f for item found.
575             The interface of \p Func functor is:
576             \code
577             struct functor {
578                 void operator()( value_type& item, Q& key );
579             };
580             \endcode
581             where \p item is the item found, \p key is the <tt>find</tt> function argument.
582
583             The functor can change non-key fields of \p item.
584             The functor does not serialize simultaneous access to the set \p item. If such access is
585             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
586
587             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
588             can modify both arguments.
589
590             Note the hash functor specified for class \p Traits template parameter
591             should accept a parameter of type \p Q that can be not the same as \p value_type.
592
593             The function returns \p true if \p key is found, \p false otherwise.
594         */
595         template <typename Q, typename Func>
596         bool find( Q& key, Func f )
597         {
598             return bucket( key ).find( key, f );
599         }
600         //@cond
601         template <typename Q, typename Func>
602         bool find( Q const& key, Func f )
603         {
604             return bucket( key ).find( key, f );
605         }
606         //@endcond
607
608         /// Finds the key \p key using \p pred predicate for searching
609         /**
610             The function is an analog of \ref cds_intrusive_MichaelHashSet_rcu_find_func "find(Q&, Func)"
611             but \p pred is used for key comparing.
612             \p Less functor has the interface like \p std::less.
613             \p pred must imply the same element order as the comparator used for building the set.
614         */
615         template <typename Q, typename Less, typename Func>
616         bool find_with( Q& key, Less pred, Func f )
617         {
618             return bucket( key ).find_with( key, pred, f );
619         }
620         //@cond
621         template <typename Q, typename Less, typename Func>
622         bool find_with( Q const& key, Less pred, Func f )
623         {
624             return bucket( key ).find_with( key, pred, f );
625         }
626         //@endcond
627
628         /// Finds the key \p key and return the item found
629         /** \anchor cds_intrusive_MichaelHashSet_rcu_get
630             The function searches the item with key equal to \p key and returns the pointer to item found.
631             If \p key is not found it returns \p nullptr.
632             Note the type of returned value depends on underlying \p ordered_list.
633             For details, see documentation of ordered list you use.
634
635             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
636
637             RCU should be locked before call of this function.
638             Returned item is valid only while RCU is locked:
639             \code
640             typedef cds::intrusive::MichaelHashSet< your_template_parameters > hash_set;
641             hash_set theSet;
642             // ...
643             // Result of get() call
644             typename hash_set::raw_ptr ptr;
645             {
646                 // Lock RCU
647                 hash_set::rcu_lock lock;
648
649                 ptr = theSet.get( 5 );
650                 if ( ptr ) {
651                     // Deal with ptr
652                     //...
653                 }
654                 // Unlock RCU by rcu_lock destructor
655                 // ptr can be reclaimed by disposer at any time after RCU has been unlocked
656             }
657             \endcode
658         */
659         template <typename Q>
660         raw_ptr get( Q const& key )
661         {
662             return bucket( key ).get( key );
663         }
664
665         /// Finds the key \p key and return the item found
666         /**
667             The function is an analog of \ref cds_intrusive_MichaelHashSet_rcu_get "get(Q const&)"
668             but \p pred is used for comparing the keys.
669
670             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
671             in any order.
672             \p pred must imply the same element order as the comparator used for building the set.
673         */
674         template <typename Q, typename Less>
675         raw_ptr get_with( Q const& key, Less pred )
676         {
677             return bucket( key ).get_with( key, pred );
678         }
679
680         /// Clears the set (non-atomic)
681         /**
682             The function unlink all items from the set.
683             The function is not atomic. It cleans up each bucket and then resets the item counter to zero.
684             If there are a thread that performs insertion while \p clear is working the result is undefined in general case:
685             <tt> empty() </tt> may return \p true but the set may contain item(s).
686             Therefore, \p clear may be used only for debugging purposes.
687
688             For each item the \p disposer is called after unlinking.
689         */
690         void clear()
691         {
692             for ( size_t i = 0; i < bucket_count(); ++i )
693                 m_Buckets[i].clear();
694             m_ItemCounter.reset();
695         }
696
697
698         /// Checks if the set is empty
699         /**
700             @warning If you use \p atomicity::empty_item_counter in \p traits::item_counter,
701             the function always returns \p true.
702         */
703         bool empty() const
704         {
705             return size() == 0;
706         }
707
708         /// Returns item count in the set
709         /**
710             If you use \p atomicity::empty_item_counter in \p traits::item_counter,
711             the function always returns 0.
712         */
713         size_t size() const
714         {
715             return m_ItemCounter;
716         }
717
718         /// Returns the size of hash table
719         /**
720             Since %MichaelHashSet cannot dynamically extend the hash table size,
721             the value returned is an constant depending on object initialization parameters;
722             see \ref cds_intrusive_MichaelHashSet_hp "MichaelHashSet" for explanation.
723         */
724         size_t bucket_count() const
725         {
726             return m_nHashBitmask + 1;
727         }
728
729         /// Returns const reference to internal statistics
730         stat const& statistics() const
731         {
732             return m_Stat;
733         }
734
735     private:
736         //@cond
737         template <typename Stat>
738         typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type * bkt )
739         {
740             new (bkt) internal_bucket_type;
741         }
742
743         template <typename Stat>
744         typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type * bkt )
745         {
746             new (bkt) internal_bucket_type( m_Stat );
747         }
748
749         /// Calculates hash value of \p key
750         template <typename Q>
751         size_t hash_value( Q const& key ) const
752         {
753             return m_HashFunctor( key ) & m_nHashBitmask;
754         }
755
756         /// Returns the bucket (ordered list) for \p key
757         template <typename Q>
758         internal_bucket_type& bucket( Q const& key )
759         {
760             return m_Buckets[hash_value( key )];
761         }
762         template <typename Q>
763         internal_bucket_type const& bucket( Q const& key ) const
764         {
765             return m_Buckets[hash_value( key )];
766         }
767         //@endcond
768     };
769
770 }} // namespace cds::intrusive
771
772 #endif // #ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_NOGC_H