3 #ifndef __CDS_CONTAINER_MICHAEL_SET_NOGC_H
4 #define __CDS_CONTAINER_MICHAEL_SET_NOGC_H
6 #include <cds/container/details/michael_set_base.h>
7 #include <cds/gc/nogc.h>
8 #include <cds/details/allocator.h>
10 namespace cds { namespace container {
12 /// Michael's hash set (template specialization for gc::nogc)
13 /** @ingroup cds_nonintrusive_set
14 \anchor cds_nonintrusive_MichaelHashSet_nogc
16 This specialization is intended for so-called persistent usage when no item
17 reclamation may be performed. The class does not support deleting of list item.
19 See \ref cds_nonintrusive_MichaelHashSet_hp "MichaelHashSet" for description of template parameters.
20 The template parameter \p OrderedList should be any gc::nogc-derived ordered list, for example,
21 \ref cds_nonintrusive_MichaelList_nogc "persistent MichaelList".
23 The interface of the specialization is a slightly different.
27 #ifdef CDS_DOXYGEN_INVOKED
28 class Traits = michael_set::type_traits
33 class MichaelHashSet< gc::nogc, OrderedList, Traits >
36 typedef OrderedList bucket_type ; ///< type of ordered list used as a bucket implementation
37 typedef Traits options ; ///< Traits template parameters
39 typedef typename bucket_type::value_type value_type ; ///< type of value stored in the list
40 typedef gc::nogc gc ; ///< Garbage collector
41 typedef typename bucket_type::key_comparator key_comparator ; ///< key comparison functor
43 /// Hash functor for \ref value_type and all its derivatives that you use
44 typedef typename cds::opt::v::hash_selector< typename options::hash >::type hash;
45 typedef typename options::item_counter item_counter ; ///< Item counter type
47 /// Bucket table allocator
48 typedef cds::details::Allocator< bucket_type, typename options::allocator > bucket_table_allocator;
52 typedef typename bucket_type::iterator bucket_iterator;
53 typedef typename bucket_type::const_iterator bucket_const_iterator;
57 item_counter m_ItemCounter ; ///< Item counter
58 hash m_HashFunctor ; ///< Hash functor
60 bucket_type * m_Buckets ; ///< bucket table
64 const size_t m_nHashBitmask;
68 /// Calculates hash value of \p key
70 size_t hash_value( const Q& key ) const
72 return m_HashFunctor( key ) & m_nHashBitmask;
75 /// Returns the bucket (ordered list) for \p key
77 bucket_type& bucket( const Q& key )
79 return m_Buckets[ hash_value( key ) ];
85 The forward iterator for Michael's set is based on \p OrderedList forward iterator and has some features:
86 - it has no post-increment operator
87 - it iterates items in unordered fashion
89 typedef michael_set::details::iterator< bucket_type, false > iterator;
91 /// Const forward iterator
93 For iterator's features and requirements see \ref iterator
95 typedef michael_set::details::iterator< bucket_type, true > const_iterator;
97 /// Returns a forward iterator addressing the first element in a set
99 For empty set \code begin() == end() \endcode
103 return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count() );
106 /// Returns an iterator that addresses the location succeeding the last element in a set
108 Do not use the value returned by <tt>end</tt> function to access any item.
109 The returned value can be used only to control reaching the end of the set.
110 For empty set \code begin() == end() \endcode
114 return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
117 /// Returns a forward const iterator addressing the first element in a set
119 const_iterator begin() const
121 return get_const_begin();
123 const_iterator cbegin()
125 return get_const_begin();
129 /// Returns an const iterator that addresses the location succeeding the last element in a set
131 const_iterator end() const
133 return get_const_end();
135 const_iterator cend()
137 return get_const_end();
143 const_iterator get_const_begin() const
145 return const_iterator( const_cast<bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
147 const_iterator get_const_end() const
149 return const_iterator( const_cast<bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
154 /// Initialize hash set
156 See \ref cds_nonintrusive_MichaelHashSet_hp "MichaelHashSet" ctor for explanation
159 size_t nMaxItemCount, ///< estimation of max item count in the hash set
160 size_t nLoadFactor ///< load factor: estimation of max number of items in the bucket
161 ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
163 // GC and OrderedList::gc must be the same
164 static_assert(( std::is_same<gc, typename bucket_type::gc>::value ), "GC and OrderedList::gc must be the same");
166 // atomicity::empty_item_counter is not allowed as a item counter
167 static_assert(( !std::is_same<item_counter, atomicity::empty_item_counter>::value ), "atomicity::empty_item_counter is not allowed as a item counter");
169 m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
172 /// Clear hash set and destroy it
176 bucket_table_allocator().Delete( m_Buckets, bucket_count() );
181 The function inserts \p val in the set if it does not contain
182 an item with key equal to \p val.
184 Return an iterator pointing to inserted item if success, otherwise \ref end()
186 template <typename Q>
187 iterator insert( const Q& val )
189 bucket_type& refBucket = bucket( val );
190 bucket_iterator it = refBucket.insert( val );
192 if ( it != refBucket.end() ) {
194 return iterator( it, &refBucket, m_Buckets + bucket_count() );
200 /// Inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
202 Return an iterator pointing to inserted item if success \ref end() otherwise
204 template <typename... Args>
205 iterator emplace( Args&&... args )
207 bucket_type& refBucket = bucket( value_type(std::forward<Args>(args)...));
208 bucket_iterator it = refBucket.emplace( std::forward<Args>(args)... );
210 if ( it != refBucket.end() ) {
212 return iterator( it, &refBucket, m_Buckets + bucket_count() );
218 /// Ensures that the item \p val exists in the set
220 The operation inserts new item if the key \p val is not found in the set.
221 Otherwise, the function returns an iterator that points to item found.
223 Returns <tt> std::pair<iterator, bool> </tt> where \p first is an iterator pointing to
224 item found or inserted, \p second is true if new item has been added or \p false if the item
225 already is in the set.
227 template <typename Q>
228 std::pair<iterator, bool> ensure( const Q& val )
230 bucket_type& refBucket = bucket( val );
231 std::pair<bucket_iterator, bool> ret = refBucket.ensure( val );
233 if ( ret.first != refBucket.end() ) {
236 return std::make_pair( iterator( ret.first, &refBucket, m_Buckets + bucket_count() ), ret.second );
239 return std::make_pair( end(), ret.second );
242 /// Find the key \p key
243 /** \anchor cds_nonintrusive_MichealSet_nogc_find
244 The function searches the item with key equal to \p key
245 and returns an iterator pointed to item found if the key is found,
246 and \ref end() otherwise
248 template <typename Q>
249 iterator find( Q const& key )
251 bucket_type& refBucket = bucket( key );
252 bucket_iterator it = refBucket.find( key );
253 if ( it != refBucket.end() )
254 return iterator( it, &refBucket, m_Buckets + bucket_count() );
259 /// Finds the key \p val using \p pred predicate for searching
261 The function is an analog of \ref cds_nonintrusive_MichealSet_nogc_find "find(Q const&)"
262 but \p pred is used for key comparing.
263 \p Less functor has the interface like \p std::less.
264 \p Less must imply the same element order as the comparator used for building the set.
266 template <typename Q, typename Less>
267 iterator find_with( Q const& key, Less pred )
269 bucket_type& refBucket = bucket( key );
270 bucket_iterator it = refBucket.find_with( key, pred );
271 if ( it != refBucket.end() )
272 return iterator( it, &refBucket, m_Buckets + bucket_count() );
278 /// Clears the set (non-atomic, not thread-safe)
280 The function deletes all items from the set.
281 The function is not atomic and even not thread-safe.
282 It cleans up each bucket and then resets the item counter to zero.
283 If there are a thread that performs insertion while \p clear is working the result is undefined in general case:
284 <tt> empty() </tt> may return \p true but the set may contain item(s).
288 for ( size_t i = 0; i < bucket_count(); ++i )
289 m_Buckets[i].clear();
290 m_ItemCounter.reset();
294 /// Checks if the set is empty
296 Emptiness is checked by item counting: if item count is zero then the set is empty.
297 Thus, the correct item counting feature is an important part of Michael's set implementation.
304 /// Returns item count in the set
307 return m_ItemCounter;
310 /// Returns the size of hash table
312 Since MichaelHashSet cannot dynamically extend the hash table size,
313 the value returned is an constant depending on object initialization parameters;
314 see MichaelHashSet::MichaelHashSet for explanation.
316 size_t bucket_count() const
318 return m_nHashBitmask + 1;
324 #endif // ifndef __CDS_CONTAINER_MICHAEL_SET_NOGC_H