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