2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
6 Source code repo: http://github.com/khizmax/libcds/
7 Download: http://sourceforge.net/projects/libcds/files/
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
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.
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.
31 #ifndef CDSLIB_CONTAINER_MICHAEL_MAP_RCU_H
32 #define CDSLIB_CONTAINER_MICHAEL_MAP_RCU_H
34 #include <cds/container/details/michael_map_base.h>
35 #include <cds/details/allocator.h>
37 namespace cds { namespace container {
39 /// Michael's hash map (template specialization for \ref cds_urcu_desc "RCU")
40 /** @ingroup cds_nonintrusive_map
41 \anchor cds_nonintrusive_MichaelHashMap_rcu
44 - [2002] Maged Michael "High performance dynamic lock-free hash tables and list-based sets"
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.
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
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
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
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>.
76 #ifdef CDS_DOXYGEN_INVOKED
77 class Traits = michael_map::traits
82 class MichaelHashMap< cds::urcu::gc< RCU >, OrderedList, Traits >
85 typedef cds::urcu::gc< RCU > gc; ///< RCU used as garbage collector
86 typedef OrderedList bucket_type; ///< type of ordered list used as a bucket implementation
87 typedef Traits traits; ///< Map traits
89 typedef typename bucket_type::key_type key_type ; ///< key type
90 typedef typename bucket_type::mapped_type mapped_type ; ///< value type
91 typedef typename bucket_type::value_type value_type ; ///< key/value pair stored in the list
92 typedef typename bucket_type::key_comparator key_comparator ; ///< key comparison functor
94 /// Hash functor for \ref key_type and all its derivatives that you use
95 typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
96 typedef typename traits::item_counter item_counter; ///< Item counter type
98 /// Bucket table allocator
99 typedef cds::details::Allocator< bucket_type, typename traits::allocator > bucket_table_allocator;
101 typedef typename bucket_type::rcu_lock rcu_lock; ///< RCU scoped lock
102 typedef typename bucket_type::exempt_ptr exempt_ptr; ///< pointer to extracted node
103 /// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
104 static CDS_CONSTEXPR const bool c_bExtractLockExternal = bucket_type::c_bExtractLockExternal;
105 /// Type of \p get() member function return value
106 typedef typename bucket_type::raw_ptr raw_ptr;
109 item_counter m_ItemCounter; ///< Item counter
110 hash m_HashFunctor; ///< Hash functor
111 bucket_type * m_Buckets; ///< bucket table
115 const size_t m_nHashBitmask;
120 /// Calculates hash value of \p key
121 template <typename Q>
122 size_t hash_value( Q const& key ) const
124 return m_HashFunctor( key ) & m_nHashBitmask;
127 /// Returns the bucket (ordered list) for \p key
128 template <typename Q>
129 bucket_type& bucket( Q const& key )
131 return m_Buckets[ hash_value( key ) ];
133 template <typename Q>
134 bucket_type const& bucket( Q const& key ) const
136 return m_Buckets[ hash_value( key ) ];
142 template <bool IsConst>
143 class iterator_type: private cds::intrusive::michael_set::details::iterator< bucket_type, IsConst >
145 typedef cds::intrusive::michael_set::details::iterator< bucket_type, IsConst > base_class;
146 friend class MichaelHashMap;
149 typedef typename base_class::bucket_ptr bucket_ptr;
150 typedef typename base_class::list_iterator list_iterator;
153 /// Value pointer type (const for const_iterator)
154 typedef typename cds::details::make_const_type<typename MichaelHashMap::mapped_type, IsConst>::pointer value_ptr;
155 /// Value reference type (const for const_iterator)
156 typedef typename cds::details::make_const_type<typename MichaelHashMap::mapped_type, IsConst>::reference value_ref;
158 /// Key-value pair pointer type (const for const_iterator)
159 typedef typename cds::details::make_const_type<typename MichaelHashMap::value_type, IsConst>::pointer pair_ptr;
160 /// Key-value pair reference type (const for const_iterator)
161 typedef typename cds::details::make_const_type<typename MichaelHashMap::value_type, IsConst>::reference pair_ref;
164 iterator_type( list_iterator const& it, bucket_ptr pFirst, bucket_ptr pLast )
165 : base_class( it, pFirst, pLast )
175 iterator_type( const iterator_type& src )
179 /// Dereference operator
180 pair_ptr operator ->() const
182 assert( base_class::m_pCurBucket != nullptr );
183 return base_class::m_itList.operator ->();
186 /// Dereference operator
187 pair_ref operator *() const
189 assert( base_class::m_pCurBucket != nullptr );
190 return base_class::m_itList.operator *();
194 iterator_type& operator ++()
196 base_class::operator++();
200 /// Assignment operator
201 iterator_type& operator = (const iterator_type& src)
203 base_class::operator =(src);
207 /// Returns current bucket (debug function)
208 bucket_ptr bucket() const
210 return base_class::bucket();
213 /// Equality operator
215 bool operator ==(iterator_type<C> const& i )
217 return base_class::operator ==( i );
219 /// Equality operator
221 bool operator !=(iterator_type<C> const& i )
223 return !( *this == i );
229 ///@name Forward iterators (thread-safe under RCU lock)
234 The forward iterator for Michael's map is based on \p OrderedList forward iterator and has some features:
235 - it has no post-increment operator
236 - it iterates items in unordered fashion
238 You may safely use iterators in multi-threaded environment only under RCU lock.
239 Otherwise, a crash is possible if another thread deletes the element the iterator points to.
241 The iterator interface:
245 // Default constructor
249 iterator( iterator const& src );
251 // Dereference operator
252 value_type * operator ->() const;
254 // Dereference operator
255 value_type& operator *() const;
257 // Preincrement operator
258 iterator& operator ++();
260 // Assignment operator
261 iterator& operator = (iterator const& src);
263 // Equality operators
264 bool operator ==(iterator const& i ) const;
265 bool operator !=(iterator const& i ) const;
269 typedef iterator_type< false > iterator;
271 /// Const forward iterator
272 typedef iterator_type< true > const_iterator;
274 /// Returns a forward iterator addressing the first element in a map
276 For empty map \code begin() == end() \endcode
280 return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count() );
283 /// Returns an iterator that addresses the location succeeding the last element in a map
285 Do not use the value returned by <tt>end</tt> function to access any item.
286 The returned value can be used only to control reaching the end of the map.
287 For empty map \code begin() == end() \endcode
291 return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
294 /// Returns a forward const iterator addressing the first element in a map
295 const_iterator begin() const
297 return get_const_begin();
300 /// Returns a forward const iterator addressing the first element in a map
301 const_iterator cbegin() const
303 return get_const_begin();
306 /// Returns an const iterator that addresses the location succeeding the last element in a map
307 const_iterator end() const
309 return get_const_end();
312 /// Returns an const iterator that addresses the location succeeding the last element in a map
313 const_iterator cend() const
315 return get_const_end();
321 const_iterator get_const_begin() const
323 return const_iterator( const_cast<bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
325 const_iterator get_const_end() const
327 return const_iterator( const_cast<bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
332 /// Initializes the map
334 The Michael's hash map is non-expandable container. You should point the average count of items \p nMaxItemCount
335 when you create an object.
336 \p nLoadFactor parameter defines average count of items per bucket and it should be small number between 1 and 10.
337 Remember, since the bucket implementation is an ordered list, searching in the bucket is linear [<tt>O(nLoadFactor)</tt>].
338 Note, that many popular STL hash map implementation uses load factor 1.
340 The ctor defines hash table size as rounding <tt>nMacItemCount / nLoadFactor</tt> up to nearest power of two.
343 size_t nMaxItemCount, ///< estimation of max item count in the hash map
344 size_t nLoadFactor ///< load factor: estimation of max number of items in the bucket
345 ) : m_nHashBitmask( michael_map::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
347 // GC and OrderedList::gc must be the same
348 static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
350 // atomicity::empty_item_counter is not allowed as a item counter
351 static_assert( !std::is_same<item_counter, cds::atomicity::empty_item_counter>::value,
352 "cds::atomicity::empty_item_counter is not allowed as a item counter");
354 m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
357 /// Clears hash map and destroys it
361 bucket_table_allocator().Delete( m_Buckets, bucket_count() );
364 /// Inserts new node with key and default value
366 The function creates a node with \p key and default value, and then inserts the node created into the map.
369 - The \p key_type should be constructible from value of type \p K.
370 In trivial case, \p K is equal to \ref key_type.
371 - The \p mapped_type should be default-constructible.
373 The function applies RCU lock internally.
375 Returns \p true if inserting successful, \p false otherwise.
377 template <typename K>
378 bool insert( const K& key )
380 const bool bRet = bucket( key ).insert( key );
388 The function creates a node with copy of \p val value
389 and then inserts the node created into the map.
392 - The \p key_type should be constructible from \p key of type \p K.
393 - The \p mapped_type should be constructible from \p val of type \p V.
395 The function applies RCU lock internally.
397 Returns \p true if \p val is inserted into the map, \p false otherwise.
399 template <typename K, typename V>
400 bool insert( K const& key, V const& val )
402 const bool bRet = bucket( key ).insert( key, val );
408 /// Inserts new node and initialize it by a functor
410 This function inserts new node with key \p key and if inserting is successful then it calls
411 \p func functor with signature
414 void operator()( value_type& item );
418 The argument \p item of user-defined functor \p func is the reference
419 to the map's item inserted:
420 - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
421 - <tt>item.second</tt> is a reference to item's value that may be changed.
423 The user-defined functor is called only if inserting is successful.
425 The key_type should be constructible from value of type \p K.
427 The function allows to split creating of new item into two part:
428 - create item from \p key;
429 - insert new item into the map;
430 - if inserting is successful, initialize the value of item by calling \p func functor
432 This can be useful if complete initialization of object of \p mapped_type is heavyweight and
433 it is preferable that the initialization should be completed only if inserting is successful.
435 The function applies RCU lock internally.
437 @warning For \ref cds_nonintrusive_MichaelKVList_rcu "MichaelKVList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
438 \ref cds_nonintrusive_LazyKVList_rcu "LazyKVList" provides exclusive access to inserted item and does not require any node-level
441 template <typename K, typename Func>
442 bool insert_with( const K& key, Func func )
444 const bool bRet = bucket( key ).insert_with( key, func );
450 /// Updates data by \p key
452 The operation performs inserting or replacing the element with lock-free manner.
454 If the \p key not found in the map, then the new item created from \p key
455 will be inserted into the map iff \p bAllowInsert is \p true.
456 (note that in this case the \ref key_type should be constructible from type \p K).
457 Otherwise, if \p key is found, the functor \p func is called with item found.
459 The functor \p Func signature is:
462 void operator()( bool bNew, value_type& item );
466 - \p bNew - \p true if the item has been inserted, \p false otherwise
467 - \p item - the item found or inserted
469 The functor may change any fields of the \p item.second that is \p mapped_type.
471 The function applies RCU lock internally.
473 Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
474 \p second is true if new item has been added or \p false if the item with \p key
477 @warning For \ref cds_nonintrusive_MichaelKVList_rcu "MichaelKVList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
478 \ref cds_nonintrusive_LazyKVList_rcu "LazyKVList" provides exclusive access to inserted item and does not require any node-level
481 template <typename K, typename Func>
482 std::pair<bool, bool> update( K const& key, Func func, bool bAllowInsert = true )
484 std::pair<bool, bool> bRet = bucket( key ).update( key, func, bAllowInsert );
490 template <typename K, typename Func>
491 CDS_DEPRECATED("ensure() is deprecated, use update()")
492 std::pair<bool, bool> ensure( K const& key, Func func )
494 return update( key, func, true );
498 /// For key \p key inserts data of type \p mapped_type created from \p args
500 \p key_type should be constructible from type \p K
502 Returns \p true if inserting successful, \p false otherwise.
504 template <typename K, typename... Args>
505 bool emplace( K&& key, Args&&... args )
507 const bool bRet = bucket( key ).emplace( std::forward<K>(key), std::forward<Args>(args)... );
513 /// Deletes \p key from the map
514 /** \anchor cds_nonintrusive_MichaelMap_rcu_erase_val
516 RCU \p synchronize method can be called. RCU should not be locked.
518 Return \p true if \p key is found and deleted, \p false otherwise
520 template <typename K>
521 bool erase( const K& key )
523 const bool bRet = bucket( key ).erase( key );
529 /// Deletes the item from the map using \p pred predicate for searching
531 The function is an analog of \ref cds_nonintrusive_MichaelMap_rcu_erase_val "erase(K const&)"
532 but \p pred is used for key comparing.
533 \p Less predicate has the interface like \p std::less.
534 \p Less must imply the same element order as the comparator used for building the map.
536 template <typename K, typename Less>
537 bool erase_with( const K& key, Less pred )
539 const bool bRet = bucket( key ).erase_with( key, pred );
545 /// Deletes \p key from the map
546 /** \anchor cds_nonintrusive_MichaelMap_rcu_erase_func
548 The function searches an item with key \p key, calls \p f functor
549 and deletes the item. If \p key is not found, the functor is not called.
551 The functor \p Func interface:
554 void operator()(value_type& item) { ... }
558 RCU \p synchronize method can be called. RCU should not be locked.
560 Return \p true if key is found and deleted, \p false otherwise
562 template <typename K, typename Func>
563 bool erase( const K& key, Func f )
565 const bool bRet = bucket( key ).erase( key, f );
571 /// Deletes the item from the map using \p pred predicate for searching
573 The function is an analog of \ref cds_nonintrusive_MichaelMap_rcu_erase_func "erase(K const&, Func)"
574 but \p pred is used for key comparing.
575 \p Less functor has the interface like \p std::less.
576 \p Less must imply the same element order as the comparator used for building the map.
578 template <typename K, typename Less, typename Func>
579 bool erase_with( const K& key, Less pred, Func f )
581 const bool bRet = bucket( key ).erase_with( key, pred, f );
587 /// Extracts an item from the map
588 /** \anchor cds_nonintrusive_MichaelHashMap_rcu_extract
589 The function searches an item with key equal to \p key,
590 unlinks it from the map, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
591 If the item is not found the function return an empty \p exempt_ptr.
593 The function just excludes the key from the map and returns a pointer to item found.
594 Depends on \p bucket_type you should or should not lock RCU before calling of this function:
595 - for the set based on \ref cds_nonintrusive_MichaelList_rcu "MichaelList" RCU should not be locked
596 - for the set based on \ref cds_nonintrusive_LazyList_rcu "LazyList" RCU should be locked
597 See ordered list implementation for details.
600 #include <cds/urcu/general_buffered.h>
601 #include <cds/container/michael_kvlist_rcu.h>
602 #include <cds/container/michael_map_rcu.h>
604 typedef cds::urcu::gc< general_buffered<> > rcu;
605 typedef cds::container::MichaelKVList< rcu, int, Foo > rcu_michael_list;
606 typedef cds::container::MichaelHashMap< rcu, rcu_michael_list, foo_traits > rcu_michael_map;
608 rcu_michael_map theMap;
611 rcu_michael_map::exempt_ptr p;
613 // For MichaelList we should not lock RCU
615 // Note that you must not delete the item found inside the RCU lock
616 p = theMap.extract( 10 );
618 // do something with p
622 // We may safely release p here
623 // release() passes the pointer to RCU reclamation cycle
627 template <typename K>
628 exempt_ptr extract( K const& key )
630 exempt_ptr p = bucket( key ).extract( key );
636 /// Extracts an item from the map using \p pred predicate for searching
638 The function is an analog of \p extract(K const&) but \p pred is used for key comparing.
639 \p Less functor has the interface like \p std::less.
640 \p pred must imply the same element order as the comparator used for building the map.
642 template <typename K, typename Less>
643 exempt_ptr extract_with( K const& key, Less pred )
645 exempt_ptr p = bucket( key ).extract_with( key, pred );
651 /// Finds the key \p key
652 /** \anchor cds_nonintrusive_MichaelMap_rcu_find_cfunc
654 The function searches the item with key equal to \p key and calls the functor \p f for item found.
655 The interface of \p Func functor is:
658 void operator()( value_type& item );
661 where \p item is the item found.
663 The functor may change \p item.second. Note that the functor is only guarantee
664 that \p item cannot be disposed during functor is executing.
665 The functor does not serialize simultaneous access to the map's \p item. If such access is
666 possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
668 The function applies RCU lock internally.
670 The function returns \p true if \p key is found, \p false otherwise.
672 template <typename K, typename Func>
673 bool find( K const& key, Func f )
675 return bucket( key ).find( key, f );
678 /// Finds the key \p val using \p pred predicate for searching
680 The function is an analog of \ref cds_nonintrusive_MichaelMap_rcu_find_cfunc "find(K const&, Func)"
681 but \p pred is used for key comparing.
682 \p Less functor has the interface like \p std::less.
683 \p Less must imply the same element order as the comparator used for building the map.
685 template <typename K, typename Less, typename Func>
686 bool find_with( K const& key, Less pred, Func f )
688 return bucket( key ).find_with( key, pred, f );
691 /// Checks whether the map contains \p key
693 The function searches the item with key equal to \p key
694 and returns \p true if it is found, and \p false otherwise.
696 The function applies RCU lock internally.
698 template <typename K>
699 bool contains( K const& key )
701 return bucket( key ).contains( key );
704 template <typename K>
705 CDS_DEPRECATED("deprecated, use contains()")
706 bool find( K const& key )
708 return bucket( key ).contains( key );
712 /// Checks whether the map contains \p key using \p pred predicate for searching
714 The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
715 \p Less functor has the interface like \p std::less.
716 \p Less must imply the same element order as the comparator used for building the map.
718 template <typename K, typename Less>
719 bool contains( K const& key, Less pred )
721 return bucket( key ).contains( key, pred );
724 template <typename K, typename Less>
725 CDS_DEPRECATED("deprecated, use contains()")
726 bool find_with( K const& key, Less pred )
728 return bucket( key ).contains( key, pred );
732 /// Finds \p key and return the item found
733 /** \anchor cds_nonintrusive_MichaelHashMap_rcu_get
734 The function searches the item with key equal to \p key and returns the pointer to item found.
735 If \p key is not found it returns \p nullptr.
736 Note the type of returned value depends on underlying \p bucket_type.
737 For details, see documentation of ordered list you use.
739 Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
741 RCU should be locked before call of this function.
742 Returned item is valid only while RCU is locked:
744 typedef cds::container::MichaelHashMap< your_template_parameters > hash_map;
747 typename hash_map::raw_ptr gp;
750 hash_map::rcu_lock lock;
752 gp = theMap.get( 5 );
757 // Unlock RCU by rcu_lock destructor
758 // gp can be reclaimed at any time after RCU has been unlocked
762 template <typename K>
763 raw_ptr get( K const& key )
765 return bucket( key ).get( key );
768 /// Finds \p key and return the item found
770 The function is an analog of \ref cds_nonintrusive_MichaelHashMap_rcu_get "get(K const&)"
771 but \p pred is used for comparing the keys.
773 \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
775 \p pred must imply the same element order as the comparator used for building the map.
777 template <typename K, typename Less>
778 raw_ptr get_with( K const& key, Less pred )
780 return bucket( key ).get_with( key, pred );
783 /// Clears the map (not atomic)
785 The function erases all items from the map.
787 The function is not atomic. It cleans up each bucket and then resets the item counter to zero.
788 If there are a thread that performs insertion while \p clear is working the result is undefined in general case:
789 <tt> empty() </tt> may return \p true but the map may contain item(s).
790 Therefore, \p clear may be used only for debugging purposes.
792 RCU \p synchronize method can be called. RCU should not be locked.
796 for ( size_t i = 0; i < bucket_count(); ++i )
797 m_Buckets[i].clear();
798 m_ItemCounter.reset();
801 /// Checks if the map is empty
803 Emptiness is checked by item counting: if item count is zero then the map is empty.
804 Thus, the correct item counting is an important part of the map implementation.
811 /// Returns item count in the map
814 return m_ItemCounter;
817 /// Returns the size of hash table
819 Since \p %MichaelHashMap cannot dynamically extend the hash table size,
820 the value returned is an constant depending on object initialization parameters;
821 see \p MichaelHashMap::MichaelHashMap for explanation.
823 size_t bucket_count() const
825 return m_nHashBitmask + 1;
828 }} // namespace cds::container
830 #endif // ifndef CDSLIB_CONTAINER_MICHAEL_MAP_RCU_H