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