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