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_IMPL_FELDMAN_HASHMAP_H
32 #define CDSLIB_CONTAINER_IMPL_FELDMAN_HASHMAP_H
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>
38 namespace cds { namespace container {
40 /// Hash map based on multi-level array
41 /** @ingroup cds_nonintrusive_map
42 @anchor cds_container_FeldmanHashMap_hp
45 - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
46 Wait-free Extensible Hash Maps"
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.
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.
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.
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.
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.
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.
98 The map supports @ref cds_container_FeldmanHashMap_iterators "bidirectional thread-safe iterators".
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.
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.
116 #ifdef CDS_DOXYGEN_INVOKED
117 ,class Traits = feldman_hashmap::traits
123 #ifdef CDS_DOXYGEN_INVOKED
124 : protected cds::intrusive::FeldmanHashSet< GC, std::pair<Key const, T>, Traits >
126 : protected cds::container::details::make_feldman_hashmap< GC, Key, T, Traits >::type
130 typedef cds::container::details::make_feldman_hashmap< GC, Key, T, Traits > maker;
131 typedef typename maker::type base_class;
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
142 typedef typename maker::hasher hasher;
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
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
155 /// Count of hazard pointers required
156 static CDS_CONSTEXPR size_t const c_nHazardPtrCount = base_class::c_nHazardPtrCount;
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;
162 typedef feldman_hashmap::level_statistics level_statistics;
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;
170 template <bool IsConst>
171 class bidirectional_iterator: public base_class::iterator_base
173 friend class FeldmanHashMap;
174 typedef typename base_class::iterator_base iterator_base;
177 static CDS_CONSTEXPR bool const c_bConstantIterator = IsConst;
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
184 bidirectional_iterator() CDS_NOEXCEPT
187 bidirectional_iterator( bidirectional_iterator const& rhs ) CDS_NOEXCEPT
188 : iterator_base( rhs )
191 bidirectional_iterator& operator=( bidirectional_iterator const& rhs ) CDS_NOEXCEPT
193 iterator_base::operator=( rhs );
197 bidirectional_iterator& operator++()
199 iterator_base::operator++();
203 bidirectional_iterator& operator--()
205 iterator_base::operator--();
209 value_ptr operator ->() const CDS_NOEXCEPT
211 node_type * p = iterator_base::pointer();
212 return p ? &p->m_Value : nullptr;
215 value_ref operator *() const CDS_NOEXCEPT
217 node_type * p = iterator_base::pointer();
224 iterator_base::release();
227 template <bool IsConst2>
228 bool operator ==( bidirectional_iterator<IsConst2> const& rhs ) const CDS_NOEXCEPT
230 return iterator_base::operator==( rhs );
233 template <bool IsConst2>
234 bool operator !=( bidirectional_iterator<IsConst2> const& rhs ) const CDS_NOEXCEPT
236 return !( *this == rhs );
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 )
244 bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
245 : iterator_base( set, pNode, idx )
249 /// Reverse bidirectional iterator
250 template <bool IsConst>
251 class reverse_bidirectional_iterator : public base_class::iterator_base
253 friend class FeldmanHashMap;
254 typedef typename base_class::iterator_base iterator_base;
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
261 reverse_bidirectional_iterator() CDS_NOEXCEPT
265 reverse_bidirectional_iterator( reverse_bidirectional_iterator const& rhs ) CDS_NOEXCEPT
266 : iterator_base( rhs )
269 reverse_bidirectional_iterator& operator=( reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
271 iterator_base::operator=( rhs );
275 reverse_bidirectional_iterator& operator++()
277 iterator_base::operator--();
281 reverse_bidirectional_iterator& operator--()
283 iterator_base::operator++();
287 value_ptr operator ->() const CDS_NOEXCEPT
289 node_type * p = iterator_base::pointer();
290 return p ? &p->m_Value : nullptr;
293 value_ref operator *() const CDS_NOEXCEPT
295 node_type * p = iterator_base::pointer();
302 iterator_base::release();
305 template <bool IsConst2>
306 bool operator ==( reverse_bidirectional_iterator<IsConst2> const& rhs ) const
308 return iterator_base::operator==( rhs );
311 template <bool IsConst2>
312 bool operator !=( reverse_bidirectional_iterator<IsConst2> const& rhs )
314 return !( *this == rhs );
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 )
322 reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
323 : iterator_base( set, pNode, idx, false )
325 iterator_base::backward();
332 #ifdef CDS_DOXYGEN_INVOKED
334 typedef typename gc::template guarded_ptr< value_type > guarded_ptr;
336 typedef typename gc::template guarded_ptr< node_type, value_type, cds::container::details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
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
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;
357 /// Creates empty map
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.
362 Equation for \p head_bits and \p array_bits:
364 c_hash_size * 8 == head_bits + N * array_bits
366 where \p N is multi-level array depth.
368 FeldmanHashMap( size_t head_bits = 8, size_t array_bits = 4 )
369 : base_class( head_bits, array_bits )
372 /// Destructs the map and frees all data
376 /// Inserts new element with key and default value
378 The function creates an element with \p key and default value, and then inserts the node created into the map.
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.
385 Returns \p true if inserting successful, \p false otherwise.
387 template <typename K>
388 bool insert( K&& key )
390 scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>( key )));
391 if ( base_class::insert( *sp )) {
398 /// Inserts new element
400 The function creates a node with copy of \p val value
401 and then inserts the node created into the map.
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.
407 Returns \p true if \p val is inserted into the map, \p false otherwise.
409 template <typename K, typename V>
410 bool insert( K&& key, V&& val )
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 )) {
420 /// Inserts new element and initialize it by a functor
422 This function inserts new element with key \p key and if inserting is successful then it calls
423 \p func functor with signature
426 void operator()( value_type& item );
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.
435 \p key_type should be constructible from value of type \p K.
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
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.
445 template <typename K, typename Func>
446 bool insert_with( K&& key, Func func )
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 ); } )) {
456 /// For key \p key inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
458 Returns \p true if inserting successful, \p false otherwise.
460 template <typename K, typename... Args>
461 bool emplace( K&& key, Args&&... args )
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 )) {
471 /// Updates data by \p key
473 The operation performs inserting or replacing the element with lock-free manner.
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
480 The functor \p Func signature:
483 void operator()( value_type& item, value_type * old );
487 - \p item - item of the map
488 - \p old - old item of the map, if \p nullptr - the new item was inserted
490 The functor may change any fields of the \p item.second.
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.
495 @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
497 template <typename K, typename Func>
498 std::pair<bool, bool> update( K&& key, Func func, bool bInsert = true )
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 );},
509 /// Delete \p key from the map
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>
514 Return \p true if \p key is found and deleted, \p false otherwise.
516 template <typename K>
517 bool erase( K const& key )
519 return base_class::erase( m_Hasher( key_type( key )));
522 /// Delete \p key from the map
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.
527 The functor \p Func interface:
530 void operator()( value_type& item ) { ... }
533 where \p item is the element found.
535 \p key_type must be constructible from value of type \p K.
537 Return \p true if key is found and deleted, \p false otherwise
539 template <typename K, typename Func>
540 bool erase( K const& key, Func f )
542 return base_class::erase( m_Hasher( key_type( key )), [&f]( node_type& node) { f( node.m_Value ); } );
545 /// Deletes the element pointed by iterator \p iter
547 Returns \p true if the operation is successful, \p false otherwise.
549 The function does not invalidate the iterator, it remains valid and can be used for further traversing.
551 bool erase_at( iterator const& iter )
553 return base_class::do_erase_at( iter );
556 bool erase_at( reverse_iterator const& iter )
558 return base_class::do_erase_at( iter );
560 bool erase_at( const_iterator const& iter )
562 return base_class::do_erase_at( iter );
564 bool erase_at( const_reverse_iterator const& iter )
566 return base_class::do_erase_at( iter );
570 /// Extracts the item from the map with specified \p key
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.
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.
582 typedef cds::container::FeldmanHashMap< cds::gc::HP, int, foo, my_traits > map_type;
586 map_type::guarded_ptr gp( theMap.extract( 5 ));
591 // Destructor of gp releases internal HP guard and frees the pointer
595 template <typename K>
596 guarded_ptr extract( K const& key )
598 return base_class::extract( m_Hasher( key_type( key )));
601 /// Checks whether the map contains \p key
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.
606 template <typename K>
607 bool contains( K const& key )
609 return base_class::contains( m_Hasher( key_type( key )));
612 /// Find the key \p key
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:
620 void operator()( value_type& item );
623 where \p item is the item found.
625 The functor may change \p item.second.
627 The function returns \p true if \p key is found, \p false otherwise.
629 template <typename K, typename Func>
630 bool find( K const& key, Func f )
632 return base_class::find( m_Hasher( key_type( key )), [&f]( node_type& node ) { f( node.m_Value );});
635 /// Finds the key \p key and return the item found
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.
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.
648 typedef cds::container::FeldmanHashMap< cds::gc::HP, int, foo, my_traits > map_type;
652 map_type::guarded_ptr gp( theMap.get( 5 ));
657 // Destructor of guarded_ptr releases internal HP guard
661 template <typename K>
662 guarded_ptr get( K const& key )
664 return base_class::get( m_Hasher( key_type( key )));
667 /// Clears the map (non-atomic)
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.
678 /// Checks if the map is empty
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.
685 return base_class::empty();
688 /// Returns item count in the map
691 return base_class::size();
694 /// Returns const reference to internal statistics
695 stat const& statistics() const
697 return base_class::statistics();
700 /// Returns the size of head node
701 size_t head_size() const
703 return base_class::head_size();
706 /// Returns the size of the array node
707 size_t array_node_size() const
709 return base_class::array_node_size();
712 /// Collects tree level statistics into \p stat
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.
719 Result can be useful for estimating efficiency of hash functor you use.
721 void get_level_statistics( std::vector< feldman_hashmap::level_statistics>& stat) const
723 base_class::get_level_statistics( stat );
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.
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.
736 Each iterator object supports the common interface:
737 - dereference operators:
739 value_type [const] * operator ->() noexcept
740 value_type [const] & operator *() noexcept
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.
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.
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.
759 /// Returns an iterator to the beginning of the map
762 return base_class::template init_begin<iterator>();
765 /// Returns an const iterator to the beginning of the map
766 const_iterator begin() const
768 return base_class::template init_begin<const_iterator>();
771 /// Returns an const iterator to the beginning of the map
772 const_iterator cbegin()
774 return base_class::template init_begin<const_iterator>();
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.
780 return base_class::template init_end<iterator>();
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
786 return base_class::template init_end<const_iterator>();
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()
792 return base_class::template init_end<const_iterator>();
795 /// Returns a reverse iterator to the first element of the reversed map
796 reverse_iterator rbegin()
798 return base_class::template init_rbegin<reverse_iterator>();
801 /// Returns a const reverse iterator to the first element of the reversed map
802 const_reverse_iterator rbegin() const
804 return base_class::template init_rbegin<const_reverse_iterator>();
807 /// Returns a const reverse iterator to the first element of the reversed map
808 const_reverse_iterator crbegin()
810 return base_class::template init_rbegin<const_reverse_iterator>();
813 /// Returns a reverse iterator to the element following the last element of the reversed map
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.
818 reverse_iterator rend()
820 return base_class::template init_rend<reverse_iterator>();
823 /// Returns a const reverse iterator to the element following the last element of the reversed map
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.
828 const_reverse_iterator rend() const
830 return base_class::template init_rend<const_reverse_iterator>();
833 /// Returns a const reverse iterator to the element following the last element of the reversed map
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.
838 const_reverse_iterator crend()
840 return base_class::template init_rend<const_reverse_iterator>();
845 }} // namespace cds::container
847 #endif // #ifndef CDSLIB_CONTAINER_IMPL_FELDMAN_HASHMAP_H