3 #ifndef __CDS_CONTAINER_SKIP_LIST_SET_IMPL_H
4 #define __CDS_CONTAINER_SKIP_LIST_SET_IMPL_H
6 #include <cds/details/binary_functor_wrapper.h>
7 #include <cds/gc/guarded_ptr.h>
8 #include <cds/container/details/guarded_ptr_cast.h>
10 namespace cds { namespace container {
12 /// Lock-free skip-list set
13 /** @ingroup cds_nonintrusive_set
14 \anchor cds_nonintrusive_SkipListSet_hp
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
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
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"
37 - \p GC - Garbage collector used.
38 - \p T - type 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 comparison 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<T>.
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 \warning The skip-list requires up to 67 hazard pointers that may be critical for some GCs for which
58 the guard count is limited (like as gc::HP, gc::HRC). Those GCs should be explicitly initialized with
59 hazard pointer enough: \code cds::gc::HP myhp( 67 ) \endcode. Otherwise an run-time exception may be raised
60 when you try to create skip-list object.
62 \note There are several specializations of \p %SkipListSet for each \p GC. You should include:
63 - <tt><cds/container/skip_list_set_hp.h></tt> for gc::HP garbage collector
64 - <tt><cds/container/skip_list_set_hrc.h></tt> for gc::HRC garbage collector
65 - <tt><cds/container/skip_list_set_ptb.h></tt> for gc::PTB garbage collector
66 - <tt><cds/container/skip_list_set_rcu.h></tt> for \ref cds_nonintrusive_SkipListSet_rcu "RCU type"
67 - <tt><cds/container/skip_list_set_nogc.h></tt> for \ref cds_nonintrusive_SkipListSet_nogc "non-deletable SkipListSet"
71 The class supports a forward iterator (\ref iterator and \ref const_iterator).
72 The iteration is ordered.
73 The iterator object is thread-safe: the element pointed by the iterator object is guarded,
74 so, the element cannot be reclaimed while the iterator object is alive.
75 However, passing an iterator object between threads is dangerous.
77 \warning Due to concurrent nature of skip-list set it is not guarantee that you can iterate
78 all elements in the set: any concurrent deletion can exclude the element
79 pointed by the iterator from the set, and your iteration can be terminated
80 before end of the set. Therefore, such iteration is more suitable for debugging purpose only
82 Remember, each iterator object requires 2 additional hazard pointers, that may be
83 a limited resource for \p GC like as gc::HP and gc::HRC (for gc::PTB the count of
86 The iterator class supports the following minimalistic interface:
93 iterator( iterator const& s);
95 value_type * operator ->() const;
96 value_type& operator *() const;
99 iterator& operator ++();
102 iterator& operator = (const iterator& src);
104 bool operator ==(iterator const& i ) const;
105 bool operator !=(iterator const& i ) const;
108 Note, the iterator object returned by \ref end, \p cend member functions points to \p nullptr and should not be dereferenced.
114 #ifdef CDS_DOXYGEN_INVOKED
115 typename Traits = skip_list::type_traits
121 #ifdef CDS_DOXYGEN_INVOKED
122 protected intrusive::SkipListSet< GC, T, Traits >
124 protected details::make_skip_list_set< GC, T, Traits >::type
128 typedef details::make_skip_list_set< GC, T, Traits > maker;
129 typedef typename maker::type base_class;
132 typedef typename base_class::gc gc ; ///< Garbage collector used
133 typedef T value_type ; ///< @anchor cds_containewr_SkipListSet_value_type Value type stored in the set
134 typedef Traits options ; ///< Options specified
136 typedef typename base_class::back_off back_off ; ///< Back-off strategy used
137 typedef typename options::allocator allocator_type ; ///< Allocator type used for allocate/deallocate the skip-list nodes
138 typedef typename base_class::item_counter item_counter ; ///< Item counting policy used
139 typedef typename maker::key_comparator key_comparator ; ///< key comparison functor
140 typedef typename base_class::memory_model memory_model ; ///< Memory ordering. See cds::opt::memory_model option
141 typedef typename options::random_level_generator random_level_generator ; ///< random level generator
142 typedef typename options::stat stat ; ///< internal statistics type
146 typedef typename maker::node_type node_type;
147 typedef typename maker::node_allocator node_allocator;
149 typedef std::unique_ptr< node_type, typename maker::node_deallocator > scoped_node_ptr;
154 typedef cds::gc::guarded_ptr< gc, node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
158 unsigned int random_level()
160 return base_class::random_level();
170 /// Destructor destroys the set object
176 typedef skip_list::details::iterator< typename base_class::iterator > iterator;
178 /// Const iterator type
179 typedef skip_list::details::iterator< typename base_class::const_iterator > const_iterator;
181 /// Returns a forward iterator addressing the first element in a set
184 return iterator( base_class::begin() );
187 /// Returns a forward const iterator addressing the first element in a set
188 const_iterator begin() const
190 return const_iterator( base_class::begin() );
193 /// Returns a forward const iterator addressing the first element in a set
194 const_iterator cbegin()
196 return const_iterator( base_class::cbegin() );
199 /// Returns a forward iterator that addresses the location succeeding the last element in a set.
202 return iterator( base_class::end() );
205 /// Returns a forward const iterator that addresses the location succeeding the last element in a set.
206 const_iterator end() const
208 return const_iterator( base_class::end() );
211 /// Returns a forward const iterator that addresses the location succeeding the last element in a set.
212 const_iterator cend()
214 return const_iterator( base_class::cend() );
220 The function creates a node with copy of \p val value
221 and then inserts the node created into the set.
223 The type \p Q should contain as minimum the complete key for the node.
224 The object of \ref value_type should be constructible from a value of type \p Q.
225 In trivial case, \p Q is equal to \ref value_type.
227 Returns \p true if \p val is inserted into the set, \p false otherwise.
229 template <typename Q>
230 bool insert( Q const& val )
232 scoped_node_ptr sp( node_allocator().New( random_level(), val ));
233 if ( base_class::insert( *sp.get() )) {
242 The function allows to split creating of new item into two part:
243 - create item with key only
244 - insert new item into the set
245 - if inserting is success, calls \p f functor to initialize value-fields of \p val.
247 The functor signature is:
249 void func( value_type& val );
251 where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
252 \p val no any other changes could be made on this set's item by concurrent threads.
253 The user-defined functor is called only if the inserting is success. It may be passed by reference
254 using <tt>boost::ref</tt>
256 template <typename Q, typename Func>
257 bool insert( Q const& val, Func f )
259 scoped_node_ptr sp( node_allocator().New( random_level(), val ));
260 if ( base_class::insert( *sp.get(), [&f]( node_type& val ) { cds::unref(f)( val.m_Value ); } )) {
267 /// Ensures that the item exists in the set
269 The operation performs inserting or changing data with lock-free manner.
271 If the \p val key not found in the set, then the new item created from \p val
272 is inserted into the set. Otherwise, the functor \p func is called with the item found.
273 The functor \p Func should be a function with signature:
275 void func( bool bNew, value_type& item, const Q& val );
280 void operator()( bool bNew, value_type& item, const Q& val );
285 - \p bNew - \p true if the item has been inserted, \p false otherwise
286 - \p item - item of the set
287 - \p val - argument \p key passed into the \p ensure function
289 The functor may change non-key fields of the \p item; however, \p func must guarantee
290 that during changing no any other modifications could be made on this item by concurrent threads.
292 You may pass \p func argument by reference using <tt>boost::ref</tt>.
294 Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
295 \p second is true if new item has been added or \p false if the item with \p key
296 already is in the set.
298 template <typename Q, typename Func>
299 std::pair<bool, bool> ensure( const Q& val, Func func )
301 scoped_node_ptr sp( node_allocator().New( random_level(), val ));
302 std::pair<bool, bool> bRes = base_class::ensure( *sp,
303 [&func, &val](bool bNew, node_type& node, node_type&){ cds::unref(func)( bNew, node.m_Value, val ); });
304 if ( bRes.first && bRes.second )
309 /// Inserts data of type \ref cds_containewr_SkipListSet_value_type "value_type" constructed with <tt>std::forward<Args>(args)...</tt>
311 Returns \p true if inserting successful, \p false otherwise.
313 template <typename... Args>
314 bool emplace( Args&&... args )
316 scoped_node_ptr sp( node_allocator().New( random_level(), std::forward<Args>(args)... ));
317 if ( base_class::insert( *sp.get() )) {
324 /// Delete \p key from the set
325 /** \anchor cds_nonintrusive_SkipListSet_erase_val
327 The set item comparator should be able to compare the type \p value_type
330 Return \p true if key is found and deleted, \p false otherwise
332 template <typename Q>
333 bool erase( Q const& key )
335 return base_class::erase( key );
338 /// Deletes the item from the set using \p pred predicate for searching
340 The function is an analog of \ref cds_nonintrusive_SkipListSet_erase_val "erase(Q const&)"
341 but \p pred is used for key comparing.
342 \p Less functor has the interface like \p std::less.
343 \p Less must imply the same element order as the comparator used for building the set.
345 template <typename Q, typename Less>
346 bool erase_with( Q const& key, Less pred )
348 return base_class::erase_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor >() );
351 /// Delete \p key from the set
352 /** \anchor cds_nonintrusive_SkipListSet_erase_func
354 The function searches an item with key \p key, calls \p f functor
355 and deletes the item. If \p key is not found, the functor is not called.
357 The functor \p Func interface:
360 void operator()(value_type const& val);
363 The functor may be passed by reference using <tt>boost:ref</tt>
365 Since the key of \p value_type is not explicitly specified,
366 template parameter \p Q defines the key type to search in the list.
367 The list item comparator should be able to compare the type \p T of list item
370 Return \p true if key is found and deleted, \p false otherwise
374 template <typename Q, typename Func>
375 bool erase( Q const& key, Func f )
377 return base_class::erase( key, [&f]( node_type const& node) { cds::unref(f)( node.m_Value ); } );
380 /// Deletes the item from the set using \p pred predicate for searching
382 The function is an analog of \ref cds_nonintrusive_SkipListSet_erase_func "erase(Q const&, Func)"
383 but \p pred is used for key comparing.
384 \p Less functor has the interface like \p std::less.
385 \p Less must imply the same element order as the comparator used for building the set.
387 template <typename Q, typename Less, typename Func>
388 bool erase_with( Q const& key, Less pred, Func f )
390 return base_class::erase_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor >(),
391 [&f]( node_type const& node) { cds::unref(f)( node.m_Value ); } );
394 /// Extracts the item from the set with specified \p key
395 /** \anchor cds_nonintrusive_SkipListSet_hp_extract
396 The function searches an item with key equal to \p key in the set,
397 unlinks it from the set, and returns it in \p result parameter.
398 If the item with key equal to \p key is not found the function returns \p false.
400 Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
402 The item extracted is freed automatically by garbage collector \p GC
403 when returned \ref guarded_ptr object will be destroyed or released.
404 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
408 typedef cds::container::SkipListSet< cds::gc::HP, foo, my_traits > skip_list;
412 skip_list::guarded_ptr gp;
413 if ( theList.extract( gp, 5 ) ) {
417 // Destructor of gp releases internal HP guard and frees the pointer
421 template <typename Q>
422 bool extract( guarded_ptr& result, Q const& key )
424 return base_class::extract_( result.guard(), key, typename base_class::key_comparator() );
427 /// Extracts the item from the set with comparing functor \p pred
429 The function is an analog of \ref cds_nonintrusive_SkipListSet_hp_extract "extract(Q const&)"
430 but \p pred predicate is used for key comparing.
432 \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
434 \p pred must imply the same element order as the comparator used for building the set.
436 template <typename Q, typename Less>
437 bool extract_with( guarded_ptr& ptr, Q const& key, Less pred )
439 typedef cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor > wrapped_less;
440 return base_class::extract_( ptr.guard(), key, cds::opt::details::make_comparator_from_less<wrapped_less>() );
443 /// Extracts an item with minimal key from the set
445 The function searches an item with minimal key, unlinks it, and returns the item found in \p result parameter.
446 If the skip-list is empty the function returns \p false.
448 The item extracted is freed automatically by garbage collector \p GC
449 when returned \ref guarded_ptr object will be destroyed or released.
450 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
454 typedef cds::continer::SkipListSet< cds::gc::HP, foo, my_traits > skip_list;
458 skip_list::guarded_ptr gp;
459 if ( theList.extract_min( gp )) {
463 // Destructor of gp releases internal HP guard and then frees the pointer
467 bool extract_min( guarded_ptr& result)
469 return base_class::extract_min_( result.guard() );
472 /// Extracts an item with maximal key from the set
474 The function searches an item with maximal key, unlinks it, and returns the pointer to item found in \p result parameter.
475 If the skip-list is empty the function returns \p false.
477 The item found is freed by garbage collector \p GC automatically
478 when returned \ref guarded_ptr object will be destroyed or released.
479 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
483 typedef cds::container::SkipListSet< cds::gc::HP, foo, my_traits > skip_list;
487 skip_list::guarded_ptr gp;
488 if ( theList.extract_max( gp )) {
492 // Destructor of gp releases internal HP guard and then frees the pointer
496 bool extract_max( guarded_ptr& result )
498 return base_class::extract_max_( result.guard() );
501 /// Find the key \p val
502 /** \anchor cds_nonintrusive_SkipListSet_find_func
504 The function searches the item with key equal to \p val and calls the functor \p f for item found.
505 The interface of \p Func functor is:
508 void operator()( value_type& item, Q& val );
511 where \p item is the item found, \p val is the <tt>find</tt> function argument.
513 You may pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
515 The functor may change non-key fields of \p item. Note that the functor is only guarantee
516 that \p item cannot be disposed during functor is executing.
517 The functor does not serialize simultaneous access to the set's \p item. If such access is
518 possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
520 The \p val argument is non-const since it can be used as \p f functor destination i.e., the functor
521 can modify both arguments.
523 Note the hash functor specified for class \p Traits template parameter
524 should accept a parameter of type \p Q that may be not the same as \p value_type.
526 The function returns \p true if \p val is found, \p false otherwise.
528 template <typename Q, typename Func>
529 bool find( Q& val, Func f )
531 return base_class::find( val, [&f]( node_type& node, Q& v ) { cds::unref(f)( node.m_Value, v ); });
534 /// Finds the key \p val using \p pred predicate for searching
536 The function is an analog of \ref cds_nonintrusive_SkipListSet_find_func "find(Q&, Func)"
537 but \p pred is used for key comparing.
538 \p Less functor has the interface like \p std::less.
539 \p Less must imply the same element order as the comparator used for building the set.
541 template <typename Q, typename Less, typename Func>
542 bool find_with( Q& val, Less pred, Func f )
544 return base_class::find_with( val, cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor >(),
545 [&f]( node_type& node, Q& v ) { cds::unref(f)( node.m_Value, v ); } );
548 /// Find the key \p val
549 /** \anchor cds_nonintrusive_SkipListSet_find_cfunc
551 The function searches the item with key equal to \p val and calls the functor \p f for item found.
552 The interface of \p Func functor is:
555 void operator()( value_type& item, Q const& val );
558 where \p item is the item found, \p val is the <tt>find</tt> function argument.
560 You may pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
562 The functor may change non-key fields of \p item. Note that the functor is only guarantee
563 that \p item cannot be disposed during functor is executing.
564 The functor does not serialize simultaneous access to the set's \p item. If such access is
565 possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
567 Note the hash functor specified for class \p Traits template parameter
568 should accept a parameter of type \p Q that may be not the same as \p value_type.
570 The function returns \p true if \p val is found, \p false otherwise.
572 template <typename Q, typename Func>
573 bool find( Q const& val, Func f )
575 return base_class::find( val, [&f]( node_type& node, Q const& v ) { cds::unref(f)( node.m_Value, v ); });
578 /// Finds the key \p val using \p pred predicate for searching
580 The function is an analog of \ref cds_nonintrusive_SkipListSet_find_cfunc "find(Q const&, Func)"
581 but \p pred is used for key comparing.
582 \p Less functor has the interface like \p std::less.
583 \p Less must imply the same element order as the comparator used for building the set.
585 template <typename Q, typename Less, typename Func>
586 bool find_with( Q const& val, Less cmp, Func f )
588 return base_class::find_with( val, cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor >(),
589 [&f]( node_type& node, Q const& v ) { cds::unref(f)( node.m_Value, v ); } );
592 /// Find the key \p val
593 /** \anchor cds_nonintrusive_SkipListSet_find_val
595 The function searches the item with key equal to \p val
596 and returns \p true if it is found, and \p false otherwise.
598 Note the hash functor specified for class \p Traits template parameter
599 should accept a parameter of type \p Q that may be not the same as \ref value_type.
601 template <typename Q>
602 bool find( Q const& val )
604 return base_class::find( val );
607 /// Finds the key \p val using \p pred predicate for searching
609 The function is an analog of \ref cds_nonintrusive_SkipListSet_find_val "find(Q const&)"
610 but \p pred is used for key comparing.
611 \p Less functor has the interface like \p std::less.
612 \p Less must imply the same element order as the comparator used for building the set.
614 template <typename Q, typename Less>
615 bool find_with( Q const& val, Less pred )
617 return base_class::find_with( val, cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor >());
620 /// Finds \p key and return the item found
621 /** \anchor cds_nonintrusive_SkipListSet_hp_get
622 The function searches the item with key equal to \p key
623 and assigns the item found to guarded pointer \p result.
624 The function returns \p true if \p key is found, and \p false otherwise.
625 If \p key is not found the \p result parameter is left unchanged.
627 It is safe when a concurrent thread erases the item returned in \p result guarded pointer.
628 In this case the item will be freed later by garbage collector \p GC automatically
629 when \p guarded_ptr object will be destroyed or released.
630 @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
634 typedef cds::container::SkipListSet< cds::gc::HP, foo, my_traits > skip_list;
638 skip_list::guarded_ptr gp;
639 if ( theList.get( gp, 5 ) ) {
643 // Destructor of guarded_ptr releases internal HP guard
647 Note the compare functor specified for class \p Traits template parameter
648 should accept a parameter of type \p Q that can be not the same as \p value_type.
650 template <typename Q>
651 bool get( guarded_ptr& result, Q const& key )
653 return base_class::get_with_( result.guard(), key, typename base_class::key_comparator() );
656 /// Finds \p key and return the item found
658 The function is an analog of \ref cds_nonintrusive_SkipListSet_hp_get "get( guarded_ptr&, Q const&)"
659 but \p pred is used for comparing the keys.
661 \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
663 \p pred must imply the same element order as the comparator used for building the set.
665 template <typename Q, typename Less>
666 bool get_with( guarded_ptr& result, Q const& key, Less pred )
668 typedef cds::details::predicate_wrapper< node_type, Less, typename maker::value_accessor > wrapped_less;
669 return base_class::get_with_( result.guard(), key, cds::opt::details::make_comparator_from_less< wrapped_less >());
672 /// Clears the set (non-atomic).
674 The function deletes all items from the set.
675 The function is not atomic, thus, in multi-threaded environment with parallel insertions
679 assert( set.empty() );
681 the assertion could be raised.
683 For each item the \ref disposer provided by \p Traits template parameter will be called.
690 /// Checks if the set is empty
693 return base_class::empty();
696 /// Returns item count in the set
698 The value returned depends on item counter type provided by \p Traits template parameter.
699 If it is atomicity::empty_item_counter this function always returns 0.
700 Therefore, the function is not suitable for checking the set emptiness, use \ref empty
701 member function for this purpose.
705 return base_class::size();
708 /// Returns const reference to internal statistics
709 stat const& statistics() const
711 return base_class::statistics();
716 }} // namespace cds::container
718 #endif // #ifndef __CDS_CONTAINER_SKIP_LIST_SET_IMPL_H