3 #ifndef __CDS_CONTAINER_IMPL_SKIP_LIST_MAP_H
4 #define __CDS_CONTAINER_IMPL_SKIP_LIST_MAP_H
6 #include <cds/gc/guarded_ptr.h>
7 #include <cds/container/details/guarded_ptr_cast.h>
9 namespace cds { namespace container {
11 /// Lock-free skip-list map
12 /** @ingroup cds_nonintrusive_map
13 \anchor cds_nonintrusive_SkipListMap_hp
15 The implementation of well-known probabilistic data structure called skip-list
16 invented by W.Pugh in his papers:
17 - [1989] W.Pugh Skip Lists: A Probabilistic Alternative to Balanced Trees
18 - [1990] W.Pugh A Skip List Cookbook
20 A skip-list is a probabilistic data structure that provides expected logarithmic
21 time search without the need of rebalance. The skip-list is a collection of sorted
22 linked list. Nodes are ordered by key. Each node is linked into a subset of the lists.
23 Each list has a level, ranging from 0 to 32. The bottom-level list contains
24 all the nodes, and each higher-level list is a sublist of the lower-level lists.
25 Each node is created with a random top level (with a random height), and belongs
26 to all lists up to that level. The probability that a node has the height 1 is 1/2.
27 The probability that a node has the height N is 1/2 ** N (more precisely,
28 the distribution depends on an random generator provided, but our generators
31 The lock-free variant of skip-list is implemented according to book
32 - [2008] M.Herlihy, N.Shavit "The Art of Multiprocessor Programming",
33 chapter 14.4 "A Lock-Free Concurrent Skiplist"
36 - \p GC - Garbage collector used.
37 - \p K - type of a key to be stored in the list.
38 - \p T - type of a value to be stored in the list.
39 - \p Traits - type traits. See skip_list::type_traits for explanation.
41 It is possible to declare option-based list with cds::container::skip_list::make_traits metafunction istead of \p Traits template
43 Template argument list \p Options of cds::container::skip_list::make_traits metafunction are:
44 - opt::compare - key compare functor. No default functor is provided.
45 If the option is not specified, the opt::less is used.
46 - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<K>.
47 - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that is no item counting.
48 - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
49 or opt::v::sequential_consistent (sequentially consisnent memory model).
50 - skip_list::random_level_generator - random level generator. Can be skip_list::xorshift, skip_list::turbo_pascal or
51 user-provided one. See skip_list::random_level_generator option description for explanation.
52 Default is \p %skip_list::turbo_pascal.
53 - opt::allocator - allocator for skip-list node. Default is \ref CDS_DEFAULT_ALLOCATOR.
54 - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::Default is used.
55 - opt::stat - internal statistics. Available types: skip_list::stat, skip_list::empty_stat (the default)
57 Like STL map class, %SkipListMap stores its key-value pair as <tt>std:pair< K const, T></tt>.
59 \warning The skip-list requires up to 67 hazard pointers that may be critical for some GCs for which
60 the guard count is limited (like as gc::HP, gc::HRC). Those GCs should be explicitly initialized with
61 hazard pointer enough: \code cds::gc::HP myhp( 67 ) \endcode. Otherwise an run-time exception may be raised
62 when you try to create skip-list object.
64 \note There are several specializations of \p %SkipListMap for each \p GC. You should include:
65 - <tt><cds/container/skip_list_map_hp.h></tt> for gc::HP garbage collector
66 - <tt><cds/container/skip_list_map_ptb.h></tt> for gc::PTB garbage collector
67 - <tt><cds/container/skip_list_map_rcu.h></tt> for \ref cds_nonintrusive_SkipListMap_rcu "RCU type"
68 - <tt><cds/container/skip_list_map_nogc.h></tt> for \ref cds_nonintrusive_SkipListMap_nogc "non-deletable SkipListMap"
72 The class supports a forward iterator (\ref iterator and \ref const_iterator).
73 The iteration is ordered.
74 The iterator object is thread-safe: the element pointed by the iterator object is guarded,
75 so, the element cannot be reclaimed while the iterator object is alive.
76 However, passing an iterator object between threads is dangerous.
78 \warning Due to concurrent nature of skip-list map it is not guarantee that you can iterate
79 all elements in the map: any concurrent deletion can exclude the element
80 pointed by the iterator from the map, and your iteration can be terminated
81 before end of the map. Therefore, such iteration is more suitable for debugging purpose only
83 Remember, each iterator object requires 2 additional hazard pointers, that may be
84 a limited resource for \p GC like as gc::HP and gc::HRC (however, for gc::PTB the count of
87 The iterator class supports the following minimalistic interface:
94 iterator( iterator const& s);
96 value_type * operator ->() const;
97 value_type& operator *() const;
100 iterator& operator ++();
103 iterator& operator = (const iterator& src);
105 bool operator ==(iterator const& i ) const;
106 bool operator !=(iterator const& i ) const;
109 Note, the iterator object returned by \ref end, \ cend member functions points to \p nullptr and should not be dereferenced.
116 #ifdef CDS_DOXYGEN_INVOKED
117 typename Traits = skip_list::type_traits
123 #ifdef CDS_DOXYGEN_INVOKED
124 protected intrusive::SkipListSet< GC, std::pair<Key const, T>, Traits >
126 protected details::make_skip_list_map< GC, Key, T, Traits >::type
130 typedef details::make_skip_list_map< GC, Key, T, Traits > maker;
131 typedef typename maker::type base_class;
134 typedef typename base_class::gc gc ; ///< Garbage collector used
135 typedef Key key_type ; ///< Key type
136 typedef T mapped_type ; ///< Mapped type
137 # ifdef CDS_DOXYGEN_INVOKED
138 typedef std::pair< K const, T> value_type ; ///< Value type stored in the map
140 typedef typename maker::value_type value_type;
142 typedef Traits options ; ///< Options specified
144 typedef typename base_class::back_off back_off ; ///< Back-off strategy used
145 typedef typename options::allocator allocator_type ; ///< Allocator type used for allocate/deallocate the skip-list nodes
146 typedef typename base_class::item_counter item_counter ; ///< Item counting policy used
147 typedef typename maker::key_comparator key_comparator ; ///< key comparison functor
148 typedef typename base_class::memory_model memory_model ; ///< Memory ordering. See cds::opt::memory_model option
149 typedef typename options::random_level_generator random_level_generator ; ///< random level generator
150 typedef typename options::stat stat ; ///< internal statistics type
154 typedef typename maker::node_type node_type;
155 typedef typename maker::node_allocator node_allocator;
157 typedef std::unique_ptr< node_type, typename maker::node_deallocator > scoped_node_ptr;
163 typedef cds::gc::guarded_ptr< gc, node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
167 unsigned int random_level()
169 return base_class::random_level();
179 /// Destructor destroys the set object
185 typedef skip_list::details::iterator< typename base_class::iterator > iterator;
187 /// Const iterator type
188 typedef skip_list::details::iterator< typename base_class::const_iterator > const_iterator;
190 /// Returns a forward iterator addressing the first element in a map
193 return iterator( base_class::begin() );
196 /// Returns a forward const iterator addressing the first element in a map
198 const_iterator begin() const
202 const_iterator cbegin()
204 return const_iterator( base_class::cbegin() );
208 /// Returns a forward iterator that addresses the location succeeding the last element in a map.
211 return iterator( base_class::end() );
214 /// Returns a forward const iterator that addresses the location succeeding the last element in a map.
216 const_iterator end() const
220 const_iterator cend()
222 return const_iterator( base_class::cend() );
227 /// Inserts new node with key and default value
229 The function creates a node with \p key and default value, and then inserts the node created into the map.
232 - The \ref key_type should be constructible from a value of type \p K.
233 In trivial case, \p K is equal to \ref key_type.
234 - The \ref mapped_type should be default-constructible.
236 Returns \p true if inserting successful, \p false otherwise.
238 template <typename K>
239 bool insert( K const& key )
241 return insert_key( key, [](value_type&){} );
246 The function creates a node with copy of \p val value
247 and then inserts the node created into the map.
250 - The \ref key_type should be constructible from \p key of type \p K.
251 - The \ref value_type should be constructible from \p val of type \p V.
253 Returns \p true if \p val is inserted into the set, \p false otherwise.
255 template <typename K, typename V>
256 bool insert( K const& key, V const& val )
258 return insert_key( key, [&val](value_type& item) { item.second = val ; } );
261 /// Inserts new node and initialize it by a functor
263 This function inserts new node with key \p key and if inserting is successful then it calls
264 \p func functor with signature
267 void operator()( value_type& item );
271 The argument \p item of user-defined functor \p func is the reference
272 to the map's item inserted:
273 - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
274 - <tt>item.second</tt> is a reference to item's value that may be changed.
276 The user-defined functor can be passed by reference using \p std::ref
277 and it is called only if inserting is successful.
279 The key_type should be constructible from value of type \p K.
281 The function allows to split creating of new item into two part:
282 - create item from \p key;
283 - insert new item into the map;
284 - if inserting is successful, initialize the value of item by calling \p func functor
286 This can be useful if complete initialization of object of \p value_type is heavyweight and
287 it is preferable that the initialization should be completed only if inserting is successful.
289 template <typename K, typename Func>
290 bool insert_key( const K& key, Func func )
292 scoped_node_ptr pNode( node_allocator().New( random_level(), key ));
293 if ( base_class::insert( *pNode, [&func]( node_type& item ) { func( item.m_Value ); } )) {
300 /// For key \p key inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
302 Returns \p true if inserting successful, \p false otherwise.
304 template <typename K, typename... Args>
305 bool emplace( K&& key, Args&&... args )
307 scoped_node_ptr pNode( node_allocator().New( random_level(), std::forward<K>(key), std::forward<Args>(args)... ));
308 if ( base_class::insert( *pNode )) {
315 /// Ensures that the \p key exists in the map
317 The operation performs inserting or changing data with lock-free manner.
319 If the \p key not found in the map, then the new item created from \p key
320 is inserted into the map (note that in this case the \ref key_type should be
321 constructible from type \p K).
322 Otherwise, the functor \p func is called with item found.
323 The functor \p Func may be a function with signature:
325 void func( bool bNew, value_type& item );
330 void operator()( bool bNew, value_type& item );
335 - \p bNew - \p true if the item has been inserted, \p false otherwise
336 - \p item - item of the list
338 The functor may change any fields of the \p item.second that is \ref value_type.
340 You may pass \p func argument by reference using \p std::ref
342 Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
343 \p second is true if new item has been added or \p false if the item with \p key
344 already is in the list.
346 template <typename K, typename Func>
347 std::pair<bool, bool> ensure( K const& key, Func func )
349 scoped_node_ptr pNode( node_allocator().New( random_level(), key ));
350 std::pair<bool, bool> res = base_class::ensure( *pNode,
351 [&func](bool bNew, node_type& item, node_type const& ){ func( bNew, item.m_Value ); }
353 if ( res.first && res.second )
358 /// Delete \p key from the map
359 /** \anchor cds_nonintrusive_SkipListMap_erase_val
361 Return \p true if \p key is found and deleted, \p false otherwise
363 template <typename K>
364 bool erase( K const& key )
366 return base_class::erase(key);
369 /// Deletes the item from the map using \p pred predicate for searching
371 The function is an analog of \ref cds_nonintrusive_SkipListMap_erase_val "erase(K const&)"
372 but \p pred is used for key comparing.
373 \p Less functor has the interface like \p std::less.
374 \p Less must imply the same element order as the comparator used for building the map.
376 template <typename K, typename Less>
377 bool erase_with( K const& key, Less pred )
379 return base_class::erase_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >());
382 /// Delete \p key from the map
383 /** \anchor cds_nonintrusive_SkipListMap_erase_func
385 The function searches an item with key \p key, calls \p f functor
386 and deletes the item. If \p key is not found, the functor is not called.
388 The functor \p Func interface:
391 void operator()(value_type& item) { ... }
394 The functor may be passed by reference using <tt>boost:ref</tt>
396 Return \p true if key is found and deleted, \p false otherwise
398 template <typename K, typename Func>
399 bool erase( K const& key, Func f )
401 return base_class::erase( key, [&f]( node_type& node) { f( node.m_Value ); } );
404 /// Deletes the item from the map using \p pred predicate for searching
406 The function is an analog of \ref cds_nonintrusive_SkipListMap_erase_func "erase(K const&, Func)"
407 but \p pred is used for key comparing.
408 \p Less functor has the interface like \p std::less.
409 \p Less must imply the same element order as the comparator used for building the map.
411 template <typename K, typename Less, typename Func>
412 bool erase_with( K const& key, Less pred, Func f )
414 return base_class::erase_with( key,
415 cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >(),
416 [&f]( node_type& node) { f( node.m_Value ); } );
419 /// Extracts the item from the map with specified \p key
420 /** \anchor cds_nonintrusive_SkipListMap_hp_extract
421 The function searches an item with key equal to \p key in the map,
422 unlinks it from the map, and returns it in \p ptr parameter.
423 If the item with key equal to \p key is not found the function returns \p false.
425 Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
427 The item extracted is freed automatically by garbage collector \p GC
428 when returned \ref guarded_ptr object will be destroyed or released.
429 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
433 typedef cds::container::SkipListMap< cds::gc::HP, int, foo, my_traits > skip_list;
437 skip_list::guarded_ptr gp;
438 if ( theList.extract( gp, 5 ) ) {
442 // Destructor of gp releases internal HP guard and frees the pointer
446 template <typename K>
447 bool extract( guarded_ptr& ptr, K const& key )
449 return base_class::extract_( ptr.guard(), key, typename base_class::key_comparator() );
452 /// Extracts the item from the map with comparing functor \p pred
454 The function is an analog of \ref cds_nonintrusive_SkipListMap_hp_extract "extract(K const&)"
455 but \p pred predicate is used for key comparing.
457 \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
459 \p pred must imply the same element order as the comparator used for building the map.
461 template <typename K, typename Less>
462 bool extract_with( guarded_ptr& ptr, K const& key, Less pred )
464 typedef cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor > wrapped_less;
465 return base_class::extract_( ptr.guard(), key, cds::opt::details::make_comparator_from_less<wrapped_less>() );
468 /// Extracts an item with minimal key from the map
470 The function searches an item with minimal key, unlinks it, and returns the item found in \p ptr parameter.
471 If the skip-list is empty the function returns \p false.
473 The item extracted is freed automatically by garbage collector \p GC
474 when returned \ref guarded_ptr object will be destroyed or released.
475 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
479 typedef cds::continer::SkipListMap< cds::gc::HP, int, foo, my_traits > skip_list;
483 skip_list::guarded_ptr gp;
484 if ( theList.extract_min( gp )) {
488 // Destructor of gp releases internal HP guard and then frees the pointer
492 bool extract_min( guarded_ptr& ptr)
494 return base_class::extract_min_( ptr.guard() );
497 /// Extracts an item with maximal key from the map
499 The function searches an item with maximal key, unlinks it, and returns the pointer to item found in \p ptr parameter.
500 If the skip-list is empty the function returns empty \p guarded_ptr.
502 The item found is freed by garbage collector \p GC automatically
503 when returned \ref guarded_ptr object will be destroyed or released.
504 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
508 typedef cds::container::SkipListMap< cds::gc::HP, int, foo, my_traits > skip_list;
512 skip_list::guarded_ptr gp;
513 if ( theList.extract_max( gp )) {
517 // Destructor of gp releases internal HP guard and then frees the pointer
521 bool extract_max( guarded_ptr& dest )
523 return base_class::extract_max_( dest.guard() );
526 /// Find the key \p key
527 /** \anchor cds_nonintrusive_SkipListMap_find_cfunc
529 The function searches the item with key equal to \p key and calls the functor \p f for item found.
530 The interface of \p Func functor is:
533 void operator()( value_type& item );
536 where \p item is the item found.
538 You can pass \p f argument by reference using \p std::ref
540 The functor may change \p item.second.
542 The function returns \p true if \p key is found, \p false otherwise.
544 template <typename K, typename Func>
545 bool find( K const& key, Func f )
547 return base_class::find( key, [&f](node_type& item, K const& ) { f( item.m_Value );});
550 /// Finds the key \p val using \p pred predicate for searching
552 The function is an analog of \ref cds_nonintrusive_SkipListMap_find_cfunc "find(K const&, Func)"
553 but \p pred is used for key comparing.
554 \p Less functor has the interface like \p std::less.
555 \p Less must imply the same element order as the comparator used for building the map.
557 template <typename K, typename Less, typename Func>
558 bool find_with( K const& key, Less pred, Func f )
560 return base_class::find_with( key,
561 cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >(),
562 [&f](node_type& item, K const& ) { f( item.m_Value );});
565 /// Find the key \p key
566 /** \anchor cds_nonintrusive_SkipListMap_find_val
568 The function searches the item with key equal to \p key
569 and returns \p true if it is found, and \p false otherwise.
571 template <typename K>
572 bool find( K const& key )
574 return base_class::find( key );
577 /// Finds the key \p val using \p pred predicate for searching
579 The function is an analog of \ref cds_nonintrusive_SkipListMap_find_val "find(K const&)"
580 but \p pred is used for key comparing.
581 \p Less functor has the interface like \p std::less.
582 \p Less must imply the same element order as the comparator used for building the map.
584 template <typename K, typename Less>
585 bool find_with( K const& key, Less pred )
587 return base_class::find_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >() );
590 /// Finds the key \p key and return the item found
591 /** \anchor cds_nonintrusive_SkipListMap_hp_get
592 The function searches the item with key equal to \p key
593 and assigns the item found to guarded pointer \p ptr.
594 The function returns \p true if \p key is found, and \p false otherwise.
595 If \p key is not found the \p ptr parameter is not changed.
597 It is safe when a concurrent thread erases the item returned in \p ptr guarded pointer.
598 In this case the item will be freed later by garbage collector \p GC automatically
599 when \p guarded_ptr object will be destroyed or released.
600 @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
604 typedef cds::container::SkipListMap< cds::gc::HP, int, foo, my_traits > skip_list;
608 skip_list::guarded_ptr gp;
609 if ( theList.get( gp, 5 ) ) {
613 // Destructor of guarded_ptr releases internal HP guard
617 Note the compare functor specified for class \p Traits template parameter
618 should accept a parameter of type \p K that can be not the same as \p value_type.
620 template <typename K>
621 bool get( guarded_ptr& ptr, K const& key )
623 return base_class::get_with_( ptr.guard(), key, typename base_class::key_comparator() );
626 /// Finds the key \p key and return the item found
628 The function is an analog of \ref cds_nonintrusive_SkipListMap_hp_get "get( guarded_ptr& ptr, K const&)"
629 but \p pred is used for comparing the keys.
631 \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
633 \p pred must imply the same element order as the comparator used for building the map.
635 template <typename K, typename Less>
636 bool get_with( guarded_ptr& ptr, K const& key, Less pred )
638 typedef cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor > wrapped_less;
639 return base_class::get_with_( ptr.guard(), key, cds::opt::details::make_comparator_from_less< wrapped_less >());
648 /// Checks if the map is empty
650 Emptiness is checked by item counting: if item count is zero then the map is empty.
654 return base_class::empty();
657 /// Returns item count in the map
660 return base_class::size();
663 /// Returns const reference to internal statistics
664 stat const& statistics() const
666 return base_class::statistics();
670 }} // namespace cds::container
672 #endif // #ifndef __CDS_CONTAINER_IMPL_SKIP_LIST_MAP_H