issue#11: cds: changed __CDS_ guard prefix to CDSLIB_ for all .h files
[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     protected:
199         item_counter    m_ItemCounter; ///< Item counter
200         hash            m_HashFunctor; ///< Hash functor
201         bucket_type *   m_Buckets;     ///< bucket table
202
203     private:
204         //@cond
205         const size_t    m_nHashBitmask;
206         //@endcond
207
208     protected:
209         //@cond
210         /// Calculates hash value of \p key
211         template <typename Q>
212         size_t hash_value( Q const& key ) const
213         {
214             return m_HashFunctor( key ) & m_nHashBitmask;
215         }
216
217         /// Returns the bucket (ordered list) for \p key
218         template <typename Q>
219         bucket_type&    bucket( Q const& key )
220         {
221             return m_Buckets[ hash_value( key ) ];
222         }
223         //@endcond
224
225     public:
226         /// Forward iterator
227         typedef michael_set::details::iterator< bucket_type, false >    iterator;
228
229         /// Const forward iterator
230         typedef michael_set::details::iterator< bucket_type, true >     const_iterator;
231
232         /// Returns a forward iterator addressing the first element in a set
233         /**
234             For empty set \code begin() == end() \endcode
235         */
236         iterator begin()
237         {
238             return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count() );
239         }
240
241         /// Returns an iterator that addresses the location succeeding the last element in a set
242         /**
243             Do not use the value returned by <tt>end</tt> function to access any item.
244             The returned value can be used only to control reaching the end of the set.
245             For empty set \code begin() == end() \endcode
246         */
247         iterator end()
248         {
249             return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
250         }
251
252         /// Returns a forward const iterator addressing the first element in a set
253         //@{
254         const_iterator begin() const
255         {
256             return get_const_begin();
257         }
258         const_iterator cbegin() const
259         {
260             return get_const_begin();
261         }
262         //@}
263
264         /// Returns an const iterator that addresses the location succeeding the last element in a set
265         //@{
266         const_iterator end() const
267         {
268             return get_const_end();
269         }
270         const_iterator cend() const
271         {
272             return get_const_end();
273         }
274         //@}
275
276     private:
277         //@cond
278         const_iterator get_const_begin() const
279         {
280             return const_iterator( const_cast<bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
281         }
282         const_iterator get_const_end() const
283         {
284             return const_iterator( const_cast<bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
285         }
286         //@endcond
287
288     public:
289         /// Initialize hash set
290         /** @anchor cds_nonintrusive_MichaelHashSet_hp_ctor
291             The Michael's hash set is non-expandable container. You should point the average count of items \p nMaxItemCount
292             when you create an object.
293             \p nLoadFactor parameter defines average count of items per bucket and it should be small number between 1 and 10.
294             Remember, since the bucket implementation is an ordered list, searching in the bucket is linear [<tt>O(nLoadFactor)</tt>].
295
296             The ctor defines hash table size as rounding <tt>nMaxItemCount / nLoadFactor</tt> up to nearest power of two.
297         */
298         MichaelHashSet(
299             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
300             size_t nLoadFactor      ///< load factor: estimation of max number of items in the bucket
301         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
302         {
303             // GC and OrderedList::gc must be the same
304             static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
305
306             // atomicity::empty_item_counter is not allowed as a item counter
307             static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
308                            "cds::atomicity::empty_item_counter is not allowed as a item counter");
309
310             m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
311         }
312
313         /// Clears hash set and destroys it
314         ~MichaelHashSet()
315         {
316             clear();
317             bucket_table_allocator().Delete( m_Buckets, bucket_count() );
318         }
319
320         /// Inserts new node
321         /**
322             The function creates a node with copy of \p val value
323             and then inserts the node created into the set.
324
325             The type \p Q should contain as minimum the complete key for the node.
326             The object of \ref value_type should be constructible from a value of type \p Q.
327             In trivial case, \p Q is equal to \ref value_type.
328
329             Returns \p true if \p val is inserted into the set, \p false otherwise.
330         */
331         template <typename Q>
332         bool insert( Q const& val )
333         {
334             const bool bRet = bucket( val ).insert( val );
335             if ( bRet )
336                 ++m_ItemCounter;
337             return bRet;
338         }
339
340         /// Inserts new node
341         /**
342             The function allows to split creating of new item into two part:
343             - create item with key only
344             - insert new item into the set
345             - if inserting is success, calls  \p f functor to initialize value-fields of \p val.
346
347             The functor signature is:
348             \code
349                 void func( value_type& val );
350             \endcode
351             where \p val is the item inserted.
352             The user-defined functor is called only if the inserting is success.
353
354             @warning For \ref cds_nonintrusive_MichaelList_gc "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
355             \ref cds_nonintrusive_LazyList_gc "LazyList" provides exclusive access to inserted item and does not require any node-level
356             synchronization.
357         */
358         template <typename Q, typename Func>
359         bool insert( Q const& val, Func f )
360         {
361             const bool bRet = bucket( val ).insert( val, f );
362             if ( bRet )
363                 ++m_ItemCounter;
364             return bRet;
365         }
366
367         /// Ensures that the item exists in the set
368         /**
369             The operation performs inserting or changing data with lock-free manner.
370
371             If the \p val key not found in the set, then the new item created from \p val
372             is inserted into the set. Otherwise, the functor \p func is called with the item found.
373             The functor \p Func signature is:
374             \code
375                 struct my_functor {
376                     void operator()( bool bNew, value_type& item, const Q& val );
377                 };
378             \endcode
379
380             with arguments:
381             - \p bNew - \p true if the item has been inserted, \p false otherwise
382             - \p item - item of the set
383             - \p val - argument \p key passed into the \p ensure function
384
385             The functor may change non-key fields of the \p item.
386
387             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
388             \p second is true if new item has been added or \p false if the item with \p key
389             already is in the set.
390
391             @warning For \ref cds_nonintrusive_MichaelList_gc "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
392             \ref cds_nonintrusive_LazyList_gc "LazyList" provides exclusive access to inserted item and does not require any node-level
393             synchronization.
394             */
395         template <typename Q, typename Func>
396         std::pair<bool, bool> ensure( const Q& val, Func func )
397         {
398             std::pair<bool, bool> bRet = bucket( val ).ensure( val, func );
399             if ( bRet.first && bRet.second )
400                 ++m_ItemCounter;
401             return bRet;
402         }
403
404         /// Inserts data of type \p value_type constructed from \p args
405         /**
406             Returns \p true if inserting successful, \p false otherwise.
407         */
408         template <typename... Args>
409         bool emplace( Args&&... args )
410         {
411             bool bRet = bucket( value_type(std::forward<Args>(args)...) ).emplace( std::forward<Args>(args)... );
412             if ( bRet )
413                 ++m_ItemCounter;
414             return bRet;
415         }
416
417         /// Deletes \p key from the set
418         /** \anchor cds_nonintrusive_MichaelSet_erase_val
419
420             Since the key of MichaelHashSet's item type \ref value_type is not explicitly specified,
421             template parameter \p Q defines the key type searching in the list.
422             The set item comparator should be able to compare the type \p value_type
423             and the type \p Q.
424
425             Return \p true if key is found and deleted, \p false otherwise
426         */
427         template <typename Q>
428         bool erase( Q const& key )
429         {
430             const bool bRet = bucket( key ).erase( key );
431             if ( bRet )
432                 --m_ItemCounter;
433             return bRet;
434         }
435
436         /// Deletes the item from the set using \p pred predicate for searching
437         /**
438             The function is an analog of \ref cds_nonintrusive_MichaelSet_erase_val "erase(Q const&)"
439             but \p pred is used for key comparing.
440             \p Less functor has the interface like \p std::less.
441             \p Less must imply the same element order as the comparator used for building the set.
442         */
443         template <typename Q, typename Less>
444         bool erase_with( Q const& key, Less pred )
445         {
446             const bool bRet = bucket( key ).erase_with( key, pred );
447             if ( bRet )
448                 --m_ItemCounter;
449             return bRet;
450         }
451
452         /// Deletes \p key from the set
453         /** \anchor cds_nonintrusive_MichaelSet_erase_func
454
455             The function searches an item with key \p key, calls \p f functor
456             and deletes the item. If \p key is not found, the functor is not called.
457
458             The functor \p Func interface:
459             \code
460             struct extractor {
461                 void operator()(value_type& item);
462             };
463             \endcode
464             where \p item - the item found.
465
466             Since the key of %MichaelHashSet's \p value_type is not explicitly specified,
467             template parameter \p Q defines the key type searching in the list.
468             The list item comparator should be able to compare the type \p T of list item
469             and the type \p Q.
470
471             Return \p true if key is found and deleted, \p false otherwise
472         */
473         template <typename Q, typename Func>
474         bool erase( Q const& key, Func f )
475         {
476             const bool bRet = bucket( key ).erase( key, f );
477             if ( bRet )
478                 --m_ItemCounter;
479             return bRet;
480         }
481
482         /// Deletes the item from the set using \p pred predicate for searching
483         /**
484             The function is an analog of \ref cds_nonintrusive_MichaelSet_erase_func "erase(Q const&, Func)"
485             but \p pred is used for key comparing.
486             \p Less functor has the interface like \p std::less.
487             \p Less must imply the same element order as the comparator used for building the set.
488         */
489         template <typename Q, typename Less, typename Func>
490         bool erase_with( Q const& key, Less pred, Func f )
491         {
492             const bool bRet = bucket( key ).erase_with( key, pred, f );
493             if ( bRet )
494                 --m_ItemCounter;
495             return bRet;
496         }
497
498         /// Extracts the item with specified \p key
499         /** \anchor cds_nonintrusive_MichaelHashSet_hp_extract
500             The function searches an item with key equal to \p key,
501             unlinks it from the set, and returns it as \p guarded_ptr.
502             If \p key is not found the function returns an empty guadd pointer.
503
504             Note the compare functor should accept a parameter of type \p Q that may be not the same as \p value_type.
505
506             The extracted item is freed automatically when returned \p guarded_ptr object will be destroyed or released.
507             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
508
509             Usage:
510             \code
511             typedef cds::container::MichaelHashSet< your_template_args > michael_set;
512             michael_set theSet;
513             // ...
514             {
515                 michael_set::guarded_ptr gp( theSet.extract( 5 ));
516                 if ( gp ) {
517                     // Deal with gp
518                     // ...
519                 }
520                 // Destructor of gp releases internal HP guard
521             }
522             \endcode
523         */
524         template <typename Q>
525         guarded_ptr extract( Q const& key )
526         {
527             guarded_ptr gp( bucket( key ).extract( key ));
528             if ( gp )
529                 --m_ItemCounter;
530             return gp;
531         }
532
533         /// Extracts the item using compare functor \p pred
534         /**
535             The function is an analog of \ref cds_nonintrusive_MichaelHashSet_hp_extract "extract(Q const&)"
536             but \p pred predicate is used for key comparing.
537
538             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
539             in any order.
540             \p pred must imply the same element order as the comparator used for building the set.
541         */
542         template <typename Q, typename Less>
543         guarded_ptr extract_with( Q const& key, Less pred )
544         {
545             guarded_ptr gp( bucket( key ).extract_with( key, pred ));
546             if ( gp )
547                 --m_ItemCounter;
548             return gp;
549         }
550
551         /// Finds the key \p key
552         /** \anchor cds_nonintrusive_MichaelSet_find_func
553
554             The function searches the item with key equal to \p key and calls the functor \p f for item found.
555             The interface of \p Func functor is:
556             \code
557             struct functor {
558                 void operator()( value_type& item, Q& key );
559             };
560             \endcode
561             where \p item is the item found, \p key is the <tt>find</tt> function argument.
562
563             The functor may change non-key fields of \p item. Note that the functor is only guarantee
564             that \p item cannot be disposed during functor is executing.
565             The functor does not serialize simultaneous access to the set's \p item. If such access is
566             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
567
568             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
569             can modify both arguments.
570
571             Note the hash functor specified for class \p Traits template parameter
572             should accept a parameter of type \p Q that may be not the same as \p value_type.
573
574             The function returns \p true if \p key is found, \p false otherwise.
575         */
576         template <typename Q, typename Func>
577         bool find( Q& key, Func f )
578         {
579             return bucket( key ).find( key, f );
580         }
581         //@cond
582         template <typename Q, typename Func>
583         bool find( Q const& key, Func f )
584         {
585             return bucket( key ).find( key, f );
586         }
587         //@endcond
588
589         /// Finds the key \p key using \p pred predicate for searching
590         /**
591             The function is an analog of \ref cds_nonintrusive_MichaelSet_find_func "find(Q&, Func)"
592             but \p pred is used for key comparing.
593             \p Less functor has the interface like \p std::less.
594             \p Less must imply the same element order as the comparator used for building the set.
595         */
596         template <typename Q, typename Less, typename Func>
597         bool find_with( Q& key, Less pred, Func f )
598         {
599             return bucket( key ).find_with( key, pred, f );
600         }
601         //@cond
602         template <typename Q, typename Less, typename Func>
603         bool find_with( Q const& key, Less pred, Func f )
604         {
605             return bucket( key ).find_with( key, pred, f );
606         }
607         //@endcond
608
609         /// Finds the key \p key
610         /** \anchor cds_nonintrusive_MichaelSet_find_val
611             The function searches the item with key equal to \p key
612             and returns \p true if it is found, and \p false otherwise.
613
614             Note the hash functor specified for class \p Traits template parameter
615             should accept a parameter of type \p Q that may be not the same as \ref value_type.
616         */
617         template <typename Q>
618         bool find( Q const& key )
619         {
620             return bucket( key ).find( key );
621         }
622
623         /// Finds the key \p key using \p pred predicate for searching
624         /**
625             The function is an analog of \ref cds_nonintrusive_MichaelSet_find_val "find(Q const&)"
626             but \p pred is used for key comparing.
627             \p Less functor has the interface like \p std::less.
628             \p Less must imply the same element order as the comparator used for building the set.
629         */
630         template <typename Q, typename Less>
631         bool find_with( Q const& key, Less pred )
632         {
633             return bucket( key ).find_with( key, pred );
634         }
635
636         /// Finds the key \p key and return the item found
637         /** \anchor cds_nonintrusive_MichaelHashSet_hp_get
638             The function searches the item with key equal to \p key
639             and returns the guarded pointer to the item found.
640             If \p key is not found the functin returns an empty guarded pointer.
641
642             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
643
644             Usage:
645             \code
646             typedef cds::container::MichaeHashSet< your_template_params >  michael_set;
647             michael_set theSet;
648             // ...
649             {
650                 michael_set::guarded_ptr gp( theSet.get( 5 ));
651                 if ( gp ) {
652                     // Deal with gp
653                     //...
654                 }
655                 // Destructor of guarded_ptr releases internal HP guard
656             }
657             \endcode
658
659             Note the compare functor specified for \p OrderedList template parameter
660             should accept a parameter of type \p Q that can be not the same as \p value_type.
661         */
662         template <typename Q>
663         guarded_ptr get( Q const& key )
664         {
665             return bucket( key ).get( key );
666         }
667
668         /// Finds the key \p key and return the item found
669         /**
670             The function is an analog of \ref cds_nonintrusive_MichaelHashSet_hp_get "get( Q const&)"
671             but \p pred is used for comparing the keys.
672
673             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
674             in any order.
675             \p pred must imply the same element order as the comparator used for building the set.
676         */
677         template <typename Q, typename Less>
678         guarded_ptr get_with( Q const& key, Less pred )
679         {
680             return bucket( key ).get_with( key, pred );
681         }
682
683         /// Clears the set (non-atomic)
684         /**
685             The function erases all items from the set.
686
687             The function is not atomic. It cleans up each bucket and then resets the item counter to zero.
688             If there are a thread that performs insertion while \p clear is working the result is undefined in general case:
689             <tt> empty() </tt> may return \p true but the set may contain item(s).
690             Therefore, \p clear may be used only for debugging purposes.
691         */
692         void clear()
693         {
694             for ( size_t i = 0; i < bucket_count(); ++i )
695                 m_Buckets[i].clear();
696             m_ItemCounter.reset();
697         }
698
699         /// Checks if the set is empty
700         /**
701             Emptiness is checked by item counting: if item count is zero then the set is empty.
702             Thus, the correct item counting feature is an important part of Michael's set implementation.
703         */
704         bool empty() const
705         {
706             return size() == 0;
707         }
708
709         /// Returns item count in the set
710         size_t size() const
711         {
712             return m_ItemCounter;
713         }
714
715         /// Returns the size of hash table
716         /**
717             Since MichaelHashSet cannot dynamically extend the hash table size,
718             the value returned is an constant depending on object initialization parameters;
719             see MichaelHashSet::MichaelHashSet for explanation.
720         */
721         size_t bucket_count() const
722         {
723             return m_nHashBitmask + 1;
724         }
725     };
726
727 }} // namespace cds::container
728
729 #endif // ifndef CDSLIB_CONTAINER_MICHAEL_SET_H