Added internal statistics to MichaelList, IterableList
[libcds.git] / cds / intrusive / michael_set.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_H
32 #define CDSLIB_INTRUSIVE_MICHAEL_SET_H
33
34 #include <cds/intrusive/details/michael_set_base.h>
35 #include <cds/details/allocator.h>
36 #include <cds/intrusive/details/iterable_list_base.h>
37
38 namespace cds { namespace intrusive {
39
40     /// Michael's hash set
41     /** @ingroup cds_intrusive_map
42         \anchor cds_intrusive_MichaelHashSet_hp
43
44         Source:
45             - [2002] Maged Michael "High performance dynamic lock-free hash tables and list-based sets"
46
47         Michael's hash table algorithm is based on lock-free ordered list and it is very simple.
48         The main structure is an array \p T of size \p M. Each element in \p T is basically a pointer
49         to a hash bucket, implemented as a singly linked list. The array of buckets cannot be dynamically expanded.
50         However, each bucket may contain unbounded number of items.
51
52         Template parameters are:
53         - \p GC - Garbage collector used. Note the \p GC must be the same as the GC used for \p OrderedList
54         - \p OrderedList - ordered list implementation used as bucket for hash set, for example, \p MichaelList, \p LazyList.
55             The intrusive ordered list implementation specifies the type \p T stored in the hash-set, the reclamation
56             schema \p GC used by hash-set, the comparison functor for the type \p T and other features specific for
57             the ordered list.
58         - \p Traits - type traits. See \p michael_set::traits for explanation.
59             Instead of defining \p Traits struct you can use option-based syntax with \p michael_set::make_traits metafunction.
60
61         There are several specializations of \p %MichaelHashSet for each GC. You should include:
62         - <tt><cds/intrusive/michael_set_rcu.h></tt> for \ref cds_intrusive_MichaelHashSet_rcu "RCU type"
63         - <tt><cds/intrusive/michael_set_nogc.h></tt> for \ref cds_intrusive_MichaelHashSet_nogc for append-only set
64         - <tt><cds/intrusive/michael_set.h></tt> for \p gc::HP, \p gc::DHP
65
66         <b>Hash functor</b>
67
68         Some member functions of Michael's hash set accept the key parameter of type \p Q which differs from \p value_type.
69         It is expected that type \p Q contains full key of \p value_type, and for equal keys of type \p Q and \p value_type
70         the hash values of these keys must be equal.
71         The hash functor \p Traits::hash should accept parameters of both type:
72         \code
73         // Our node type
74         struct Foo {
75             std::string     key_; // key field
76             // ... other fields
77         };
78
79         // Hash functor
80         struct fooHash {
81             size_t operator()( const std::string& s ) const
82             {
83                 return std::hash( s );
84             }
85
86             size_t operator()( const Foo& f ) const
87             {
88                 return (*this)( f.key_ );
89             }
90         };
91         \endcode
92
93         <b>How to use</b>
94
95         First, you should define ordered list type to use in your hash set:
96         \code
97         // For gc::HP-based MichaelList implementation
98         #include <cds/intrusive/michael_list_hp.h>
99
100         // cds::intrusive::MichaelHashSet declaration
101         #include <cds/intrusive/michael_set.h>
102
103         // Type of hash-set items
104         struct Foo: public cds::intrusive::michael_list::node< cds::gc::HP >
105         {
106             std::string     key_    ;   // key field
107             unsigned        val_    ;   // value field
108             // ...  other value fields
109         };
110
111         // Declare comparator for the item
112         struct FooCmp
113         {
114             int operator()( const Foo& f1, const Foo& f2 ) const
115             {
116                 return f1.key_.compare( f2.key_ );
117             }
118         };
119
120         // Declare bucket type for Michael's hash set
121         // The bucket type is any ordered list type like MichaelList, LazyList
122         typedef cds::intrusive::MichaelList< cds::gc::HP, Foo,
123             typename cds::intrusive::michael_list::make_traits<
124                 // hook option
125                 cds::intrusive::opt::hook< cds::intrusive::michael_list::base_hook< cds::opt::gc< cds::gc::HP > > >
126                 // item comparator option
127                 ,cds::opt::compare< FooCmp >
128             >::type
129         >  Foo_bucket;
130         \endcode
131
132         Second, you should declare Michael's hash set container:
133         \code
134
135         // Declare hash functor
136         // Note, the hash functor accepts parameter type Foo and std::string
137         struct FooHash {
138             size_t operator()( const Foo& f ) const
139             {
140                 return cds::opt::v::hash<std::string>()( f.key_ );
141             }
142             size_t operator()( const std::string& f ) const
143             {
144                 return cds::opt::v::hash<std::string>()( f );
145             }
146         };
147
148         // Michael's set typedef
149         typedef cds::intrusive::MichaelHashSet<
150             cds::gc::HP
151             ,Foo_bucket
152             ,typename cds::intrusive::michael_set::make_traits<
153                 cds::opt::hash< FooHash >
154             >::type
155         > Foo_set;
156         \endcode
157
158         Now, you can use \p Foo_set in your application.
159
160         Like other intrusive containers, you may build several containers on single item structure:
161         \code
162         #include <cds/intrusive/michael_list_hp.h>
163         #include <cds/intrusive/michael_list_dhp.h>
164         #include <cds/intrusive/michael_set.h>
165
166         struct tag_key1_idx;
167         struct tag_key2_idx;
168
169         // Your two-key data
170         // The first key is maintained by gc::HP, second key is maintained by gc::DHP garbage collectors
171         // (I don't know what is needed for, but it is correct)
172         struct Foo
173             : public cds::intrusive::michael_list::node< cds::gc::HP, tag_key1_idx >
174             , public cds::intrusive::michael_list::node< cds::gc::DHP, tag_key2_idx >
175         {
176             std::string     key1_   ;   // first key field
177             unsigned int    key2_   ;   // second key field
178
179             // ... value fields and fields for controlling item's lifetime
180         };
181
182         // Declare comparators for the item
183         struct Key1Cmp
184         {
185             int operator()( const Foo& f1, const Foo& f2 ) const { return f1.key1_.compare( f2.key1_ ) ; }
186         };
187         struct Key2Less
188         {
189             bool operator()( const Foo& f1, const Foo& f2 ) const { return f1.key2_ < f2.key1_ ; }
190         };
191
192         // Declare bucket type for Michael's hash set indexed by key1_ field and maintained by gc::HP
193         typedef cds::intrusive::MichaelList< cds::gc::HP, Foo,
194             typename cds::intrusive::michael_list::make_traits<
195                 // hook option
196                 cds::intrusive::opt::hook< cds::intrusive::michael_list::base_hook< cds::opt::gc< cds::gc::HP >, tag_key1_idx > >
197                 // item comparator option
198                 ,cds::opt::compare< Key1Cmp >
199             >::type
200         >  Key1_bucket;
201
202         // Declare bucket type for Michael's hash set indexed by key2_ field and maintained by gc::DHP
203         typedef cds::intrusive::MichaelList< cds::gc::DHP, Foo,
204             typename cds::intrusive::michael_list::make_traits<
205                 // hook option
206                 cds::intrusive::opt::hook< cds::intrusive::michael_list::base_hook< cds::opt::gc< cds::gc::DHP >, tag_key2_idx > >
207                 // item comparator option
208                 ,cds::opt::less< Key2Less >
209             >::type
210         >  Key2_bucket;
211
212         // Declare hash functor
213         struct Key1Hash {
214             size_t operator()( const Foo& f ) const { return cds::opt::v::hash<std::string>()( f.key1_ ) ; }
215             size_t operator()( const std::string& s ) const { return cds::opt::v::hash<std::string>()( s ) ; }
216         };
217         inline size_t Key2Hash( const Foo& f ) { return (size_t) f.key2_  ; }
218
219         // Michael's set indexed by key1_ field
220         typedef cds::intrusive::MichaelHashSet<
221             cds::gc::HP
222             ,Key1_bucket
223             ,typename cds::intrusive::michael_set::make_traits<
224                 cds::opt::hash< Key1Hash >
225             >::type
226         > key1_set;
227
228         // Michael's set indexed by key2_ field
229         typedef cds::intrusive::MichaelHashSet<
230             cds::gc::DHP
231             ,Key2_bucket
232             ,typename cds::intrusive::michael_set::make_traits<
233                 cds::opt::hash< Key2Hash >
234             >::type
235         > key2_set;
236         \endcode
237     */
238     template <
239         class GC,
240         class OrderedList,
241 #ifdef CDS_DOXYGEN_INVOKED
242         class Traits = michael_set::traits
243 #else
244         class Traits
245 #endif
246     >
247     class MichaelHashSet
248     {
249     public:
250         typedef GC           gc;            ///< Garbage collector
251         typedef OrderedList  ordered_list;  ///< type of ordered list used as a bucket implementation
252         typedef ordered_list bucket_type;   ///< bucket type
253         typedef Traits       traits;       ///< Set traits
254
255         typedef typename ordered_list::value_type       value_type      ;   ///< type of value to be stored in the set
256         typedef typename ordered_list::key_comparator   key_comparator  ;   ///< key comparing functor
257         typedef typename ordered_list::disposer         disposer        ;   ///< Node disposer functor
258
259         /// Hash functor for \p value_type and all its derivatives that you use
260         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
261         typedef typename traits::item_counter item_counter;   ///< Item counter type
262
263         typedef typename ordered_list::guarded_ptr guarded_ptr; ///< Guarded pointer
264
265         /// Bucket table allocator
266         typedef cds::details::Allocator< bucket_type, typename traits::allocator > bucket_table_allocator;
267
268         /// Count of hazard pointer required for the algorithm
269         static CDS_CONSTEXPR const size_t c_nHazardPtrCount = ordered_list::c_nHazardPtrCount;
270
271     protected:
272         item_counter    m_ItemCounter;   ///< Item counter
273         hash            m_HashFunctor;   ///< Hash functor
274         bucket_type *   m_Buckets;      ///< bucket table
275
276     private:
277         //@cond
278         const size_t    m_nHashBitmask;
279         //@endcond
280
281     protected:
282         //@cond
283         /// Calculates hash value of \p key
284         template <typename Q>
285         size_t hash_value( const Q& key ) const
286         {
287             return m_HashFunctor( key ) & m_nHashBitmask;
288         }
289
290         /// Returns the bucket (ordered list) for \p key
291         template <typename Q>
292         bucket_type&    bucket( const Q& key )
293         {
294             return m_Buckets[ hash_value( key ) ];
295         }
296         //@endcond
297
298     public:
299     ///@name Forward iterators
300     //@{
301         /// Forward iterator
302         /**
303             The forward iterator for Michael's set is based on \p OrderedList forward iterator and has some features:
304             - it has no post-increment operator
305             - it iterates items in unordered fashion
306             - The iterator cannot be moved across thread boundary because it may contain GC's guard that is thread-private GC data.
307
308             Iterator thread safety depends on type of \p OrderedList:
309             - for \p MichaelList and \p LazyList: iterator guarantees safety even if you delete the item that iterator points to
310               because that item is guarded by hazard pointer.
311               However, in case of concurrent deleting operations it is no guarantee that you iterate all item in the set.
312               Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
313               Use this iterator on the concurrent container for debugging purpose only.
314             - for \p IterableList: iterator is thread-safe. You may use it freely in concurrent environment.
315               
316         */
317         typedef michael_set::details::iterator< bucket_type, false > iterator;
318
319         /// Const forward iterator
320         /**
321             For iterator's features and requirements see \ref iterator
322         */
323         typedef michael_set::details::iterator< bucket_type, true > const_iterator;
324
325         /// Returns a forward iterator addressing the first element in a set
326         /**
327             For empty set \code begin() == end() \endcode
328         */
329         iterator begin()
330         {
331             return iterator( m_Buckets[0].begin(), bucket_begin(), bucket_end() );
332         }
333
334         /// Returns an iterator that addresses the location succeeding the last element in a set
335         /**
336             Do not use the value returned by <tt>end</tt> function to access any item.
337             The returned value can be used only to control reaching the end of the set.
338             For empty set \code begin() == end() \endcode
339         */
340         iterator end()
341         {
342             return iterator( m_Buckets[bucket_count() - 1].end(), bucket_end() + 1, bucket_end() );
343         }
344
345         /// Returns a forward const iterator addressing the first element in a set
346         const_iterator begin() const
347         {
348             return get_const_begin();
349         }
350
351         /// Returns a forward const iterator addressing the first element in a set
352         const_iterator cbegin() const
353         {
354             return get_const_begin();
355         }
356
357         /// Returns an const iterator that addresses the location succeeding the last element in a set
358         const_iterator end() const
359         {
360             return get_const_end();
361         }
362
363         /// Returns an const iterator that addresses the location succeeding the last element in a set
364         const_iterator cend() const
365         {
366             return get_const_end();
367         }
368     //@}
369
370     private:
371         //@cond
372         bucket_type * bucket_begin() const
373         {
374             return m_Buckets;
375         }
376
377         bucket_type * bucket_end() const
378         {
379             return m_Buckets + bucket_count();
380         }
381
382         const_iterator get_const_begin() const
383         {
384             return const_iterator( m_Buckets[0].cbegin(), bucket_begin(), bucket_end() );
385         }
386         const_iterator get_const_end() const
387         {
388             return const_iterator( m_Buckets[bucket_count() - 1].cend(), bucket_end() - 1, bucket_end() );
389         }
390         //@endcond
391
392     public:
393         /// Initializes hash set
394         /** @anchor cds_intrusive_MichaelHashSet_hp_ctor
395             The Michael's hash set is an unbounded container, but its hash table is non-expandable.
396             At construction time you should pass estimated maximum item count and a load factor.
397             The load factor is average size of one bucket - a small number between 1 and 10.
398             The bucket is an ordered single-linked list, searching in the bucket has linear complexity <tt>O(nLoadFactor)</tt>.
399             The constructor defines hash table size as rounding <tt>nMaxItemCount / nLoadFactor</tt> up to nearest power of two.
400         */
401         MichaelHashSet(
402             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
403             size_t nLoadFactor      ///< load factor: estimation of max number of items in the bucket. Small integer up to 10.
404         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
405         {
406             // GC and OrderedList::gc must be the same
407             static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
408
409             // atomicity::empty_item_counter is not allowed as a item counter
410             static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
411                            "cds::atomicity::empty_item_counter is not allowed as a item counter");
412
413             m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
414         }
415
416         /// Clears hash set object and destroys it
417         ~MichaelHashSet()
418         {
419             clear();
420             bucket_table_allocator().Delete( m_Buckets, bucket_count() );
421         }
422
423         /// Inserts new node
424         /**
425             The function inserts \p val in the set if it does not contain
426             an item with key equal to \p val.
427
428             Returns \p true if \p val is placed into the set, \p false otherwise.
429         */
430         bool insert( value_type& val )
431         {
432             bool bRet = bucket( val ).insert( val );
433             if ( bRet )
434                 ++m_ItemCounter;
435             return bRet;
436         }
437
438         /// Inserts new node
439         /**
440             This function is intended for derived non-intrusive containers.
441
442             The function allows to split creating of new item into two part:
443             - create item with key only
444             - insert new item into the set
445             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
446
447             The functor signature is:
448             \code
449                 void func( value_type& val );
450             \endcode
451             where \p val is the item inserted.
452
453             The user-defined functor is called only if the inserting is success.
454
455             @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
456             \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
457             synchronization.
458         */
459         template <typename Func>
460         bool insert( value_type& val, Func f )
461         {
462             bool bRet = bucket( val ).insert( val, f );
463             if ( bRet )
464                 ++m_ItemCounter;
465             return bRet;
466         }
467
468         /// Updates the element
469         /**
470             The operation performs inserting or changing data with lock-free manner.
471
472             If the item \p val not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
473             Otherwise, the functor \p func is called with item found.
474
475             The functor signature depends of the type of \p OrderedList:
476
477             <b>for \p MichaelList, \p LazyList</b>
478                 \code
479                     struct functor {
480                         void operator()( bool bNew, value_type& item, value_type& val );
481                     };
482                 \endcode
483                 with arguments:
484                 - \p bNew - \p true if the item has been inserted, \p false otherwise
485                 - \p item - item of the set
486                 - \p val - argument \p val passed into the \p %update() function
487                 If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
488                 refers to the same thing.
489
490                 The functor may change non-key fields of the \p item.
491                 @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
492                 \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
493                 synchronization.
494
495             <b>for \p IterableList</b>
496                 \code
497                 void func( value_type& val, value_type * old );
498                 \endcode
499                 where
500                 - \p val - argument \p val passed into the \p %update() function
501                 - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
502
503             Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
504             \p second is \p true if new item has been added or \p false if the item with \p key
505             already is in the set.
506         */
507         template <typename Func>
508         std::pair<bool, bool> update( value_type& val, Func func, bool bAllowInsert = true )
509         {
510             std::pair<bool, bool> bRet = bucket( val ).update( val, func, bAllowInsert );
511             if ( bRet.second )
512                 ++m_ItemCounter;
513             return bRet;
514         }
515         //@cond
516         template <typename Func>
517         CDS_DEPRECATED("ensure() is deprecated, use update()")
518         std::pair<bool, bool> ensure( value_type& val, Func func )
519         {
520             return update( val, func, true );
521         }
522         //@endcond
523
524         /// Inserts or updates the node (only for \p IterableList)
525         /**
526             The operation performs inserting or changing data with lock-free manner.
527
528             If the item \p val is not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
529             Otherwise, the current element is changed to \p val, the old element will be retired later
530             by call \p Traits::disposer.
531
532             Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
533             \p second is \p true if \p val has been added or \p false if the item with that key
534             already in the set.
535         */
536 #ifdef CDS_DOXYGEN_INVOKED
537         std::pair<bool, bool> upsert( value_type& val, bool bAllowInsert = true )
538 #else
539         template <typename Q>
540         typename std::enable_if< 
541             std::is_same< Q, value_type>::value && is_iterable_list< ordered_list >::value,
542             std::pair<bool, bool>
543         >::type
544         upsert( Q& val, bool bAllowInsert = true )
545 #endif
546         {
547             std::pair<bool, bool> bRet = bucket( val ).upsert( val, bAllowInsert );
548             if ( bRet.second )
549                 ++m_ItemCounter;
550             return bRet;
551         }
552
553         /// Unlinks the item \p val from the set
554         /**
555             The function searches the item \p val in the set and unlink it
556             if it is found and is equal to \p val.
557
558             The function returns \p true if success and \p false otherwise.
559         */
560         bool unlink( value_type& val )
561         {
562             bool bRet = bucket( val ).unlink( val );
563             if ( bRet )
564                 --m_ItemCounter;
565             return bRet;
566         }
567
568         /// Deletes the item from the set
569         /** \anchor cds_intrusive_MichaelHashSet_hp_erase
570             The function searches an item with key equal to \p key in the set,
571             unlinks it, and returns \p true.
572             If the item with key equal to \p key is not found the function return \p false.
573
574             Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
575         */
576         template <typename Q>
577         bool erase( Q const& key )
578         {
579             if ( bucket( key ).erase( key )) {
580                 --m_ItemCounter;
581                 return true;
582             }
583             return false;
584         }
585
586         /// Deletes the item from the set using \p pred predicate for searching
587         /**
588             The function is an analog of \ref cds_intrusive_MichaelHashSet_hp_erase "erase(Q const&)"
589             but \p pred is used for key comparing.
590             \p Less functor has the interface like \p std::less.
591             \p pred must imply the same element order as the comparator used for building the set.
592         */
593         template <typename Q, typename Less>
594         bool erase_with( Q const& key, Less pred )
595         {
596             if ( bucket( key ).erase_with( key, pred )) {
597                 --m_ItemCounter;
598                 return true;
599             }
600             return false;
601         }
602
603         /// Deletes the item from the set
604         /** \anchor cds_intrusive_MichaelHashSet_hp_erase_func
605             The function searches an item with key equal to \p key in the set,
606             call \p f functor with item found, and unlinks it from the set.
607             The \ref disposer specified in \p OrderedList class template parameter is called
608             by garbage collector \p GC asynchronously.
609
610             The \p Func interface is
611             \code
612             struct functor {
613                 void operator()( value_type const& item );
614             };
615             \endcode
616
617             If the item with key equal to \p key is not found the function return \p false.
618
619             Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
620         */
621         template <typename Q, typename Func>
622         bool erase( Q const& key, Func f )
623         {
624             if ( bucket( key ).erase( key, f )) {
625                 --m_ItemCounter;
626                 return true;
627             }
628             return false;
629         }
630
631         /// Deletes the item from the set using \p pred predicate for searching
632         /**
633             The function is an analog of \ref cds_intrusive_MichaelHashSet_hp_erase_func "erase(Q const&, Func)"
634             but \p pred is used for key comparing.
635             \p Less functor has the interface like \p std::less.
636             \p pred must imply the same element order as the comparator used for building the set.
637         */
638         template <typename Q, typename Less, typename Func>
639         bool erase_with( Q const& key, Less pred, Func f )
640         {
641             if ( bucket( key ).erase_with( key, pred, f )) {
642                 --m_ItemCounter;
643                 return true;
644             }
645             return false;
646         }
647
648         /// Extracts the item with specified \p key
649         /** \anchor cds_intrusive_MichaelHashSet_hp_extract
650             The function searches an item with key equal to \p key,
651             unlinks it from the set, and returns an guarded pointer to the item extracted.
652             If \p key is not found the function returns an empty guarded pointer.
653
654             Note the compare functor should accept a parameter of type \p Q that may be not the same as \p value_type.
655
656             The \p disposer specified in \p OrderedList class' template parameter is called automatically
657             by garbage collector \p GC when returned \ref guarded_ptr object will be destroyed or released.
658             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
659
660             Usage:
661             \code
662             typedef cds::intrusive::MichaelHashSet< your_template_args > michael_set;
663             michael_set theSet;
664             // ...
665             {
666                 michael_set::guarded_ptr gp( theSet.extract( 5 ));
667                 if ( gp ) {
668                     // Deal with gp
669                     // ...
670                 }
671                 // Destructor of gp releases internal HP guard
672             }
673             \endcode
674         */
675         template <typename Q>
676         guarded_ptr extract( Q const& key )
677         {
678             guarded_ptr gp = bucket( key ).extract( key );
679             if ( gp )
680                 --m_ItemCounter;
681             return gp;
682         }
683
684         /// Extracts the item using compare functor \p pred
685         /**
686             The function is an analog of \ref cds_intrusive_MichaelHashSet_hp_extract "extract(Q const&)"
687             but \p pred predicate is used for key comparing.
688
689             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
690             in any order.
691             \p pred must imply the same element order as the comparator used for building the list.
692         */
693         template <typename Q, typename Less>
694         guarded_ptr extract_with( Q const& key, Less pred )
695         {
696             guarded_ptr gp = bucket( key ).extract_with( key, pred );
697             if ( gp )
698                 --m_ItemCounter;
699             return gp;
700         }
701
702         /// Finds the key \p key
703         /** \anchor cds_intrusive_MichaelHashSet_hp_find_func
704             The function searches the item with key equal to \p key and calls the functor \p f for item found.
705             The interface of \p Func functor is:
706             \code
707             struct functor {
708                 void operator()( value_type& item, Q& key );
709             };
710             \endcode
711             where \p item is the item found, \p key is the <tt>find</tt> function argument.
712
713             The functor may change non-key fields of \p item. Note that the functor is only guarantee
714             that \p item cannot be disposed during functor is executing.
715             The functor does not serialize simultaneous access to the set \p item. If such access is
716             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
717
718             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
719             may modify both arguments.
720
721             Note the hash functor specified for class \p Traits template parameter
722             should accept a parameter of type \p Q that can be not the same as \p value_type.
723
724             The function returns \p true if \p key is found, \p false otherwise.
725         */
726         template <typename Q, typename Func>
727         bool find( Q& key, Func f )
728         {
729             return bucket( key ).find( key, f );
730         }
731         //@cond
732         template <typename Q, typename Func>
733         bool find( Q const& key, Func f )
734         {
735             return bucket( key ).find( key, f );
736         }
737         //@endcond
738
739         /// Finds \p key and returns iterator pointed to the item found (only for \p IterableList)
740         /**
741             If \p key is not found the function returns \p end().
742
743             @note This function is supported only for the set based on \p IterableList
744         */
745         template <typename Q>
746 #ifdef CDS_DOXYGEN_INVOKED
747         iterator
748 #else
749         typename std::enable_if< std::is_same<Q,Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
750 #endif
751         find( Q& key )
752         {
753             bucket_type& b = bucket( key );
754             typename ordered_list::iterator it = b.find( key );
755             if ( it == b.end() )
756                 return end();
757             return iterator( it, &b, bucket_end());
758         }
759         //@cond
760         template <typename Q>
761         typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
762         find( Q const& key )
763         {
764             bucket_type& b = bucket( key );
765             typename ordered_list::iterator it = b.find( key );
766             if ( it == b.end() )
767                 return end();
768             return iterator( it, &b, bucket_end() );
769         }
770         //@endcond
771
772
773         /// Finds the key \p key using \p pred predicate for searching
774         /**
775             The function is an analog of \ref cds_intrusive_MichaelHashSet_hp_find_func "find(Q&, Func)"
776             but \p pred is used for key comparing.
777             \p Less functor has the interface like \p std::less.
778             \p pred must imply the same element order as the comparator used for building the set.
779         */
780         template <typename Q, typename Less, typename Func>
781         bool find_with( Q& key, Less pred, Func f )
782         {
783             return bucket( key ).find_with( key, pred, f );
784         }
785         //@cond
786         template <typename Q, typename Less, typename Func>
787         bool find_with( Q const& key, Less pred, Func f )
788         {
789             return bucket( key ).find_with( key, pred, f );
790         }
791         //@endcond
792
793         /// Finds \p key using \p pred predicate and returns iterator pointed to the item found (only for \p IterableList)
794         /**
795             The function is an analog of \p find(Q&) but \p pred is used for key comparing.
796             \p Less functor has the interface like \p std::less.
797             \p pred must imply the same element order as the comparator used for building the set.
798
799             If \p key is not found the function returns \p end().
800
801             @note This function is supported only for the set based on \p IterableList
802         */
803         template <typename Q, typename Less>
804 #ifdef CDS_DOXYGEN_INVOKED
805         iterator
806 #else
807         typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
808 #endif
809         find_with( Q& key, Less pred )
810         {
811             bucket_type& b = bucket( key );
812             typename ordered_list::iterator it = b.find_with( key, pred );
813             if ( it == b.end() )
814                 return end();
815             return iterator( it, &b, bucket_end() );
816         }
817         //@cond
818         template <typename Q, typename Less>
819         typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
820         find_with( Q const& key, Less pred )
821         {
822             bucket_type& b = bucket( key );
823             typename ordered_list::iterator it = b.find_with( key, pred );
824             if ( it == b.end() )
825                 return end();
826             return iterator( it, &b, bucket_end() );
827         }
828         //@endcond
829
830         /// Checks whether the set contains \p key
831         /**
832
833             The function searches the item with key equal to \p key
834             and returns \p true if the key is found, and \p false otherwise.
835
836             Note the hash functor specified for class \p Traits template parameter
837             should accept a parameter of type \p Q that can be not the same as \p value_type.
838         */
839         template <typename Q>
840         bool contains( Q const& key )
841         {
842             return bucket( key ).contains( key );
843         }
844
845         /// Checks whether the set contains \p key using \p pred predicate for searching
846         /**
847             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
848             \p Less functor has the interface like \p std::less.
849             \p Less must imply the same element order as the comparator used for building the set.
850         */
851         template <typename Q, typename Less>
852         bool contains( Q const& key, Less pred )
853         {
854             return bucket( key ).contains( key, pred );
855         }
856
857         /// Finds the key \p key and return the item found
858         /** \anchor cds_intrusive_MichaelHashSet_hp_get
859             The function searches the item with key equal to \p key
860             and returns the guarded pointer to the item found.
861             If \p key is not found the function returns an empty \p guarded_ptr.
862
863             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
864
865             Usage:
866             \code
867             typedef cds::intrusive::MichaelHashSet< your_template_params >  michael_set;
868             michael_set theSet;
869             // ...
870             {
871                 michael_set::guarded_ptr gp( theSet.get( 5 ));
872                 if ( theSet.get( 5 )) {
873                     // Deal with gp
874                     //...
875                 }
876                 // Destructor of guarded_ptr releases internal HP guard
877             }
878             \endcode
879
880             Note the compare functor specified for \p OrderedList template parameter
881             should accept a parameter of type \p Q that can be not the same as \p value_type.
882         */
883         template <typename Q>
884         guarded_ptr get( Q const& key )
885         {
886             return bucket( key ).get( key );
887         }
888
889         /// Finds the key \p key and return the item found
890         /**
891             The function is an analog of \ref cds_intrusive_MichaelHashSet_hp_get "get( Q const&)"
892             but \p pred is used for comparing the keys.
893
894             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
895             in any order.
896             \p pred must imply the same element order as the comparator used for building the set.
897         */
898         template <typename Q, typename Less>
899         guarded_ptr get_with( Q const& key, Less pred )
900         {
901             return bucket( key ).get_with( key, pred );
902         }
903
904         /// Clears the set (non-atomic)
905         /**
906             The function unlink all items from the set.
907             The function is not atomic. It cleans up each bucket and then resets the item counter to zero.
908             If there are a thread that performs insertion while \p %clear() is working the result is undefined in general case:
909             \p empty() may return \p true but the set may contain item(s).
910             Therefore, \p %clear() may be used only for debugging purposes.
911
912             For each item the \p disposer is called after unlinking.
913         */
914         void clear()
915         {
916             for ( size_t i = 0; i < bucket_count(); ++i )
917                 m_Buckets[i].clear();
918             m_ItemCounter.reset();
919         }
920
921         /// Checks if the set is empty
922         /**
923             Emptiness is checked by item counting: if item count is zero then the set is empty.
924             Thus, the correct item counting feature is an important part of Michael's set implementation.
925         */
926         bool empty() const
927         {
928             return size() == 0;
929         }
930
931         /// Returns item count in the set
932         size_t size() const
933         {
934             return m_ItemCounter;
935         }
936
937         /// Returns the size of hash table
938         /**
939             Since \p %MichaelHashSet cannot dynamically extend the hash table size,
940             the value returned is an constant depending on object initialization parameters,
941             see \p MichaelHashSet::MichaelHashSet.
942         */
943         size_t bucket_count() const
944         {
945             return m_nHashBitmask + 1;
946         }
947     };
948
949 }}  // namespace cds::intrusive
950
951 #endif // ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_H