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