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