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