Removed unused implementation_tag typedef
[libcds.git] / cds / container / michael_set_nogc.h
1 //$$CDS-header$$
2
3 #ifndef CDSLIB_CONTAINER_MICHAEL_SET_NOGC_H
4 #define CDSLIB_CONTAINER_MICHAEL_SET_NOGC_H
5
6 #include <cds/container/details/michael_set_base.h>
7 #include <cds/gc/nogc.h>
8 #include <cds/details/allocator.h>
9
10 namespace cds { namespace container {
11
12     /// Michael's hash set (template specialization for gc::nogc)
13     /** @ingroup cds_nonintrusive_set
14         \anchor cds_nonintrusive_MichaelHashSet_nogc
15
16         This specialization is so-called append-only when no item
17         reclamation may be performed. The class does not support deleting of list item.
18
19         See \ref cds_nonintrusive_MichaelHashSet_hp "MichaelHashSet" for description of template parameters.
20         The template parameter \p OrderedList should be any \p gc::nogc -derived ordered list, for example,
21         \ref cds_nonintrusive_MichaelList_nogc "append-only MichaelList".
22     */
23     template <
24         class OrderedList,
25 #ifdef CDS_DOXYGEN_INVOKED
26         class Traits = michael_set::traits
27 #else
28         class Traits
29 #endif
30     >
31     class MichaelHashSet< cds::gc::nogc, OrderedList, Traits >
32     {
33     public:
34         typedef cds::gc::nogc gc;        ///< Garbage collector
35         typedef OrderedList bucket_type; ///< type of ordered list to be used as a bucket implementation
36         typedef Traits      traits;      ///< Set traits
37
38         typedef typename bucket_type::value_type        value_type;     ///< type of value stored in the list
39         typedef typename bucket_type::key_comparator    key_comparator; ///< key comparison functor
40
41         /// Hash functor for \ref value_type and all its derivatives that you use
42         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
43         typedef typename traits::item_counter  item_counter; ///< Item counter type
44
45         /// Bucket table allocator
46         typedef cds::details::Allocator< bucket_type, typename traits::allocator >  bucket_table_allocator;
47
48     protected:
49         //@cond
50         typedef typename bucket_type::iterator        bucket_iterator;
51         typedef typename bucket_type::const_iterator  bucket_const_iterator;
52         //@endcond
53
54     protected:
55         item_counter    m_ItemCounter;   ///< Item counter
56         hash            m_HashFunctor;   ///< Hash functor
57         bucket_type *   m_Buckets;       ///< bucket table
58
59     private:
60         //@cond
61         const size_t    m_nHashBitmask;
62         //@endcond
63
64     protected:
65         //@cond
66         /// Calculates hash value of \p key
67         template <typename Q>
68         size_t hash_value( const Q& key ) const
69         {
70             return m_HashFunctor( key ) & m_nHashBitmask;
71         }
72
73         /// Returns the bucket (ordered list) for \p key
74         template <typename Q>
75         bucket_type&    bucket( const Q& key )
76         {
77             return m_Buckets[ hash_value( key ) ];
78         }
79         //@endcond
80
81     public:
82         /// Forward iterator
83         /**
84             The forward iterator for Michael's set is based on \p OrderedList forward iterator and has some features:
85             - it has no post-increment operator
86             - it iterates items in unordered fashion
87         */
88         typedef michael_set::details::iterator< bucket_type, false >    iterator;
89
90         /// Const forward iterator
91         /**
92             For iterator's features and requirements see \ref iterator
93         */
94         typedef michael_set::details::iterator< bucket_type, true >     const_iterator;
95
96         /// Returns a forward iterator addressing the first element in a set
97         /**
98             For empty set \code begin() == end() \endcode
99         */
100         iterator begin()
101         {
102             return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count() );
103         }
104
105         /// Returns an iterator that addresses the location succeeding the last element in a set
106         /**
107             Do not use the value returned by <tt>end</tt> function to access any item.
108             The returned value can be used only to control reaching the end of the set.
109             For empty set \code begin() == end() \endcode
110         */
111         iterator end()
112         {
113             return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
114         }
115
116         /// Returns a forward const iterator addressing the first element in a set
117         //@{
118         const_iterator begin() const
119         {
120             return get_const_begin();
121         }
122         const_iterator cbegin() const
123         {
124             return get_const_begin();
125         }
126         //@}
127
128         /// Returns an const iterator that addresses the location succeeding the last element in a set
129         //@{
130         const_iterator end() const
131         {
132             return get_const_end();
133         }
134         const_iterator cend() const
135         {
136             return get_const_end();
137         }
138         //@}
139
140     private:
141         //@cond
142         const_iterator get_const_begin() const
143         {
144             return const_iterator( const_cast<bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
145         }
146         const_iterator get_const_end() const
147         {
148             return const_iterator( const_cast<bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
149         }
150         //@endcond
151
152     public:
153         /// Initialize hash set
154         /**
155             The Michael's hash set is non-expandable container. You should point the average count of items \p nMaxItemCount
156             when you create an object.
157             \p nLoadFactor parameter defines average count of items per bucket and it should be small number between 1 and 10.
158             Remember, since the bucket implementation is an ordered list, searching in the bucket is linear [<tt>O(nLoadFactor)</tt>].
159
160             The ctor defines hash table size as rounding <tt>nMaxItemCount / nLoadFactor</tt> up to nearest power of two.
161         */
162         MichaelHashSet(
163             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
164             size_t nLoadFactor      ///< load factor: estimation of max number of items in the bucket
165         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
166         {
167             // GC and OrderedList::gc must be the same
168             static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
169
170             // atomicity::empty_item_counter is not allowed as a item counter
171             static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
172                            "cds::atomicity::empty_item_counter is not allowed as a item counter");
173
174             m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
175         }
176
177         /// Clears hash set and destroys it
178         ~MichaelHashSet()
179         {
180             clear();
181             bucket_table_allocator().Delete( m_Buckets, bucket_count() );
182         }
183
184         /// Inserts new node
185         /**
186             The function inserts \p val in the set if it does not contain
187             an item with key equal to \p val.
188
189             Return an iterator pointing to inserted item if success, otherwise \ref end()
190         */
191         template <typename Q>
192         iterator insert( const Q& val )
193         {
194             bucket_type& refBucket = bucket( val );
195             bucket_iterator it = refBucket.insert( val );
196
197             if ( it != refBucket.end() ) {
198                 ++m_ItemCounter;
199                 return iterator( it, &refBucket, m_Buckets + bucket_count() );
200             }
201
202             return end();
203         }
204
205         /// Inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
206         /**
207             Return an iterator pointing to inserted item if success \ref end() otherwise
208         */
209         template <typename... Args>
210         iterator emplace( Args&&... args )
211         {
212             bucket_type& refBucket = bucket( value_type(std::forward<Args>(args)...));
213             bucket_iterator it = refBucket.emplace( std::forward<Args>(args)... );
214
215             if ( it != refBucket.end() ) {
216                 ++m_ItemCounter;
217                 return iterator( it, &refBucket, m_Buckets + bucket_count() );
218             }
219
220             return end();
221         }
222
223         /// Updates the element
224         /**
225             The operation performs inserting or changing data with lock-free manner.
226
227             If the item \p val not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
228
229             Returns <tt> std::pair<iterator, bool> </tt> where \p first is an iterator pointing to
230             item found or inserted, or \p end() if \p bAllowInsert is \p false, 
231             \p second is true if new item has been added or \p false if the item is already in the set.
232
233             @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
234             \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
235             synchronization.
236         */
237         template <typename Q>
238         std::pair<iterator, bool> update( Q const& val, bool bAllowInsert = true )
239         {
240             bucket_type& refBucket = bucket( val );
241             std::pair<bucket_iterator, bool> ret = refBucket.update( val, bAllowInsert );
242
243             if ( ret.first != refBucket.end() ) {
244                 if ( ret.second )
245                     ++m_ItemCounter;
246                 return std::make_pair( iterator( ret.first, &refBucket, m_Buckets + bucket_count() ), ret.second );
247             }
248             return std::make_pair( end(), ret.second );
249         }
250         //@cond
251         template <typename Q>
252         CDS_DEPRECATED("ensure() is deprecated, use update()")
253         std::pair<iterator, bool> ensure( Q const& val )
254         {
255             return update( val, true );
256         }
257         //@endcond
258
259         /// Checks whether the set contains \p key
260         /**
261             The function searches the item with key equal to \p key
262             and returns an iterator pointed to item found if the key is found,
263             or \ref end() otherwise.
264
265             Note the hash functor specified for class \p Traits template parameter
266             should accept a parameter of type \p Q that can be not the same as \p value_type.
267         */
268         template <typename Q>
269         iterator contains( Q const& key )
270         {
271             bucket_type& refBucket = bucket( key );
272             bucket_iterator it = refBucket.contains( key );
273             if ( it != refBucket.end() )
274                 return iterator( it, &refBucket, m_Buckets + bucket_count() );
275
276             return end();
277         }
278         //@cond
279         template <typename Q>
280         CDS_DEPRECATED("use contains()")
281         iterator find( Q const& key )
282         {
283             return contains( key );
284         }
285         //@endcond
286
287         /// Checks whether the set contains \p key using \p pred predicate for searching
288         /**
289             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
290             \p Less functor has the interface like \p std::less.
291             \p Less must imply the same element order as the comparator used for building the set.
292         */
293         template <typename Q, typename Less>
294         iterator contains( Q const& key, Less pred )
295         {
296             bucket_type& refBucket = bucket( key );
297             bucket_iterator it = refBucket.contains( key, pred );
298             if ( it != refBucket.end() )
299                 return iterator( it, &refBucket, m_Buckets + bucket_count() );
300
301             return end();
302         }
303         //@cond
304         template <typename Q, typename Less>
305         CDS_DEPRECATED("use contains()")
306         iterator find_with( Q const& key, Less pred )
307         {
308             return contains( key, pred );
309         }
310         //@endcond
311
312         /// Clears the set (not atomic)
313         void clear()
314         {
315             for ( size_t i = 0; i < bucket_count(); ++i )
316                 m_Buckets[i].clear();
317             m_ItemCounter.reset();
318         }
319
320         /// Checks if the set is empty
321         /**
322             The emptiness is checked by the item counting: if item count is zero then the set is empty.
323             Thus, the correct item counting feature is an important part of Michael's set implementation.
324         */
325         bool empty() const
326         {
327             return size() == 0;
328         }
329
330         /// Returns item count in the set
331         size_t size() const
332         {
333             return m_ItemCounter;
334         }
335
336         /// Returns the size of hash table
337         /**
338             Since \p %MichaelHashSet cannot dynamically extend the hash table size,
339             the value returned is an constant depending on object initialization parameters;
340             see MichaelHashSet::MichaelHashSet for explanation.
341         */
342         size_t bucket_count() const
343         {
344             return m_nHashBitmask + 1;
345         }
346     };
347
348 }} // cds::container
349
350 #endif // ifndef CDSLIB_CONTAINER_MICHAEL_SET_NOGC_H