Removed unused implementation_tag typedef
[libcds.git] / cds / container / michael_map_nogc.h
1 //$$CDS-header$$
2
3 #ifndef CDSLIB_CONTAINER_MICHAEL_MAP_NOGC_H
4 #define CDSLIB_CONTAINER_MICHAEL_MAP_NOGC_H
5
6 #include <cds/container/details/michael_map_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 map (template specialization for \p cds::gc::nogc)
13     /** @ingroup cds_nonintrusive_map
14         \anchor cds_nonintrusive_MichaelHashMap_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 map item.
18
19         See @ref cds_nonintrusive_MichaelHashMap_hp "MichaelHashMap" for description of template parameters.
20     */
21     template <
22         class OrderedList,
23 #ifdef CDS_DOXYGEN_INVOKED
24         class Traits = michael_map::traits
25 #else
26         class Traits
27 #endif
28     >
29     class MichaelHashMap<cds::gc::nogc, OrderedList, Traits>
30     {
31     public:
32         typedef cds::gc::nogc gc;        ///< No garbage collector
33         typedef OrderedList bucket_type; ///< type of ordered list used as a bucket implementation
34         typedef Traits      traits;      ///< Map traits
35
36         typedef typename bucket_type::key_type    key_type;    ///< key type
37         typedef typename bucket_type::mapped_type mapped_type; ///< type of value to be stored in the map
38         typedef typename bucket_type::value_type  value_type;  ///< Pair used as the some functor's argument
39
40         typedef typename bucket_type::key_comparator key_comparator;   ///< key comparing functor
41
42         /// Hash functor for \ref key_type and all its derivatives that you use
43         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
44         typedef typename traits::item_counter item_counter;   ///< Item counter type
45
46         /// Bucket table allocator
47         typedef cds::details::Allocator< bucket_type, typename traits::allocator >  bucket_table_allocator;
48
49     protected:
50         //@cond
51         typedef typename bucket_type::iterator       bucket_iterator;
52         typedef typename bucket_type::const_iterator bucket_const_iterator;
53         //@endcond
54
55     protected:
56         item_counter    m_ItemCounter; ///< Item counter
57         hash            m_HashFunctor; ///< Hash functor
58         bucket_type *   m_Buckets;     ///< bucket table
59
60     private:
61         //@cond
62         const size_t    m_nHashBitmask;
63         //@endcond
64
65     protected:
66         //@cond
67         /// Calculates hash value of \p key
68         size_t hash_value( key_type const & key ) const
69         {
70             return m_HashFunctor( key ) & m_nHashBitmask;
71         }
72
73         /// Returns the bucket (ordered list) for \p key
74         bucket_type&    bucket( key_type const& key )
75         {
76             return m_Buckets[ hash_value( key ) ];
77         }
78         //@endcond
79
80     protected:
81         /// Forward iterator
82         /**
83             \p IsConst - constness boolean flag
84
85             The forward iterator for Michael's map is based on \p OrderedList forward iterator and has some features:
86             - it has no post-increment operator, only pre-increment
87             - it iterates items in unordered fashion
88         */
89         template <bool IsConst>
90         class iterator_type: private cds::intrusive::michael_set::details::iterator< bucket_type, IsConst >
91         {
92             //@cond
93             typedef cds::intrusive::michael_set::details::iterator< bucket_type, IsConst >  base_class;
94             friend class MichaelHashMap;
95             //@endcond
96
97         protected:
98             //@cond
99             //typedef typename base_class::bucket_type    bucket_type;
100             typedef typename base_class::bucket_ptr     bucket_ptr;
101             typedef typename base_class::list_iterator  list_iterator;
102
103             //typedef typename bucket_type::key_type      key_type;
104             //@endcond
105
106         public:
107             /// Value pointer type (const for const_iterator)
108             typedef typename cds::details::make_const_type<typename MichaelHashMap::mapped_type, IsConst>::pointer   value_ptr;
109             /// Value reference type (const for const_iterator)
110             typedef typename cds::details::make_const_type<typename MichaelHashMap::mapped_type, IsConst>::reference value_ref;
111
112             /// Key-value pair pointer type (const for const_iterator)
113             typedef typename cds::details::make_const_type<typename MichaelHashMap::value_type, IsConst>::pointer   pair_ptr;
114             /// Key-value pair reference type (const for const_iterator)
115             typedef typename cds::details::make_const_type<typename MichaelHashMap::value_type, IsConst>::reference pair_ref;
116
117         protected:
118             //@cond
119             iterator_type( list_iterator const& it, bucket_ptr pFirst, bucket_ptr pLast )
120                 : base_class( it, pFirst, pLast )
121             {}
122             //@endcond
123
124         public:
125             /// Default ctor
126             iterator_type()
127                 : base_class()
128             {}
129
130             /// Copy ctor
131             iterator_type( const iterator_type& src )
132                 : base_class( src )
133             {}
134
135             /// Dereference operator
136             pair_ptr operator ->() const
137             {
138                 assert( base_class::m_pCurBucket != nullptr );
139                 return base_class::m_itList.operator ->();
140             }
141
142             /// Dereference operator
143             pair_ref operator *() const
144             {
145                 assert( base_class::m_pCurBucket != nullptr );
146                 return base_class::m_itList.operator *();
147             }
148
149             /// Pre-increment
150             iterator_type& operator ++()
151             {
152                 base_class::operator++();
153                 return *this;
154             }
155
156             /// Assignment operator
157             iterator_type& operator = (const iterator_type& src)
158             {
159                 base_class::operator =(src);
160                 return *this;
161             }
162
163             /// Returns current bucket (debug function)
164             bucket_ptr bucket() const
165             {
166                 return base_class::bucket();
167             }
168
169             /// Equality operator
170             template <bool C>
171             bool operator ==(iterator_type<C> const& i ) const
172             {
173                 return base_class::operator ==( i );
174             }
175             /// Equality operator
176             template <bool C>
177             bool operator !=(iterator_type<C> const& i ) const
178             {
179                 return !( *this == i );
180             }
181         };
182
183
184     public:
185         /// Forward iterator
186         typedef iterator_type< false >    iterator;
187
188         /// Const forward iterator
189         typedef iterator_type< true >     const_iterator;
190
191         /// Returns a forward iterator addressing the first element in a set
192         /**
193             For empty set \code begin() == end() \endcode
194         */
195         iterator begin()
196         {
197             return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count() );
198         }
199
200         /// Returns an iterator that addresses the location succeeding the last element in a set
201         /**
202             Do not use the value returned by <tt>end</tt> function to access any item.
203             The returned value can be used only to control reaching the end of the set.
204             For empty set \code begin() == end() \endcode
205         */
206         iterator end()
207         {
208             return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
209         }
210
211         /// Returns a forward const iterator addressing the first element in a set
212         //@{
213         const_iterator begin() const
214         {
215             return get_const_begin();
216         }
217         const_iterator cbegin() const
218         {
219             return get_const_begin();
220         }
221         //@}
222
223         /// Returns an const iterator that addresses the location succeeding the last element in a set
224         //@{
225         const_iterator end() const
226         {
227             return get_const_end();
228         }
229         const_iterator cend() const
230         {
231             return get_const_end();
232         }
233         //@}
234
235     private:
236         //@cond
237         const_iterator get_const_begin() const
238         {
239             return const_iterator( const_cast<bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
240         }
241         const_iterator get_const_end() const
242         {
243             return const_iterator( const_cast<bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
244         }
245         //@endcond
246
247     public:
248         /// Initialize the map
249         /**
250             The Michael's hash map is non-expandable container. You should point the average count of items \p nMaxItemCount
251             when you create an object.
252             \p nLoadFactor parameter defines average count of items per bucket and it should be small number between 1 and 10.
253             Remember, since the bucket implementation is an ordered list, searching in the bucket is linear [<tt>O(nLoadFactor)</tt>].
254             Note, that many popular STL hash map implementation uses load factor 1.
255
256             The ctor defines hash table size as rounding <tt>nMacItemCount / nLoadFactor</tt> up to nearest power of two.
257         */
258         MichaelHashMap(
259             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
260             size_t nLoadFactor      ///< load factor: estimation of max number of items in the bucket
261         ) : m_nHashBitmask( michael_map::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
262         {
263             // GC and OrderedList::gc must be the same
264             static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
265
266             // atomicity::empty_item_counter is not allowed as a item counter
267             static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
268                            "cds::atomicity::empty_item_counter is not allowed as a item counter");
269
270             m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
271         }
272
273         /// Clears hash set and destroys it
274         ~MichaelHashMap()
275         {
276             clear();
277             bucket_table_allocator().Delete( m_Buckets, bucket_count() );
278         }
279
280         /// Inserts new node with key and default value
281         /**
282             The function creates a node with \p key and default value, and then inserts the node created into the map.
283
284             Preconditions:
285             - The \ref key_type should be constructible from value of type \p K.
286                 In trivial case, \p K is equal to \ref key_type.
287             - The \ref mapped_type should be default-constructible.
288
289             Returns an iterator pointed to inserted value, or \p end() if inserting is failed
290         */
291         template <typename K>
292         iterator insert( const K& key )
293         {
294             bucket_type& refBucket = bucket( key );
295             bucket_iterator it = refBucket.insert( key );
296
297             if ( it != refBucket.end() ) {
298                 ++m_ItemCounter;
299                 return iterator( it, &refBucket, m_Buckets + bucket_count() );
300             }
301
302             return end();
303         }
304
305         /// Inserts new node
306         /**
307             The function creates a node with copy of \p val value
308             and then inserts the node created into the map.
309
310             Preconditions:
311             - The \ref key_type should be constructible from \p key of type \p K.
312             - The \ref mapped_type should be constructible from \p val of type \p V.
313
314             Returns an iterator pointed to inserted value, or \p end() if inserting is failed
315         */
316         template <typename K, typename V>
317         iterator insert( K const& key, V const& val )
318         {
319             bucket_type& refBucket = bucket( key );
320             bucket_iterator it = refBucket.insert( key, val );
321
322             if ( it != refBucket.end() ) {
323                 ++m_ItemCounter;
324                 return iterator( it, &refBucket, m_Buckets + bucket_count() );
325             }
326
327             return end();
328         }
329
330         /// Inserts new node and initialize it by a functor
331         /**
332             This function inserts new node with key \p key and if inserting is successful then it calls
333             \p func functor with signature
334             \code
335             struct functor {
336                 void operator()( value_type& item );
337             };
338             \endcode
339
340             The argument \p item of user-defined functor \p func is the reference
341             to the map's item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
342
343             The user-defined functor it is called only if the inserting is successful.
344             The \p key_type should be constructible from value of type \p K.
345
346             The function allows to split creating of new item into two part:
347             - create item from \p key;
348             - insert new item into the map;
349             - if inserting is successful, initialize the value of item by calling \p f functor
350
351             This can be useful if complete initialization of object of \p mapped_type is heavyweight and
352             it is preferable that the initialization should be completed only if inserting is successful.
353
354             Returns an iterator pointed to inserted value, or \p end() if inserting is failed
355
356             @warning For \ref cds_nonintrusive_MichaelKVList_nogc "MichaelKVList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
357             \ref cds_nonintrusive_LazyKVList_nogc "LazyKVList" provides exclusive access to inserted item and does not require any node-level
358             synchronization.
359         */
360         template <typename K, typename Func>
361         iterator insert_with( const K& key, Func func )
362         {
363             bucket_type& refBucket = bucket( key );
364             bucket_iterator it = refBucket.insert_with( key, func );
365
366             if ( it != refBucket.end() ) {
367                 ++m_ItemCounter;
368                 return iterator( it, &refBucket, m_Buckets + bucket_count() );
369             }
370
371             return end();
372         }
373
374         /// For key \p key inserts data of type \p mapped_type created from \p args
375         /**
376             \p key_type should be constructible from type \p K
377
378             Returns an iterator pointed to inserted value, or \p end() if inserting is failed
379         */
380         template <typename K, typename... Args>
381         iterator emplace( K&& key, Args&&... args )
382         {
383             bucket_type& refBucket = bucket( key );
384             bucket_iterator it = refBucket.emplace( std::forward<K>(key), std::forward<Args>(args)... );
385
386             if ( it != refBucket.end() ) {
387                 ++m_ItemCounter;
388                 return iterator( it, &refBucket, m_Buckets + bucket_count() );
389             }
390
391             return end();
392         }
393
394         /// Updates the item
395         /**
396             If \p key is not in the map and \p bAllowInsert is \p true, the function inserts a new item.
397             Otherwise, the function returns an iterator pointing to the item found.
398
399             Returns <tt> std::pair<iterator, bool> </tt> where \p first is an iterator pointing to
400             item found or inserted (if inserting is not allowed and \p key is not found, the iterator will be \p end()), 
401             \p second is true if new item has been added or \p false if the item
402             already is in the map.
403
404             @warning For \ref cds_nonintrusive_MichaelKVList_nogc "MichaelKVList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
405             \ref cds_nonintrusive_LazyKVList_nogc "LazyKVList" provides exclusive access to inserted item and does not require any node-level
406             synchronization.
407         */
408         template <typename K>
409         std::pair<iterator, bool> update( const K& key, bool bAllowInsert = true )
410         {
411             bucket_type& refBucket = bucket( key );
412             std::pair<bucket_iterator, bool> ret = refBucket.update( key, bAllowInsert );
413
414             if ( ret.second  )
415                 ++m_ItemCounter;
416
417             return std::make_pair( iterator( ret.first, &refBucket, m_Buckets + bucket_count() ), ret.second );
418         }
419         //@cond
420         // Deprecated, use update()
421         template <typename K>
422         std::pair<iterator, bool> ensure( K const& key )
423         {
424             return update( key, true );
425         }
426         //@endcond
427
428         /// Checks whether the map contains \p key
429         /**
430             The function searches the item with key equal to \p key
431             and returns an iterator pointed to item found and \ref end() otherwise
432         */
433         template <typename K>
434         iterator contains( K const& key )
435         {
436             bucket_type& refBucket = bucket( key );
437             bucket_iterator it = refBucket.contains( key );
438
439             if ( it != refBucket.end() )
440                 return iterator( it, &refBucket, m_Buckets + bucket_count() );
441
442             return end();
443         }
444         //@cond
445         // Deprecated, use contains()
446         template <typename K>
447         iterator find( K const& key )
448         {
449             return contains( key );
450         }
451         //@endcond
452
453         /// Checks whether the map contains \p key using \p pred predicate for searching
454         /**
455             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
456             \p Less functor has the interface like \p std::less.
457             \p pred must imply the same element order as the comparator used for building the map.
458         */
459         template <typename K, typename Less>
460         iterator contains( K const& key, Less pred )
461         {
462             bucket_type& refBucket = bucket( key );
463             bucket_iterator it = refBucket.contains( key, pred );
464
465             if ( it != refBucket.end() )
466                 return iterator( it, &refBucket, m_Buckets + bucket_count() );
467
468             return end();
469         }
470         //@cond
471         // Deprecated, use contains()
472         template <typename K, typename Less>
473         iterator find_with( K const& key, Less pred )
474         {
475             return contains( key, pred );
476         }
477         //@endcond
478
479         /// Clears the map (not atomic)
480         void clear()
481         {
482             for ( size_t i = 0; i < bucket_count(); ++i )
483                 m_Buckets[i].clear();
484             m_ItemCounter.reset();
485         }
486
487         /// Checks whether the map is empty
488         /**
489             Emptiness is checked by item counting: if item count is zero then the map is empty.
490             Thus, the correct item counting feature is an important part of Michael's map implementation.
491         */
492         bool empty() const
493         {
494             return size() == 0;
495         }
496
497         /// Returns item count in the map
498         size_t size() const
499         {
500             return m_ItemCounter;
501         }
502
503         /// Returns the size of hash table
504         /**
505             Since \p %MichaelHashMap cannot dynamically extend the hash table size,
506             the value returned is an constant depending on object initialization parameters;
507             see \p MichaelHashMap::MichaelHashMap for explanation.
508         */
509         size_t bucket_count() const
510         {
511             return m_nHashBitmask + 1;
512         }
513     };
514 }} // namespace cds::container
515
516 #endif // ifndef CDSLIB_CONTAINER_MICHAEL_MAP_NOGC_H