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