Uses different pass count for different parallel queue test cases
[libcds.git] / cds / container / michael_map_rcu.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_RCU_H
32 #define CDSLIB_CONTAINER_MICHAEL_MAP_RCU_H
33
34 #include <cds/container/details/michael_map_base.h>
35 #include <cds/details/allocator.h>
36
37 namespace cds { namespace container {
38
39     /// Michael's hash map (template specialization for \ref cds_urcu_desc "RCU")
40     /** @ingroup cds_nonintrusive_map
41         \anchor cds_nonintrusive_MichaelHashMap_rcu
42
43         Source:
44             - [2002] Maged Michael "High performance dynamic lock-free hash tables and list-based sets"
45
46         Michael's hash table algorithm is based on lock-free ordered list and it is very simple.
47         The main structure is an array \p T of size \p M. Each element in \p T is basically a pointer
48         to a hash bucket, implemented as a singly linked list. The array of buckets cannot be dynamically expanded.
49         However, each bucket may contain unbounded number of items.
50
51         Template parameters are:
52         - \p RCU - one of \ref cds_urcu_gc "RCU type"
53         - \p OrderedList - ordered key-value list implementation used as bucket for hash map, for example, \p MichaelKVList.
54             The ordered list implementation specifies the \p Key and \p Value types stored in the hash-map, the reclamation
55             schema \p GC used by hash-map, the comparison functor for the type \p Key and other features specific for
56             the ordered list.
57         - \p Traits - map traits, default is \p michael_map::traits.
58             Instead of defining \p Traits struct you may use option-based syntax with \p michael_map::make_traits metafunction
59
60         Many of the class function take a key argument of type \p K that in general is not \p key_type.
61         \p key_type and an argument of template type \p K must meet the following requirements:
62         - \p key_type should be constructible from value of type \p K;
63         - the hash functor should be able to calculate correct hash value from argument \p key of type \p K:
64             <tt> hash( key_type(key)) == hash( key ) </tt>
65         - values of type \p key_type and \p K should be comparable
66
67         <b>How to use</b>
68
69         The tips about how to use Michael's map see \ref cds_nonintrusive_MichaelHashMap_how_touse "MichaelHashMap".
70         Remember, that you should include RCU-related header file (for example, <tt>cds/urcu/general_buffered.h</tt>)
71         before including <tt>cds/container/michael_map_rcu.h</tt>.
72     */
73     template <
74         class RCU,
75         class OrderedList,
76 #ifdef CDS_DOXYGEN_INVOKED
77         class Traits = michael_map::traits
78 #else
79         class Traits
80 #endif
81     >
82     class MichaelHashMap< cds::urcu::gc< RCU >, OrderedList, Traits >
83     {
84     public:
85         typedef cds::urcu::gc< RCU > gc;   ///< RCU used as garbage collector
86         typedef OrderedList ordered_list;   ///< type of ordered list used as a bucket implementation
87         typedef Traits      traits;        ///< Map traits
88
89         typedef typename ordered_list::key_type          key_type;      ///< key type
90         typedef typename ordered_list::mapped_type       mapped_type;   ///< value type
91         typedef typename ordered_list::value_type        value_type;    ///< key/value pair stored in the list
92         typedef typename ordered_list::key_comparator    key_comparator;///< key comparison functor
93 #ifdef CDS_DOXYGEN_INVOKED
94         typedef typename ordered_list::stat         stat;       ///< Internal statistics
95         typedef typename ordered_list::exempt_ptr   exempt_ptr; ///< pointer to extracted node
96         /// Type of \p get() member function return value
97         typedef typename ordered_list::raw_ptr      raw_ptr;
98         typedef typename ordered_list::rcu_lock     rcu_lock;   ///< RCU scoped lock
99 #endif
100
101         /// Hash functor for \ref key_type and all its derivatives that you use
102         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type   hash;
103         typedef typename traits::item_counter  item_counter;   ///< Item counter type
104         typedef typename traits::allocator     allocator;    ///< Bucket table allocator
105
106         /// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
107         static CDS_CONSTEXPR const bool c_bExtractLockExternal = ordered_list::c_bExtractLockExternal;
108
109         // GC and OrderedList::gc must be the same
110         static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
111
112     protected:
113         //@cond
114         typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
115
116         typedef typename ordered_list::template rebind_traits<
117             cds::opt::item_counter< cds::atomicity::empty_item_counter >
118             , cds::opt::stat< typename bucket_stat::wrapped_stat >
119         >::type internal_bucket_type;
120
121         /// Bucket table allocator
122         typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
123         //@endcond
124
125     public:
126         //@cond
127         typedef typename bucket_stat::stat stat;
128         typedef typename internal_bucket_type::exempt_ptr   exempt_ptr;
129         typedef typename internal_bucket_type::raw_ptr      raw_ptr;
130         typedef typename internal_bucket_type::rcu_lock     rcu_lock;
131         //@endcond
132
133     protected:
134         //@cond
135         const size_t    m_nHashBitmask;
136         hash            m_HashFunctor;      ///< Hash functor
137         internal_bucket_type*  m_Buckets;   ///< bucket table
138         item_counter    m_ItemCounter;      ///< Item counter
139         stat            m_Stat;             ///< Internal statistics
140         //@endcond
141
142     protected:
143         //@cond
144         template <bool IsConst>
145         class iterator_type: private cds::intrusive::michael_set::details::iterator< internal_bucket_type, IsConst >
146         {
147             typedef cds::intrusive::michael_set::details::iterator< internal_bucket_type, IsConst >  base_class;
148             friend class MichaelHashMap;
149
150         protected:
151             typedef typename base_class::bucket_ptr     bucket_ptr;
152             typedef typename base_class::list_iterator  list_iterator;
153
154         public:
155             /// Value pointer type (const for const_iterator)
156             typedef typename cds::details::make_const_type<typename MichaelHashMap::mapped_type, IsConst>::pointer   value_ptr;
157             /// Value reference type (const for const_iterator)
158             typedef typename cds::details::make_const_type<typename MichaelHashMap::mapped_type, IsConst>::reference value_ref;
159
160             /// Key-value pair pointer type (const for const_iterator)
161             typedef typename cds::details::make_const_type<typename MichaelHashMap::value_type, IsConst>::pointer   pair_ptr;
162             /// Key-value pair reference type (const for const_iterator)
163             typedef typename cds::details::make_const_type<typename MichaelHashMap::value_type, IsConst>::reference pair_ref;
164
165         protected:
166             iterator_type( list_iterator const& it, bucket_ptr pFirst, bucket_ptr pLast )
167                 : base_class( it, pFirst, pLast )
168             {}
169
170         public:
171             /// Default ctor
172             iterator_type()
173                 : base_class()
174             {}
175
176             /// Copy ctor
177             iterator_type( const iterator_type& src )
178                 : base_class( src )
179             {}
180
181             /// Dereference operator
182             pair_ptr operator ->() const
183             {
184                 assert( base_class::m_pCurBucket != nullptr );
185                 return base_class::m_itList.operator ->();
186             }
187
188             /// Dereference operator
189             pair_ref operator *() const
190             {
191                 assert( base_class::m_pCurBucket != nullptr );
192                 return base_class::m_itList.operator *();
193             }
194
195             /// Pre-increment
196             iterator_type& operator ++()
197             {
198                 base_class::operator++();
199                 return *this;
200             }
201
202             /// Assignment operator
203             iterator_type& operator = (const iterator_type& src)
204             {
205                 base_class::operator =(src);
206                 return *this;
207             }
208
209             /// Returns current bucket (debug function)
210             bucket_ptr bucket() const
211             {
212                 return base_class::bucket();
213             }
214
215             /// Equality operator
216             template <bool C>
217             bool operator ==(iterator_type<C> const& i )
218             {
219                 return base_class::operator ==( i );
220             }
221             /// Equality operator
222             template <bool C>
223             bool operator !=(iterator_type<C> const& i )
224             {
225                 return !( *this == i );
226             }
227         };
228         //@endcond
229
230     public:
231     ///@name Forward iterators (thread-safe under RCU lock)
232     //@{
233
234         /// Forward iterator
235         /**
236             The forward iterator for Michael's map is based on \p OrderedList forward iterator and has some features:
237             - it has no post-increment operator
238             - it iterates items in unordered fashion
239
240             You may safely use iterators in multi-threaded environment only under RCU lock.
241             Otherwise, a crash is possible if another thread deletes the element the iterator points to.
242
243             The iterator interface:
244             \code
245             class iterator {
246             public:
247                 // Default constructor
248                 iterator();
249
250                 // Copy construtor
251                 iterator( iterator const& src );
252
253                 // Dereference operator
254                 value_type * operator ->() const;
255
256                 // Dereference operator
257                 value_type& operator *() const;
258
259                 // Preincrement operator
260                 iterator& operator ++();
261
262                 // Assignment operator
263                 iterator& operator = (iterator const& src);
264
265                 // Equality operators
266                 bool operator ==(iterator const& i ) const;
267                 bool operator !=(iterator const& i ) const;
268             };
269             \endcode
270         */
271         typedef iterator_type< false >    iterator;
272
273         /// Const forward iterator
274         typedef iterator_type< true >     const_iterator;
275
276         /// Returns a forward iterator addressing the first element in a map
277         /**
278             For empty map \code begin() == end() \endcode
279         */
280         iterator begin()
281         {
282             return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count());
283         }
284
285         /// Returns an iterator that addresses the location succeeding the last element in a map
286         /**
287             Do not use the value returned by <tt>end</tt> function to access any item.
288             The returned value can be used only to control reaching the end of the map.
289             For empty map \code begin() == end() \endcode
290         */
291         iterator end()
292         {
293             return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count());
294         }
295
296         /// Returns a forward const iterator addressing the first element in a map
297         const_iterator begin() const
298         {
299             return get_const_begin();
300         }
301
302         /// Returns a forward const iterator addressing the first element in a map
303         const_iterator cbegin() const
304         {
305             return get_const_begin();
306         }
307
308         /// Returns an const iterator that addresses the location succeeding the last element in a map
309         const_iterator end() const
310         {
311             return get_const_end();
312         }
313
314         /// Returns an const iterator that addresses the location succeeding the last element in a map
315         const_iterator cend() const
316         {
317             return get_const_end();
318         }
319     //@}
320
321     public:
322         /// Initializes the map
323         /**
324             The Michael's hash map is non-expandable container. You should point the average count of items \p nMaxItemCount
325             when you create an object.
326             \p nLoadFactor parameter defines average count of items per bucket and it should be small number between 1 and 10.
327             Remember, since the bucket implementation is an ordered list, searching in the bucket is linear [<tt>O(nLoadFactor)</tt>].
328             Note, that many popular STL hash map implementation uses load factor 1.
329
330             The ctor defines hash table size as rounding <tt>nMacItemCount / nLoadFactor</tt> up to nearest power of two.
331         */
332         MichaelHashMap(
333             size_t nMaxItemCount,   ///< estimation of max item count in the hash map
334             size_t nLoadFactor      ///< load factor: estimation of max number of items in the bucket
335         ) : m_nHashBitmask( michael_map::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
336           , m_Buckets( bucket_table_allocator().allocate( bucket_count()))
337         {
338             for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
339                 construct_bucket<bucket_stat>( it );
340         }
341
342         /// Clears hash map and destroys it
343         ~MichaelHashMap()
344         {
345             clear();
346             for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
347                 it->~internal_bucket_type();
348             bucket_table_allocator().deallocate( m_Buckets, bucket_count());
349         }
350
351         /// Inserts new node with key and default value
352         /**
353             The function creates a node with \p key and default value, and then inserts the node created into the map.
354
355             Preconditions:
356             - The \p key_type should be constructible from value of type \p K.
357                 In trivial case, \p K is equal to \ref key_type.
358             - The \p mapped_type should be default-constructible.
359
360             The function applies RCU lock internally.
361
362             Returns \p true if inserting successful, \p false otherwise.
363         */
364         template <typename K>
365         bool insert( const K& key )
366         {
367             const bool bRet = bucket( key ).insert( key );
368             if ( bRet )
369                 ++m_ItemCounter;
370             return bRet;
371         }
372
373         /// Inserts new node
374         /**
375             The function creates a node with copy of \p val value
376             and then inserts the node created into the map.
377
378             Preconditions:
379             - The \p key_type should be constructible from \p key of type \p K.
380             - The \p mapped_type should be constructible from \p val of type \p V.
381
382             The function applies RCU lock internally.
383
384             Returns \p true if \p val is inserted into the map, \p false otherwise.
385         */
386         template <typename K, typename V>
387         bool insert( K const& key, V const& val )
388         {
389             const bool bRet = bucket( key ).insert( key, val );
390             if ( bRet )
391                 ++m_ItemCounter;
392             return bRet;
393         }
394
395         /// Inserts new node and initialize it by a functor
396         /**
397             This function inserts new node with key \p key and if inserting is successful then it calls
398             \p func functor with signature
399             \code
400                 struct functor {
401                     void operator()( value_type& item );
402                 };
403             \endcode
404
405             The argument \p item of user-defined functor \p func is the reference
406             to the map's item inserted:
407                 - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
408                 - <tt>item.second</tt> is a reference to item's value that may be changed.
409
410             The user-defined functor is called only if inserting is successful.
411
412             The key_type should be constructible from value of type \p K.
413
414             The function allows to split creating of new item into two part:
415             - create item from \p key;
416             - insert new item into the map;
417             - if inserting is successful, initialize the value of item by calling \p func functor
418
419             This can be useful if complete initialization of object of \p mapped_type is heavyweight and
420             it is preferable that the initialization should be completed only if inserting is successful.
421
422             The function applies RCU lock internally.
423
424             @warning For \ref cds_nonintrusive_MichaelKVList_rcu "MichaelKVList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
425             \ref cds_nonintrusive_LazyKVList_rcu "LazyKVList" provides exclusive access to inserted item and does not require any node-level
426             synchronization.
427         */
428         template <typename K, typename Func>
429         bool insert_with( const K& key, Func func )
430         {
431             const bool bRet = bucket( key ).insert_with( key, func );
432             if ( bRet )
433                 ++m_ItemCounter;
434             return bRet;
435         }
436
437         /// Updates data by \p key
438         /**
439             The operation performs inserting or replacing the element with lock-free manner.
440
441             If the \p key not found in the map, then the new item created from \p key
442             will be inserted into the map iff \p bAllowInsert is \p true.
443             (note that in this case the \ref key_type should be constructible from type \p K).
444             Otherwise, if \p key is found, the functor \p func is called with item found.
445
446             The functor \p Func signature is:
447             \code
448                 struct my_functor {
449                     void operator()( bool bNew, value_type& item );
450                 };
451             \endcode
452             with arguments:
453             - \p bNew - \p true if the item has been inserted, \p false otherwise
454             - \p item - the item found or inserted
455
456             The functor may change any fields of the \p item.second that is \p mapped_type.
457
458             The function applies RCU lock internally.
459
460             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
461             \p second is true if new item has been added or \p false if the item with \p key
462             already exists.
463
464             @warning For \ref cds_nonintrusive_MichaelKVList_rcu "MichaelKVList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
465             \ref cds_nonintrusive_LazyKVList_rcu "LazyKVList" provides exclusive access to inserted item and does not require any node-level
466             synchronization.
467         */
468         template <typename K, typename Func>
469         std::pair<bool, bool> update( K const& key, Func func, bool bAllowInsert = true )
470         {
471             std::pair<bool, bool> bRet = bucket( key ).update( key, func, bAllowInsert );
472             if ( bRet.second )
473                 ++m_ItemCounter;
474             return bRet;
475         }
476         //@cond
477         template <typename K, typename Func>
478         CDS_DEPRECATED("ensure() is deprecated, use update()")
479         std::pair<bool, bool> ensure( K const& key, Func func )
480         {
481             return update( key, func, true );
482         }
483         //@endcond
484
485         /// For key \p key inserts data of type \p mapped_type created from \p args
486         /**
487             \p key_type should be constructible from type \p K
488
489             Returns \p true if inserting successful, \p false otherwise.
490         */
491         template <typename K, typename... Args>
492         bool emplace( K&& key, Args&&... args )
493         {
494             const bool bRet = bucket( key ).emplace( std::forward<K>(key), std::forward<Args>(args)... );
495             if ( bRet )
496                 ++m_ItemCounter;
497             return bRet;
498         }
499
500         /// Deletes \p key from the map
501         /** \anchor cds_nonintrusive_MichaelMap_rcu_erase_val
502
503             RCU \p synchronize method can be called. RCU should not be locked.
504
505             Return \p true if \p key is found and deleted, \p false otherwise
506         */
507         template <typename K>
508         bool erase( const K& key )
509         {
510             const bool bRet = bucket( key ).erase( key );
511             if ( bRet )
512                 --m_ItemCounter;
513             return bRet;
514         }
515
516         /// Deletes the item from the map using \p pred predicate for searching
517         /**
518             The function is an analog of \ref cds_nonintrusive_MichaelMap_rcu_erase_val "erase(K const&)"
519             but \p pred is used for key comparing.
520             \p Less predicate has the interface like \p std::less.
521             \p Less must imply the same element order as the comparator used for building the map.
522         */
523         template <typename K, typename Less>
524         bool erase_with( const K& key, Less pred )
525         {
526             const bool bRet = bucket( key ).erase_with( key, pred );
527             if ( bRet )
528                 --m_ItemCounter;
529             return bRet;
530         }
531
532         /// Deletes \p key from the map
533         /** \anchor cds_nonintrusive_MichaelMap_rcu_erase_func
534
535             The function searches an item with key \p key, calls \p f functor
536             and deletes the item. If \p key is not found, the functor is not called.
537
538             The functor \p Func interface:
539             \code
540             struct extractor {
541                 void operator()(value_type& item) { ... }
542             };
543             \endcode
544
545             RCU \p synchronize method can be called. RCU should not be locked.
546
547             Return \p true if key is found and deleted, \p false otherwise
548         */
549         template <typename K, typename Func>
550         bool erase( const K& key, Func f )
551         {
552             const bool bRet = bucket( key ).erase( key, f );
553             if ( bRet )
554                 --m_ItemCounter;
555             return bRet;
556         }
557
558         /// Deletes the item from the map using \p pred predicate for searching
559         /**
560             The function is an analog of \ref cds_nonintrusive_MichaelMap_rcu_erase_func "erase(K const&, Func)"
561             but \p pred is used for key comparing.
562             \p Less functor has the interface like \p std::less.
563             \p Less must imply the same element order as the comparator used for building the map.
564         */
565         template <typename K, typename Less, typename Func>
566         bool erase_with( const K& key, Less pred, Func f )
567         {
568             const bool bRet = bucket( key ).erase_with( key, pred, f );
569             if ( bRet )
570                 --m_ItemCounter;
571             return bRet;
572         }
573
574         /// Extracts an item from the map
575         /** \anchor cds_nonintrusive_MichaelHashMap_rcu_extract
576             The function searches an item with key equal to \p key,
577             unlinks it from the map, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
578             If the item is not found the function return an empty \p exempt_ptr.
579
580             The function just excludes the key from the map and returns a pointer to item found.
581             Depends on \p ordered_list you should or should not lock RCU before calling of this function:
582             - for the set based on \ref cds_nonintrusive_MichaelList_rcu "MichaelList" RCU should not be locked
583             - for the set based on \ref cds_nonintrusive_LazyList_rcu "LazyList" RCU should be locked
584             See ordered list implementation for details.
585
586             \code
587             #include <cds/urcu/general_buffered.h>
588             #include <cds/container/michael_kvlist_rcu.h>
589             #include <cds/container/michael_map_rcu.h>
590
591             typedef cds::urcu::gc< general_buffered<> > rcu;
592             typedef cds::container::MichaelKVList< rcu, int, Foo > rcu_michael_list;
593             typedef cds::container::MichaelHashMap< rcu, rcu_michael_list, foo_traits > rcu_michael_map;
594
595             rcu_michael_map theMap;
596             // ...
597
598             rcu_michael_map::exempt_ptr p;
599
600             // For MichaelList we should not lock RCU
601
602             // Note that you must not delete the item found inside the RCU lock
603             p = theMap.extract( 10 );
604             if ( p ) {
605                 // do something with p
606                 ...
607             }
608
609             // We may safely release p here
610             // release() passes the pointer to RCU reclamation cycle
611             p.release();
612             \endcode
613         */
614         template <typename K>
615         exempt_ptr extract( K const& key )
616         {
617             exempt_ptr p = bucket( key ).extract( key );
618             if ( p )
619                 --m_ItemCounter;
620             return p;
621         }
622
623         /// Extracts an item from the map using \p pred predicate for searching
624         /**
625             The function is an analog of \p extract(K const&) but \p pred is used for key comparing.
626             \p Less functor has the interface like \p std::less.
627             \p pred must imply the same element order as the comparator used for building the map.
628         */
629         template <typename K, typename Less>
630         exempt_ptr extract_with( K const& key, Less pred )
631         {
632             exempt_ptr p = bucket( key ).extract_with( key, pred );
633             if ( p )
634                 --m_ItemCounter;
635             return p;
636         }
637
638         /// Finds the key \p key
639         /** \anchor cds_nonintrusive_MichaelMap_rcu_find_cfunc
640
641             The function searches the item with key equal to \p key and calls the functor \p f for item found.
642             The interface of \p Func functor is:
643             \code
644             struct functor {
645                 void operator()( value_type& item );
646             };
647             \endcode
648             where \p item is the item found.
649
650             The functor may change \p item.second. Note that the functor is only guarantee
651             that \p item cannot be disposed during functor is executing.
652             The functor does not serialize simultaneous access to the map's \p item. If such access is
653             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
654
655             The function applies RCU lock internally.
656
657             The function returns \p true if \p key is found, \p false otherwise.
658         */
659         template <typename K, typename Func>
660         bool find( K const& key, Func f )
661         {
662             return bucket( key ).find( key, f );
663         }
664
665         /// Finds the key \p val using \p pred predicate for searching
666         /**
667             The function is an analog of \ref cds_nonintrusive_MichaelMap_rcu_find_cfunc "find(K const&, Func)"
668             but \p pred is used for key comparing.
669             \p Less functor has the interface like \p std::less.
670             \p Less must imply the same element order as the comparator used for building the map.
671         */
672         template <typename K, typename Less, typename Func>
673         bool find_with( K const& key, Less pred, Func f )
674         {
675             return bucket( key ).find_with( key, pred, f );
676         }
677
678         /// Checks whether the map contains \p key
679         /**
680             The function searches the item with key equal to \p key
681             and returns \p true if it is found, and \p false otherwise.
682
683             The function applies RCU lock internally.
684         */
685         template <typename K>
686         bool contains( K const& key )
687         {
688             return bucket( key ).contains( key );
689         }
690         //@cond
691         template <typename K>
692         CDS_DEPRECATED("deprecated, use contains()")
693         bool find( K const& key )
694         {
695             return bucket( key ).contains( key );
696         }
697         //@endcond
698
699         /// Checks whether the map contains \p key using \p pred predicate for searching
700         /**
701             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
702             \p Less functor has the interface like \p std::less.
703             \p Less must imply the same element order as the comparator used for building the map.
704         */
705         template <typename K, typename Less>
706         bool contains( K const& key, Less pred )
707         {
708             return bucket( key ).contains( key, pred );
709         }
710         //@cond
711         template <typename K, typename Less>
712         CDS_DEPRECATED("deprecated, use contains()")
713         bool find_with( K const& key, Less pred )
714         {
715             return bucket( key ).contains( key, pred );
716         }
717         //@endcond
718
719         /// Finds \p key and return the item found
720         /** \anchor cds_nonintrusive_MichaelHashMap_rcu_get
721             The function searches the item with key equal to \p key and returns the pointer to item found.
722             If \p key is not found it returns \p nullptr.
723             Note the type of returned value depends on underlying \p ordered_list.
724             For details, see documentation of ordered list you use.
725
726             Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
727
728             RCU should be locked before call of this function.
729             Returned item is valid only while RCU is locked:
730             \code
731             typedef cds::container::MichaelHashMap< your_template_parameters > hash_map;
732             hash_map theMap;
733             // ...
734             typename hash_map::raw_ptr gp;
735             {
736                 // Lock RCU
737                 hash_map::rcu_lock lock;
738
739                 gp = theMap.get( 5 );
740                 if ( gp ) {
741                     // Deal with gp
742                     //...
743                 }
744                 // Unlock RCU by rcu_lock destructor
745                 // gp can be reclaimed at any time after RCU has been unlocked
746             }
747             \endcode
748         */
749         template <typename K>
750         raw_ptr get( K const& key )
751         {
752             return bucket( key ).get( key );
753         }
754
755         /// Finds \p key and return the item found
756         /**
757             The function is an analog of \ref cds_nonintrusive_MichaelHashMap_rcu_get "get(K const&)"
758             but \p pred is used for comparing the keys.
759
760             \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
761             in any order.
762             \p pred must imply the same element order as the comparator used for building the map.
763         */
764         template <typename K, typename Less>
765         raw_ptr get_with( K const& key, Less pred )
766         {
767             return bucket( key ).get_with( key, pred );
768         }
769
770         /// Clears the map (not atomic)
771         /**
772             The function erases all items from the map.
773
774             The function is not atomic. It cleans up each bucket and then resets the item counter to zero.
775             If there are a thread that performs insertion while \p clear is working the result is undefined in general case:
776             <tt> empty() </tt> may return \p true but the map may contain item(s).
777             Therefore, \p clear may be used only for debugging purposes.
778
779             RCU \p synchronize method can be called. RCU should not be locked.
780         */
781         void clear()
782         {
783             for ( size_t i = 0; i < bucket_count(); ++i )
784                 m_Buckets[i].clear();
785             m_ItemCounter.reset();
786         }
787
788         /// Checks if the map is empty
789         /**
790             @warning If you use \p atomicity::empty_item_counter in \p traits::item_counter,
791             the function always returns \p true.
792         */
793         bool empty() const
794         {
795             return size() == 0;
796         }
797
798         /// Returns item count in the map
799         /**
800             @warning If you use \p atomicity::empty_item_counter in \p traits::item_counter,
801             the function always returns 0.
802         */
803         size_t size() const
804         {
805             return m_ItemCounter;
806         }
807
808         /// Returns const reference to internal statistics
809         stat const& statistics() const
810         {
811             return m_Stat;
812         }
813
814         /// Returns the size of hash table
815         /**
816             Since \p %MichaelHashMap cannot dynamically extend the hash table size,
817             the value returned is an constant depending on object initialization parameters;
818             see \p MichaelHashMap::MichaelHashMap for explanation.
819         */
820         size_t bucket_count() const
821         {
822             return m_nHashBitmask + 1;
823         }
824
825     protected:
826         //@cond
827         /// Calculates hash value of \p key
828         template <typename Q>
829         size_t hash_value( Q const& key ) const
830         {
831             return m_HashFunctor( key ) & m_nHashBitmask;
832         }
833
834         /// Returns the bucket (ordered list) for \p key
835         template <typename Q>
836         internal_bucket_type&    bucket( Q const& key )
837         {
838             return m_Buckets[hash_value( key )];
839         }
840         template <typename Q>
841         internal_bucket_type const&    bucket( Q const& key ) const
842         {
843             return m_Buckets[hash_value( key )];
844         }
845         //@endcond
846     private:
847         //@cond
848         const_iterator get_const_begin() const
849         {
850             return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count());
851         }
852         const_iterator get_const_end() const
853         {
854             return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count());
855         }
856
857         template <typename Stat>
858         typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type* bkt )
859         {
860             new (bkt) internal_bucket_type;
861         }
862
863         template <typename Stat>
864         typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type* bkt )
865         {
866             new (bkt) internal_bucket_type( m_Stat );
867         }
868         //@endcond
869     };
870 }}  // namespace cds::container
871
872 #endif // ifndef CDSLIB_CONTAINER_MICHAEL_MAP_RCU_H