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