22b2dccf8ed6898c650b04dc3da83192edab55a6
[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: protected 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 ) const
279             {
280                 return base_class::operator ==( i );
281             }
282             /// Equality operator
283             template <bool C>
284             bool operator !=(iterator_type<C> const& i ) const
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         /// Deletes the item pointed by iterator \p iter (only for \p IterableList based map)
678         /**
679             Returns \p true if the operation is successful, \p false otherwise.
680             The function can return \p false if the node the iterator points to has already been deleted
681             by other thread.
682
683             The function does not invalidate the iterator, it remains valid and can be used for further traversing.
684
685             @note \p %erase_at() is supported only for \p %MichaelHashMap based on \p IterableList.
686         */
687 #ifdef CDS_DOXYGEN_INVOKED
688         bool erase_at( iterator const& iter )
689 #else
690         template <typename Iterator>
691         typename std::enable_if< std::is_same<Iterator, iterator>::value && is_iterable_list< ordered_list >::value, bool >::type
692         erase_at( Iterator const& iter )
693 #endif
694         {
695             assert( iter != end() );
696             assert( iter.bucket() != nullptr );
697
698             if ( iter.bucket()->erase_at( iter.underlying_iterator())) {
699                 --m_ItemCounter;
700                 return true;
701             }
702             return false;
703         }
704
705         /// Extracts the item with specified \p key
706         /** \anchor cds_nonintrusive_MichaelHashMap_hp_extract
707             The function searches an item with key equal to \p key,
708             unlinks it from the map, and returns it as \p guarded_ptr.
709             If \p key is not found the function returns an empty guarded pointer.
710
711             Note the compare functor should accept a parameter of type \p K that may be not the same as \p key_type.
712
713             The extracted item is freed automatically when returned \p guarded_ptr object will be destroyed or released.
714             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
715
716             Usage:
717             \code
718             typedef cds::container::MichaelHashMap< your_template_args > michael_map;
719             michael_map theMap;
720             // ...
721             {
722                 michael_map::guarded_ptr gp( theMap.extract( 5 ));
723                 if ( gp ) {
724                     // Deal with gp
725                     // ...
726                 }
727                 // Destructor of gp releases internal HP guard
728             }
729             \endcode
730         */
731         template <typename K>
732         guarded_ptr extract( K const& key )
733         {
734             guarded_ptr gp( bucket( key ).extract( key ));
735             if ( gp )
736                 --m_ItemCounter;
737             return gp;
738         }
739
740         /// Extracts the item using compare functor \p pred
741         /**
742             The function is an analog of \ref cds_nonintrusive_MichaelHashMap_hp_extract "extract(K const&)"
743             but \p pred predicate is used for key comparing.
744
745             \p Less functor has the semantics like \p std::less but should take arguments of type \p key_type and \p K
746             in any order.
747             \p pred must imply the same element order as the comparator used for building the map.
748         */
749         template <typename K, typename Less>
750         guarded_ptr extract_with( K const& key, Less pred )
751         {
752             guarded_ptr gp( bucket( key ).extract_with( key, pred ));
753             if ( gp )
754                 --m_ItemCounter;
755             return gp;
756         }
757
758         /// Finds the key \p key
759         /** \anchor cds_nonintrusive_MichaelMap_find_cfunc
760
761             The function searches the item with key equal to \p key and calls the functor \p f for item found.
762             The interface of \p Func functor is:
763             \code
764             struct functor {
765                 void operator()( value_type& item );
766             };
767             \endcode
768             where \p item is the item found.
769
770             The functor may change \p item.second. Note that the functor is only guarantee
771             that \p item cannot be disposed during functor is executing.
772             The functor does not serialize simultaneous access to the map's \p item. If such access is
773             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
774
775             The function returns \p true if \p key is found, \p false otherwise.
776         */
777         template <typename K, typename Func>
778         bool find( K const& key, Func f )
779         {
780             return bucket( key ).find( key, f );
781         }
782
783         /// Finds \p key and returns iterator pointed to the item found (only for \p IterableList)
784         /**
785             If \p key is not found the function returns \p end().
786
787             @note This function is supported only for map based on \p IterableList
788         */
789         template <typename K>
790 #ifdef CDS_DOXYGEN_INVOKED
791         iterator
792 #else
793         typename std::enable_if< std::is_same<K,K>::value && is_iterable_list< ordered_list >::value, iterator >::type
794 #endif
795         find( K const& key )
796         {
797             auto& b = bucket( key );
798             auto it = b.find( key );
799             if ( it == b.end())
800                 return end();
801             return iterator( it, &b, bucket_end());
802         }
803
804
805         /// Finds the key \p val using \p pred predicate for searching
806         /**
807             The function is an analog of \ref cds_nonintrusive_MichaelMap_find_cfunc "find(K const&, Func)"
808             but \p pred is used for key comparing.
809             \p Less functor has the interface like \p std::less.
810             \p Less must imply the same element order as the comparator used for building the map.
811         */
812         template <typename K, typename Less, typename Func>
813         bool find_with( K const& key, Less pred, Func f )
814         {
815             return bucket( key ).find_with( key, pred, f );
816         }
817
818         /// Finds \p key using \p pred predicate and returns iterator pointed to the item found (only for \p IterableList)
819         /**
820             The function is an analog of \p find(K&) but \p pred is used for key comparing.
821             \p Less functor has the interface like \p std::less.
822             \p pred must imply the same element order as the comparator used for building the set.
823
824             If \p key is not found the function returns \p end().
825
826             @note This function is supported only for map based on \p IterableList
827         */
828         template <typename K, typename Less>
829 #ifdef CDS_DOXYGEN_INVOKED
830         iterator
831 #else
832         typename std::enable_if< std::is_same<K, K>::value && is_iterable_list< ordered_list >::value, iterator >::type
833 #endif
834         find_with( K const& key, Less pred )
835         {
836             auto& b = bucket( key );
837             auto it = b.find_with( key, pred );
838             if ( it == b.end())
839                 return end();
840             return iterator( it, &b, bucket_end());
841         }
842
843         /// Checks whether the map contains \p key
844         /**
845             The function searches the item with key equal to \p key
846             and returns \p true if it is found, and \p false otherwise.
847         */
848         template <typename K>
849         bool contains( K const& key )
850         {
851             return bucket( key ).contains( key );
852         }
853
854         /// Checks whether the map contains \p key using \p pred predicate for searching
855         /**
856             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
857             \p Less functor has the interface like \p std::less.
858             \p Less must imply the same element order as the comparator used for building the map.
859         */
860         template <typename K, typename Less>
861         bool contains( K const& key, Less pred )
862         {
863             return bucket( key ).contains( key, pred );
864         }
865
866         /// Finds \p key and return the item found
867         /** \anchor cds_nonintrusive_MichaelHashMap_hp_get
868             The function searches the item with key equal to \p key
869             and returns the guarded pointer to the item found.
870             If \p key is not found the function returns an empty guarded pointer,
871
872             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
873
874             Usage:
875             \code
876             typedef cds::container::MichaeHashMap< your_template_params >  michael_map;
877             michael_map theMap;
878             // ...
879             {
880                 michael_map::guarded_ptr gp( theMap.get( 5 ));
881                 if ( gp ) {
882                     // Deal with gp
883                     //...
884                 }
885                 // Destructor of guarded_ptr releases internal HP guard
886             }
887             \endcode
888
889             Note the compare functor specified for \p OrderedList template parameter
890             should accept a parameter of type \p K that can be not the same as \p key_type.
891         */
892         template <typename K>
893         guarded_ptr get( K const& key )
894         {
895             return bucket( key ).get( key );
896         }
897
898         /// Finds \p key and return the item found
899         /**
900             The function is an analog of \ref cds_nonintrusive_MichaelHashMap_hp_get "get( K const&)"
901             but \p pred is used for comparing the keys.
902
903             \p Less functor has the semantics like \p std::less but should take arguments of type \p key_type and \p K
904             in any order.
905             \p pred must imply the same element order as the comparator used for building the map.
906         */
907         template <typename K, typename Less>
908         guarded_ptr get_with( K const& key, Less pred )
909         {
910             return bucket( key ).get_with( key, pred );
911         }
912
913         /// Clears the map (not atomic)
914         void clear()
915         {
916             for ( size_t i = 0; i < bucket_count(); ++i )
917                 m_Buckets[i].clear();
918             m_ItemCounter.reset();
919         }
920
921         /// Checks if the map is empty
922         /**
923             Emptiness is checked by item counting: if item count is zero then the map is empty.
924             Thus, the correct item counting is an important part of the map implementation.
925         */
926         bool empty() const
927         {
928             return size() == 0;
929         }
930
931         /// Returns item count in the map
932         size_t size() const
933         {
934             return m_ItemCounter;
935         }
936
937         /// Returns the size of hash table
938         /**
939             Since \p %MichaelHashMap cannot dynamically extend the hash table size,
940             the value returned is an constant depending on object initialization parameters;
941             see \p MichaelHashMap::MichaelHashMap for explanation.
942         */
943         size_t bucket_count() const
944         {
945             return m_nHashBitmask + 1;
946         }
947
948         /// Returns const reference to internal statistics
949         stat const& statistics() const
950         {
951             return m_Stat;
952         }
953
954     protected:
955         //@cond
956         /// Calculates hash value of \p key
957         template <typename Q>
958         size_t hash_value( Q const& key ) const
959         {
960             return m_HashFunctor( key ) & m_nHashBitmask;
961         }
962
963         /// Returns the bucket (ordered list) for \p key
964         template <typename Q>
965         internal_bucket_type& bucket( Q const& key )
966         {
967             return m_Buckets[hash_value( key )];
968         }
969         //@endcond
970
971     private:
972         //@cond
973         internal_bucket_type* bucket_begin() const
974         {
975             return m_Buckets;
976         }
977
978         internal_bucket_type* bucket_end() const
979         {
980             return m_Buckets + bucket_count();
981         }
982
983         const_iterator get_const_begin() const
984         {
985             return const_iterator( bucket_begin()->cbegin(), bucket_begin(), bucket_end());
986         }
987         const_iterator get_const_end() const
988         {
989             return const_iterator( (bucket_end() - 1)->cend(), bucket_end() - 1, bucket_end());
990         }
991
992         template <typename Stat>
993         typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
994         {
995             new (bucket) internal_bucket_type;
996         }
997
998         template <typename Stat>
999         typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
1000         {
1001             new (bucket) internal_bucket_type( m_Stat );
1002         }
1003         //@endcond
1004     };
1005 }}  // namespace cds::container
1006
1007 #endif // ifndef CDSLIB_CONTAINER_MICHAEL_MAP_H