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_H
32 #define CDSLIB_CONTAINER_MICHAEL_MAP_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
40 /** @ingroup cds_nonintrusive_map
41 \anchor cds_nonintrusive_MichaelHashMap_hp
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 GC - Garbage collector used. You may use any \ref cds_garbage_collector "Garbage collector"
53 from the \p libcds library.
54 Note the \p GC must be the same as the GC used for \p OrderedList
55 - \p OrderedList - ordered key-value list implementation used as bucket for hash map, for example, \p MichaelKVList
56 or \p LazyKVList. The ordered list implementation specifies the \p Key and \p Value types stored in the hash-map,
57 the reclamation schema \p GC used by hash-map, the comparison functor for the type \p Key and other features
58 specific for the ordered list.
59 - \p Traits - map traits, default is \p michael_map::traits.
60 Instead of defining \p Traits struct you may use option-based syntax with \p michael_map::make_traits metafunction.
62 Many of the class function take a key argument of type \p K that in general is not \p key_type.
63 \p key_type and an argument of template type \p K must meet the following requirements:
64 - \p key_type should be constructible from value of type \p K;
65 - the hash functor should be able to calculate correct hash value from argument \p key of type \p K:
66 <tt> hash( key_type(key) ) == hash( key ) </tt>
67 - values of type \p key_type and \p K should be comparable
69 There are the specializations:
70 - for \ref cds_urcu_desc "RCU" - declared in <tt>cds/container/michael_map_rcu.h</tt>,
71 see \ref cds_nonintrusive_MichaelHashMap_rcu "MichaelHashMap<RCU>".
72 - for \p cds::gc::nogc declared in <tt>cds/container/michael_map_nogc.h</tt>,
73 see \ref cds_nonintrusive_MichaelHashMap_nogc "MichaelHashMap<gc::nogc>".
77 The class supports a forward iterator (\ref iterator and \ref const_iterator).
78 The iteration is unordered.
79 The iterator object is thread-safe: the element pointed by the iterator object is guarded,
80 so, the element cannot be reclaimed while the iterator object is alive.
81 However, passing an iterator object between threads is dangerous.
83 @warning Due to concurrent nature of Michael's set it is not guarantee that you can iterate
84 all elements in the set: any concurrent deletion can exclude the element
85 pointed by the iterator from the set, and your iteration can be terminated
86 before end of the set. Therefore, such iteration is more suitable for debugging purpose only
88 Remember, each iterator object requires an additional hazard pointer, that may be
89 a limited resource for \p GC like \p gc::HP (for \p gc::DHP the count of
92 The iterator class supports the following minimalistic interface:
99 iterator( iterator const& s);
101 value_type * operator ->() const;
102 value_type& operator *() const;
105 iterator& operator ++();
108 iterator& operator = (const iterator& src);
110 bool operator ==(iterator const& i ) const;
111 bool operator !=(iterator const& i ) const;
114 Note, the iterator object returned by \ref end, \p cend member functions points to \p nullptr and should not be dereferenced.
116 \anchor cds_nonintrusive_MichaelHashMap_how_touse
119 Suppose, you want to make \p int to \p int map for Hazard Pointer garbage collector. You should
120 choose suitable ordered list class that will be used as a bucket for the map; it may be \p MichaelKVList.
122 #include <cds/container/michael_kvlist_hp.h> // MichaelKVList for gc::HP
123 #include <cds/container/michael_map.h> // MichaelHashMap
125 // List traits based on std::less predicate
126 struct list_traits: public cds::container::michael_list::traits
128 typedef std::less<int> less;
132 typedef cds::container::MichaelKVList< cds::gc::HP, int, int, list_traits> int2int_list;
135 struct map_traits: public cds::container::michael_map::traits
138 size_t operator()( int i ) const
140 return cds::opt::v::hash<int>()( i );
146 typedef cds::container::MichaelHashMap< cds::gc::HP, int2int_list, map_traits > int2int_map;
148 // Now you can use int2int_map class
154 theMap.insert( 100 );
159 You may use option-based declaration:
161 #include <cds/container/michael_kvlist_hp.h> // MichaelKVList for gc::HP
162 #include <cds/container/michael_map.h> // MichaelHashMap
165 typedef cds::container::MichaelKVList< cds::gc::HP, int, int,
166 typename cds::container::michael_list::make_traits<
167 cds::container::opt::less< std::less<int> > // item comparator option
172 typedef cds::container::MichaelHashMap< cds::gc::HP, int2int_list,
173 cds::container::michael_map::make_traits<
174 cc::opt::hash< cds::opt::v::hash<int> >
182 #ifdef CDS_DOXYGEN_INVOKED
183 class Traits = michael_map::traits
191 typedef GC gc; ///< Garbage collector
192 typedef OrderedList bucket_type; ///< type of ordered list to be used as a bucket
193 typedef Traits traits; ///< Map traits
195 typedef typename bucket_type::key_type key_type; ///< key type
196 typedef typename bucket_type::mapped_type mapped_type; ///< value type
197 typedef typename bucket_type::value_type value_type; ///< key/value pair stored in the map
199 typedef typename bucket_type::key_comparator key_comparator; ///< key compare functor
201 /// Hash functor for \ref key_type and all its derivatives that you use
202 typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
203 typedef typename traits::item_counter item_counter; ///< Item counter type
205 /// Bucket table allocator
206 typedef cds::details::Allocator< bucket_type, typename traits::allocator > bucket_table_allocator;
207 typedef typename bucket_type::guarded_ptr guarded_ptr; ///< Guarded pointer
210 item_counter m_ItemCounter; ///< Item counter
211 hash m_HashFunctor; ///< Hash functor
212 bucket_type * m_Buckets; ///< bucket table
216 const size_t m_nHashBitmask;
221 /// Calculates hash value of \p key
222 template <typename Q>
223 size_t hash_value( Q const& key ) const
225 return m_HashFunctor( key ) & m_nHashBitmask;
228 /// Returns the bucket (ordered list) for \p key
229 template <typename Q>
230 bucket_type& bucket( Q const& key )
232 return m_Buckets[ hash_value( key ) ];
239 template <bool IsConst>
240 class iterator_type: private cds::intrusive::michael_set::details::iterator< bucket_type, IsConst >
242 typedef cds::intrusive::michael_set::details::iterator< bucket_type, IsConst > base_class;
243 friend class MichaelHashMap;
246 typedef typename base_class::bucket_ptr bucket_ptr;
247 typedef typename base_class::list_iterator list_iterator;
250 /// Value pointer type (const for const_iterator)
251 typedef typename cds::details::make_const_type<typename MichaelHashMap::mapped_type, IsConst>::pointer value_ptr;
252 /// Value reference type (const for const_iterator)
253 typedef typename cds::details::make_const_type<typename MichaelHashMap::mapped_type, IsConst>::reference value_ref;
255 /// Key-value pair pointer type (const for const_iterator)
256 typedef typename cds::details::make_const_type<typename MichaelHashMap::value_type, IsConst>::pointer pair_ptr;
257 /// Key-value pair reference type (const for const_iterator)
258 typedef typename cds::details::make_const_type<typename MichaelHashMap::value_type, IsConst>::reference pair_ref;
261 iterator_type( list_iterator const& it, bucket_ptr pFirst, bucket_ptr pLast )
262 : base_class( it, pFirst, pLast )
272 iterator_type( const iterator_type& src )
276 /// Dereference operator
277 pair_ptr operator ->() const
279 assert( base_class::m_pCurBucket != nullptr );
280 return base_class::m_itList.operator ->();
283 /// Dereference operator
284 pair_ref operator *() const
286 assert( base_class::m_pCurBucket != nullptr );
287 return base_class::m_itList.operator *();
291 iterator_type& operator ++()
293 base_class::operator++();
297 /// Assignment operator
298 iterator_type& operator = (const iterator_type& src)
300 base_class::operator =(src);
304 /// Returns current bucket (debug function)
305 bucket_ptr bucket() const
307 return base_class::bucket();
310 /// Equality operator
312 bool operator ==(iterator_type<C> const& i )
314 return base_class::operator ==( i );
316 /// Equality operator
318 bool operator !=(iterator_type<C> const& i )
320 return !( *this == i );
327 typedef iterator_type< false > iterator;
329 /// Const forward iterator
330 typedef iterator_type< true > const_iterator;
332 /// Returns a forward iterator addressing the first element in a map
334 For empty map \code begin() == end() \endcode
338 return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count() );
341 /// Returns an iterator that addresses the location succeeding the last element in a map
343 Do not use the value returned by <tt>end</tt> function to access any item.
344 The returned value can be used only to control reaching the end of the map.
345 For empty map \code begin() == end() \endcode
349 return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
352 /// Returns a forward const iterator addressing the first element in a map
354 const_iterator begin() const
356 return get_const_begin();
358 const_iterator cbegin() const
360 return get_const_begin();
364 /// Returns an const iterator that addresses the location succeeding the last element in a map
366 const_iterator end() const
368 return get_const_end();
370 const_iterator cend() const
372 return get_const_end();
378 const_iterator get_const_begin() const
380 return const_iterator( const_cast<bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
382 const_iterator get_const_end() const
384 return const_iterator( const_cast<bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
389 /// Initializes the map
390 /** @anchor cds_nonintrusive_MichaelHashMap_hp_ctor
391 The Michael's hash map is non-expandable container. You should point the average count of items \p nMaxItemCount
392 when you create an object.
393 \p nLoadFactor parameter defines average count of items per bucket and it should be small number between 1 and 10.
394 Remember, since the bucket implementation is an ordered list, searching in the bucket is linear [<tt>O(nLoadFactor)</tt>].
395 Note, that many popular STL hash map implementation uses load factor 1.
397 The ctor defines hash table size as rounding <tt>nMacItemCount / nLoadFactor</tt> up to nearest power of two.
400 size_t nMaxItemCount, ///< estimation of max item count in the hash map
401 size_t nLoadFactor ///< load factor: estimation of max number of items in the bucket
402 ) : m_nHashBitmask( michael_map::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
404 // GC and OrderedList::gc must be the same
405 static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
407 // atomicity::empty_item_counter is not allowed as a item counter
408 static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
409 "atomicity::empty_item_counter is not allowed as a item counter");
411 m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
414 /// Clears hash map and destroys it
418 bucket_table_allocator().Delete( m_Buckets, bucket_count() );
421 /// Inserts new node with key and default value
423 The function creates a node with \p key and default value, and then inserts the node created into the map.
426 - The \p key_type should be constructible from value of type \p K.
427 In trivial case, \p K is equal to \p key_type.
428 - The \p mapped_type should be default-constructible.
430 Returns \p true if inserting successful, \p false otherwise.
432 template <typename K>
433 bool insert( const K& key )
435 const bool bRet = bucket( key ).insert( key );
443 The function creates a node with copy of \p val value
444 and then inserts the node created into the map.
447 - The \p key_type should be constructible from \p key of type \p K.
448 - The \p mapped_type should be constructible from \p val of type \p V.
450 Returns \p true if \p val is inserted into the map, \p false otherwise.
452 template <typename K, typename V>
453 bool insert( K const& key, V const& val )
455 const bool bRet = bucket( key ).insert( key, val );
461 /// Inserts new node and initialize it by a functor
463 This function inserts new node with key \p key and if inserting is successful then it calls
464 \p func functor with signature
467 void operator()( value_type& item );
471 The argument \p item of user-defined functor \p func is the reference
472 to the map's item inserted:
473 - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
474 - <tt>item.second</tt> is a reference to item's value that may be changed.
476 The user-defined functor is called only if inserting is successful.
478 The \p key_type should be constructible from value of type \p K.
480 The function allows to split creating of new item into two part:
481 - create item from \p key;
482 - insert new item into the map;
483 - if inserting is successful, initialize the value of item by calling \p func functor
485 This can be useful if complete initialization of object of \p mapped_type is heavyweight and
486 it is preferable that the initialization should be completed only if inserting is successful.
488 @warning For \ref cds_nonintrusive_MichaelKVList_gc "MichaelKVList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
489 \ref cds_nonintrusive_LazyKVList_gc "LazyKVList" provides exclusive access to inserted item and does not require any node-level
492 template <typename K, typename Func>
493 bool insert_with( const K& key, Func func )
495 const bool bRet = bucket( key ).insert_with( key, func );
501 /// Updates data by \p key
503 The operation performs inserting or replacing the element with lock-free manner.
505 If the \p key not found in the map, then the new item created from \p key
506 will be inserted into the map iff \p bAllowInsert is \p true.
507 (note that in this case the \ref key_type should be constructible from type \p K).
508 Otherwise, if \p key is found, the functor \p func is called with item found.
510 The functor \p Func signature is:
513 void operator()( bool bNew, value_type& item );
517 - \p bNew - \p true if the item has been inserted, \p false otherwise
518 - \p item - the item found or inserted
520 The functor may change any fields of the \p item.second that is \p mapped_type.
522 Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
523 \p second is true if new item has been added or \p false if the item with \p key
526 @warning For \ref cds_nonintrusive_MichaelKVList_gc "MichaelKVList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
527 \ref cds_nonintrusive_LazyKVList_gc "LazyKVList" provides exclusive access to inserted item and does not require any node-level
530 template <typename K, typename Func >
531 std::pair<bool, bool> update( K const& key, Func func, bool bAllowInsert = true )
533 std::pair<bool, bool> bRet = bucket( key ).update( key, func, bAllowInsert );
534 if ( bRet.first && bRet.second )
539 template <typename K, typename Func>
540 CDS_DEPRECATED("ensure() is deprecated, use update()")
541 std::pair<bool, bool> ensure( K const& key, Func func )
543 std::pair<bool, bool> bRet = bucket( key ).update( key, func, true );
544 if ( bRet.first && bRet.second )
550 /// For key \p key inserts data of type \p mapped_type created from \p args
552 \p key_type should be constructible from type \p K
554 Returns \p true if inserting successful, \p false otherwise.
556 template <typename K, typename... Args>
557 bool emplace( K&& key, Args&&... args )
559 const bool bRet = bucket( key ).emplace( std::forward<K>(key), std::forward<Args>(args)... );
565 /// Deletes \p key from the map
566 /** \anchor cds_nonintrusive_MichaelMap_erase_val
568 Return \p true if \p key is found and deleted, \p false otherwise
570 template <typename K>
571 bool erase( K const& key )
573 const bool bRet = bucket( key ).erase( key );
579 /// Deletes the item from the map using \p pred predicate for searching
581 The function is an analog of \ref cds_nonintrusive_MichaelMap_erase_val "erase(K const&)"
582 but \p pred is used for key comparing.
583 \p Less functor has the interface like \p std::less.
584 \p Less must imply the same element order as the comparator used for building the map.
586 template <typename K, typename Less>
587 bool erase_with( K const& key, Less pred )
589 const bool bRet = bucket( key ).erase_with( key, pred );
595 /// Deletes \p key from the map
596 /** \anchor cds_nonintrusive_MichaelMap_erase_func
598 The function searches an item with key \p key, calls \p f functor
599 and deletes the item. If \p key is not found, the functor is not called.
601 The functor \p Func interface:
604 void operator()(value_type& item) { ... }
608 Return \p true if key is found and deleted, \p false otherwise
610 template <typename K, typename Func>
611 bool erase( K const& key, Func f )
613 const bool bRet = bucket( key ).erase( key, f );
619 /// Deletes the item from the map using \p pred predicate for searching
621 The function is an analog of \ref cds_nonintrusive_MichaelMap_erase_func "erase(K const&, Func)"
622 but \p pred is used for key comparing.
623 \p Less functor has the interface like \p std::less.
624 \p Less must imply the same element order as the comparator used for building the map.
626 template <typename K, typename Less, typename Func>
627 bool erase_with( K const& key, Less pred, Func f )
629 const bool bRet = bucket( key ).erase_with( key, pred, f );
635 /// Extracts the item with specified \p key
636 /** \anchor cds_nonintrusive_MichaelHashMap_hp_extract
637 The function searches an item with key equal to \p key,
638 unlinks it from the set, and returns it as \p guarded_ptr.
639 If \p key is not found the function returns an empty guarded pointer.
641 Note the compare functor should accept a parameter of type \p K that may be not the same as \p key_type.
643 The extracted item is freed automatically when returned \p guarded_ptr object will be destroyed or released.
644 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
648 typedef cds::container::MichaelHashMap< your_template_args > michael_map;
652 michael_map::guarded_ptr gp( theMap.extract( 5 ));
657 // Destructor of gp releases internal HP guard
661 template <typename K>
662 guarded_ptr extract( K const& key )
664 guarded_ptr gp( bucket( key ).extract( key ));
670 /// Extracts the item using compare functor \p pred
672 The function is an analog of \ref cds_nonintrusive_MichaelHashMap_hp_extract "extract(K const&)"
673 but \p pred predicate is used for key comparing.
675 \p Less functor has the semantics like \p std::less but should take arguments of type \p key_type and \p K
677 \p pred must imply the same element order as the comparator used for building the map.
679 template <typename K, typename Less>
680 guarded_ptr extract_with( K const& key, Less pred )
682 guarded_ptr gp( bucket( key ).extract_with( key, pred ));
688 /// Finds the key \p key
689 /** \anchor cds_nonintrusive_MichaelMap_find_cfunc
691 The function searches the item with key equal to \p key and calls the functor \p f for item found.
692 The interface of \p Func functor is:
695 void operator()( value_type& item );
698 where \p item is the item found.
700 The functor may change \p item.second. Note that the functor is only guarantee
701 that \p item cannot be disposed during functor is executing.
702 The functor does not serialize simultaneous access to the map's \p item. If such access is
703 possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
705 The function returns \p true if \p key is found, \p false otherwise.
707 template <typename K, typename Func>
708 bool find( K const& key, Func f )
710 return bucket( key ).find( key, f );
713 /// Finds the key \p val using \p pred predicate for searching
715 The function is an analog of \ref cds_nonintrusive_MichaelMap_find_cfunc "find(K const&, Func)"
716 but \p pred is used for key comparing.
717 \p Less functor has the interface like \p std::less.
718 \p Less must imply the same element order as the comparator used for building the map.
720 template <typename K, typename Less, typename Func>
721 bool find_with( K const& key, Less pred, Func f )
723 return bucket( key ).find_with( key, pred, f );
726 /// Checks whether the map contains \p key
728 The function searches the item with key equal to \p key
729 and returns \p true if it is found, and \p false otherwise.
731 template <typename K>
732 bool contains( K const& key )
734 return bucket( key ).contains( key );
737 template <typename K>
738 CDS_DEPRECATED("deprecated, use contains()")
739 bool find( K const& key )
741 return bucket( key ).contains( key );
745 /// Checks whether the map contains \p key using \p pred predicate for searching
747 The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
748 \p Less functor has the interface like \p std::less.
749 \p Less must imply the same element order as the comparator used for building the map.
751 template <typename K, typename Less>
752 bool contains( K const& key, Less pred )
754 return bucket( key ).contains( key, pred );
757 template <typename K, typename Less>
758 CDS_DEPRECATED("deprecated, use contains()")
759 bool find_with( K const& key, Less pred )
761 return bucket( key ).contains( key, pred );
765 /// Finds \p key and return the item found
766 /** \anchor cds_nonintrusive_MichaelHashMap_hp_get
767 The function searches the item with key equal to \p key
768 and returns the guarded pointer to the item found.
769 If \p key is not found the function returns an empty guarded pointer,
771 @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
775 typedef cds::container::MichaeHashMap< your_template_params > michael_map;
779 michael_map::guarded_ptr gp( theMap.get( 5 ));
784 // Destructor of guarded_ptr releases internal HP guard
788 Note the compare functor specified for \p OrderedList template parameter
789 should accept a parameter of type \p K that can be not the same as \p key_type.
791 template <typename K>
792 guarded_ptr get( K const& key )
794 return bucket( key ).get( key );
797 /// Finds \p key and return the item found
799 The function is an analog of \ref cds_nonintrusive_MichaelHashMap_hp_get "get( K const&)"
800 but \p pred is used for comparing the keys.
802 \p Less functor has the semantics like \p std::less but should take arguments of type \p key_type and \p K
804 \p pred must imply the same element order as the comparator used for building the map.
806 template <typename K, typename Less>
807 guarded_ptr get_with( K const& key, Less pred )
809 return bucket( key ).get_with( key, pred );
812 /// Clears the map (not atomic)
815 for ( size_t i = 0; i < bucket_count(); ++i )
816 m_Buckets[i].clear();
817 m_ItemCounter.reset();
820 /// Checks if the map is empty
822 Emptiness is checked by item counting: if item count is zero then the map is empty.
823 Thus, the correct item counting is an important part of the map implementation.
830 /// Returns item count in the map
833 return m_ItemCounter;
836 /// Returns the size of hash table
838 Since \p %MichaelHashMap cannot dynamically extend the hash table size,
839 the value returned is an constant depending on object initialization parameters;
840 see \p MichaelHashMap::MichaelHashMap for explanation.
842 size_t bucket_count() const
844 return m_nHashBitmask + 1;
847 }} // namespace cds::container
849 #endif // ifndef CDSLIB_CONTAINER_MICHAEL_MAP_H