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