8b78ba8133851f695251d6d4af0782b2e06770da
[libcds.git] / cds / container / skip_list_map_rcu.h
1 //$$CDS-header$$
2
3 #ifndef CDSLIB_CONTAINER_SKIP_LIST_MAP_RCU_H
4 #define CDSLIB_CONTAINER_SKIP_LIST_MAP_RCU_H
5
6 #include <cds/container/details/skip_list_base.h>
7 #include <cds/intrusive/skip_list_rcu.h>
8 #include <cds/container/details/make_skip_list_map.h>
9
10 namespace cds { namespace container {
11
12     /// Lock-free skip-list map (template specialization for \ref cds_urcu_desc "RCU")
13     /** @ingroup cds_nonintrusive_map
14         \anchor cds_nonintrusive_SkipListMap_rcu
15
16         The implementation of well-known probabilistic data structure called skip-list
17         invented by W.Pugh in his papers:
18             - [1989] W.Pugh Skip Lists: A Probabilistic Alternative to Balanced Trees
19             - [1990] W.Pugh A Skip List Cookbook
20
21         A skip-list is a probabilistic data structure that provides expected logarithmic
22         time search without the need of rebalance. The skip-list is a collection of sorted
23         linked list. Nodes are ordered by key. Each node is linked into a subset of the lists.
24         Each list has a level, ranging from 0 to 32. The bottom-level list contains
25         all the nodes, and each higher-level list is a sublist of the lower-level lists.
26         Each node is created with a random top level (with a random height), and belongs
27         to all lists up to that level. The probability that a node has the height 1 is 1/2.
28         The probability that a node has the height N is 1/2 ** N (more precisely,
29         the distribution depends on an random generator provided, but our generators
30         have this property).
31
32         The lock-free variant of skip-list is implemented according to book
33             - [2008] M.Herlihy, N.Shavit "The Art of Multiprocessor Programming",
34                 chapter 14.4 "A Lock-Free Concurrent Skiplist"
35
36         Template arguments:
37         - \p RCU - one of \ref cds_urcu_gc "RCU type".
38         - \p K - type of a key to be stored in the list.
39         - \p T - type of a value to be stored in the list.
40         - \p Traits - map traits, default is \p skip_list::traits.
41             It is possible to declare option-based list with \p cds::container::skip_list::make_traits metafunction
42             instead of \p Traits template argument.
43
44         Like STL map class, \p %SkipListMap stores its key-value pair as <tt>std:pair< K const, T></tt>.
45
46         @note Before including <tt><cds/container/skip_list_map_rcu.h></tt> you should include appropriate RCU header file,
47         see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
48
49         <b>Iterators</b>
50
51         The class supports a forward iterator (\ref iterator and \ref const_iterator).
52         The iteration is ordered.
53         You may iterate over skip-list set items only under RCU lock.
54         Only in this case the iterator is thread-safe since
55         while RCU is locked any set's item cannot be reclaimed.
56
57         The requirement of RCU lock during iterating means that deletion of the elements (i.e. \ref erase)
58         is not possible.
59
60         @warning The iterator object cannot be passed between threads
61
62         The iterator class supports the following minimalistic interface:
63         \code
64         struct iterator {
65             // Default ctor
66             iterator();
67
68             // Copy ctor
69             iterator( iterator const& s);
70
71             value_type * operator ->() const;
72             value_type& operator *() const;
73
74             // Pre-increment
75             iterator& operator ++();
76
77             // Copy assignment
78             iterator& operator = (const iterator& src);
79
80             bool operator ==(iterator const& i ) const;
81             bool operator !=(iterator const& i ) const;
82         };
83         \endcode
84         Note, the iterator object returned by \ref end, \p cend member functions points to \p nullptr and should not be dereferenced.
85
86     */
87     template <
88         typename RCU,
89         typename Key,
90         typename T,
91 #ifdef CDS_DOXYGEN_INVOKED
92         typename Traits = skip_list::traits
93 #else
94         typename Traits
95 #endif
96     >
97     class SkipListMap< cds::urcu::gc< RCU >, Key, T, Traits >:
98 #ifdef CDS_DOXYGEN_INVOKED
99         protected intrusive::SkipListSet< cds::urcu::gc< RCU >, std::pair<Key const, T>, Traits >
100 #else
101         protected details::make_skip_list_map< cds::urcu::gc< RCU >, Key, T, Traits >::type
102 #endif
103     {
104         //@cond
105         typedef details::make_skip_list_map< cds::urcu::gc< RCU >, Key, T, Traits >    maker;
106         typedef typename maker::type base_class;
107         //@endcond
108     public:
109         typedef cds::urcu::gc< RCU > gc; ///< Garbage collector used
110         typedef Key     key_type;       ///< Key type
111         typedef T       mapped_type;    ///< Mapped type
112 #   ifdef CDS_DOXYGEN_INVOKED
113         typedef std::pair< K const, T> value_type;   ///< Value type stored in the map
114 #   else
115         typedef typename maker::value_type  value_type;
116 #   endif
117         typedef Traits  traits;   ///< Map traits
118
119         typedef typename base_class::back_off       back_off;       ///< Back-off strategy used
120         typedef typename traits::allocator          allocator_type; ///< Allocator type used for allocate/deallocate the skip-list nodes
121         typedef typename base_class::item_counter   item_counter;   ///< Item counting policy used
122         typedef typename maker::key_comparator      key_comparator; ///< key comparison functor
123         typedef typename base_class::memory_model   memory_model;   ///< Memory ordering. See cds::opt::memory_model option
124         typedef typename traits::random_level_generator random_level_generator; ///< random level generator
125         typedef typename traits::stat               stat;   ///< internal statistics type
126
127         //@cond
128         typedef cds::container::skip_list::implementation_tag implementation_tag;
129         //@endcond
130
131     protected:
132         //@cond
133         typedef typename maker::node_type           node_type;
134         typedef typename maker::node_allocator      node_allocator;
135
136         typedef std::unique_ptr< node_type, typename maker::node_deallocator >    scoped_node_ptr;
137         //@endcond
138
139     public:
140         typedef typename base_class::rcu_lock  rcu_lock;   ///< RCU scoped lock
141         /// Group of \p extract_xxx functions do not require external locking
142         static CDS_CONSTEXPR const bool c_bExtractLockExternal = base_class::c_bExtractLockExternal;
143
144         /// pointer to extracted node
145         using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_type_traits::disposer >;
146
147     private:
148         //@cond
149         struct raw_ptr_converter
150         {
151             value_type * operator()( node_type * p ) const
152             {
153                return p ? &p->m_Value : nullptr;
154             }
155
156             value_type& operator()( node_type& n ) const
157             {
158                 return n.m_Value;
159             }
160
161             value_type const& operator()( node_type const& n ) const
162             {
163                 return n.m_Value;
164             }
165         };
166         //@endcond
167
168     public:
169         /// Result of \p get(), \p get_with() functions - pointer to the node found
170         typedef cds::urcu::raw_ptr_adaptor< value_type, typename base_class::raw_ptr, raw_ptr_converter > raw_ptr;
171
172     protected:
173         //@cond
174         unsigned int random_level()
175         {
176             return base_class::random_level();
177         }
178         //@endcond
179
180     public:
181         /// Default ctor
182         SkipListMap()
183             : base_class()
184         {}
185
186         /// Destructor destroys the set object
187         ~SkipListMap()
188         {}
189
190     public:
191         /// Iterator type
192         typedef skip_list::details::iterator< typename base_class::iterator >  iterator;
193
194         /// Const iterator type
195         typedef skip_list::details::iterator< typename base_class::const_iterator >   const_iterator;
196
197         /// Returns a forward iterator addressing the first element in a map
198         iterator begin()
199         {
200             return iterator( base_class::begin() );
201         }
202
203         /// Returns a forward const iterator addressing the first element in a map
204         const_iterator begin() const
205         {
206             return cbegin();
207         }
208         /// Returns a forward const iterator addressing the first element in a map
209         const_iterator cbegin() const
210         {
211             return const_iterator( base_class::cbegin() );
212         }
213
214         /// Returns a forward iterator that addresses the location succeeding the last element in a map.
215         iterator end()
216         {
217             return iterator( base_class::end() );
218         }
219
220         /// Returns a forward const iterator that addresses the location succeeding the last element in a map.
221         const_iterator end() const
222         {
223             return cend();
224         }
225         /// Returns a forward const iterator that addresses the location succeeding the last element in a map.
226         const_iterator cend() const
227         {
228             return const_iterator( base_class::cend() );
229         }
230
231     public:
232         /// Inserts new node with key and default value
233         /**
234             The function creates a node with \p key and default value, and then inserts the node created into the map.
235
236             Preconditions:
237             - The \p key_type should be constructible from a value of type \p K.
238                 In trivial case, \p K is equal to \p key_type.
239             - The \p mapped_type should be default-constructible.
240
241             RCU \p synchronize method can be called. RCU should not be locked.
242
243             Returns \p true if inserting successful, \p false otherwise.
244         */
245         template <typename K>
246         bool insert( K const& key )
247         {
248             return insert_with( key, [](value_type&){} );
249         }
250
251         /// Inserts new node
252         /**
253             The function creates a node with copy of \p val value
254             and then inserts the node created into the map.
255
256             Preconditions:
257             - The \p key_type should be constructible from \p key of type \p K.
258             - The \p value_type should be constructible from \p val of type \p V.
259
260             RCU \p synchronize method can be called. RCU should not be locked.
261
262             Returns \p true if \p val is inserted into the set, \p false otherwise.
263         */
264         template <typename K, typename V>
265         bool insert( K const& key, V const& val )
266         {
267             scoped_node_ptr pNode( node_allocator().New( random_level(), key, val ));
268             if ( base_class::insert( *pNode ))
269             {
270                 pNode.release();
271                 return true;
272             }
273             return false;
274         }
275
276         /// Inserts new node and initialize it by a functor
277         /**
278             This function inserts new node with key \p key and if inserting is successful then it calls
279             \p func functor with signature
280             \code
281                 struct functor {
282                     void operator()( value_type& item );
283                 };
284             \endcode
285
286             The argument \p item of user-defined functor \p func is the reference
287             to the map's item inserted:
288                 - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
289                 - <tt>item.second</tt> is a reference to item's value that may be changed.
290
291             The function allows to split creating of new item into three part:
292             - create item from \p key;
293             - insert new item into the map;
294             - if inserting is successful, initialize the value of item by calling \p func functor
295
296             This can be useful if complete initialization of object of \p value_type is heavyweight and
297             it is preferable that the initialization should be completed only if inserting is successful.
298
299             RCU \p synchronize method can be called. RCU should not be locked.
300         */
301         template <typename K, typename Func>
302         bool insert_with( const K& key, Func func )
303         {
304             scoped_node_ptr pNode( node_allocator().New( random_level(), key ));
305             if ( base_class::insert( *pNode, [&func]( node_type& item ) { func( item.m_Value ); } )) {
306                 pNode.release();
307                 return true;
308             }
309             return false;
310         }
311
312         /// For key \p key inserts data of type \p value_type created in-place from \p args
313         /**
314             Returns \p true if inserting successful, \p false otherwise.
315
316             RCU \p synchronize() method can be called. RCU should not be locked.
317         */
318         template <typename K, typename... Args>
319         bool emplace( K&& key, Args&&... args )
320         {
321             scoped_node_ptr pNode( node_allocator().New( random_level(), std::forward<K>(key), std::forward<Args>(args)... ));
322             if ( base_class::insert( *pNode )) {
323                 pNode.release();
324                 return true;
325             }
326             return false;
327         }
328
329         /// Ensures that the \p key exists in the map
330         /**
331             The operation performs inserting or changing data with lock-free manner.
332
333             If the \p key not found in the map, then the new item created from \p key
334             is inserted into the map (note that in this case the \ref key_type should be
335             constructible from type \p K).
336             Otherwise, the functor \p func is called with item found.
337             The functor \p Func interface is:
338             \code
339                 struct my_functor {
340                     void operator()( bool bNew, value_type& item );
341                 };
342             \endcode
343             with arguments:
344             - \p bNew - \p true if the item has been inserted, \p false otherwise
345             - \p item - item of the list
346
347             The functor may change any fields of \p item.second.
348
349             RCU \p synchronize() method can be called. RCU should not be locked.
350
351             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
352             \p second is true if new item has been added or \p false if the item with \p key
353             already is in the list.
354
355             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
356         */
357         template <typename K, typename Func>
358         std::pair<bool, bool> ensure( K const& key, Func func )
359         {
360             scoped_node_ptr pNode( node_allocator().New( random_level(), key ));
361             std::pair<bool, bool> res = base_class::ensure( *pNode,
362                 [&func](bool bNew, node_type& item, node_type const& ){ func( bNew, item.m_Value ); }
363             );
364             if ( res.first && res.second )
365                 pNode.release();
366             return res;
367         }
368
369         /// Delete \p key from the map
370         /**\anchor cds_nonintrusive_SkipListMap_rcu_erase_val
371
372             RCU \p synchronize method can be called. RCU should not be locked.
373
374             Return \p true if \p key is found and deleted, \p false otherwise
375         */
376         template <typename K>
377         bool erase( K const& key )
378         {
379             return base_class::erase(key);
380         }
381
382         /// Deletes the item from the map using \p pred predicate for searching
383         /**
384             The function is an analog of \ref cds_nonintrusive_SkipListMap_rcu_erase_val "erase(K const&)"
385             but \p pred is used for key comparing.
386             \p Less functor has the interface like \p std::less.
387             \p Less must imply the same element order as the comparator used for building the map.
388         */
389         template <typename K, typename Less>
390         bool erase_with( K const& key, Less pred )
391         {
392             CDS_UNUSED( pred );
393             return base_class::erase_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >());
394         }
395
396         /// Delete \p key from the map
397         /** \anchor cds_nonintrusive_SkipListMap_rcu_erase_func
398
399             The function searches an item with key \p key, calls \p f functor
400             and deletes the item. If \p key is not found, the functor is not called.
401
402             The functor \p Func interface:
403             \code
404             struct extractor {
405                 void operator()(value_type& item) { ... }
406             };
407             \endcode
408
409             RCU \p synchronize method can be called. RCU should not be locked.
410
411             Return \p true if key is found and deleted, \p false otherwise
412         */
413         template <typename K, typename Func>
414         bool erase( K const& key, Func f )
415         {
416             return base_class::erase( key, [&f]( node_type& node) { f( node.m_Value ); } );
417         }
418
419         /// Deletes the item from the map using \p pred predicate for searching
420         /**
421             The function is an analog of \ref cds_nonintrusive_SkipListMap_rcu_erase_func "erase(K const&, Func)"
422             but \p pred is used for key comparing.
423             \p Less functor has the interface like \p std::less.
424             \p Less must imply the same element order as the comparator used for building the map.
425         */
426         template <typename K, typename Less, typename Func>
427         bool erase_with( K const& key, Less pred, Func f )
428         {
429             CDS_UNUSED( pred );
430             return base_class::erase_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >(),
431                 [&f]( node_type& node) { f( node.m_Value ); } );
432         }
433
434         /// Extracts the item from the map with specified \p key
435         /** \anchor cds_nonintrusive_SkipListMap_rcu_extract
436             The function searches an item with key equal to \p key in the map,
437             unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
438             If the item is not found the function returns an empty \p exempt_ptr
439
440             Note the compare functor from \p Traits class' template argument
441             should accept a parameter of type \p K that can be not the same as \p key_type.
442
443             RCU \p synchronize() method can be called. RCU should NOT be locked.
444
445             The function does not free the item found.
446             The item will be implicitly freed when the returned object is destroyed or when
447             its \p release() member function is called.
448         */
449         template <typename K>
450         exempt_ptr extract( K const& key )
451         {
452             return exempt_ptr( base_class::do_extract( key ));
453         }
454
455         /// Extracts the item from the map with comparing functor \p pred
456         /**
457             The function is an analog of \p extract(K const&) but \p pred predicate is used for key comparing.
458             \p Less has the semantics like \p std::less.
459             \p pred must imply the same element order as the comparator used for building the map.
460         */
461         template <typename K, typename Less>
462         exempt_ptr extract_with( K const& key, Less pred )
463         {
464             CDS_UNUSED( pred );
465             return exempt_ptr( base_class::do_extract_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >()));
466         }
467
468         /// Extracts an item with minimal key from the map
469         /**
470             The function searches an item with minimal key, unlinks it,
471             and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item.
472             If the skip-list is empty the function returns an empty \p exempt_ptr.
473
474             RCU \p synchronize method can be called. RCU should NOT be locked.
475
476             The function does not free the item found.
477             The item will be implicitly freed when the returned object is destroyed or when
478             its \p release() member function is called.
479         */
480         exempt_ptr extract_min()
481         {
482             return exempt_ptr( base_class::do_extract_min());
483         }
484
485         /// Extracts an item with maximal key from the map
486         /**
487             The function searches an item with maximal key, unlinks it from the set,
488             and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item.
489             If the skip-list is empty the function returns an empty \p exempt_ptr.
490
491             RCU \p synchronize method can be called. RCU should NOT be locked.
492
493             The function does not free the item found.
494             The item will be implicitly freed when the returned object is destroyed or when
495             its \p release() member function is called.
496             */
497         exempt_ptr extract_max()
498         {
499             return exempt_ptr( base_class::do_extract_max());
500         }
501
502         /// Find the key \p key
503         /** \anchor cds_nonintrusive_SkipListMap_rcu_find_cfunc
504
505             The function searches the item with key equal to \p key and calls the functor \p f for item found.
506             The interface of \p Func functor is:
507             \code
508             struct functor {
509                 void operator()( value_type& item );
510             };
511             \endcode
512             where \p item is the item found.
513
514             The functor may change \p item.second.
515
516             The function applies RCU lock internally.
517
518             The function returns \p true if \p key is found, \p false otherwise.
519         */
520         template <typename K, typename Func>
521         bool find( K const& key, Func f )
522         {
523             return base_class::find( key, [&f](node_type& item, K const& ) { f( item.m_Value );});
524         }
525
526         /// Finds the key \p val using \p pred predicate for searching
527         /**
528             The function is an analog of \ref cds_nonintrusive_SkipListMap_rcu_find_cfunc "find(K const&, Func)"
529             but \p pred is used for key comparing.
530             \p Less functor has the interface like \p std::less.
531             \p Less must imply the same element order as the comparator used for building the map.
532         */
533         template <typename K, typename Less, typename Func>
534         bool find_with( K const& key, Less pred, Func f )
535         {
536             CDS_UNUSED( pred );
537             return base_class::find_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >(),
538                 [&f](node_type& item, K const& ) { f( item.m_Value );});
539         }
540
541         /// Find the key \p key
542         /** \anchor cds_nonintrusive_SkipListMap_rcu_find_val
543
544             The function searches the item with key equal to \p key
545             and returns \p true if it is found, and \p false otherwise.
546
547             The function applies RCU lock internally.
548         */
549         template <typename K>
550         bool find( K const& key )
551         {
552             return base_class::find( key );
553         }
554
555         /// Finds the key \p val using \p pred predicate for searching
556         /**
557             The function is an analog of \ref cds_nonintrusive_SkipListMap_rcu_find_val "find(K const&)"
558             but \p pred is used for key comparing.
559             \p Less functor has the interface like \p std::less.
560             \p Less must imply the same element order as the comparator used for building the map.
561         */
562         template <typename K, typename Less>
563         bool find_with( K const& key, Less pred )
564         {
565             CDS_UNUSED( pred );
566             return base_class::find_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >() );
567         }
568
569         /// Finds the key \p key and return the item found
570         /** \anchor cds_nonintrusive_SkipListMap_rcu_get
571             The function searches the item with key equal to \p key and returns a \p raw_ptr object pointing to an item found.
572             If \p key is not found it returns empty \p raw_ptr.
573
574             Note the compare functor in \p Traits class' template argument
575             should accept a parameter of type \p K that can be not the same as \p key_type.
576
577             RCU should be locked before call of this function.
578             Returned item is valid only while RCU is locked:
579             \code
580             typedef cds::container::SkipListMap< cds::urcu::gc< cds::urcu::general_buffered<> >, int, foo, my_traits > skip_list;
581             skip_list theList;
582             // ...
583             typename skip_list::raw_ptr pVal;
584             {
585                 // Lock RCU
586                 skip_list::rcu_lock lock;
587
588                 pVal = theList.get( 5 );
589                 if ( pVal ) {
590                     // Deal with pVal
591                     //...
592                 }
593             }
594             // You can manually release pVal after RCU-locked section
595             pVal.release();
596             \endcode
597         */
598         template <typename K>
599         raw_ptr get( K const& key )
600         {
601             return raw_ptr( base_class::get( key ));
602         }
603
604         /// Finds the key \p key and return the item found
605         /**
606             The function is an analog of \ref cds_nonintrusive_SkipListMap_rcu_get "get(K const&)"
607             but \p pred is used for comparing the keys.
608
609             \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
610             in any order.
611             \p pred must imply the same element order as the comparator used for building the map.
612         */
613         template <typename K, typename Less>
614         raw_ptr get_with( K const& key, Less pred )
615         {
616             CDS_UNUSED( pred );
617             return raw_ptr( base_class::get_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >() ));
618         }
619
620         /// Clears the map (not atomic)
621         void clear()
622         {
623             base_class::clear();
624         }
625
626         /// Checks if the map is empty
627         /**
628             Emptiness is checked by item counting: if item count is zero then the map is empty.
629         */
630         bool empty() const
631         {
632             return base_class::empty();
633         }
634
635         /// Returns item count in the map
636         size_t size() const
637         {
638             return base_class::size();
639         }
640
641         /// Returns const reference to internal statistics
642         stat const& statistics() const
643         {
644             return base_class::statistics();
645         }
646     };
647 }} // namespace cds::container
648
649 #endif // #ifndef CDSLIB_CONTAINER_SKIP_LIST_MAP_RCU_H