Extending intrusive MichaelSet<HP> to IterableList
[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-2016
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         typedef typename ordered_list::stat           stat;             ///< Internal statistics
112
113         /// Hash functor for \ref value_type and all its derivatives that you use
114         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
115         typedef typename traits::item_counter item_counter;   ///< Item counter type
116         typedef typename traits::allocator    allocator;      ///< Bucket table allocator
117
118         typedef typename ordered_list::rcu_lock    rcu_lock;   ///< RCU scoped lock
119         /// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
120         static CDS_CONSTEXPR const bool c_bExtractLockExternal = ordered_list::c_bExtractLockExternal;
121
122         // GC and OrderedList::gc must be the same
123         static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
124
125         // atomicity::empty_item_counter is not allowed as a item counter
126         static_assert(!std::is_same<item_counter, atomicity::empty_item_counter>::value,
127             "atomicity::empty_item_counter is not allowed as a item counter");
128
129     protected:
130         //@cond
131         typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
132
133         typedef typename ordered_list::template rebind_traits<
134             cds::opt::item_counter< cds::atomicity::empty_item_counter >
135             , cds::opt::stat< typename bucket_stat::wrapped_stat >
136         >::type internal_bucket_type;
137
138         typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
139         //@endcond
140
141     public:
142         typedef typename internal_bucket_type::exempt_ptr  exempt_ptr; ///< pointer to extracted node
143         typedef typename internal_bucket_type::raw_ptr     raw_ptr;    ///< Return type of \p get() member function and its derivatives
144
145     private:
146         //@cond
147         hash                        m_HashFunctor;   ///< Hash functor
148         size_t const                m_nHashBitmask;
149         internal_bucket_type*       m_Buckets;       ///< bucket table
150         item_counter                m_ItemCounter;   ///< Item counter
151         typename bucket_stat::stat  m_Stat;          ///< Internal statistics
152         //@endcond
153
154     public:
155     ///@name Forward iterators (thread-safe under RCU lock)
156     //@{
157         /// Forward iterator
158         /**
159             The forward iterator for Michael's set is based on \p OrderedList forward iterator and has some features:
160             - it has no post-increment operator
161             - it iterates items in unordered fashion
162
163             You may safely use iterators in multi-threaded environment only under RCU lock.
164             Otherwise, a crash is possible if another thread deletes the element the iterator points to.
165
166             The iterator interface:
167             \code
168             class iterator {
169             public:
170                 // Default constructor
171                 iterator();
172
173                 // Copy construtor
174                 iterator( iterator const& src );
175
176                 // Dereference operator
177                 value_type * operator ->() const;
178
179                 // Dereference operator
180                 value_type& operator *() const;
181
182                 // Preincrement operator
183                 iterator& operator ++();
184
185                 // Assignment operator
186                 iterator& operator = (iterator const& src);
187
188                 // Equality operators
189                 bool operator ==(iterator const& i ) const;
190                 bool operator !=(iterator const& i ) const;
191             };
192             \endcode
193         */
194         typedef michael_set::details::iterator< internal_bucket_type, false >    iterator;
195
196         /// Const forward iterator
197         /**
198             For iterator's features and requirements see \ref iterator
199         */
200         typedef michael_set::details::iterator< internal_bucket_type, true >     const_iterator;
201
202         /// Returns a forward iterator addressing the first element in a set
203         /**
204             For empty set \code begin() == end() \endcode
205         */
206         iterator begin()
207         {
208             return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count() );
209         }
210
211         /// Returns an iterator that addresses the location succeeding the last element in a set
212         /**
213             Do not use the value returned by <tt>end</tt> function to access any item.
214             The returned value can be used only to control reaching the end of the set.
215             For empty set \code begin() == end() \endcode
216         */
217         iterator end()
218         {
219             return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
220         }
221
222         /// Returns a forward const iterator addressing the first element in a set
223         const_iterator begin() const
224         {
225             return cbegin();
226         }
227
228         /// Returns a forward const iterator addressing the first element in a set
229         const_iterator cbegin() const
230         {
231             return const_iterator( m_Buckets[0].cbegin(), m_Buckets, m_Buckets + bucket_count() );
232         }
233
234         /// Returns an const iterator that addresses the location succeeding the last element in a set
235         const_iterator end() const
236         {
237             return cend();
238         }
239
240         /// Returns an const iterator that addresses the location succeeding the last element in a set
241         const_iterator cend() const
242         {
243             return const_iterator( m_Buckets[bucket_count() - 1].cend(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
244         }
245     //@}
246
247     public:
248         /// Initialize hash set
249         /**
250             The Michael's hash set is an unbounded container, but its hash table is non-expandable.
251             At construction time you should pass estimated maximum item count and a load factor.
252             The load factor is average size of one bucket - a small number between 1 and 10.
253             The bucket is an ordered single-linked list, the complexity of searching in the bucket is linear <tt>O(nLoadFactor)</tt>.
254             The constructor defines hash table size as rounding <tt>nMaxItemCount / nLoadFactor</tt> up to nearest power of two.
255         */
256         MichaelHashSet(
257             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
258             size_t nLoadFactor      ///< load factor: average size of the bucket
259         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
260           , m_Buckets( bucket_table_allocator().allocate( bucket_count() ) )
261         {
262             for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
263                 construct_bucket<bucket_stat>( it );
264         }
265
266         /// Clear hash set and destroy it
267         ~MichaelHashSet()
268         {
269             clear();
270
271             for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
272                 it->~internal_bucket_type();
273             bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
274         }
275
276         /// Inserts new node
277         /**
278             The function inserts \p val in the set if it does not contain
279             an item with key equal to \p val.
280
281             Returns \p true if \p val is placed into the set, \p false otherwise.
282         */
283         bool insert( value_type& val )
284         {
285             bool bRet = bucket( val ).insert( val );
286             if ( bRet )
287                 ++m_ItemCounter;
288             return bRet;
289         }
290
291         /// Inserts new node
292         /**
293             This function is intended for derived non-intrusive containers.
294
295             The function allows to split creating of new item into two part:
296             - create item with key only
297             - insert new item into the set
298             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
299
300             The functor signature is:
301             \code
302                 void func( value_type& val );
303             \endcode
304             where \p val is the item inserted.
305             The user-defined functor is called only if the inserting is success.
306
307             @warning For \ref cds_intrusive_MichaelList_rcu "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
308             \ref cds_intrusive_LazyList_rcu "LazyList" provides exclusive access to inserted item and does not require any node-level
309             synchronization.
310         */
311         template <typename Func>
312         bool insert( value_type& val, Func f )
313         {
314             bool bRet = bucket( val ).insert( val, f );
315             if ( bRet )
316                 ++m_ItemCounter;
317             return bRet;
318         }
319
320         /// Updates the element
321         /**
322             The operation performs inserting or changing data with lock-free manner.
323
324             If the item \p val not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
325             Otherwise, the functor \p func is called with item found.
326             The functor signature is:
327             \code
328                 struct functor {
329                     void operator()( bool bNew, value_type& item, value_type& val );
330                 };
331             \endcode
332             with arguments:
333             - \p bNew - \p true if the item has been inserted, \p false otherwise
334             - \p item - item of the set
335             - \p val - argument \p val passed into the \p %update() function
336             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
337             refers to the same thing.
338
339             The functor may change non-key fields of the \p item.
340
341             Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
342             \p second is \p true if new item has been added or \p false if the item with \p key
343             already is in the set.
344
345             @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
346             \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
347             synchronization.
348         */
349         template <typename Func>
350         std::pair<bool, bool> update( value_type& val, Func func, bool bAllowInsert = true )
351         {
352             std::pair<bool, bool> bRet = bucket( val ).update( val, func, bAllowInsert );
353             if ( bRet.second )
354                 ++m_ItemCounter;
355             return bRet;
356         }
357         //@cond
358         template <typename Func>
359         CDS_DEPRECATED("ensure() is deprecated, use update()")
360         std::pair<bool, bool> ensure( value_type& val, Func func )
361         {
362             return update( val, func, true );
363         }
364         //@endcond
365
366         /// Unlinks the item \p val from the set
367         /**
368             The function searches the item \p val in the set and unlink it from the set
369             if it is found and is equal to \p val.
370
371             The function returns \p true if success and \p false otherwise.
372         */
373         bool unlink( value_type& val )
374         {
375             bool bRet = bucket( val ).unlink( val );
376             if ( bRet )
377                 --m_ItemCounter;
378             return bRet;
379         }
380
381         /// Deletes the item from the set
382         /** \anchor cds_intrusive_MichaelHashSet_rcu_erase
383             The function searches an item with key equal to \p key in the set,
384             unlinks it from the set, and returns \p true.
385             If the item with key equal to \p key is not found the function return \p false.
386
387             Note the hash functor should accept a parameter of type \p Q that may be not the same as \p value_type.
388         */
389         template <typename Q>
390         bool erase( Q const& key )
391         {
392             if ( bucket( key ).erase( key )) {
393                 --m_ItemCounter;
394                 return true;
395             }
396             return false;
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_intrusive_MichaelHashSet_rcu_erase "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 pred 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             if ( bucket( key ).erase_with( key, pred )) {
410                 --m_ItemCounter;
411                 return true;
412             }
413             return false;
414         }
415
416         /// Deletes the item from the set
417         /** \anchor cds_intrusive_MichaelHashSet_rcu_erase_func
418             The function searches an item with key equal to \p key in the set,
419             call \p f functor with item found, and unlinks it from the set.
420             The \ref disposer specified in \p OrderedList class template parameter is called
421             by garbage collector \p GC asynchronously.
422
423             The \p Func interface is
424             \code
425             struct functor {
426                 void operator()( value_type const& item );
427             };
428             \endcode
429
430             If the item with key equal to \p key is not found the function return \p false.
431
432             Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
433         */
434         template <typename Q, typename Func>
435         bool erase( const Q& key, Func f )
436         {
437             if ( bucket( key ).erase( key, f )) {
438                 --m_ItemCounter;
439                 return true;
440             }
441             return false;
442         }
443
444         /// Deletes the item from the set using \p pred predicate for searching
445         /**
446             The function is an analog of \ref cds_intrusive_MichaelHashSet_rcu_erase_func "erase(Q const&)"
447             but \p pred is used for key comparing.
448             \p Less functor has the interface like \p std::less.
449             \p pred must imply the same element order as the comparator used for building the set.
450         */
451         template <typename Q, typename Less, typename Func>
452         bool erase_with( const Q& key, Less pred, Func f )
453         {
454             if ( bucket( key ).erase_with( key, pred, f )) {
455                 --m_ItemCounter;
456                 return true;
457             }
458             return false;
459         }
460
461         /// Extracts an item from the set
462         /** \anchor cds_intrusive_MichaelHashSet_rcu_extract
463             The function searches an item with key equal to \p key in the set,
464             unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
465             If the item with the key equal to \p key is not found the function returns an empty \p exempt_ptr.
466
467             Depends on \p ordered_list you should or should not lock RCU before calling of this function:
468             - for the set based on \ref cds_intrusive_MichaelList_rcu "MichaelList" RCU should not be locked
469             - for the set based on \ref cds_intrusive_LazyList_rcu "LazyList" RCU should be locked
470
471             See ordered list implementation for details.
472
473             \code
474             #include <cds/urcu/general_buffered.h>
475             #include <cds/intrusive/michael_list_rcu.h>
476             #include <cds/intrusive/michael_set_rcu.h>
477
478             typedef cds::urcu::gc< general_buffered<> > rcu;
479             typedef cds::intrusive::MichaelList< rcu, Foo > rcu_michael_list;
480             typedef cds::intrusive::MichaelHashSet< rcu, rcu_michael_list, foo_traits > rcu_michael_set;
481
482             rcu_michael_set theSet;
483             // ...
484
485             typename rcu_michael_set::exempt_ptr p;
486
487             // For MichaelList we should not lock RCU
488
489             // Now, you can apply extract function
490             // Note that you must not delete the item found inside the RCU lock
491             p = theSet.extract( 10 )
492             if ( p ) {
493                 // do something with p
494                 ...
495             }
496
497             // We may safely release p here
498             // release() passes the pointer to RCU reclamation cycle:
499             // it invokes RCU retire_ptr function with the disposer you provided for rcu_michael_list.
500             p.release();
501             \endcode
502         */
503         template <typename Q>
504         exempt_ptr extract( Q const& key )
505         {
506             exempt_ptr p( bucket( key ).extract( key ) );
507             if ( p )
508                 --m_ItemCounter;
509             return p;
510         }
511
512         /// Extracts an item from the set using \p pred predicate for searching
513         /**
514             The function is an analog of \p extract(Q const&) but \p pred is used for key comparing.
515             \p Less functor has the interface like \p std::less.
516             \p pred must imply the same element order as the comparator used for building the set.
517         */
518         template <typename Q, typename Less>
519         exempt_ptr extract_with( Q const& key, Less pred )
520         {
521             exempt_ptr p( bucket( key ).extract_with( key, pred ) );
522             if ( p )
523                 --m_ItemCounter;
524             return p;
525         }
526
527         /// Checks whether the set contains \p key
528         /**
529
530             The function searches the item with key equal to \p key
531             and returns \p true if the key is found, and \p false otherwise.
532
533             Note the hash functor specified for class \p Traits template parameter
534             should accept a parameter of type \p Q that can be not the same as \p value_type.
535         */
536         template <typename Q>
537         bool contains( Q const& key )
538         {
539             return bucket( key ).contains( key );
540         }
541         //@cond
542         template <typename Q>
543         CDS_DEPRECATED("use contains()")
544         bool find( Q const& key )
545         {
546             return contains( key );
547         }
548         //@endcond
549
550         /// Checks whether the set contains \p key using \p pred predicate for searching
551         /**
552             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
553             \p Less functor has the interface like \p std::less.
554             \p Less must imply the same element order as the comparator used for building the set.
555         */
556         template <typename Q, typename Less>
557         bool contains( Q const& key, Less pred )
558         {
559             return bucket( key ).contains( key, pred );
560         }
561         //@cond
562         template <typename Q, typename Less>
563         CDS_DEPRECATED("use contains()")
564         bool find_with( Q const& key, Less pred )
565         {
566             return contains( key, pred );
567         }
568         //@endcond
569
570         /// Find the key \p key
571         /** \anchor cds_intrusive_MichaelHashSet_rcu_find_func
572             The function searches the item with key equal to \p key and calls the functor \p f for item found.
573             The interface of \p Func functor is:
574             \code
575             struct functor {
576                 void operator()( value_type& item, Q& key );
577             };
578             \endcode
579             where \p item is the item found, \p key is the <tt>find</tt> function argument.
580
581             The functor can change non-key fields of \p item.
582             The functor does not serialize simultaneous access to the set \p item. If such access is
583             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
584
585             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
586             can modify both arguments.
587
588             Note the hash functor specified for class \p Traits template parameter
589             should accept a parameter of type \p Q that can be not the same as \p value_type.
590
591             The function returns \p true if \p key is found, \p false otherwise.
592         */
593         template <typename Q, typename Func>
594         bool find( Q& key, Func f )
595         {
596             return bucket( key ).find( key, f );
597         }
598         //@cond
599         template <typename Q, typename Func>
600         bool find( Q const& key, Func f )
601         {
602             return bucket( key ).find( key, f );
603         }
604         //@endcond
605
606         /// Finds the key \p key using \p pred predicate for searching
607         /**
608             The function is an analog of \ref cds_intrusive_MichaelHashSet_rcu_find_func "find(Q&, Func)"
609             but \p pred is used for key comparing.
610             \p Less functor has the interface like \p std::less.
611             \p pred must imply the same element order as the comparator used for building the set.
612         */
613         template <typename Q, typename Less, typename Func>
614         bool find_with( Q& key, Less pred, Func f )
615         {
616             return bucket( key ).find_with( key, pred, f );
617         }
618         //@cond
619         template <typename Q, typename Less, typename Func>
620         bool find_with( Q const& key, Less pred, Func f )
621         {
622             return bucket( key ).find_with( key, pred, f );
623         }
624         //@endcond
625
626         /// Finds the key \p key and return the item found
627         /** \anchor cds_intrusive_MichaelHashSet_rcu_get
628             The function searches the item with key equal to \p key and returns the pointer to item found.
629             If \p key is not found it returns \p nullptr.
630             Note the type of returned value depends on underlying \p ordered_list.
631             For details, see documentation of ordered list you use.
632
633             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
634
635             RCU should be locked before call of this function.
636             Returned item is valid only while RCU is locked:
637             \code
638             typedef cds::intrusive::MichaelHashSet< your_template_parameters > hash_set;
639             hash_set theSet;
640             // ...
641             // Result of get() call
642             typename hash_set::raw_ptr ptr;
643             {
644                 // Lock RCU
645                 hash_set::rcu_lock lock;
646
647                 ptr = theSet.get( 5 );
648                 if ( ptr ) {
649                     // Deal with ptr
650                     //...
651                 }
652                 // Unlock RCU by rcu_lock destructor
653                 // ptr can be reclaimed by disposer at any time after RCU has been unlocked
654             }
655             \endcode
656         */
657         template <typename Q>
658         raw_ptr get( Q const& key )
659         {
660             return bucket( key ).get( key );
661         }
662
663         /// Finds the key \p key and return the item found
664         /**
665             The function is an analog of \ref cds_intrusive_MichaelHashSet_rcu_get "get(Q const&)"
666             but \p pred is used for comparing the keys.
667
668             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
669             in any order.
670             \p pred must imply the same element order as the comparator used for building the set.
671         */
672         template <typename Q, typename Less>
673         raw_ptr get_with( Q const& key, Less pred )
674         {
675             return bucket( key ).get_with( key, pred );
676         }
677
678         /// Clears the set (non-atomic)
679         /**
680             The function unlink all items from the set.
681             The function is not atomic. It cleans up each bucket and then resets the item counter to zero.
682             If there are a thread that performs insertion while \p clear is working the result is undefined in general case:
683             <tt> empty() </tt> may return \p true but the set may contain item(s).
684             Therefore, \p clear may be used only for debugging purposes.
685
686             For each item the \p disposer is called after unlinking.
687         */
688         void clear()
689         {
690             for ( size_t i = 0; i < bucket_count(); ++i )
691                 m_Buckets[i].clear();
692             m_ItemCounter.reset();
693         }
694
695
696         /// Checks if the set is empty
697         /**
698             Emptiness is checked by item counting: if item count is zero then the set is empty.
699             Thus, the correct item counting feature is an important part of Michael's set implementation.
700         */
701         bool empty() const
702         {
703             return size() == 0;
704         }
705
706         /// Returns item count in the set
707         size_t size() const
708         {
709             return m_ItemCounter;
710         }
711
712         /// Returns the size of hash table
713         /**
714             Since %MichaelHashSet cannot dynamically extend the hash table size,
715             the value returned is an constant depending on object initialization parameters;
716             see \ref cds_intrusive_MichaelHashSet_hp "MichaelHashSet" for explanation.
717         */
718         size_t bucket_count() const
719         {
720             return m_nHashBitmask + 1;
721         }
722
723         /// Returns const reference to internal statistics
724         stat const& statistics() const
725         {
726             return m_Stat;
727         }
728
729     private:
730         //@cond
731         template <typename Stat>
732         typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
733         {
734             new (bucket) internal_bucket_type;
735         }
736
737         template <typename Stat>
738         typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
739         {
740             new (bucket) internal_bucket_type( m_Stat );
741         }
742
743         /// Calculates hash value of \p key
744         template <typename Q>
745         size_t hash_value( Q const& key ) const
746         {
747             return m_HashFunctor( key ) & m_nHashBitmask;
748         }
749
750         /// Returns the bucket (ordered list) for \p key
751         template <typename Q>
752         internal_bucket_type& bucket( Q const& key )
753         {
754             return m_Buckets[hash_value( key )];
755         }
756         template <typename Q>
757         internal_bucket_type const& bucket( Q const& key ) const
758         {
759             return m_Buckets[hash_value( key )];
760         }
761         //@endcond
762     };
763
764 }} // namespace cds::intrusive
765
766 #endif // #ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_NOGC_H