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;
160 typedef typename maker::node_type node_type;
161 typedef typename maker::cxx_node_allocator cxx_node_allocator;
162 typedef std::unique_ptr< node_type, typename maker::node_disposer > scoped_node_ptr;
164 template <bool IsConst>
165 class bidirectional_iterator: public base_class::iterator_base
167 friend class FeldmanHashMap;
168 typedef typename base_class::iterator_base iterator_base;
171 static CDS_CONSTEXPR bool const c_bConstantIterator = IsConst;
174 typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
175 typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
178 bidirectional_iterator() CDS_NOEXCEPT
181 bidirectional_iterator( bidirectional_iterator const& rhs ) CDS_NOEXCEPT
182 : iterator_base( rhs )
185 bidirectional_iterator& operator=(bidirectional_iterator const& rhs) CDS_NOEXCEPT
187 iterator_base::operator=( rhs );
191 bidirectional_iterator& operator++()
193 iterator_base::operator++();
197 bidirectional_iterator& operator--()
199 iterator_base::operator--();
203 value_ptr operator ->() const CDS_NOEXCEPT
205 node_type * p = iterator_base::pointer();
206 return p ? &p->m_Value : nullptr;
209 value_ref operator *() const CDS_NOEXCEPT
211 node_type * p = iterator_base::pointer();
218 iterator_base::release();
221 template <bool IsConst2>
222 bool operator ==(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
224 return iterator_base::operator==( rhs );
227 template <bool IsConst2>
228 bool operator !=(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
230 return !( *this == rhs );
233 public: // for internal use only!
234 bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx, bool )
235 : iterator_base( set, pNode, idx, false )
238 bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
239 : iterator_base( set, pNode, idx )
243 /// Reverse bidirectional iterator
244 template <bool IsConst>
245 class reverse_bidirectional_iterator : public base_class::iterator_base
247 friend class FeldmanHashMap;
248 typedef typename base_class::iterator_base iterator_base;
251 typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
252 typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
255 reverse_bidirectional_iterator() CDS_NOEXCEPT
259 reverse_bidirectional_iterator( reverse_bidirectional_iterator const& rhs ) CDS_NOEXCEPT
260 : iterator_base( rhs )
263 reverse_bidirectional_iterator& operator=( reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
265 iterator_base::operator=( rhs );
269 reverse_bidirectional_iterator& operator++()
271 iterator_base::operator--();
275 reverse_bidirectional_iterator& operator--()
277 iterator_base::operator++();
281 value_ptr operator ->() const CDS_NOEXCEPT
283 node_type * p = iterator_base::pointer();
284 return p ? &p->m_Value : nullptr;
287 value_ref operator *() const CDS_NOEXCEPT
289 node_type * p = iterator_base::pointer();
296 iterator_base::release();
299 template <bool IsConst2>
300 bool operator ==(reverse_bidirectional_iterator<IsConst2> const& rhs) const
302 return iterator_base::operator==( rhs );
305 template <bool IsConst2>
306 bool operator !=(reverse_bidirectional_iterator<IsConst2> const& rhs)
308 return !( *this == rhs );
311 public: // for internal use only!
312 reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx, bool )
313 : iterator_base( set, pNode, idx, false )
316 reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
317 : iterator_base( set, pNode, idx, false )
319 iterator_base::backward();
326 #ifdef CDS_DOXYGEN_INVOKED
328 typedef typename gc::template guarded_ptr< value_type > guarded_ptr;
330 typedef typename gc::template guarded_ptr< node_type, value_type, cds::container::details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
333 #ifdef CDS_DOXYGEN_INVOKED
334 typedef implementation_defined iterator; ///< @ref cds_container_FeldmanHashMap_iterators "bidirectional iterator" type
335 typedef implementation_defined const_iterator; ///< @ref cds_container_FeldmanHashMap_iterators "bidirectional const iterator" type
336 typedef implementation_defined reverse_iterator; ///< @ref cds_container_FeldmanHashMap_iterators "bidirectional reverse iterator" type
337 typedef implementation_defined const_reverse_iterator; ///< @ref cds_container_FeldmanHashMap_iterators "bidirectional reverse const iterator" type
339 typedef bidirectional_iterator<false> iterator;
340 typedef bidirectional_iterator<true> const_iterator;
341 typedef reverse_bidirectional_iterator<false> reverse_iterator;
342 typedef reverse_bidirectional_iterator<true> const_reverse_iterator;
351 /// Creates empty map
353 @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
354 @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
356 Equation for \p head_bits and \p array_bits:
358 sizeof(hash_type) * 8 == head_bits + N * array_bits
360 where \p N is multi-level array depth.
362 FeldmanHashMap( size_t head_bits = 8, size_t array_bits = 4 )
363 : base_class( head_bits, array_bits )
366 /// Destructs the map and frees all data
370 /// Inserts new element with key and default value
372 The function creates an element with \p key and default value, and then inserts the node created into the map.
375 - The \p key_type should be constructible from a value of type \p K.
376 In trivial case, \p K is equal to \p key_type.
377 - The \p mapped_type should be default-constructible.
379 Returns \p true if inserting successful, \p false otherwise.
381 template <typename K>
382 bool insert( K&& key )
384 scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key) ));
385 if ( base_class::insert( *sp )) {
392 /// Inserts new element
394 The function creates a node with copy of \p val value
395 and then inserts the node created into the map.
398 - The \p key_type should be constructible from \p key of type \p K.
399 - The \p value_type should be constructible from \p val of type \p V.
401 Returns \p true if \p val is inserted into the map, \p false otherwise.
403 template <typename K, typename V>
404 bool insert( K&& key, V&& val )
406 scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<V>(val)));
407 if ( base_class::insert( *sp )) {
414 /// Inserts new element and initialize it by a functor
416 This function inserts new element with key \p key and if inserting is successful then it calls
417 \p func functor with signature
420 void operator()( value_type& item );
424 The argument \p item of user-defined functor \p func is the reference
425 to the map's item inserted:
426 - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
427 - <tt>item.second</tt> is a reference to item's value that may be changed.
429 \p key_type should be constructible from value of type \p K.
431 The function allows to split creating of new item into two part:
432 - create item from \p key;
433 - insert new item into the map;
434 - if inserting is successful, initialize the value of item by calling \p func functor
436 This can be useful if complete initialization of object of \p value_type is heavyweight and
437 it is preferable that the initialization should be completed only if inserting is successful.
439 template <typename K, typename Func>
440 bool insert_with( K&& key, Func func )
442 scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
443 if ( base_class::insert( *sp, [&func]( node_type& item ) { func( item.m_Value ); } )) {
450 /// For key \p key inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
452 Returns \p true if inserting successful, \p false otherwise.
454 template <typename K, typename... Args>
455 bool emplace( K&& key, Args&&... args )
457 scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<Args>(args)... ));
458 if ( base_class::insert( *sp )) {
465 /// Updates data by \p key
467 The operation performs inserting or replacing the element with lock-free manner.
469 If the \p key not found in the map, then the new item created from \p key
470 will be inserted into the map iff \p bInsert is \p true
471 (note that in this case the \ref key_type should be constructible from type \p K).
472 Otherwise, if \p key is found, it is replaced with a new item created from
474 The functor \p Func signature:
477 void operator()( value_type& item, value_type * old );
481 - \p item - item of the map
482 - \p old - old item of the map, if \p nullptr - the new item was inserted
484 The functor may change any fields of the \p item.second.
486 Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
487 \p second is \p true if new item has been added or \p false if \p key already exists.
489 @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
491 template <typename K, typename Func>
492 std::pair<bool, bool> update( K&& key, Func func, bool bInsert = true )
494 scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
495 std::pair<bool, bool> result = base_class::do_update( *sp,
496 [&func]( node_type& node, node_type * old ) { func( node.m_Value, old ? &old->m_Value : nullptr );},
503 /// Delete \p key from the map
505 \p key_type must be constructible from value of type \p K.
506 The function deletes the element with hash value equal to <tt>hash( key_type( key ))</tt>
508 Return \p true if \p key is found and deleted, \p false otherwise.
510 template <typename K>
511 bool erase( K const& key )
513 return base_class::erase( m_Hasher( key_type( key )));
516 /// Delete \p key from the map
518 The function searches an item with hash value equal to <tt>hash( key_type( key ))</tt>,
519 calls \p f functor and deletes the item. If \p key is not found, the functor is not called.
521 The functor \p Func interface:
524 void operator()(value_type& item) { ... }
527 where \p item is the element found.
529 \p key_type must be constructible from value of type \p K.
531 Return \p true if key is found and deleted, \p false otherwise
533 template <typename K, typename Func>
534 bool erase( K const& key, Func f )
536 return base_class::erase( m_Hasher(key_type(key)), [&f]( node_type& node) { f( node.m_Value ); } );
539 /// Deletes the element pointed by iterator \p iter
541 Returns \p true if the operation is successful, \p false otherwise.
543 The function does not invalidate the iterator, it remains valid and can be used for further traversing.
545 bool erase_at( iterator const& iter )
547 return base_class::do_erase_at( iter );
550 bool erase_at( reverse_iterator const& iter )
552 return base_class::do_erase_at( iter );
556 /// Extracts the item from the map with specified \p key
558 The function searches an item with key equal to <tt>hash( key_type( key ))</tt> in the map,
559 unlinks it from the map, and returns a guarded pointer to the item found.
560 If \p key is not found the function returns an empty guarded pointer.
562 The item extracted is freed automatically by garbage collector \p GC
563 when returned \p guarded_ptr object will be destroyed or released.
564 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
568 typedef cds::container::FeldmanHashMap< cds::gc::HP, int, foo, my_traits > map_type;
572 map_type::guarded_ptr gp( theMap.extract( 5 ));
577 // Destructor of gp releases internal HP guard and frees the pointer
581 template <typename K>
582 guarded_ptr extract( K const& key )
585 typename gc::Guard guard;
586 node_type * p = base_class::do_erase( m_Hasher( key_type( key )), guard, []( node_type const&) -> bool {return true;} );
588 // p is guarded by HP
594 /// Checks whether the map contains \p key
596 The function searches the item by its hash that is equal to <tt>hash( key_type( key ))</tt>
597 and returns \p true if it is found, or \p false otherwise.
599 template <typename K>
600 bool contains( K const& key )
602 return base_class::contains( m_Hasher( key_type( key )) );
605 /// Find the key \p key
608 The function searches the item by its hash that is equal to <tt>hash( key_type( key ))</tt>
609 and calls the functor \p f for item found.
610 The interface of \p Func functor is:
613 void operator()( value_type& item );
616 where \p item is the item found.
618 The functor may change \p item.second.
620 The function returns \p true if \p key is found, \p false otherwise.
622 template <typename K, typename Func>
623 bool find( K const& key, Func f )
625 return base_class::find( m_Hasher( key_type( key )), [&f](node_type& node) { f( node.m_Value );});
628 /// Finds the key \p key and return the item found
630 The function searches the item with a hash equal to <tt>hash( key_type( key ))</tt>
631 and returns a guarded pointer to the item found.
632 If \p key is not found the function returns an empty guarded pointer.
634 It is safe when a concurrent thread erases the item returned as \p guarded_ptr.
635 In this case the item will be freed later by garbage collector \p GC automatically
636 when \p guarded_ptr object will be destroyed or released.
637 @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
641 typedef cds::container::FeldmanHashMap< cds::gc::HP, int, foo, my_traits > map_type;
645 map_type::guarded_ptr gp( theMap.get( 5 ));
650 // Destructor of guarded_ptr releases internal HP guard
654 template <typename K>
655 guarded_ptr get( K const& key )
659 typename gc::Guard guard;
660 gp.reset( base_class::search( m_Hasher( key_type( key )), guard ));
665 /// Clears the map (non-atomic)
667 The function unlink all data node from the map.
668 The function is not atomic but is thread-safe.
669 After \p %clear() the map may not be empty because another threads may insert items.
676 /// Checks if the map is empty
678 Emptiness is checked by item counting: if item count is zero then the map is empty.
679 Thus, the correct item counting feature is an important part of the map implementation.
683 return base_class::empty();
686 /// Returns item count in the map
689 return base_class::size();
692 /// Returns const reference to internal statistics
693 stat const& statistics() const
695 return base_class::statistics();
698 /// Returns the size of head node
699 size_t head_size() const
701 return base_class::head_size();
704 /// Returns the size of the array node
705 size_t array_node_size() const
707 return base_class::array_node_size();
710 /// Collects tree level statistics into \p stat
712 The function traverses the set and collects statistics for each level of the tree
713 into \p feldman_hashset::level_statistics struct. The element of \p stat[i]
714 represents statistics for level \p i, level 0 is head array.
715 The function is thread-safe and may be called in multi-threaded environment.
717 Result can be useful for estimating efficiency of hash functor you use.
719 void get_level_statistics(std::vector< feldman_hashmap::level_statistics>& stat) const
721 base_class::get_level_statistics( stat );
725 ///@name Thread-safe iterators
726 /** @anchor cds_container_FeldmanHashMap_iterators
727 The map supports thread-safe iterators: you may iterate over the map in multi-threaded environment.
728 It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:
729 Hazard Pointer embedded into the iterator object protects the node from physical reclamation.
731 @note Since the iterator object contains hazard pointer that is a thread-local resource,
732 the iterator should not be passed to another thread.
734 Each iterator object supports the common interface:
735 - dereference operators:
737 value_type [const] * operator ->() noexcept
738 value_type [const] & operator *() noexcept
740 - pre-increment and pre-decrement. Post-operators is not supported
741 - equality operators <tt>==</tt> and <tt>!=</tt>.
742 Iterators are equal iff they point to the same cell of the same array node.
743 Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
744 does not entail <tt> &(*it1) == &(*it2) </tt>
745 - helper member function \p release() that clears internal hazard pointer.
746 After \p release() the iterator points to \p nullptr but it still remain valid: further iterating is possible.
748 During iteration you may safely erase any item from the set;
749 @ref erase_at() function call doesn't invalidate any iterator.
750 If some iterator points to the item to be erased, that item is not deleted immediately
751 but only after that iterator will be advanced forward or backward.
753 @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
754 in array node that is being splitted.
757 /// Returns an iterator to the beginning of the map
760 return base_class::template init_begin<iterator>();
763 /// Returns an const iterator to the beginning of the map
764 const_iterator begin() const
766 return base_class::template init_begin<const_iterator>();
769 /// Returns an const iterator to the beginning of the map
770 const_iterator cbegin()
772 return base_class::template init_begin<const_iterator>();
775 /// 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 return base_class::template init_end<iterator>();
781 /// 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.
782 const_iterator end() const
784 return base_class::template init_end<const_iterator>();
787 /// 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.
788 const_iterator cend()
790 return base_class::template init_end<const_iterator>();
793 /// Returns a reverse iterator to the first element of the reversed map
794 reverse_iterator rbegin()
796 return base_class::template init_rbegin<reverse_iterator>();
799 /// Returns a const reverse iterator to the first element of the reversed map
800 const_reverse_iterator rbegin() const
802 return base_class::template init_rbegin<const_reverse_iterator>();
805 /// Returns a const reverse iterator to the first element of the reversed map
806 const_reverse_iterator crbegin()
808 return base_class::template init_rbegin<const_reverse_iterator>();
811 /// Returns a reverse iterator to the element following the last element of the reversed map
813 It corresponds to the element preceding the first element of the non-reversed container.
814 This element acts as a placeholder, attempting to access it results in undefined behavior.
816 reverse_iterator rend()
818 return base_class::template init_rend<reverse_iterator>();
821 /// Returns a const reverse iterator to the element following the last element of the reversed map
823 It corresponds to the element preceding the first element of the non-reversed container.
824 This element acts as a placeholder, attempting to access it results in undefined behavior.
826 const_reverse_iterator rend() const
828 return base_class::template init_rend<const_reverse_iterator>();
831 /// Returns a const reverse iterator to the element following the last element of the reversed map
833 It corresponds to the element preceding the first element of the non-reversed container.
834 This element acts as a placeholder, attempting to access it results in undefined behavior.
836 const_reverse_iterator crend()
838 return base_class::template init_rend<const_reverse_iterator>();
843 }} // namespace cds::container
845 #endif // #ifndef CDSLIB_CONTAINER_IMPL_FELDMAN_HASHMAP_H