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