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