Added intrusive::MultiLevelHashSet<RCU> implementation
[libcds.git] / cds / container / impl / multilevel_hashmap.h
1 //$$CDS-header$$
2
3 #ifndef CDSLIB_CONTAINER_IMPL_MULTILEVEL_HASHMAP_H
4 #define CDSLIB_CONTAINER_IMPL_MULTILEVEL_HASHMAP_H
5
6 #include <cds/intrusive/impl/multilevel_hashset.h>
7 #include <cds/container/details/multilevel_hashmap_base.h>
8 #include <cds/container/details/guarded_ptr_cast.h>
9
10 namespace cds { namespace container {
11
12     /// Hash map based on multi-level array
13     /** @ingroup cds_nonintrusive_map
14         @anchor cds_container_MultilevelHashMap_hp
15
16         Source:
17         - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
18                  Wait-free Extensible Hash Maps"
19
20         [From the paper] The hardest problem encountered while developing a parallel hash map is how to perform
21         a global resize, the process of redistributing the elements in a hash map that occurs when adding new
22         buckets. The negative impact of blocking synchronization is multiplied during a global resize, because all
23         threads will be forced to wait on the thread that is performing the involved process of resizing the hash map
24         and redistributing the elements. \p %MultilevelHashSet implementation avoids global resizes through new array
25         allocation. By allowing concurrent expansion this structure is free from the overhead of an explicit resize,
26         which facilitates concurrent operations.
27
28         The presented design includes dynamic hashing, the use of sub-arrays within the hash map data structure;
29         which, in combination with <b>perfect hashing</b>, means that each element has a unique final, as well as current, position.
30         It is important to note that the perfect hash function required by our hash map is trivial to realize as
31         any hash function that permutes the bits of the key is suitable. This is possible because of our approach
32         to the hash function; we require that it produces hash values that are equal in size to that of the key.
33         We know that if we expand the hash map a fixed number of times there can be no collision as duplicate keys
34         are not provided for in the standard semantics of a hash map.
35
36         \p %MultiLevelHashMap is a multi-level array which has an internal structure similar to a tree:
37         @image html multilevel_hashset.png
38         The multi-level array differs from a tree in that each position on the tree could hold an array of nodes or a single node.
39         A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated
40         with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.
41         A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)
42         of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;
43         any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds
44         an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark
45         on the second-least significant bit.
46
47         \p %MultiLevelHashMap multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array
48         called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;
49         a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.
50         The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.
51         We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which
52         we need to operate; this is initially one, because of \p head.
53
54         That approach to the structure of the hash map uses an extensible hashing scheme; <b> the hash value is treated as a bit
55         string</b> and rehash incrementally.
56
57         @note Two important things you should keep in mind when you're using \p %MultiLevelHashMap:
58         - all keys is converted to fixed-size bit-string by hash functor provided.
59           You can use variable-length keys, for example, \p std::string as a key for \p %MultiLevelHashMap,
60           but real key in the map will be fixed-ize hash values of your keys.
61           For the strings you may use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
62           <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
63           or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
64           converts variable-length strings to fixed-length bit-strings, and such hash values will be the keys in \p %MultiLevelHashMap.
65         - \p %MultiLevelHashMap uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
66           have identical hash then you cannot insert both that keys in the map. \p %MultiLevelHashMap does not maintain the key,
67           it maintains its fixed-size hash value.
68
69         The map supports @ref cds_container_MultilevelHashMap_iterators "bidirectional thread-safe iterators".
70
71         Template parameters:
72         - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"
73         - \p Key - a key type to be stored in the map
74         - \p T - a value type to be stored in the map
75         - \p Traits - type traits, the structure based on \p multilevel_hashmap::traits or result of \p multilevel_hashmap::make_traits metafunction.
76
77         There are several specializations of \p %MultiLevelHashMap for each \p GC. You should include:
78         - <tt><cds/container/multilevel_hashmap_hp.h></tt> for \p gc::HP garbage collector
79         - <tt><cds/container/multilevel_hashmap_dhp.h></tt> for \p gc::DHP garbage collector
80         - <tt><cds/container/multilevel_hashmap_rcu.h></tt> for \ref cds_intrusive_MultiLevelHashMap_rcu "RCU type". RCU specialization
81             has a slightly different interface.
82     */
83     template <
84         class GC
85         ,typename Key
86         ,typename T
87 #ifdef CDS_DOXYGEN_INVOKED
88         ,class Traits = multilevel_hashmap::traits
89 #else
90         ,class Traits
91 #endif
92     >
93     class MultiLevelHashMap
94 #ifdef CDS_DOXYGEN_INVOKED
95         : protected cds::intrusive::MultiLevelHashSet< GC, std::pair<Key const, T>, Traits >
96 #else
97         : protected cds::container::details::make_multilevel_hashmap< GC, Key, T, Traits >::type
98 #endif
99     {
100         //@cond
101         typedef cds::container::details::make_multilevel_hashmap< GC, Key, T, Traits > maker;
102         typedef typename maker::type base_class;
103         //@endcond
104     public:
105         typedef GC      gc;          ///< Garbage collector
106         typedef Key     key_type;    ///< Key type
107         typedef T       mapped_type; ///< Mapped type
108         typedef std::pair< key_type const, mapped_type> value_type;   ///< Key-value pair to be stored in the map
109         typedef Traits  traits;      ///< Map traits
110 #ifdef CDS_DOXYGEN_INVOKED
111         typedef typename traits::hash hasher; ///< Hash functor, see \p multilevel_hashmap::traits::hash
112 #else
113         typedef typename maker::hasher hasher;
114 #endif
115
116         typedef typename maker::hash_type hash_type; ///< Hash type deduced from \p hasher return type
117         typedef typename base_class::hash_comparator hash_comparator; ///< hash compare functor based on \p Traits::compare and \p Traits::less
118
119         typedef typename traits::item_counter   item_counter;   ///< Item counter type
120         typedef typename traits::allocator      allocator;      ///< Element allocator
121         typedef typename traits::node_allocator node_allocator; ///< Array node allocator
122         typedef typename traits::memory_model   memory_model;   ///< Memory model
123         typedef typename traits::back_off       back_off;       ///< Backoff strategy
124         typedef typename traits::stat           stat;           ///< Internal statistics type
125
126         /// Count of hazard pointers required
127         static CDS_CONSTEXPR size_t const c_nHazardPtrCount = base_class::c_nHazardPtrCount;
128
129     protected:
130         //@cond
131         typedef typename maker::node_type node_type;
132         typedef typename maker::cxx_node_allocator cxx_node_allocator;
133         typedef std::unique_ptr< node_type, typename maker::node_disposer > scoped_node_ptr;
134
135         template <bool IsConst>
136         class bidirectional_iterator: public base_class::iterator_base
137         {
138             friend class MultiLevelHashMap;
139             typedef typename base_class::iterator_base iterator_base;
140
141         protected:
142             static CDS_CONSTEXPR bool const c_bConstantIterator = IsConst;
143
144         public:
145             typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
146             typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
147
148         public:
149             bidirectional_iterator() CDS_NOEXCEPT
150             {}
151
152             bidirectional_iterator( bidirectional_iterator const& rhs ) CDS_NOEXCEPT
153                 : iterator_base( rhs )
154             {}
155
156             bidirectional_iterator& operator=(bidirectional_iterator const& rhs) CDS_NOEXCEPT
157             {
158                 iterator_base::operator=( rhs );
159                 return *this;
160             }
161
162             bidirectional_iterator& operator++()
163             {
164                 iterator_base::operator++();
165                 return *this;
166             }
167
168             bidirectional_iterator& operator--()
169             {
170                 iterator_base::operator--();
171                 return *this;
172             }
173
174             value_ptr operator ->() const CDS_NOEXCEPT
175             {
176                 node_type * p = iterator_base::pointer();
177                 return p ? &p->m_Value : nullptr;
178             }
179
180             value_ref operator *() const CDS_NOEXCEPT
181             {
182                 node_type * p = iterator_base::pointer();
183                 assert( p );
184                 return p->m_Value;
185             }
186
187             void release()
188             {
189                 iterator_base::release();
190             }
191
192             template <bool IsConst2>
193             bool operator ==(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
194             {
195                 return iterator_base::operator==( rhs );
196             }
197
198             template <bool IsConst2>
199             bool operator !=(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
200             {
201                 return !( *this == rhs );
202             }
203
204         public: // for internal use only!
205             bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx, bool )
206                 : iterator_base( set, pNode, idx, false )
207             {}
208
209             bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
210                 : iterator_base( set, pNode, idx )
211             {}
212         };
213
214         /// Reverse bidirectional iterator
215         template <bool IsConst>
216         class reverse_bidirectional_iterator : public base_class::iterator_base
217         {
218             friend class MultiLevelHashMap;
219             typedef typename base_class::iterator_base iterator_base;
220
221         public:
222             typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
223             typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
224
225         public:
226             reverse_bidirectional_iterator() CDS_NOEXCEPT
227                 : iterator_base()
228             {}
229
230             reverse_bidirectional_iterator( reverse_bidirectional_iterator const& rhs ) CDS_NOEXCEPT
231                 : iterator_base( rhs )
232             {}
233
234             reverse_bidirectional_iterator& operator=( reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
235             {
236                 iterator_base::operator=( rhs );
237                 return *this;
238             }
239
240             reverse_bidirectional_iterator& operator++()
241             {
242                 iterator_base::operator--();
243                 return *this;
244             }
245
246             reverse_bidirectional_iterator& operator--()
247             {
248                 iterator_base::operator++();
249                 return *this;
250             }
251
252             value_ptr operator ->() const CDS_NOEXCEPT
253             {
254                 node_type * p = iterator_base::pointer();
255                 return p ? &p->m_Value : nullptr;
256             }
257
258             value_ref operator *() const CDS_NOEXCEPT
259             {
260                 node_type * p = iterator_base::pointer();
261                 assert( p );
262                 return p->m_Value;
263             }
264
265             void release()
266             {
267                 iterator_base::release();
268             }
269
270             template <bool IsConst2>
271             bool operator ==(reverse_bidirectional_iterator<IsConst2> const& rhs) const
272             {
273                 return iterator_base::operator==( rhs );
274             }
275
276             template <bool IsConst2>
277             bool operator !=(reverse_bidirectional_iterator<IsConst2> const& rhs)
278             {
279                 return !( *this == rhs );
280             }
281
282         public: // for internal use only!
283             reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx, bool )
284                 : iterator_base( set, pNode, idx, false )
285             {}
286
287             reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
288                 : iterator_base( set, pNode, idx, false )
289             {
290                 iterator_base::backward();
291             }
292         };
293
294         //@endcond
295
296     public:
297 #ifdef CDS_DOXYGEN_INVOKED
298         /// Guarded pointer
299         typedef typename gc::template guarded_ptr< value_type > guarded_ptr;
300 #else
301         typedef typename gc::template guarded_ptr< node_type, value_type, cds::container::details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
302 #endif
303
304 #ifdef CDS_DOXYGEN_INVOKED
305         typedef implementation_defined iterator;            ///< @ref cds_container_MultilevelHashMap_iterators "bidirectional iterator" type
306         typedef implementation_defined const_iterator;      ///< @ref cds_container_MultilevelHashMap_iterators "bidirectional const iterator" type
307         typedef implementation_defined reverse_iterator;    ///< @ref cds_container_MultilevelHashMap_iterators "bidirectional reverse iterator" type
308         typedef implementation_defined const_reverse_iterator; ///< @ref cds_container_MultilevelHashMap_iterators "bidirectional reverse const iterator" type
309 #else
310         typedef bidirectional_iterator<false> iterator;
311         typedef bidirectional_iterator<true>  const_iterator;
312         typedef reverse_bidirectional_iterator<false> reverse_iterator;
313         typedef reverse_bidirectional_iterator<true>  const_reverse_iterator;
314 #endif
315
316     protected:
317         //@cond
318         hasher  m_Hasher;
319         //@endcond
320
321     public:
322         /// Creates empty map
323         /**
324             @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
325             @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
326
327             Equation for \p head_bits and \p array_bits:
328             \code
329             sizeof(hash_type) * 8 == head_bits + N * array_bits
330             \endcode
331             where \p N is multi-level array depth.
332         */
333         MultiLevelHashMap( size_t head_bits = 8, size_t array_bits = 4 )
334             : base_class( head_bits, array_bits )
335         {}
336
337         /// Destructs the map and frees all data
338         ~MultiLevelHashMap()
339         {}
340
341         /// Inserts new element with key and default value
342         /**
343             The function creates an element with \p key and default value, and then inserts the node created into the map.
344
345             Preconditions:
346             - The \p key_type should be constructible from a value of type \p K.
347                 In trivial case, \p K is equal to \p key_type.
348             - The \p mapped_type should be default-constructible.
349
350             Returns \p true if inserting successful, \p false otherwise.
351         */
352         template <typename K>
353         bool insert( K&& key )
354         {
355             scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key) ));
356             if ( base_class::insert( *sp )) {
357                 sp.release();
358                 return true;
359             }
360             return false;
361         }
362
363         /// Inserts new element
364         /**
365             The function creates a node with copy of \p val value
366             and then inserts the node created into the map.
367
368             Preconditions:
369             - The \p key_type should be constructible from \p key of type \p K.
370             - The \p value_type should be constructible from \p val of type \p V.
371
372             Returns \p true if \p val is inserted into the map, \p false otherwise.
373         */
374         template <typename K, typename V>
375         bool insert( K&& key, V&& val )
376         {
377             scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<V>(val)));
378             if ( base_class::insert( *sp )) {
379                 sp.release();
380                 return true;
381             }
382             return false;
383         }
384
385         /// Inserts new element and initialize it by a functor
386         /**
387             This function inserts new element with key \p key and if inserting is successful then it calls
388             \p func functor with signature
389             \code
390                 struct functor {
391                     void operator()( value_type& item );
392                 };
393             \endcode
394
395             The argument \p item of user-defined functor \p func is the reference
396             to the map's item inserted:
397                 - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
398                 - <tt>item.second</tt> is a reference to item's value that may be changed.
399
400             \p key_type should be constructible from value of type \p K.
401
402             The function allows to split creating of new item into two part:
403             - create item from \p key;
404             - insert new item into the map;
405             - if inserting is successful, initialize the value of item by calling \p func functor
406
407             This can be useful if complete initialization of object of \p value_type is heavyweight and
408             it is preferable that the initialization should be completed only if inserting is successful.
409         */
410         template <typename K, typename Func>
411         bool insert_with( K&& key, Func func )
412         {
413             scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
414             if ( base_class::insert( *sp, [&func]( node_type& item ) { func( item.m_Value ); } )) {
415                 sp.release();
416                 return true;
417             }
418             return false;
419         }
420
421         /// For key \p key inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
422         /**
423             Returns \p true if inserting successful, \p false otherwise.
424         */
425         template <typename K, typename... Args>
426         bool emplace( K&& key, Args&&... args )
427         {
428             scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<Args>(args)... ));
429             if ( base_class::insert( *sp )) {
430                 sp.release();
431                 return true;
432             }
433             return false;
434         }
435
436         /// Updates data by \p key
437         /**
438             The operation performs inserting or replacing the element with lock-free manner.
439
440             If the \p key not found in the map, then the new item created from \p key
441             will be inserted into the map iff \p bInsert is \p true
442             (note that in this case the \ref key_type should be constructible from type \p K).
443             Otherwise, if \p key is found, it is replaced with a new item created from
444             \p key.
445             The functor \p Func signature:
446             \code
447                 struct my_functor {
448                     void operator()( value_type& item, value_type * old );
449                 };
450             \endcode
451             where:
452             - \p item - item of the map
453             - \p old - old item of the map, if \p nullptr - the new item was inserted
454
455             The functor may change any fields of the \p item.second.
456
457             Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
458             \p second is \p true if new item has been added or \p false if \p key already exists.
459
460             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
461         */
462         template <typename K, typename Func>
463         std::pair<bool, bool> update( K&& key, Func func, bool bInsert = true )
464         {
465             scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
466             std::pair<bool, bool> result = base_class::do_update( *sp,
467                 [&func]( node_type& node, node_type * old ) { func( node.m_Value, old ? &old->m_Value : nullptr );},
468                 bInsert );
469             if ( result.first )
470                 sp.release();
471             return result;
472         }
473
474         /// Delete \p key from the map
475         /**
476             \p key_type must be constructible from value of type \p K.
477             The function deeltes the element with hash value equal to <tt>hash( key_type( key ))</tt>
478
479             Return \p true if \p key is found and deleted, \p false otherwise.
480         */
481         template <typename K>
482         bool erase( K const& key )
483         {
484             hash_type h = m_Hasher( key_type( key ));
485             return base_class::erase( h );
486         }
487
488         /// Delete \p key from the map
489         /**
490             The function searches an item with hash value equal to <tt>hash( key_type( key ))</tt>,
491             calls \p f functor and deletes the item. If \p key is not found, the functor is not called.
492
493             The functor \p Func interface:
494             \code
495             struct extractor {
496                 void operator()(value_type& item) { ... }
497             };
498             \endcode
499             where \p item is the element found.
500
501             \p key_type must be constructible from value of type \p K.
502
503             Return \p true if key is found and deleted, \p false otherwise
504         */
505         template <typename K, typename Func>
506         bool erase( K const& key, Func f )
507         {
508             hash_type h = m_Hasher( key_type( key ));
509             return base_class::erase( h, [&f]( node_type& node) { f( node.m_Value ); } );
510         }
511
512         /// Deletes the element pointed by iterator \p iter
513         /**
514             Returns \p true if the operation is successful, \p false otherwise.
515
516             The function does not invalidate the iterator, it remains valid and can be used for further traversing.
517         */
518         bool erase_at( iterator const& iter )
519         {
520             return base_class::do_erase_at( iter );
521         }
522         //@cond
523         bool erase_at( reverse_iterator const& iter )
524         {
525             return base_class::do_erase_at( iter );
526         }
527         //@endcond
528
529         /// Extracts the item from the map with specified \p key
530         /**
531             The function searches an item with key equal to <tt>hash( key_type( key ))</tt> in the map,
532             unlinks it from the map, and returns a guarded pointer to the item found.
533             If \p key is not found the function returns an empty guarded pointer.
534
535             The item extracted is freed automatically by garbage collector \p GC
536             when returned \p guarded_ptr object will be destroyed or released.
537             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
538
539             Usage:
540             \code
541             typedef cds::container::MultiLevelHashMap< cds::gc::HP, int, foo, my_traits > map_type;
542             map_type theMap;
543             // ...
544             {
545                 map_type::guarded_ptr gp( theMap.extract( 5 ));
546                 if ( gp ) {
547                     // Deal with gp
548                     // ...
549                 }
550                 // Destructor of gp releases internal HP guard and frees the pointer
551             }
552             \endcode
553         */
554         template <typename K>
555         guarded_ptr extract( K const& key )
556         {
557             guarded_ptr gp;
558             typename gc::Guard guard;
559             node_type * p = base_class::do_erase( m_Hasher( key_type( key )), guard, []( node_type const&) -> bool {return true;} );
560
561             // p is guarded by HP
562             if ( p )
563                 gp.reset( p );
564             return gp;
565         }
566
567         /// Checks whether the map contains \p key
568         /**
569             The function searches the item by its hash that is equal to <tt>hash( key_type( key ))</tt>
570             and returns \p true if it is found, or \p false otherwise.
571         */
572         template <typename K>
573         bool contains( K const& key )
574         {
575             return base_class::contains( m_Hasher( key_type( key )) );
576         }
577
578         /// Find the key \p key
579         /**
580
581             The function searches the item by its hash that is equal to <tt>hash( key_type( key ))</tt>
582             and calls the functor \p f for item found.
583             The interface of \p Func functor is:
584             \code
585             struct functor {
586                 void operator()( value_type& item );
587             };
588             \endcode
589             where \p item is the item found.
590
591             The functor may change \p item.second.
592
593             The function returns \p true if \p key is found, \p false otherwise.
594         */
595         template <typename K, typename Func>
596         bool find( K const& key, Func f )
597         {
598             return base_class::find( m_Hasher( key_type( key )), [&f](node_type& node) { f( node.m_Value );});
599         }
600
601         /// Finds the key \p key and return the item found
602         /**
603             The function searches the item with a hash equal to <tt>hash( key_type( key ))</tt>
604             and returns a guarded pointer to the item found.
605             If \p key is not found the function returns an empty guarded pointer.
606
607             It is safe when a concurrent thread erases the item returned as \p guarded_ptr.
608             In this case the item will be freed later by garbage collector \p GC automatically
609             when \p guarded_ptr object will be destroyed or released.
610             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
611
612             Usage:
613             \code
614             typedef cds::container::MultiLevelHashMap< cds::gc::HP, int, foo, my_traits >  map_type;
615             map_type theMap;
616             // ...
617             {
618                 map_type::guarded_ptr gp( theMap.get( 5 ));
619                 if ( gp ) {
620                     // Deal with gp
621                     //...
622                 }
623                 // Destructor of guarded_ptr releases internal HP guard
624             }
625             \endcode
626         */
627         template <typename K>
628         guarded_ptr get( K const& key )
629         {
630             guarded_ptr gp;
631             {
632                 typename gc::Guard guard;
633                 gp.reset( base_class::search( m_Hasher( key_type( key )), guard ));
634             }
635             return gp;
636         }
637
638         /// Clears the map (non-atomic)
639         /**
640             The function unlink all data node from the map.
641             The function is not atomic but is thread-safe.
642             After \p %clear() the map may not be empty because another threads may insert items.
643         */
644         void clear()
645         {
646             base_class::clear();
647         }
648
649         /// Checks if the map is empty
650         /**
651             Emptiness is checked by item counting: if item count is zero then the map is empty.
652             Thus, the correct item counting feature is an important part of the map implementation.
653         */
654         bool empty() const
655         {
656             return base_class::empty();
657         }
658
659         /// Returns item count in the map
660         size_t size() const
661         {
662             return base_class::size();
663         }
664
665         /// Returns const reference to internal statistics
666         stat const& statistics() const
667         {
668             return base_class::statistics();
669         }
670
671         /// Returns the size of head node
672         size_t head_size() const
673         {
674             return base_class::head_size();
675         }
676
677         /// Returns the size of the array node
678         size_t array_node_size() const
679         {
680             return base_class::array_node_size();
681         }
682
683     public:
684     ///@name Thread-safe iterators
685         /** @anchor cds_container_MultilevelHashMap_iterators
686             The map supports thread-safe iterators: you may iterate over the map in multi-threaded environment.
687             It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:
688             Hazard Pointer embedded into the iterator object protects the node from physical reclamation.
689
690             @note Since the iterator object contains hazard pointer that is a thread-local resource,
691             the iterator should not be passed to another thread.
692
693             Each iterator object supports the common interface:
694             - dereference operators:
695                 @code
696                 value_type [const] * operator ->() noexcept
697                 value_type [const] & operator *() noexcept
698                 @endcode
699             - pre-increment and pre-decrement. Post-operators is not supported
700             - equality operators <tt>==</tt> and <tt>!=</tt>.
701                 Iterators are equal iff they point to the same cell of the same array node.
702                 Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
703                 does not entail <tt> &(*it1) == &(*it2) </tt>
704             - helper member function \p release() that clears internal hazard pointer.
705                 After \p release() the iterator points to \p nullptr but it still remain valid: further iterating is possible.
706
707             During iteration you may safely erase any item from the set;
708             @ref erase_at() function call doesn't invalidate any iterator.
709             If some iterator points to the item to be erased, that item is not deleted immediately
710             but only after that iterator will be advanced forward or backward.
711
712             @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
713             in array node that is being splitted.
714         */
715     ///@{
716         /// Returns an iterator to the beginning of the map
717         iterator begin()
718         {
719             return base_class::template init_begin<iterator>();
720         }
721
722         /// Returns an const iterator to the beginning of the map
723         const_iterator begin() const
724         {
725             return base_class::template init_begin<const_iterator>();
726         }
727
728         /// Returns an const iterator to the beginning of the map
729         const_iterator cbegin()
730         {
731             return base_class::template init_begin<const_iterator>();
732         }
733
734         /// Returns an iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
735         iterator end()
736         {
737             return base_class::template init_end<iterator>();
738         }
739
740         /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
741         const_iterator end() const
742         {
743             return base_class::template init_end<const_iterator>();
744         }
745
746         /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
747         const_iterator cend()
748         {
749             return base_class::template init_end<const_iterator>();
750         }
751
752         /// Returns a reverse iterator to the first element of the reversed map
753         reverse_iterator rbegin()
754         {
755             return base_class::template init_rbegin<reverse_iterator>();
756         }
757
758         /// Returns a const reverse iterator to the first element of the reversed map
759         const_reverse_iterator rbegin() const
760         {
761             return base_class::template init_rbegin<const_reverse_iterator>();
762         }
763
764         /// Returns a const reverse iterator to the first element of the reversed map
765         const_reverse_iterator crbegin()
766         {
767             return base_class::template init_rbegin<const_reverse_iterator>();
768         }
769
770         /// Returns a reverse iterator to the element following the last element of the reversed map
771         /**
772             It corresponds to the element preceding the first element of the non-reversed container.
773             This element acts as a placeholder, attempting to access it results in undefined behavior.
774         */
775         reverse_iterator rend()
776         {
777             return base_class::template init_rend<reverse_iterator>();
778         }
779
780         /// Returns a const reverse iterator to the element following the last element of the reversed map
781         /**
782             It corresponds to the element preceding the first element of the non-reversed container.
783             This element acts as a placeholder, attempting to access it results in undefined behavior.
784         */
785         const_reverse_iterator rend() const
786         {
787             return base_class::template init_rend<const_reverse_iterator>();
788         }
789
790         /// Returns a const reverse iterator to the element following the last element of the reversed map
791         /**
792             It corresponds to the element preceding the first element of the non-reversed container.
793             This element acts as a placeholder, attempting to access it results in undefined behavior.
794         */
795         const_reverse_iterator crend()
796         {
797             return base_class::template init_rend<const_reverse_iterator>();
798         }
799     ///@}
800     };
801
802 }} // namespace cds::container
803
804 #endif // #ifndef CDSLIB_CONTAINER_IMPL_MULTILEVEL_HASHMAP_H