Uses different pass count for different parallel queue test cases
[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-2017
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_H
32 #define CDSLIB_INTRUSIVE_MICHAEL_SET_H
33
34 #include <cds/intrusive/details/michael_set_base.h>
35 #include <cds/intrusive/details/iterable_list_base.h>
36
37 namespace cds { namespace intrusive {
38
39     /// Michael's hash set
40     /** @ingroup cds_intrusive_map
41         \anchor cds_intrusive_MichaelHashSet_hp
42
43         Source:
44             - [2002] Maged Michael "High performance dynamic lock-free hash tables and list-based sets"
45
46         Michael's hash table algorithm is based on lock-free ordered list and it is very simple.
47         The main structure is an array \p T of size \p M. Each element in \p T is basically a pointer
48         to a hash bucket, implemented as a singly linked list. The array of buckets cannot be dynamically expanded.
49         However, each bucket may contain unbounded number of items.
50
51         Template parameters are:
52         - \p GC - Garbage collector used. Note the \p GC must be the same as the GC used for \p OrderedList
53         - \p OrderedList - ordered list implementation used as bucket for hash set, possible implementations:
54             \p MichaelList, \p LazyList, \p IterableList.
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 Traits       traits;        ///< Set traits
253
254         typedef typename ordered_list::value_type       value_type      ; ///< type of value to be stored in the set
255         typedef typename ordered_list::key_comparator   key_comparator  ; ///< key comparing functor
256         typedef typename ordered_list::disposer         disposer        ; ///< Node disposer functor
257 #ifdef CDS_DOXYGEN_INVOKED
258         typedef typename ordered_list::stat             stat            ; ///< Internal statistics
259 #endif
260
261         /// Hash functor for \p value_type and all its derivatives that you use
262         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
263         typedef typename traits::item_counter item_counter;   ///< Item counter type
264         typedef typename traits::allocator    allocator;      ///< Bucket table allocator
265
266         typedef typename ordered_list::guarded_ptr guarded_ptr; ///< Guarded pointer
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         // GC and OrderedList::gc must be the same
272         static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
273
274     protected:
275         //@cond
276         typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
277
278         typedef typename ordered_list::template rebind_traits<
279             cds::opt::item_counter< cds::atomicity::empty_item_counter >
280             , cds::opt::stat< typename bucket_stat::wrapped_stat >
281         >::type internal_bucket_type;
282
283         typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
284         //@endcond
285
286     public:
287         //@cond
288         typedef typename bucket_stat::stat stat;
289         //@endcond
290
291     protected:
292         //@cond
293         hash                    m_HashFunctor;   ///< Hash functor
294         size_t const            m_nHashBitmask;
295         internal_bucket_type*   m_Buckets;       ///< bucket table
296         item_counter            m_ItemCounter;   ///< Item counter
297         stat                    m_Stat;          ///< Internal statistics
298         //@endcond
299
300     public:
301     ///@name Forward iterators
302     //@{
303         /// Forward iterator
304         /**
305             The forward iterator for Michael's set is based on \p OrderedList forward iterator and has some features:
306             - it has no post-increment operator
307             - it iterates items in unordered fashion
308             - The iterator cannot be moved across thread boundary because it may contain GC's guard that is thread-private GC data.
309
310             Iterator thread safety depends on type of \p OrderedList:
311             - for \p MichaelList and \p LazyList: iterator guarantees safety even if you delete the item that iterator points to
312               because that item is guarded by hazard pointer.
313               However, in case of concurrent deleting operations it is no guarantee that you iterate all item in the set.
314               Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
315               Use this iterator on the concurrent container for debugging purpose only.
316             - for \p IterableList: iterator is thread-safe. You may use it freely in concurrent environment.
317         */
318         typedef michael_set::details::iterator< internal_bucket_type, false > iterator;
319
320         /// Const forward iterator
321         /**
322             For iterator's features and requirements see \ref iterator
323         */
324         typedef michael_set::details::iterator< internal_bucket_type, true > const_iterator;
325
326         /// Returns a forward iterator addressing the first element in a set
327         /**
328             For empty set \code begin() == end() \endcode
329         */
330         iterator begin()
331         {
332             return iterator( m_Buckets[0].begin(), bucket_begin(), bucket_end());
333         }
334
335         /// Returns an iterator that addresses the location succeeding the last element in a set
336         /**
337             Do not use the value returned by <tt>end</tt> function to access any item.
338             The returned value can be used only to control reaching the end of the set.
339             For empty set \code begin() == end() \endcode
340         */
341         iterator end()
342         {
343             return iterator( bucket_end()[-1].end(), bucket_end() - 1, bucket_end());
344         }
345
346         /// Returns a forward const iterator addressing the first element in a set
347         const_iterator begin() const
348         {
349             return get_const_begin();
350         }
351
352         /// Returns a forward const iterator addressing the first element in a set
353         const_iterator cbegin() const
354         {
355             return get_const_begin();
356         }
357
358         /// Returns an const iterator that addresses the location succeeding the last element in a set
359         const_iterator end() const
360         {
361             return get_const_end();
362         }
363
364         /// Returns an const iterator that addresses the location succeeding the last element in a set
365         const_iterator cend() const
366         {
367             return get_const_end();
368         }
369     //@}
370
371     public:
372         /// Initializes hash set
373         /**
374             The Michael's hash set is an unbounded container, but its hash table is non-expandable.
375             At construction time you should pass estimated maximum item count and a load factor.
376             The load factor is average size of one bucket - a small number between 1 and 10.
377             The bucket is an ordered single-linked list, searching in the bucket has linear complexity <tt>O(nLoadFactor)</tt>.
378             The constructor defines hash table size as rounding <tt>nMaxItemCount / nLoadFactor</tt> up to nearest power of two.
379         */
380         MichaelHashSet(
381             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
382             size_t nLoadFactor      ///< load factor: estimation of max number of items in the bucket. Small integer up to 10.
383         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
384           , m_Buckets( bucket_table_allocator().allocate( bucket_count()))
385         {
386             for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
387                 construct_bucket<bucket_stat>( it );
388         }
389
390         /// Clears hash set object and destroys it
391         ~MichaelHashSet()
392         {
393             clear();
394
395             for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
396                 it->~internal_bucket_type();
397             bucket_table_allocator().deallocate( m_Buckets, bucket_count());
398         }
399
400         /// Inserts new node
401         /**
402             The function inserts \p val in the set if it does not contain
403             an item with key equal to \p val.
404
405             Returns \p true if \p val is placed into the set, \p false otherwise.
406         */
407         bool insert( value_type& val )
408         {
409             bool bRet = bucket( val ).insert( val );
410             if ( bRet )
411                 ++m_ItemCounter;
412             return bRet;
413         }
414
415         /// Inserts new node
416         /**
417             This function is intended for derived non-intrusive containers.
418
419             The function allows to split creating of new item into two part:
420             - create item with key only
421             - insert new item into the set
422             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
423
424             The functor signature is:
425             \code
426                 void func( value_type& val );
427             \endcode
428             where \p val is the item inserted.
429
430             The user-defined functor is called only if the inserting is success.
431
432             @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
433             \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
434             synchronization.
435         */
436         template <typename Func>
437         bool insert( value_type& val, Func f )
438         {
439             bool bRet = bucket( val ).insert( val, f );
440             if ( bRet )
441                 ++m_ItemCounter;
442             return bRet;
443         }
444
445         /// Updates the element
446         /**
447             The operation performs inserting or changing data with lock-free manner.
448
449             If the item \p val not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
450             Otherwise, the functor \p func is called with item found.
451
452             The functor signature depends of the type of \p OrderedList:
453
454             <b>for \p MichaelList, \p LazyList</b>
455                 \code
456                     struct functor {
457                         void operator()( bool bNew, value_type& item, value_type& val );
458                     };
459                 \endcode
460                 with arguments:
461                 - \p bNew - \p true if the item has been inserted, \p false otherwise
462                 - \p item - item of the set
463                 - \p val - argument \p val passed into the \p %update() function
464                 If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
465                 refers to the same thing.
466
467                 The functor may change non-key fields of the \p item.
468                 @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
469                 \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
470                 synchronization.
471
472             <b>for \p IterableList</b>
473                 \code
474                 void func( value_type& val, value_type * old );
475                 \endcode
476                 where
477                 - \p val - argument \p val passed into the \p %update() function
478                 - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
479
480             Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
481             \p second is \p true if new item has been added or \p false if the item with \p key
482             already is in the set.
483         */
484         template <typename Func>
485         std::pair<bool, bool> update( value_type& val, Func func, bool bAllowInsert = true )
486         {
487             std::pair<bool, bool> bRet = bucket( val ).update( val, func, bAllowInsert );
488             if ( bRet.second )
489                 ++m_ItemCounter;
490             return bRet;
491         }
492         //@cond
493         template <typename Func>
494         CDS_DEPRECATED("ensure() is deprecated, use update()")
495         std::pair<bool, bool> ensure( value_type& val, Func func )
496         {
497             return update( val, func, true );
498         }
499         //@endcond
500
501         /// Inserts or updates the node (only for \p IterableList)
502         /**
503             The operation performs inserting or changing data with lock-free manner.
504
505             If the item \p val is not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
506             Otherwise, the current element is changed to \p val, the old element will be retired later
507             by call \p Traits::disposer.
508
509             Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
510             \p second is \p true if \p val has been added or \p false if the item with that key
511             already in the set.
512         */
513 #ifdef CDS_DOXYGEN_INVOKED
514         std::pair<bool, bool> upsert( value_type& val, bool bAllowInsert = true )
515 #else
516         template <typename Q>
517         typename std::enable_if<
518             std::is_same< Q, value_type>::value && is_iterable_list< ordered_list >::value,
519             std::pair<bool, bool>
520         >::type
521         upsert( Q& val, bool bAllowInsert = true )
522 #endif
523         {
524             std::pair<bool, bool> bRet = bucket( val ).upsert( val, bAllowInsert );
525             if ( bRet.second )
526                 ++m_ItemCounter;
527             return bRet;
528         }
529
530         /// Unlinks the item \p val from the set
531         /**
532             The function searches the item \p val in the set and unlink it
533             if it is found and is equal to \p val.
534
535             The function returns \p true if success and \p false otherwise.
536         */
537         bool unlink( value_type& val )
538         {
539             bool bRet = bucket( val ).unlink( val );
540             if ( bRet )
541                 --m_ItemCounter;
542             return bRet;
543         }
544
545         /// Deletes the item from the set
546         /** \anchor cds_intrusive_MichaelHashSet_hp_erase
547             The function searches an item with key equal to \p key in the set,
548             unlinks it, and returns \p true.
549             If the item with key equal to \p key is not found the function return \p false.
550
551             Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
552         */
553         template <typename Q>
554         bool erase( Q const& key )
555         {
556             if ( bucket( key ).erase( key )) {
557                 --m_ItemCounter;
558                 return true;
559             }
560             return false;
561         }
562
563         /// Deletes the item from the set using \p pred predicate for searching
564         /**
565             The function is an analog of \ref cds_intrusive_MichaelHashSet_hp_erase "erase(Q const&)"
566             but \p pred is used for key comparing.
567             \p Less functor has the interface like \p std::less.
568             \p pred must imply the same element order as the comparator used for building the set.
569         */
570         template <typename Q, typename Less>
571         bool erase_with( Q const& key, Less pred )
572         {
573             if ( bucket( key ).erase_with( key, pred )) {
574                 --m_ItemCounter;
575                 return true;
576             }
577             return false;
578         }
579
580         /// Deletes the item from the set
581         /** \anchor cds_intrusive_MichaelHashSet_hp_erase_func
582             The function searches an item with key equal to \p key in the set,
583             call \p f functor with item found, and unlinks it from the set.
584             The \ref disposer specified in \p OrderedList class template parameter is called
585             by garbage collector \p GC asynchronously.
586
587             The \p Func interface is
588             \code
589             struct functor {
590                 void operator()( value_type const& item );
591             };
592             \endcode
593
594             If the item with key equal to \p key is not found the function return \p false.
595
596             Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
597         */
598         template <typename Q, typename Func>
599         bool erase( Q const& key, Func f )
600         {
601             if ( bucket( key ).erase( key, f )) {
602                 --m_ItemCounter;
603                 return true;
604             }
605             return false;
606         }
607
608         /// Deletes the item from the set using \p pred predicate for searching
609         /**
610             The function is an analog of \ref cds_intrusive_MichaelHashSet_hp_erase_func "erase(Q const&, Func)"
611             but \p pred is used for key comparing.
612             \p Less functor has the interface like \p std::less.
613             \p pred must imply the same element order as the comparator used for building the set.
614         */
615         template <typename Q, typename Less, typename Func>
616         bool erase_with( Q const& key, Less pred, Func f )
617         {
618             if ( bucket( key ).erase_with( key, pred, f )) {
619                 --m_ItemCounter;
620                 return true;
621             }
622             return false;
623         }
624
625         /// Deletes the item pointed by iterator \p iter (only for \p IterableList based set)
626         /**
627             Returns \p true if the operation is successful, \p false otherwise.
628             The function can return \p false if the node the iterator points to has already been deleted
629             by other thread.
630
631             The function does not invalidate the iterator, it remains valid and can be used for further traversing.
632
633             @note \p %erase_at() is supported only for \p %MichaelHashSet based on \p IterableList.
634         */
635 #ifdef CDS_DOXYGEN_INVOKED
636         bool erase_at( iterator const& iter )
637 #else
638         template <typename Iterator>
639         typename std::enable_if< std::is_same<Iterator, iterator>::value && is_iterable_list< ordered_list >::value, bool >::type
640         erase_at( Iterator const& iter )
641 #endif
642         {
643             assert( iter != end());
644             assert( iter.bucket() != nullptr );
645
646             if ( iter.bucket()->erase_at( iter.underlying_iterator())) {
647                 --m_ItemCounter;
648                 return true;
649             }
650             return false;
651         }
652
653         /// Extracts the item with specified \p key
654         /** \anchor cds_intrusive_MichaelHashSet_hp_extract
655             The function searches an item with key equal to \p key,
656             unlinks it from the set, and returns an guarded pointer to the item extracted.
657             If \p key is not found the function returns an empty guarded pointer.
658
659             Note the compare functor should accept a parameter of type \p Q that may be not the same as \p value_type.
660
661             The \p disposer specified in \p OrderedList class' template parameter is called automatically
662             by garbage collector \p GC when returned \ref guarded_ptr object will be destroyed or released.
663             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
664
665             Usage:
666             \code
667             typedef cds::intrusive::MichaelHashSet< your_template_args > michael_set;
668             michael_set theSet;
669             // ...
670             {
671                 michael_set::guarded_ptr gp( theSet.extract( 5 ));
672                 if ( gp ) {
673                     // Deal with gp
674                     // ...
675                 }
676                 // Destructor of gp releases internal HP guard
677             }
678             \endcode
679         */
680         template <typename Q>
681         guarded_ptr extract( Q const& key )
682         {
683             guarded_ptr gp = bucket( key ).extract( key );
684             if ( gp )
685                 --m_ItemCounter;
686             return gp;
687         }
688
689         /// Extracts the item using compare functor \p pred
690         /**
691             The function is an analog of \ref cds_intrusive_MichaelHashSet_hp_extract "extract(Q const&)"
692             but \p pred predicate is used for key comparing.
693
694             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
695             in any order.
696             \p pred must imply the same element order as the comparator used for building the list.
697         */
698         template <typename Q, typename Less>
699         guarded_ptr extract_with( Q const& key, Less pred )
700         {
701             guarded_ptr gp = bucket( key ).extract_with( key, pred );
702             if ( gp )
703                 --m_ItemCounter;
704             return gp;
705         }
706
707         /// Finds the key \p key
708         /** \anchor cds_intrusive_MichaelHashSet_hp_find_func
709             The function searches the item with key equal to \p key and calls the functor \p f for item found.
710             The interface of \p Func functor is:
711             \code
712             struct functor {
713                 void operator()( value_type& item, Q& key );
714             };
715             \endcode
716             where \p item is the item found, \p key is the <tt>find</tt> function argument.
717
718             The functor may change non-key fields of \p item. Note that the functor is only guarantee
719             that \p item cannot be disposed during functor is executing.
720             The functor does not serialize simultaneous access to the set \p item. If such access is
721             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
722
723             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
724             may modify both arguments.
725
726             Note the hash functor specified for class \p Traits template parameter
727             should accept a parameter of type \p Q that can be not the same as \p value_type.
728
729             The function returns \p true if \p key is found, \p false otherwise.
730         */
731         template <typename Q, typename Func>
732         bool find( Q& key, Func f )
733         {
734             return bucket( key ).find( key, f );
735         }
736         //@cond
737         template <typename Q, typename Func>
738         bool find( Q const& key, Func f )
739         {
740             return bucket( key ).find( key, f );
741         }
742         //@endcond
743
744         /// Finds \p key and returns iterator pointed to the item found (only for \p IterableList)
745         /**
746             If \p key is not found the function returns \p end().
747
748             @note This function is supported only for the set based on \p IterableList
749         */
750         template <typename Q>
751 #ifdef CDS_DOXYGEN_INVOKED
752         iterator
753 #else
754         typename std::enable_if< std::is_same<Q,Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
755 #endif
756         find( Q& key )
757         {
758             internal_bucket_type& b = bucket( key );
759             typename internal_bucket_type::iterator it = b.find( key );
760             if ( it == b.end())
761                 return end();
762             return iterator( it, &b, bucket_end());
763         }
764         //@cond
765         template <typename Q>
766         typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
767         find( Q const& key )
768         {
769             internal_bucket_type& b = bucket( key );
770             typename internal_bucket_type::iterator it = b.find( key );
771             if ( it == b.end())
772                 return end();
773             return iterator( it, &b, bucket_end());
774         }
775         //@endcond
776
777
778         /// Finds the key \p key using \p pred predicate for searching
779         /**
780             The function is an analog of \ref cds_intrusive_MichaelHashSet_hp_find_func "find(Q&, Func)"
781             but \p pred is used for key comparing.
782             \p Less functor has the interface like \p std::less.
783             \p pred must imply the same element order as the comparator used for building the set.
784         */
785         template <typename Q, typename Less, typename Func>
786         bool find_with( Q& key, Less pred, Func f )
787         {
788             return bucket( key ).find_with( key, pred, f );
789         }
790         //@cond
791         template <typename Q, typename Less, typename Func>
792         bool find_with( Q const& key, Less pred, Func f )
793         {
794             return bucket( key ).find_with( key, pred, f );
795         }
796         //@endcond
797
798         /// Finds \p key using \p pred predicate and returns iterator pointed to the item found (only for \p IterableList)
799         /**
800             The function is an analog of \p find(Q&) but \p pred is used for key comparing.
801             \p Less functor has the interface like \p std::less.
802             \p pred must imply the same element order as the comparator used for building the set.
803
804             If \p key is not found the function returns \p end().
805
806             @note This function is supported only for the set based on \p IterableList
807         */
808         template <typename Q, typename Less>
809 #ifdef CDS_DOXYGEN_INVOKED
810         iterator
811 #else
812         typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
813 #endif
814         find_with( Q& key, Less pred )
815         {
816             internal_bucket_type& b = bucket( key );
817             typename internal_bucket_type::iterator it = b.find_with( key, pred );
818             if ( it == b.end())
819                 return end();
820             return iterator( it, &b, bucket_end());
821         }
822         //@cond
823         template <typename Q, typename Less>
824         typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
825         find_with( Q const& key, Less pred )
826         {
827             internal_bucket_type& b = bucket( key );
828             typename internal_bucket_type::iterator it = b.find_with( key, pred );
829             if ( it == b.end())
830                 return end();
831             return iterator( it, &b, bucket_end());
832         }
833         //@endcond
834
835         /// Checks whether the set contains \p key
836         /**
837
838             The function searches the item with key equal to \p key
839             and returns \p true if the key is found, and \p false otherwise.
840
841             Note the hash functor specified for class \p Traits template parameter
842             should accept a parameter of type \p Q that can be not the same as \p value_type.
843         */
844         template <typename Q>
845         bool contains( Q const& key )
846         {
847             return bucket( key ).contains( key );
848         }
849
850         /// Checks whether the set contains \p key using \p pred predicate for searching
851         /**
852             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
853             \p Less functor has the interface like \p std::less.
854             \p Less must imply the same element order as the comparator used for building the set.
855         */
856         template <typename Q, typename Less>
857         bool contains( Q const& key, Less pred )
858         {
859             return bucket( key ).contains( key, pred );
860         }
861
862         /// Finds the key \p key and return the item found
863         /** \anchor cds_intrusive_MichaelHashSet_hp_get
864             The function searches the item with key equal to \p key
865             and returns the guarded pointer to the item found.
866             If \p key is not found the function returns an empty \p guarded_ptr.
867
868             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
869
870             Usage:
871             \code
872             typedef cds::intrusive::MichaelHashSet< your_template_params >  michael_set;
873             michael_set theSet;
874             // ...
875             {
876                 michael_set::guarded_ptr gp( theSet.get( 5 ));
877                 if ( theSet.get( 5 )) {
878                     // Deal with gp
879                     //...
880                 }
881                 // Destructor of guarded_ptr releases internal HP guard
882             }
883             \endcode
884
885             Note the compare functor specified for \p OrderedList template parameter
886             should accept a parameter of type \p Q that can be not the same as \p value_type.
887         */
888         template <typename Q>
889         guarded_ptr get( Q const& key )
890         {
891             return bucket( key ).get( key );
892         }
893
894         /// Finds the key \p key and return the item found
895         /**
896             The function is an analog of \ref cds_intrusive_MichaelHashSet_hp_get "get( Q const&)"
897             but \p pred is used for comparing the keys.
898
899             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
900             in any order.
901             \p pred must imply the same element order as the comparator used for building the set.
902         */
903         template <typename Q, typename Less>
904         guarded_ptr get_with( Q const& key, Less pred )
905         {
906             return bucket( key ).get_with( key, pred );
907         }
908
909         /// Clears the set (non-atomic)
910         /**
911             The function unlink all items from the set.
912             The function is not atomic. It cleans up each bucket and then resets the item counter to zero.
913             If there are a thread that performs insertion while \p %clear() is working the result is undefined in general case:
914             \p empty() may return \p true but the set may contain item(s).
915             Therefore, \p %clear() may be used only for debugging purposes.
916
917             For each item the \p disposer is called after unlinking.
918         */
919         void clear()
920         {
921             for ( size_t i = 0; i < bucket_count(); ++i )
922                 m_Buckets[i].clear();
923             m_ItemCounter.reset();
924         }
925
926         /// Checks if the set is empty
927         /**
928             @warning If you use \p atomicity::empty_item_counter in \p traits::item_counter,
929             the function always returns \p true.
930         */
931         bool empty() const
932         {
933             return size() == 0;
934         }
935
936         /// Returns item count in the set
937         /**
938             If you use \p atomicity::empty_item_counter in \p traits::item_counter,
939             the function always returns 0.
940         */
941         size_t size() const
942         {
943             return m_ItemCounter;
944         }
945
946         /// Returns const reference to internal statistics
947         stat const& statistics() const
948         {
949             return m_Stat;
950         }
951
952         /// Returns the size of hash table
953         /**
954             Since \p %MichaelHashSet cannot dynamically extend the hash table size,
955             the value returned is an constant depending on object initialization parameters,
956             see \p MichaelHashSet::MichaelHashSet.
957         */
958         size_t bucket_count() const
959         {
960             return m_nHashBitmask + 1;
961         }
962
963     private:
964         //@cond
965         internal_bucket_type * bucket_begin() const
966         {
967             return m_Buckets;
968         }
969
970         internal_bucket_type * bucket_end() const
971         {
972             return m_Buckets + bucket_count();
973         }
974
975         const_iterator get_const_begin() const
976         {
977             return const_iterator( m_Buckets[0].cbegin(), bucket_begin(), bucket_end());
978         }
979         const_iterator get_const_end() const
980         {
981             return const_iterator( bucket_end()[-1].cend(), bucket_end() - 1, bucket_end());
982         }
983
984         template <typename Stat>
985         typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type * b )
986         {
987             new (b) internal_bucket_type;
988         }
989
990         template <typename Stat>
991         typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type * b )
992         {
993             new (b) internal_bucket_type( m_Stat );
994         }
995
996         /// Calculates hash value of \p key
997         template <typename Q>
998         size_t hash_value( const Q& key ) const
999         {
1000             return m_HashFunctor( key ) & m_nHashBitmask;
1001         }
1002
1003         /// Returns the bucket (ordered list) for \p key
1004         template <typename Q>
1005         internal_bucket_type& bucket( const Q& key )
1006         {
1007             return m_Buckets[hash_value( key )];
1008         }
1009         //@endcond
1010     };
1011
1012 }}  // namespace cds::intrusive
1013
1014 #endif // ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_H