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