3 #ifndef CDSLIB_CONTAINER_IMPL_SKIP_LIST_MAP_H
4 #define CDSLIB_CONTAINER_IMPL_SKIP_LIST_MAP_H
6 #include <cds/container/details/guarded_ptr_cast.h>
8 namespace cds { namespace container {
10 /// Lock-free skip-list map
11 /** @ingroup cds_nonintrusive_map
12 \anchor cds_nonintrusive_SkipListMap_hp
14 The implementation of well-known probabilistic data structure called skip-list
15 invented by W.Pugh in his papers:
16 - [1989] W.Pugh Skip Lists: A Probabilistic Alternative to Balanced Trees
17 - [1990] W.Pugh A Skip List Cookbook
19 A skip-list is a probabilistic data structure that provides expected logarithmic
20 time search without the need of rebalance. The skip-list is a collection of sorted
21 linked list. Nodes are ordered by key. Each node is linked into a subset of the lists.
22 Each list has a level, ranging from 0 to 32. The bottom-level list contains
23 all the nodes, and each higher-level list is a sublist of the lower-level lists.
24 Each node is created with a random top level (with a random height), and belongs
25 to all lists up to that level. The probability that a node has the height 1 is 1/2.
26 The probability that a node has the height N is 1/2 ** N (more precisely,
27 the distribution depends on an random generator provided, but our generators
30 The lock-free variant of skip-list is implemented according to book
31 - [2008] M.Herlihy, N.Shavit "The Art of Multiprocessor Programming",
32 chapter 14.4 "A Lock-Free Concurrent Skiplist"
35 - \p GC - Garbage collector used.
36 - \p K - type of a key to be stored in the list.
37 - \p T - type of a value to be stored in the list.
38 - \p Traits - map traits, default is \p skip_list::traits
39 It is possible to declare option-based list with \p cds::container::skip_list::make_traits metafunction
40 istead of \p Traits template argument.
42 Like STL map class, \p %SkipListMap stores the key-value pair as <tt>std:pair< K const, T></tt>.
44 @warning The skip-list requires up to 67 hazard pointers that may be critical for some GCs for which
45 the guard count is limited (like \p gc::HP). Those GCs should be explicitly initialized with
46 hazard pointer enough: \code cds::gc::HP myhp( 67 ) \endcode. Otherwise an run-time exception may be raised
47 when you try to create skip-list object.
49 @note There are several specializations of \p %SkipListMap for each \p GC. You should include:
50 - <tt><cds/container/skip_list_map_hp.h></tt> for \p gc::HP garbage collector
51 - <tt><cds/container/skip_list_map_dhp.h></tt> for \p gc::DHP garbage collector
52 - <tt><cds/container/skip_list_map_rcu.h></tt> for \ref cds_nonintrusive_SkipListMap_rcu "RCU type"
53 - <tt><cds/container/skip_list_map_nogc.h></tt> for \ref cds_nonintrusive_SkipListMap_nogc "non-deletable SkipListMap"
57 The class supports a forward iterator (\ref iterator and \ref const_iterator).
58 The iteration is ordered.
59 The iterator object is thread-safe: the element pointed by the iterator object is guarded,
60 so, the element cannot be reclaimed while the iterator object is alive.
61 However, passing an iterator object between threads is dangerous.
63 \warning Due to concurrent nature of skip-list map it is not guarantee that you can iterate
64 all elements in the map: any concurrent deletion can exclude the element
65 pointed by the iterator from the map, and your iteration can be terminated
66 before end of the map. Therefore, such iteration is more suitable for debugging purpose only
68 Remember, each iterator object requires 2 additional hazard pointers, that may be
69 a limited resource for \p GC like \p gc::HP (for gc::DHP the count of
72 The iterator class supports the following minimalistic interface:
79 iterator( iterator const& s);
81 value_type * operator ->() const;
82 value_type& operator *() const;
85 iterator& operator ++();
88 iterator& operator = (const iterator& src);
90 bool operator ==(iterator const& i ) const;
91 bool operator !=(iterator const& i ) const;
94 Note, the iterator object returned by \ref end, \ cend member functions points to \p nullptr and should not be dereferenced.
101 #ifdef CDS_DOXYGEN_INVOKED
102 typename Traits = skip_list::traits
108 #ifdef CDS_DOXYGEN_INVOKED
109 protected intrusive::SkipListSet< GC, std::pair<Key const, T>, Traits >
111 protected details::make_skip_list_map< GC, Key, T, Traits >::type
115 typedef details::make_skip_list_map< GC, Key, T, Traits > maker;
116 typedef typename maker::type base_class;
119 typedef GC gc; ///< Garbage collector
120 typedef Key key_type; ///< Key type
121 typedef T mapped_type; ///< Mapped type
122 typedef Traits traits; ///< Map traits
123 # ifdef CDS_DOXYGEN_INVOKED
124 typedef std::pair< Key const, T> value_type; ///< Key-value pair to be stored in the map
126 typedef typename maker::value_type value_type;
129 typedef typename base_class::back_off back_off; ///< Back-off strategy
130 typedef typename traits::allocator allocator_type; ///< Allocator type used for allocate/deallocate the skip-list nodes
131 typedef typename base_class::item_counter item_counter; ///< Item counting policy used
132 typedef typename maker::key_comparator key_comparator; ///< key comparison functor
133 typedef typename base_class::memory_model memory_model; ///< Memory ordering, see \p cds::opt::memory_model
134 typedef typename traits::random_level_generator random_level_generator ; ///< random level generator
135 typedef typename traits::stat stat; ///< internal statistics type
139 typedef typename maker::node_type node_type;
140 typedef typename maker::node_allocator node_allocator;
142 typedef std::unique_ptr< node_type, typename maker::node_deallocator > scoped_node_ptr;
147 typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
151 unsigned int random_level()
153 return base_class::random_level();
163 /// Destructor destroys the set object
169 typedef skip_list::details::iterator< typename base_class::iterator > iterator;
171 /// Const iterator type
172 typedef skip_list::details::iterator< typename base_class::const_iterator > const_iterator;
174 /// Returns a forward iterator addressing the first element in a map
177 return iterator( base_class::begin() );
180 /// Returns a forward const iterator addressing the first element in a map
181 const_iterator begin() const
185 /// Returns a forward const iterator addressing the first element in a map
186 const_iterator cbegin() const
188 return const_iterator( base_class::cbegin() );
191 /// Returns a forward iterator that addresses the location succeeding the last element in a map.
194 return iterator( base_class::end() );
197 /// Returns a forward const iterator that addresses the location succeeding the last element in a map.
198 const_iterator end() const
202 /// Returns a forward const iterator that addresses the location succeeding the last element in a map.
203 const_iterator cend() const
205 return const_iterator( base_class::cend() );
209 /// Inserts new node with key and default value
211 The function creates a node with \p key and default value, and then inserts the node created into the map.
214 - The \p key_type should be constructible from a value of type \p K.
215 In trivial case, \p K is equal to \p key_type.
216 - The \p mapped_type should be default-constructible.
218 Returns \p true if inserting successful, \p false otherwise.
220 template <typename K>
221 bool insert( K const& key )
223 return insert_with( key, [](value_type&){} );
228 The function creates a node with copy of \p val value
229 and then inserts the node created into the map.
232 - The \p key_type should be constructible from \p key of type \p K.
233 - The \p value_type should be constructible from \p val of type \p V.
235 Returns \p true if \p val is inserted into the set, \p false otherwise.
237 template <typename K, typename V>
238 bool insert( K const& key, V const& val )
240 return insert_with( key, [&val](value_type& item) { item.second = val ; } );
243 /// Inserts new node and initialize it by a functor
245 This function inserts new node with key \p key and if inserting is successful then it calls
246 \p func functor with signature
249 void operator()( value_type& item );
253 The argument \p item of user-defined functor \p func is the reference
254 to the map's item inserted:
255 - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
256 - <tt>item.second</tt> is a reference to item's value that may be changed.
258 \p key_type should be constructible from value of type \p K.
260 The function allows to split creating of new item into two part:
261 - create item from \p key;
262 - insert new item into the map;
263 - if inserting is successful, initialize the value of item by calling \p func functor
265 This can be useful if complete initialization of object of \p value_type is heavyweight and
266 it is preferable that the initialization should be completed only if inserting is successful.
268 template <typename K, typename Func>
269 bool insert_with( K const& key, Func func )
271 scoped_node_ptr pNode( node_allocator().New( random_level(), key ));
272 if ( base_class::insert( *pNode, [&func]( node_type& item ) { func( item.m_Value ); } )) {
279 /// For key \p key inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
281 Returns \p true if inserting successful, \p false otherwise.
283 template <typename K, typename... Args>
284 bool emplace( K&& key, Args&&... args )
286 scoped_node_ptr pNode( node_allocator().New( random_level(), std::forward<K>(key), std::forward<Args>(args)... ));
287 if ( base_class::insert( *pNode )) {
294 /// Updates data by \p key
296 The operation performs inserting or changing data with lock-free manner.
298 If the \p key not found in the map, then the new item created from \p key
299 will be inserted into the map iff \p bInsert is \p true
300 (note that in this case the \ref key_type should be constructible from type \p K).
301 Otherwise, if \p key is found, the functor \p func is called with item found.
302 The functor \p Func signature:
305 void operator()( bool bNew, value_type& item );
309 - \p bNew - \p true if the item has been inserted, \p false otherwise
310 - \p item - item of the map
312 The functor may change any fields of the \p item.second that is \ref value_type.
314 Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
315 \p second is \p true if new item has been added or \p false if \p key already exists.
317 @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
319 template <typename K, typename Func>
320 std::pair<bool, bool> update( K const& key, Func func, bool bInsert = true )
322 scoped_node_ptr pNode( node_allocator().New( random_level(), key ));
323 std::pair<bool, bool> res = base_class::update( *pNode,
324 [&func](bool bNew, node_type& item, node_type const& ){ func( bNew, item.m_Value );},
327 if ( res.first && res.second )
332 template <typename K, typename Func>
333 CDS_DEPRECATED("ensure() is deprecated, use update()")
334 std::pair<bool, bool> ensure( K const& key, Func func )
336 return update( key, func, true );
340 /// Delete \p key from the map
341 /** \anchor cds_nonintrusive_SkipListMap_erase_val
343 Return \p true if \p key is found and deleted, \p false otherwise
345 template <typename K>
346 bool erase( K const& key )
348 return base_class::erase(key);
351 /// Deletes the item from the map using \p pred predicate for searching
353 The function is an analog of \ref cds_nonintrusive_SkipListMap_erase_val "erase(K const&)"
354 but \p pred is used for key comparing.
355 \p Less functor has the interface like \p std::less.
356 \p Less must imply the same element order as the comparator used for building the map.
358 template <typename K, typename Less>
359 bool erase_with( K const& key, Less pred )
362 return base_class::erase_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >());
365 /// Delete \p key from the map
366 /** \anchor cds_nonintrusive_SkipListMap_erase_func
368 The function searches an item with key \p key, calls \p f functor
369 and deletes the item. If \p key is not found, the functor is not called.
371 The functor \p Func interface:
374 void operator()(value_type& item) { ... }
378 Return \p true if key is found and deleted, \p false otherwise
380 template <typename K, typename Func>
381 bool erase( K const& key, Func f )
383 return base_class::erase( key, [&f]( node_type& node) { f( node.m_Value ); } );
386 /// Deletes the item from the map using \p pred predicate for searching
388 The function is an analog of \ref cds_nonintrusive_SkipListMap_erase_func "erase(K const&, Func)"
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.
393 template <typename K, typename Less, typename Func>
394 bool erase_with( K const& key, Less pred, Func f )
397 return base_class::erase_with( key,
398 cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >(),
399 [&f]( node_type& node) { f( node.m_Value ); } );
402 /// Extracts the item from the map with specified \p key
403 /** \anchor cds_nonintrusive_SkipListMap_hp_extract
404 The function searches an item with key equal to \p key in the map,
405 unlinks it from the map, and returns a guarded pointer to the item found.
406 If \p key is not found the function returns an empty guarded pointer.
408 Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
410 The item extracted is freed automatically by garbage collector \p GC
411 when returned \p guarded_ptr object will be destroyed or released.
412 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
416 typedef cds::container::SkipListMap< cds::gc::HP, int, foo, my_traits > skip_list;
420 skip_list::guarded_ptr gp( theList.extract( 5 ));
425 // Destructor of gp releases internal HP guard and frees the pointer
429 template <typename K>
430 guarded_ptr extract( K const& key )
433 base_class::extract_( gp.guard(), key, typename base_class::key_comparator() );
437 /// Extracts the item from the map with comparing functor \p pred
439 The function is an analog of \ref cds_nonintrusive_SkipListMap_hp_extract "extract(K const&)"
440 but \p pred predicate is used for key comparing.
442 \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
444 \p pred must imply the same element order as the comparator used for building the map.
446 template <typename K, typename Less>
447 guarded_ptr extract_with( K const& key, Less pred )
450 typedef cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor > wrapped_less;
452 base_class::extract_( gp.guard(), key, cds::opt::details::make_comparator_from_less<wrapped_less>() );
456 /// Extracts an item with minimal key from the map
458 The function searches an item with minimal key, unlinks it, and returns an guarded pointer to the item found.
459 If the skip-list is empty the function returns an empty guarded pointer.
461 The item extracted is freed automatically by garbage collector \p GC
462 when returned \p guarded_ptr object will be destroyed or released.
463 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
467 typedef cds::continer::SkipListMap< cds::gc::HP, int, foo, my_traits > skip_list;
471 skip_list::guarded_ptr gp( theList.extract_min());
476 // Destructor of gp releases internal HP guard and then frees the pointer
480 guarded_ptr extract_min()
483 base_class::extract_min_( gp.guard() );
487 /// Extracts an item with maximal key from the map
489 The function searches an item with maximal key, unlinks it, and returns a guarded pointer to item found.
490 If the skip-list is empty the function returns an empty \p guarded_ptr.
492 The item found is freed by garbage collector \p GC automatically
493 when returned \p guarded_ptr object will be destroyed or released.
494 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
498 typedef cds::container::SkipListMap< cds::gc::HP, int, foo, my_traits > skip_list;
502 skip_list::guarded_ptr gp( theList.extract_max());
507 // Destructor of gp releases internal HP guard and then frees the pointer
511 guarded_ptr extract_max()
514 base_class::extract_max_( gp.guard() );
518 /// Find the key \p key
519 /** \anchor cds_nonintrusive_SkipListMap_find_cfunc
521 The function searches the item with key equal to \p key and calls the functor \p f for item found.
522 The interface of \p Func functor is:
525 void operator()( value_type& item );
528 where \p item is the item found.
530 The functor may change \p item.second.
532 The function returns \p true if \p key is found, \p false otherwise.
534 template <typename K, typename Func>
535 bool find( K const& key, Func f )
537 return base_class::find( key, [&f](node_type& item, K const& ) { f( item.m_Value );});
540 /// Finds the key \p val using \p pred predicate for searching
542 The function is an analog of \ref cds_nonintrusive_SkipListMap_find_cfunc "find(K const&, Func)"
543 but \p pred is used for key comparing.
544 \p Less functor has the interface like \p std::less.
545 \p Less must imply the same element order as the comparator used for building the map.
547 template <typename K, typename Less, typename Func>
548 bool find_with( K const& key, Less pred, Func f )
551 return base_class::find_with( key,
552 cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >(),
553 [&f](node_type& item, K const& ) { f( item.m_Value );});
556 /// Checks whether the map contains \p key
558 The function searches the item with key equal to \p key
559 and returns \p true if it is found, and \p false otherwise.
561 template <typename K>
562 bool contains( K const& key )
564 return base_class::contains( key );
567 template <typename K>
568 CDS_DEPRECATED("deprecated, use contains()")
569 bool find( K const& key )
571 return contains( key );
575 /// Checks whether the set contains \p key using \p pred predicate for searching
577 The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
578 \p Less functor has the interface like \p std::less.
579 \p Less must imply the same element order as the comparator used for building the set.
581 template <typename K, typename Less>
582 bool contains( K const& key, Less pred )
585 return base_class::contains( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >() );
588 template <typename K, typename Less>
589 CDS_DEPRECATED("deprecated, use contains()")
590 bool find_with( K const& key, Less pred )
592 return contains( key, pred );
596 /// Finds the key \p key and return the item found
597 /** \anchor cds_nonintrusive_SkipListMap_hp_get
598 The function searches the item with key equal to \p key
599 and returns a guarded pointer to the item found.
600 If \p key is not found the function returns an empty guarded pointer.
602 It is safe when a concurrent thread erases the item returned as \p guarded_ptr.
603 In this case the item will be freed later by garbage collector \p GC automatically
604 when \p guarded_ptr object will be destroyed or released.
605 @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
609 typedef cds::container::SkipListMap< cds::gc::HP, int, foo, my_traits > skip_list;
613 skip_list::guarded_ptr gp( theList.get( 5 ));
618 // Destructor of guarded_ptr releases internal HP guard
622 Note the compare functor specified for class \p Traits template parameter
623 should accept a parameter of type \p K that can be not the same as \p value_type.
625 template <typename K>
626 guarded_ptr get( K const& key )
629 base_class::get_with_( gp.guard(), key, typename base_class::key_comparator() );
633 /// Finds the key \p key and return the item found
635 The function is an analog of \ref cds_nonintrusive_SkipListMap_hp_get "get( K const&)"
636 but \p pred is used for comparing the keys.
638 \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
640 \p pred must imply the same element order as the comparator used for building the map.
642 template <typename K, typename Less>
643 guarded_ptr get_with( K const& key, Less pred )
646 typedef cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor > wrapped_less;
648 base_class::get_with_( gp.guard(), key, cds::opt::details::make_comparator_from_less< wrapped_less >());
658 /// Checks if the map is empty
661 return base_class::empty();
664 /// Returns item count in the map
667 return base_class::size();
670 /// Returns const reference to internal statistics
671 stat const& statistics() const
673 return base_class::statistics();
676 }} // namespace cds::container
678 #endif // #ifndef CDSLIB_CONTAINER_IMPL_SKIP_LIST_MAP_H