3 #ifndef CDSLIB_INTRUSIVE_IMPL_ELLEN_BINTREE_H
4 #define CDSLIB_INTRUSIVE_IMPL_ELLEN_BINTREE_H
7 #include <cds/intrusive/details/ellen_bintree_base.h>
8 #include <cds/opt/compare.h>
9 #include <cds/details/binary_functor_wrapper.h>
10 #include <cds/urcu/details/check_deadlock.h>
12 namespace cds { namespace intrusive {
14 /// Ellen's et al binary search tree
15 /** @ingroup cds_intrusive_map
16 @ingroup cds_intrusive_tree
17 @anchor cds_intrusive_EllenBinTree
20 - [2010] F.Ellen, P.Fatourou, E.Ruppert, F.van Breugel "Non-blocking Binary Search Tree"
22 %EllenBinTree is an <i>unbalanced</i> leaf-oriented binary search tree that implements the <i>set</i>
23 abstract data type. Nodes maintains child pointers but not parent pointers.
24 Every internal node has exactly two children, and all data of type \p T currently in
25 the tree are stored in the leaves. Internal nodes of the tree are used to direct \p find()
26 operation along the path to the correct leaf. The keys (of \p Key type) stored in internal nodes
27 may or may not be in the set. \p Key type is a subset of \p T type.
28 There should be exactly defined a key extracting functor for converting object of type \p T to
29 object of type \p Key.
31 Due to \p extract_min() and \p extract_max() member functions the \p %EllenBinTree can act as
32 a <i>priority queue</i>. In this case you should provide unique compound key, for example,
33 the priority value plus some uniformly distributed random value.
35 @note In the current implementation we do not use helping technique described in the original paper.
36 In Hazard Pointer schema helping is too complicated and does not give any observable benefits.
37 Instead of helping, when a thread encounters a concurrent operation it just spins waiting for
38 the operation done. Such solution allows greatly simplify the implementation of tree.
40 @warning Recall the tree is <b>unbalanced</b>. The complexity of operations is <tt>O(log N)</tt>
41 for uniformly distributed random keys, but in worst case the complexity is <tt>O(N)</tt>.
43 @note Do not include <tt><cds/intrusive/impl/ellen_bintree.h></tt> header file explicitly.
44 There are header file for each GC type:
45 - <tt><cds/intrusive/ellen_bintree_hp.h></tt> - for Hazard Pointer GC \p cds::gc::HP
46 - <tt><cds/intrusive/ellen_bintree_dhp.h></tt> - for Dynamic Hazard Pointer GC \p cds::gc::DHP
47 - <tt><cds/intrusive/ellen_bintree_rcu.h></tt> - for RCU (see \ref cds_intrusive_EllenBinTree_rcu "RCU-based EllenBinTree")
49 <b>Template arguments</b> :
50 - \p GC - garbage collector, possible types are cds::gc::HP, cds::gc::DHP.
51 - \p Key - key type, a subset of \p T
52 - \p T - type to be stored in tree's leaf nodes. The type must be based on \p ellen_bintree::node
53 (for \p ellen_bintree::base_hook) or it must have a member of type \p ellen_bintree::node
54 (for \p ellen_bintree::member_hook).
55 - \p Traits - tree traits, default is \p ellen_bintree::traits
56 It is possible to declare option-based tree with \p ellen_bintree::make_traits metafunction
57 instead of \p Traits template argument.
59 @anchor cds_intrusive_EllenBinTree_less
60 <b>Predicate requirements</b>
62 \p Traits::less, \p Traits::compare and other predicates using with member fuctions should accept at least parameters
63 of type \p T and \p Key in any combination.
64 For example, for \p Foo struct with \p std::string key field the appropiate \p less functor is:
66 struct Foo: public cds::intrusive::ellen_bintree::node< ... >
73 bool operator()( Foo const& v1, Foo const& v2 ) const
74 { return v1.m_strKey < v2.m_strKey ; }
76 bool operator()( Foo const& v, std::string const& s ) const
77 { return v.m_strKey < s ; }
79 bool operator()( std::string const& s, Foo const& v ) const
80 { return s < v.m_strKey ; }
82 // Support comparing std::string and char const *
83 bool operator()( std::string const& s, char const * p ) const
84 { return s.compare(p) < 0 ; }
86 bool operator()( Foo const& v, char const * p ) const
87 { return v.m_strKey.compare(p) < 0 ; }
89 bool operator()( char const * p, std::string const& s ) const
90 { return s.compare(p) > 0; }
92 bool operator()( char const * p, Foo const& v ) const
93 { return v.m_strKey.compare(p) > 0; }
97 Usage examples see \ref cds_intrusive_EllenBinTree_usage "here"
102 #ifdef CDS_DOXYGEN_INVOKED
103 class Traits = ellen_bintree::traits
111 typedef GC gc; ///< Garbage collector
112 typedef Key key_type; ///< type of a key to be stored in internal nodes; key is a part of \p value_type
113 typedef T value_type; ///< type of value stored in the binary tree
114 typedef Traits traits; ///< Traits template parameter
116 typedef typename traits::hook hook; ///< hook type
117 typedef typename hook::node_type node_type; ///< node type
118 typedef typename traits::disposer disposer; ///< leaf node disposer
119 typedef typename traits::back_off back_off; ///< back-off strategy
121 typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
124 typedef cds::intrusive::ellen_bintree::implementation_tag implementation_tag;
129 typedef ellen_bintree::base_node< gc > tree_node; ///< Base type of tree node
130 typedef node_type leaf_node; ///< Leaf node type
131 typedef ellen_bintree::node_types< gc, key_type, typename leaf_node::tag > node_factory;
132 typedef typename node_factory::internal_node_type internal_node; ///< Internal node type
133 typedef typename node_factory::update_desc_type update_desc; ///< Update descriptor
134 typedef typename update_desc::update_ptr update_ptr; ///< Marked pointer to update descriptor
138 # ifdef CDS_DOXYGEN_INVOKED
139 typedef implementation_defined key_comparator; ///< key compare functor based on \p Traits::compare and \p Traits::less
140 typedef typename get_node_traits< value_type, node_type, hook>::type node_traits; ///< Node traits
142 typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;
143 struct node_traits: public get_node_traits< value_type, node_type, hook>::type
145 static internal_node const& to_internal_node( tree_node const& n )
147 assert( n.is_internal() );
148 return static_cast<internal_node const&>( n );
151 static leaf_node const& to_leaf_node( tree_node const& n )
153 assert( n.is_leaf() );
154 return static_cast<leaf_node const&>( n );
159 typedef typename traits::item_counter item_counter; ///< Item counting policy
160 typedef typename traits::memory_model memory_model; ///< Memory ordering, see \p cds::opt::memory_model
161 typedef typename traits::stat stat; ///< internal statistics type
162 typedef typename traits::key_extractor key_extractor; ///< key extracting functor
164 typedef typename traits::node_allocator node_allocator; ///< Allocator for internal node
165 typedef typename traits::update_desc_allocator update_desc_allocator; ///< Update descriptor allocator
167 static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 8; ///< Count of hazard pointer required for the algorithm
171 typedef ellen_bintree::details::compare< key_type, value_type, key_comparator, node_traits > node_compare;
173 typedef cds::details::Allocator< internal_node, node_allocator > cxx_node_allocator;
174 typedef cds::details::Allocator< update_desc, update_desc_allocator > cxx_update_desc_allocator;
176 struct search_result {
181 Guard_updGrandParent,
184 // end of guard indices
188 typedef typename gc::template GuardArray< guard_count > guard_array;
191 internal_node * pGrandParent;
192 internal_node * pParent;
194 update_ptr updParent;
195 update_ptr updGrandParent;
196 bool bRightLeaf; // true if pLeaf is right child of pParent, false otherwise
197 bool bRightParent; // true if pParent is right child of pGrandParent, false otherwise
200 :pGrandParent( nullptr )
204 ,bRightParent( false )
211 internal_node m_Root; ///< Tree root node (key= Infinite2)
212 leaf_node m_LeafInf1; ///< Infinite leaf 1 (key= Infinite1)
213 leaf_node m_LeafInf2; ///< Infinite leaf 2 (key= Infinite2)
216 item_counter m_ItemCounter; ///< item counter
217 mutable stat m_Stat; ///< internal statistics
221 static void free_leaf_node( value_type * p )
226 internal_node * alloc_internal_node() const
228 m_Stat.onInternalNodeCreated();
229 internal_node * pNode = cxx_node_allocator().New();
233 static void free_internal_node( internal_node * pNode )
235 cxx_node_allocator().Delete( pNode );
238 struct internal_node_deleter {
239 void operator()( internal_node * p) const
241 free_internal_node( p );
245 typedef std::unique_ptr< internal_node, internal_node_deleter> unique_internal_node_ptr;
247 update_desc * alloc_update_desc() const
249 m_Stat.onUpdateDescCreated();
250 return cxx_update_desc_allocator().New();
253 static void free_update_desc( update_desc * pDesc )
255 cxx_update_desc_allocator().Delete( pDesc );
258 void retire_node( tree_node * pNode ) const
260 if ( pNode->is_leaf() ) {
261 assert( static_cast<leaf_node *>( pNode ) != &m_LeafInf1 );
262 assert( static_cast<leaf_node *>( pNode ) != &m_LeafInf2 );
264 gc::template retire( node_traits::to_value_ptr( static_cast<leaf_node *>( pNode )), free_leaf_node );
267 assert( static_cast<internal_node *>( pNode ) != &m_Root );
268 m_Stat.onInternalNodeDeleted();
270 gc::template retire( static_cast<internal_node *>( pNode ), free_internal_node );
274 void retire_update_desc( update_desc * p ) const
276 m_Stat.onUpdateDescDeleted();
277 gc::template retire( p, free_update_desc );
280 void make_empty_tree()
282 m_Root.infinite_key( 2 );
283 m_LeafInf1.infinite_key( 1 );
284 m_LeafInf2.infinite_key( 2 );
285 m_Root.m_pLeft.store( &m_LeafInf1, memory_model::memory_order_relaxed );
286 m_Root.m_pRight.store( &m_LeafInf2, memory_model::memory_order_release );
291 /// Default constructor
294 static_assert( !std::is_same< key_extractor, opt::none >::value, "The key extractor option must be specified" );
306 The function inserts \p val in the tree if it does not contain
307 an item with key equal to \p val.
309 Returns \p true if \p val is placed into the tree, \p false otherwise.
311 bool insert( value_type& val )
313 return insert( val, []( value_type& ) {} );
318 This function is intended for derived non-intrusive containers.
320 The function allows to split creating of new item into two part:
321 - create item with key only
322 - insert new item into the tree
323 - if inserting is success, calls \p f functor to initialize value-field of \p val.
325 The functor signature is:
327 void func( value_type& val );
329 where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
330 \p val no any other changes could be made on this tree's item by concurrent threads.
331 The user-defined functor is called only if the inserting is success.
333 template <typename Func>
334 bool insert( value_type& val, Func f )
336 typename gc::Guard guardInsert;
337 guardInsert.assign( &val );
339 unique_internal_node_ptr pNewInternal;
344 if ( search( res, val, node_compare() )) {
345 if ( pNewInternal.get() )
346 m_Stat.onInternalNodeDeleted() ; // unique_internal_node_ptr deletes internal node
347 m_Stat.onInsertFailed();
351 if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean ) {
353 if ( !pNewInternal.get() )
354 pNewInternal.reset( alloc_internal_node() );
356 if ( try_insert( val, pNewInternal.get(), res )) {
358 pNewInternal.release(); // internal node is linked into the tree and should not be deleted
364 m_Stat.onInsertRetry();
368 m_Stat.onInsertSuccess();
374 The operation performs inserting or changing data with lock-free manner.
376 If the item \p val is not found in the set, then \p val is inserted into the set
377 iff \p bAllowInsert is \p true.
378 Otherwise, the functor \p func is called with item found.
379 The functor \p func signature is:
381 void func( bool bNew, value_type& item, value_type& val );
384 - \p bNew - \p true if the item has been inserted, \p false otherwise
385 - \p item - item of the set
386 - \p val - argument \p val passed into the \p %update() function
387 If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
388 refer to the same thing.
390 The functor can change non-key fields of the \p item; however, \p func must guarantee
391 that during changing no any other modifications could be made on this item by concurrent threads.
393 Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
394 i.e. the node has been inserted or updated,
395 \p second is \p true if new item has been added or \p false if the item with \p key
398 @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
400 template <typename Func>
401 std::pair<bool, bool> update( value_type& val, Func func, bool bAllowInsert = true )
403 typename gc::Guard guardInsert;
404 guardInsert.assign( &val );
406 unique_internal_node_ptr pNewInternal;
411 if ( search( res, val, node_compare() )) {
412 func( false, *node_traits::to_value_ptr( res.pLeaf ), val );
413 if ( pNewInternal.get() )
414 m_Stat.onInternalNodeDeleted() ; // unique_internal_node_ptr deletes internal node
415 m_Stat.onEnsureExist();
416 return std::make_pair( true, false );
419 if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean ) {
421 return std::make_pair( false, false );
423 if ( !pNewInternal.get() )
424 pNewInternal.reset( alloc_internal_node() );
426 if ( try_insert( val, pNewInternal.get(), res )) {
427 func( true, val, val );
428 pNewInternal.release() ; // internal node has been linked into the tree and should not be deleted
434 m_Stat.onEnsureRetry();
438 m_Stat.onEnsureNew();
439 return std::make_pair( true, true );
442 // Deprecated, us update()
443 template <typename Func>
444 std::pair<bool, bool> ensure( value_type& val, Func func )
446 return update( val, func, true );
450 /// Unlinks the item \p val from the tree
452 The function searches the item \p val in the tree and unlink it from the tree
453 if it is found and is equal to \p val.
455 Difference between \ref erase and \p unlink functions: \p erase finds <i>a key</i>
456 and deletes the item found. \p unlink finds an item by key and deletes it
457 only if \p val is a node, i.e. the pointer to item found is equal to <tt> &val </tt>.
459 The \p disposer specified in \p Traits class template parameter is called
460 by garbage collector \p GC asynchronously.
462 The function returns \p true if success and \p false otherwise.
464 bool unlink( value_type& val )
466 return erase_( val, node_compare(),
467 []( value_type const& v, leaf_node const& n ) -> bool { return &v == node_traits::to_value_ptr( n ); },
468 [](value_type const&) {} );
471 /// Deletes the item from the tree
472 /** \anchor cds_intrusive_EllenBinTree_erase
473 The function searches an item with key equal to \p key in the tree,
474 unlinks it from the tree, and returns \p true.
475 If the item with key equal to \p key is not found the function return \p false.
477 Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
479 template <typename Q>
480 bool erase( const Q& key )
482 return erase_( key, node_compare(),
483 []( Q const&, leaf_node const& ) -> bool { return true; },
484 [](value_type const&) {} );
487 /// Delete the item from the tree with comparing functor \p pred
489 The function is an analog of \ref cds_intrusive_EllenBinTree_erase "erase(Q const&)"
490 but \p pred predicate is used for key comparing.
491 \p Less has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_less
492 "Predicate requirements".
493 \p pred must imply the same element order as the comparator used for building the tree.
495 template <typename Q, typename Less>
496 bool erase_with( const Q& key, Less pred )
499 typedef ellen_bintree::details::compare<
502 opt::details::make_comparator_from_less<Less>,
506 return erase_( key, compare_functor(),
507 []( Q const&, leaf_node const& ) -> bool { return true; },
508 [](value_type const&) {} );
511 /// Deletes the item from the tree
512 /** \anchor cds_intrusive_EllenBinTree_erase_func
513 The function searches an item with key equal to \p key in the tree,
514 call \p f functor with item found, unlinks it from the tree, and returns \p true.
515 The \ref disposer specified in \p Traits class template parameter is called
516 by garbage collector \p GC asynchronously.
518 The \p Func interface is
521 void operator()( value_type const& item );
525 If the item with key equal to \p key is not found the function return \p false.
527 Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
529 template <typename Q, typename Func>
530 bool erase( Q const& key, Func f )
532 return erase_( key, node_compare(),
533 []( Q const&, leaf_node const& ) -> bool { return true; },
537 /// Delete the item from the tree with comparing functor \p pred
539 The function is an analog of \ref cds_intrusive_EllenBinTree_erase_func "erase(Q const&, Func)"
540 but \p pred predicate is used for key comparing.
541 \p Less has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_less
542 "Predicate requirements".
543 \p pred must imply the same element order as the comparator used for building the tree.
545 template <typename Q, typename Less, typename Func>
546 bool erase_with( Q const& key, Less pred, Func f )
549 typedef ellen_bintree::details::compare<
552 opt::details::make_comparator_from_less<Less>,
556 return erase_( key, compare_functor(),
557 []( Q const&, leaf_node const& ) -> bool { return true; },
561 /// Extracts an item with minimal key from the tree
563 The function searches an item with minimal key, unlinks it, and returns a guarded pointer to an item found.
564 If the tree is empty the function returns an empty guarded pointer.
566 @note Due the concurrent nature of the tree, the function extracts <i>nearly</i> minimum key.
567 It means that the function gets leftmost leaf of the tree and tries to unlink it.
568 During unlinking, a concurrent thread may insert an item with key less than leftmost item's key.
569 So, the function returns the item with minimum key at the moment of tree traversing.
571 The returned \p guarded_ptr prevents disposer invocation for returned item,
572 see \p cds::gc::guarded_ptr for explanation.
573 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
575 guarded_ptr extract_min()
578 extract_min_( gp.guard() );
582 /// Extracts an item with maximal key from the tree
584 The function searches an item with maximal key, unlinks it, and returns a guarded pointer to an item found.
585 If the tree is empty the function returns an empty \p guarded_ptr.
587 @note Due the concurrent nature of the tree, the function extracts <i>nearly</i> maximal key.
588 It means that the function gets rightmost leaf of the tree and tries to unlink it.
589 During unlinking, a concurrent thread may insert an item with key great than rightmost item's key.
590 So, the function returns the item with maximal key at the moment of tree traversing.
592 The returned \p guarded_ptr prevents disposer invocation for returned item,
593 see cds::gc::guarded_ptr for explanation.
594 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
596 guarded_ptr extract_max()
599 extract_max_( gp.guard());
603 /// Extracts an item from the tree
604 /** \anchor cds_intrusive_EllenBinTree_extract
605 The function searches an item with key equal to \p key in the tree,
606 unlinks it, and returns a guarded pointer to an item found.
607 If the item is not found the function returns an empty \p guarded_ptr.
609 \p guarded_ptr prevents disposer invocation for returned item,
610 see cds::gc::guarded_ptr for explanation.
611 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
613 template <typename Q>
614 guarded_ptr extract( Q const& key )
617 extract_( gp.guard(), key );
621 /// Extracts an item from the tree using \p pred for searching
623 The function is an analog of \ref cds_intrusive_EllenBinTree_extract "extract(Q const&)"
624 but \p pred is used for key compare.
625 \p Less has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_less
626 "Predicate requirements".
627 \p pred must imply the same element order as the comparator used for building the tree.
629 template <typename Q, typename Less>
630 guarded_ptr extract_with( Q const& key, Less pred )
633 extract_with_( gp.guard(), key, pred );
637 /// Checks whether the set contains \p key
639 The function searches the item with key equal to \p key
640 and returns \p true if it is found, and \p false otherwise.
642 template <typename Q>
643 bool contains( Q const& key ) const
646 if ( search( res, key, node_compare() )) {
647 m_Stat.onFindSuccess();
651 m_Stat.onFindFailed();
655 // Deprecated, use contains()
656 template <typename Q>
657 bool find( Q const& key ) const
659 return contains( key );
663 /// Checks whether the set contains \p key using \p pred predicate for searching
665 The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
666 \p Less functor has the interface like \p std::less.
667 \p Less must imply the same element order as the comparator used for building the set.
669 template <typename Q, typename Less>
670 bool contains( Q const& key, Less pred ) const
673 typedef ellen_bintree::details::compare<
676 opt::details::make_comparator_from_less<Less>,
681 if ( search( res, key, compare_functor() )) {
682 m_Stat.onFindSuccess();
685 m_Stat.onFindFailed();
689 // Deprecated, use contains()
690 template <typename Q, typename Less>
691 bool find_with( Q const& key, Less pred ) const
693 return contains( key, pred );
697 /// Finds the key \p key
698 /** @anchor cds_intrusive_EllenBinTree_find_func
699 The function searches the item with key equal to \p key and calls the functor \p f for item found.
700 The interface of \p Func functor is:
703 void operator()( value_type& item, Q& key );
706 where \p item is the item found, \p key is the <tt>find</tt> function argument.
708 The functor can change non-key fields of \p item. Note that the functor is only guarantee
709 that \p item cannot be disposed during functor is executing.
710 The functor does not serialize simultaneous access to the tree \p item. If such access is
711 possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
713 The function returns \p true if \p key is found, \p false otherwise.
715 template <typename Q, typename Func>
716 bool find( Q& key, Func f ) const
718 return find_( key, f );
721 template <typename Q, typename Func>
722 bool find( Q const& key, Func f ) const
724 return find_( key, f );
728 /// Finds the key \p key with comparing functor \p pred
730 The function is an analog of \ref cds_intrusive_EllenBinTree_find_func "find(Q&, Func)"
731 but \p pred is used for key comparison.
732 \p Less functor has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_less
733 "Predicate requirements".
734 \p pred must imply the same element order as the comparator used for building the tree.
736 template <typename Q, typename Less, typename Func>
737 bool find_with( Q& key, Less pred, Func f ) const
739 return find_with_( key, pred, f );
742 template <typename Q, typename Less, typename Func>
743 bool find_with( Q const& key, Less pred, Func f ) const
745 return find_with_( key, pred, f );
749 /// Finds \p key and returns the item found
750 /** @anchor cds_intrusive_EllenBinTree_get
751 The function searches the item with key equal to \p key and returns the item found as \p guarded_ptr object.
752 The function returns an empty guarded pointer is \p key is not found.
754 \p guarded_ptr prevents disposer invocation for returned item,
755 see \p cds::gc::guarded_ptr for explanation.
756 @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
758 template <typename Q>
759 guarded_ptr get( Q const& key ) const
762 get_( gp.guard(), key );
766 /// Finds \p key with predicate \p pred and returns the item found
768 The function is an analog of \ref cds_intrusive_EllenBinTree_get "get(Q const&)"
769 but \p pred is used for key comparing.
770 \p Less functor has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_less
771 "Predicate requirements".
772 \p pred must imply the same element order as the comparator used for building the tree.
774 template <typename Q, typename Less>
775 guarded_ptr get_with( Q const& key, Less pred ) const
778 get_with_( gp.guard(), key, pred );
782 /// Checks if the tree is empty
785 return m_Root.m_pLeft.load( memory_model::memory_order_relaxed )->is_leaf();
788 /// Clears the tree (thread safe, not atomic)
790 The function unlink all items from the tree.
791 The function is thread safe but not atomic: in multi-threaded environment with parallel insertions
795 assert( tree.empty() );
797 the assertion could be raised.
799 For each leaf the \p disposer will be called after unlinking.
809 /// Clears the tree (not thread safe)
811 This function is not thread safe and may be called only when no other thread deals with the tree.
812 The function is used in the tree destructor.
817 internal_node * pParent = nullptr;
818 internal_node * pGrandParent = nullptr;
819 tree_node * pLeaf = const_cast<internal_node *>( &m_Root );
822 while ( pLeaf->is_internal() ) {
823 pGrandParent = pParent;
824 pParent = static_cast<internal_node *>( pLeaf );
825 pLeaf = pParent->m_pLeft.load( memory_model::memory_order_relaxed );
828 if ( pLeaf->infinite_key()) {
833 // Remove leftmost leaf and its parent node
834 assert( pGrandParent );
836 assert( pLeaf->is_leaf() );
838 pGrandParent->m_pLeft.store( pParent->m_pRight.load( memory_model::memory_order_relaxed ), memory_model::memory_order_relaxed );
839 free_leaf_node( node_traits::to_value_ptr( static_cast<leaf_node *>( pLeaf ) ) );
840 free_internal_node( pParent );
844 /// Returns item count in the tree
846 Only leaf nodes containing user data are counted.
848 The value returned depends on item counter type provided by \p Traits template parameter.
849 If it is \p atomicity::empty_item_counter this function always returns 0.
850 The function is not suitable for checking the tree emptiness, use \p empty()
851 member function for this purpose.
855 return m_ItemCounter;
858 /// Returns const reference to internal statistics
859 stat const& statistics() const
864 /// Checks internal consistency (not atomic, not thread-safe)
866 The debugging function to check internal consistency of the tree.
868 bool check_consistency() const
870 return check_consistency( &m_Root );
876 bool check_consistency( internal_node const * pRoot ) const
878 tree_node * pLeft = pRoot->m_pLeft.load( atomics::memory_order_relaxed );
879 tree_node * pRight = pRoot->m_pRight.load( atomics::memory_order_relaxed );
883 if ( node_compare()( *pLeft, *pRoot ) < 0
884 && node_compare()( *pRoot, *pRight ) <= 0
885 && node_compare()( *pLeft, *pRight ) < 0 )
888 if ( pLeft->is_internal() )
889 bRet = check_consistency( static_cast<internal_node *>( pLeft ) );
892 if ( bRet && pRight->is_internal() )
893 bRet = bRet && check_consistency( static_cast<internal_node *>( pRight ));
901 static tree_node * protect_child_node( search_result& res, internal_node * pParent, bool bRight, update_ptr updParent )
903 tree_node * p = bRight
904 ? res.guards.protect( search_result::Guard_Leaf, pParent->m_pRight,
905 []( tree_node * p ) -> internal_node* { return static_cast<internal_node *>(p);})
906 : res.guards.protect( search_result::Guard_Leaf, pParent->m_pLeft,
907 []( tree_node * p ) -> internal_node* { return static_cast<internal_node *>(p);});
908 if ( p && p->is_leaf() )
909 res.guards.assign( search_result::Guard_Leaf, node_traits::to_value_ptr( static_cast<leaf_node *>( p )));
911 // child node is guarded
912 // See whether pParent->m_pUpdate has not been changed
913 if ( pParent->m_pUpdate.load( memory_model::memory_order_acquire ) != updParent ) {
914 // update has been changed - returns nullptr as a flag to search retry
920 static update_ptr search_protect_update( search_result& res, atomics::atomic<update_ptr> const& src )
922 return res.guards.protect( search_result::Guard_updParent, src, [](update_ptr p) -> update_desc* { return p.ptr(); });
925 template <typename KeyValue, typename Compare>
926 bool search( search_result& res, KeyValue const& key, Compare cmp ) const
928 internal_node * pParent;
929 internal_node * pGrandParent = nullptr;
930 update_ptr updParent;
931 update_ptr updGrandParent;
933 bool bRightParent = false;
939 //pGrandParent = nullptr;
942 tree_node * pLeaf = const_cast<internal_node *>( &m_Root );
943 while ( pLeaf->is_internal() ) {
944 res.guards.copy( search_result::Guard_GrandParent, search_result::Guard_Parent );
945 pGrandParent = pParent;
946 res.guards.copy( search_result::Guard_Parent, search_result::Guard_Leaf );
947 pParent = static_cast<internal_node *>( pLeaf );
948 bRightParent = bRightLeaf;
949 res.guards.copy( search_result::Guard_updGrandParent, search_result::Guard_updParent );
950 updGrandParent = updParent;
952 updParent = search_protect_update( res, pParent->m_pUpdate );
954 switch ( updParent.bits() ) {
955 case update_desc::DFlag:
956 case update_desc::Mark:
957 m_Stat.onSearchRetry();
961 nCmp = cmp( key, *pParent );
962 bRightLeaf = nCmp >= 0;
964 pLeaf = protect_child_node( res, pParent, bRightLeaf, updParent );
966 m_Stat.onSearchRetry();
971 assert( pLeaf->is_leaf() );
972 nCmp = cmp( key, *static_cast<leaf_node *>(pLeaf) );
974 res.pGrandParent = pGrandParent;
975 res.pParent = pParent;
976 res.pLeaf = static_cast<leaf_node *>( pLeaf );
977 res.updParent = updParent;
978 res.updGrandParent = updGrandParent;
979 res.bRightParent = bRightParent;
980 res.bRightLeaf = bRightLeaf;
985 bool search_min( search_result& res ) const
987 internal_node * pParent;
988 internal_node * pGrandParent;
989 update_ptr updParent;
990 update_ptr updGrandParent;
994 pGrandParent = nullptr;
996 tree_node * pLeaf = const_cast<internal_node *>( &m_Root );
997 while ( pLeaf->is_internal() ) {
998 res.guards.copy( search_result::Guard_GrandParent, search_result::Guard_Parent );
999 pGrandParent = pParent;
1000 res.guards.copy( search_result::Guard_Parent, search_result::Guard_Leaf );
1001 pParent = static_cast<internal_node *>( pLeaf );
1002 res.guards.copy( search_result::Guard_updGrandParent, search_result::Guard_updParent );
1003 updGrandParent = updParent;
1005 updParent = search_protect_update( res, pParent->m_pUpdate );
1007 switch ( updParent.bits() ) {
1008 case update_desc::DFlag:
1009 case update_desc::Mark:
1010 m_Stat.onSearchRetry();
1014 pLeaf = protect_child_node( res, pParent, false, updParent );
1016 m_Stat.onSearchRetry();
1021 if ( pLeaf->infinite_key())
1024 res.pGrandParent = pGrandParent;
1025 res.pParent = pParent;
1026 assert( pLeaf->is_leaf() );
1027 res.pLeaf = static_cast<leaf_node *>( pLeaf );
1028 res.updParent = updParent;
1029 res.updGrandParent = updGrandParent;
1030 res.bRightParent = false;
1031 res.bRightLeaf = false;
1036 bool search_max( search_result& res ) const
1038 internal_node * pParent;
1039 internal_node * pGrandParent;
1040 update_ptr updParent;
1041 update_ptr updGrandParent;
1043 bool bRightParent = false;
1047 pGrandParent = nullptr;
1048 updParent = nullptr;
1050 tree_node * pLeaf = const_cast<internal_node *>( &m_Root );
1051 while ( pLeaf->is_internal() ) {
1052 res.guards.copy( search_result::Guard_GrandParent, search_result::Guard_Parent );
1053 pGrandParent = pParent;
1054 res.guards.copy( search_result::Guard_Parent, search_result::Guard_Leaf );
1055 pParent = static_cast<internal_node *>( pLeaf );
1056 bRightParent = bRightLeaf;
1057 res.guards.copy( search_result::Guard_updGrandParent, search_result::Guard_updParent );
1058 updGrandParent = updParent;
1060 updParent = search_protect_update( res, pParent->m_pUpdate );
1062 switch ( updParent.bits() ) {
1063 case update_desc::DFlag:
1064 case update_desc::Mark:
1065 m_Stat.onSearchRetry();
1069 bRightLeaf = !pParent->infinite_key();
1070 pLeaf = protect_child_node( res, pParent, bRightLeaf, updParent );
1072 m_Stat.onSearchRetry();
1077 if ( pLeaf->infinite_key())
1080 res.pGrandParent = pGrandParent;
1081 res.pParent = pParent;
1082 assert( pLeaf->is_leaf() );
1083 res.pLeaf = static_cast<leaf_node *>( pLeaf );
1084 res.updParent = updParent;
1085 res.updGrandParent = updGrandParent;
1086 res.bRightParent = bRightParent;
1087 res.bRightLeaf = bRightLeaf;
1093 void help( update_ptr pUpdate )
1095 // pUpdate must be guarded!
1096 switch ( pUpdate.bits() ) {
1097 case update_desc::IFlag:
1098 help_insert( pUpdate.ptr() );
1099 m_Stat.onHelpInsert();
1101 case update_desc::DFlag:
1102 help_delete( pUpdate.ptr() );
1103 m_Stat.onHelpDelete();
1105 case update_desc::Mark:
1106 //m_Stat.onHelpMark();
1107 //help_marked( pUpdate.ptr() );
1113 void help_insert( update_desc * pOp )
1115 // pOp must be guarded
1117 tree_node * pLeaf = static_cast<tree_node *>( pOp->iInfo.pLeaf );
1118 if ( pOp->iInfo.bRightLeaf ) {
1119 CDS_VERIFY( pOp->iInfo.pParent->m_pRight.compare_exchange_strong( pLeaf, static_cast<tree_node *>( pOp->iInfo.pNew ),
1120 memory_model::memory_order_relaxed, atomics::memory_order_relaxed ));
1123 CDS_VERIFY( pOp->iInfo.pParent->m_pLeft.compare_exchange_strong( pLeaf, static_cast<tree_node *>( pOp->iInfo.pNew ),
1124 memory_model::memory_order_relaxed, atomics::memory_order_relaxed ));
1128 update_ptr cur( pOp, update_desc::IFlag );
1129 CDS_VERIFY( pOp->iInfo.pParent->m_pUpdate.compare_exchange_strong( cur, pOp->iInfo.pParent->null_update_desc(),
1130 memory_model::memory_order_release, atomics::memory_order_relaxed ));
1133 bool check_delete_precondition( search_result& res ) const
1135 // precondition: all member of res must be guarded
1137 assert( res.pGrandParent != nullptr );
1140 static_cast<internal_node *>(
1142 ? res.pGrandParent->m_pRight.load(memory_model::memory_order_relaxed)
1143 : res.pGrandParent->m_pLeft.load(memory_model::memory_order_relaxed)
1146 static_cast<leaf_node *>(
1148 ? res.pParent->m_pRight.load(memory_model::memory_order_relaxed)
1149 : res.pParent->m_pLeft.load(memory_model::memory_order_relaxed)
1153 bool help_delete( update_desc * pOp )
1155 // precondition: pOp must be guarded
1157 update_ptr pUpdate( pOp->dInfo.pUpdateParent );
1158 update_ptr pMark( pOp, update_desc::Mark );
1159 if ( pOp->dInfo.pParent->m_pUpdate.compare_exchange_strong( pUpdate, pMark, // *
1160 memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1164 retire_node( pOp->dInfo.pParent );
1165 retire_node( pOp->dInfo.pLeaf );
1166 retire_update_desc( pOp );
1169 else if ( pUpdate == pMark ) {
1170 // some other thread is processing help_marked()
1172 m_Stat.onHelpMark();
1176 // Undo grandparent dInfo
1177 update_ptr pDel( pOp, update_desc::DFlag );
1178 if ( pOp->dInfo.pGrandParent->m_pUpdate.compare_exchange_strong( pDel, pOp->dInfo.pGrandParent->null_update_desc(),
1179 memory_model::memory_order_release, atomics::memory_order_relaxed ))
1181 retire_update_desc( pOp );
1187 static tree_node * protect_sibling( typename gc::Guard& guard, atomics::atomic<tree_node *>& sibling )
1189 tree_node * pSibling = guard.protect( sibling, [](tree_node * p) -> internal_node* { return static_cast<internal_node *>(p); } );
1190 if ( pSibling->is_leaf() )
1191 guard.assign( node_traits::to_value_ptr( static_cast<leaf_node *>( pSibling )));
1195 void help_marked( update_desc * pOp )
1197 // precondition: pOp must be guarded
1199 tree_node * pParent = pOp->dInfo.pParent;
1201 typename gc::Guard guard;
1202 tree_node * pOpposite = protect_sibling( guard, pOp->dInfo.bRightLeaf ? pOp->dInfo.pParent->m_pLeft : pOp->dInfo.pParent->m_pRight );
1204 if ( pOp->dInfo.bRightParent ) {
1205 CDS_VERIFY( pOp->dInfo.pGrandParent->m_pRight.compare_exchange_strong( pParent, pOpposite,
1206 memory_model::memory_order_release, atomics::memory_order_relaxed ));
1209 CDS_VERIFY( pOp->dInfo.pGrandParent->m_pLeft.compare_exchange_strong( pParent, pOpposite,
1210 memory_model::memory_order_release, atomics::memory_order_relaxed ));
1213 update_ptr upd( pOp, update_desc::DFlag );
1214 CDS_VERIFY( pOp->dInfo.pGrandParent->m_pUpdate.compare_exchange_strong( upd, pOp->dInfo.pGrandParent->null_update_desc(),
1215 memory_model::memory_order_release, atomics::memory_order_relaxed ));
1218 bool try_insert( value_type& val, internal_node * pNewInternal, search_result& res )
1220 assert( res.updParent.bits() == update_desc::Clean );
1221 assert( res.pLeaf->is_leaf() );
1223 // check search result
1224 if ( (res.bRightLeaf
1225 ? res.pParent->m_pRight.load( memory_model::memory_order_acquire )
1226 : res.pParent->m_pLeft.load( memory_model::memory_order_acquire )) == res.pLeaf ) {
1227 leaf_node * pNewLeaf = node_traits::to_node_ptr( val );
1229 int nCmp = node_compare()(val, *res.pLeaf);
1231 if ( res.pGrandParent ) {
1232 assert( !res.pLeaf->infinite_key() );
1233 pNewInternal->infinite_key( 0 );
1234 key_extractor()(pNewInternal->m_Key, *node_traits::to_value_ptr( res.pLeaf ));
1237 assert( res.pLeaf->infinite_key() == tree_node::key_infinite1 );
1238 pNewInternal->infinite_key( 1 );
1240 pNewInternal->m_pLeft.store( static_cast<tree_node *>(pNewLeaf), memory_model::memory_order_relaxed );
1241 pNewInternal->m_pRight.store( static_cast<tree_node *>(res.pLeaf), memory_model::memory_order_release );
1244 assert( !res.pLeaf->is_internal() );
1246 pNewInternal->infinite_key( 0 );
1247 key_extractor()(pNewInternal->m_Key, val);
1248 pNewInternal->m_pLeft.store( static_cast<tree_node *>(res.pLeaf), memory_model::memory_order_relaxed );
1249 pNewInternal->m_pRight.store( static_cast<tree_node *>(pNewLeaf), memory_model::memory_order_release );
1250 assert( !res.pLeaf->infinite_key() );
1253 typename gc::Guard guard;
1254 update_desc * pOp = alloc_update_desc();
1255 guard.assign( pOp );
1257 pOp->iInfo.pParent = res.pParent;
1258 pOp->iInfo.pNew = pNewInternal;
1259 pOp->iInfo.pLeaf = res.pLeaf;
1260 pOp->iInfo.bRightLeaf = res.bRightLeaf;
1262 update_ptr updCur( res.updParent.ptr() );
1263 if ( res.pParent->m_pUpdate.compare_exchange_strong( updCur, update_ptr( pOp, update_desc::IFlag ),
1264 memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) {
1267 retire_update_desc( pOp );
1271 m_Stat.onUpdateDescDeleted();
1272 free_update_desc( pOp );
1279 template <typename Q, typename Compare, typename Equal, typename Func>
1280 bool erase_( Q const& val, Compare cmp, Equal eq, Func f )
1282 update_desc * pOp = nullptr;
1287 if ( !search( res, val, cmp ) || !eq( val, *res.pLeaf ) ) {
1289 retire_update_desc( pOp );
1290 m_Stat.onEraseFailed();
1294 if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean ) {
1296 pOp = alloc_update_desc();
1297 if ( check_delete_precondition( res ) ) {
1298 typename gc::Guard guard;
1299 guard.assign( pOp );
1301 pOp->dInfo.pGrandParent = res.pGrandParent;
1302 pOp->dInfo.pParent = res.pParent;
1303 pOp->dInfo.pLeaf = res.pLeaf;
1304 pOp->dInfo.pUpdateParent = res.updParent.ptr();
1305 pOp->dInfo.bRightParent = res.bRightParent;
1306 pOp->dInfo.bRightLeaf = res.bRightLeaf;
1308 update_ptr updGP( res.updGrandParent.ptr() );
1309 if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
1310 memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) {
1311 if ( help_delete( pOp ) ) {
1312 // res.pLeaf is not deleted yet since it is guarded
1313 f( *node_traits::to_value_ptr( res.pLeaf ) );
1322 m_Stat.onEraseRetry();
1326 m_Stat.onEraseSuccess();
1330 template <typename Q>
1331 bool extract_( typename guarded_ptr::native_guard& guard, Q const& key )
1333 return erase_( key, node_compare(),
1334 []( Q const&, leaf_node const& ) -> bool { return true; },
1335 [&guard]( value_type& found ) { guard.set( &found ); } );
1338 template <typename Q, typename Less>
1339 bool extract_with_( typename guarded_ptr::native_guard& guard, Q const& key, Less /*pred*/ )
1341 typedef ellen_bintree::details::compare<
1344 opt::details::make_comparator_from_less<Less>,
1348 return erase_( key, compare_functor(),
1349 []( Q const&, leaf_node const& ) -> bool { return true; },
1350 [&guard]( value_type& found ) { guard.set( &found ); } );
1353 bool extract_max_( typename guarded_ptr::native_guard& gp )
1355 update_desc * pOp = nullptr;
1360 if ( !search_max( res )) {
1363 retire_update_desc( pOp );
1364 m_Stat.onExtractMaxFailed();
1368 if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean ) {
1370 pOp = alloc_update_desc();
1371 if ( check_delete_precondition( res ) ) {
1372 typename gc::Guard guard;
1373 guard.assign( pOp );
1375 pOp->dInfo.pGrandParent = res.pGrandParent;
1376 pOp->dInfo.pParent = res.pParent;
1377 pOp->dInfo.pLeaf = res.pLeaf;
1378 pOp->dInfo.pUpdateParent = res.updParent.ptr();
1379 pOp->dInfo.bRightParent = res.bRightParent;
1380 pOp->dInfo.bRightLeaf = res.bRightLeaf;
1382 update_ptr updGP( res.updGrandParent.ptr() );
1383 if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
1384 memory_model::memory_order_acquire, atomics::memory_order_relaxed ) )
1386 if ( help_delete( pOp ) )
1394 m_Stat.onExtractMaxRetry();
1398 m_Stat.onExtractMaxSuccess();
1399 gp.set( node_traits::to_value_ptr( res.pLeaf ));
1403 bool extract_min_( typename guarded_ptr::native_guard& gp )
1405 update_desc * pOp = nullptr;
1410 if ( !search_min( res )) {
1413 retire_update_desc( pOp );
1414 m_Stat.onExtractMinFailed();
1418 if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean ) {
1420 pOp = alloc_update_desc();
1421 if ( check_delete_precondition( res ) ) {
1422 typename gc::Guard guard;
1423 guard.assign( pOp );
1425 pOp->dInfo.pGrandParent = res.pGrandParent;
1426 pOp->dInfo.pParent = res.pParent;
1427 pOp->dInfo.pLeaf = res.pLeaf;
1428 pOp->dInfo.pUpdateParent = res.updParent.ptr();
1429 pOp->dInfo.bRightParent = res.bRightParent;
1430 pOp->dInfo.bRightLeaf = res.bRightLeaf;
1432 update_ptr updGP( res.updGrandParent.ptr() );
1433 if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
1434 memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1436 if ( help_delete( pOp ))
1444 m_Stat.onExtractMinRetry();
1448 m_Stat.onExtractMinSuccess();
1449 gp.set( node_traits::to_value_ptr( res.pLeaf ));
1453 template <typename Q, typename Func>
1454 bool find_( Q& val, Func f ) const
1457 if ( search( res, val, node_compare() )) {
1458 assert( res.pLeaf );
1459 f( *node_traits::to_value_ptr( res.pLeaf ), val );
1461 m_Stat.onFindSuccess();
1465 m_Stat.onFindFailed();
1469 template <typename Q, typename Less, typename Func>
1470 bool find_with_( Q& val, Less /*pred*/, Func f ) const
1472 typedef ellen_bintree::details::compare<
1475 opt::details::make_comparator_from_less<Less>,
1480 if ( search( res, val, compare_functor() )) {
1481 assert( res.pLeaf );
1482 f( *node_traits::to_value_ptr( res.pLeaf ), val );
1484 m_Stat.onFindSuccess();
1488 m_Stat.onFindFailed();
1492 template <typename Q>
1493 bool get_( typename guarded_ptr::native_guard& guard, Q const& val ) const
1495 return find_( val, [&guard]( value_type& found, Q const& ) { guard.set( &found ); } );
1498 template <typename Q, typename Less>
1499 bool get_with_( typename guarded_ptr::native_guard& guard, Q const& val, Less pred ) const
1501 return find_with_( val, pred, [&guard]( value_type& found, Q const& ) { guard.set( &found ); } );
1507 }} // namespace cds::intrusive
1509 #endif // #ifndef CDSLIB_INTRUSIVE_IMPL_ELLEN_BINTREE_H