Remove std::ref and boost::ref from docs
[libcds.git] / cds / intrusive / ellen_bintree_rcu.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_INTRUSIVE_ELLEN_BINTREE_RCU_H
4 #define __CDS_INTRUSIVE_ELLEN_BINTREE_RCU_H
5
6 #include <memory>
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>
11 #include <cds/urcu/exempt_ptr.h>
12
13 namespace cds { namespace intrusive {
14     //@cond
15     namespace ellen_bintree {
16
17         template <class RCU>
18         struct base_node<cds::urcu::gc<RCU> >: public basic_node
19         {
20             typedef basic_node base_class;
21
22             base_node * m_pNextRetired;
23
24             typedef cds::urcu::gc<RCU> gc       ;   ///< Garbage collector
25
26             /// Constructs leaf (bIntrenal == false) or internal (bInternal == true) node
27             explicit base_node( bool bInternal )
28                 : basic_node( bInternal ? internal : 0 )
29                 , m_pNextRetired( nullptr )
30             {}
31         };
32
33     } // namespace ellen_bintree
34     //@endcond
35
36     /// Ellen's et al binary search tree (RCU specialization)
37     /** @ingroup cds_intrusive_map
38         @ingroup cds_intrusive_tree
39         @anchor cds_intrusive_EllenBinTree_rcu
40
41         Source:
42             - [2010] F.Ellen, P.Fatourou, E.Ruppert, F.van Breugel "Non-blocking Binary Search Tree"
43
44         %EllenBinTree is an unbalanced leaf-oriented binary search tree that implements the <i>set</i>
45         abstract data type. Nodes maintains child pointers but not parent pointers.
46         Every internal node has exactly two children, and all data of type \p T currently in
47         the tree are stored in the leaves. Internal nodes of the tree are used to direct \p find
48         operation along the path to the correct leaf. The keys (of \p Key type) stored in internal nodes
49         may or may not be in the set. \p Key type is a subset of \p T type.
50         There should be exactly defined a key extracting functor for converting object of type \p T to
51         object of type \p Key.
52
53         Due to \p extract_min and \p extract_max member functions the \p %EllenBinTree can act as
54         a <i>priority queue</i>. In this case you should provide unique compound key, for example,
55         the priority value plus some uniformly distributed random value.
56
57         @warning Recall the tree is <b>unbalanced</b>. The complexity of operations is <tt>O(log N)</tt>
58         for uniformly distributed random keys, but in worst case the complexity is <tt>O(N)</tt>.
59
60         @note In the current implementation we do not use helping technique described in the original paper.
61         In Hazard Pointer schema helping is too complicated and does not give any observable benefits.
62         Instead of helping, when a thread encounters a concurrent operation it just spins waiting for
63         the operation done. Such solution allows greatly simplify the implementation of tree.
64
65         <b>Template arguments</b> :
66         - \p RCU - one of \ref cds_urcu_gc "RCU type"
67         - \p Key - key type, a subset of \p T
68         - \p T - type to be stored in tree's leaf nodes. The type must be based on \p ellen_bintree::node
69             (for \p ellen_bintree::base_hook) or it must have a member of type \p ellen_bintree::node
70             (for \p ellen_bintree::member_hook).
71         - \p Traits - tree traits, default is \p ellen_bintree::traits
72             It is possible to declare option-based tree with \p ellen_bintree::make_traits metafunction
73             instead of \p Traits template argument.
74
75         @anchor cds_intrusive_EllenBinTree_rcu_less
76         <b>Predicate requirements</b>
77
78         \p Traits::less, \p Traits::compare and other predicates using with member fuctions should accept at least parameters
79         of type \p T and \p Key in any combination.
80         For example, for \p Foo struct with \p std::string key field the appropiate \p less functor is:
81         \code
82         struct Foo: public cds::intrusive::ellen_bintree::node< ... >
83         {
84             std::string m_strKey;
85             ...
86         };
87
88         struct less {
89             bool operator()( Foo const& v1, Foo const& v2 ) const
90             { return v1.m_strKey < v2.m_strKey ; }
91
92             bool operator()( Foo const& v, std::string const& s ) const
93             { return v.m_strKey < s ; }
94
95             bool operator()( std::string const& s, Foo const& v ) const
96             { return s < v.m_strKey ; }
97
98             // Support comparing std::string and char const *
99             bool operator()( std::string const& s, char const * p ) const
100             { return s.compare(p) < 0 ; }
101
102             bool operator()( Foo const& v, char const * p ) const
103             { return v.m_strKey.compare(p) < 0 ; }
104
105             bool operator()( char const * p, std::string const& s ) const
106             { return s.compare(p) > 0; }
107
108             bool operator()( char const * p, Foo const& v ) const
109             { return v.m_strKey.compare(p) > 0; }
110         };
111         \endcode
112
113         @note Before including <tt><cds/intrusive/ellen_bintree_rcu.h></tt> you should include appropriate RCU header file,
114         see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
115
116         @anchor cds_intrusive_EllenBinTree_usage
117         <b>Usage</b>
118
119         Suppose we have the following Foo struct with string key type:
120         \code
121         struct Foo {
122             std::string     m_strKey    ;   // The key
123             //...                           // other non-key data
124         };
125         \endcode
126
127         We want to utilize RCU-based \p %cds::intrusive::EllenBinTree set for \p Foo data.
128         We may use base hook or member hook. Consider base hook variant.
129         First, we need deriving \p Foo struct from \p cds::intrusive::ellen_bintree::node:
130         \code
131         #include <cds/urcu/general_buffered.h>
132         #include <cds/intrusive/ellen_bintree_rcu.h>
133
134         // RCU type we use
135         typedef cds::urcu::gc< cds::urcu::general_buffered<> >  gpb_rcu;
136
137         struct Foo: public cds::intrusive:ellen_bintree::node< gpb_rcu >
138         {
139             std::string     m_strKey    ;   // The key
140             //...                           // other non-key data
141         };
142         \endcode
143
144         Second, we need to implement auxiliary structures and functors:
145         - key extractor functor for extracting the key from \p Foo object.
146             Such functor is necessary because the tree internal nodes store the keys.
147         - \p less predicate. We want our set should accept \p std::string
148             and <tt>char const *</tt> parameters for searching, so our \p less
149             predicate will not be trivial, see below.
150         - item counting feature: we want our set's \p size() member function
151             returns actual item count.
152
153         \code
154         // Key extractor functor
155         struct my_key_extractor
156         {
157             void operator ()( std::string& key, Foo const& src ) const
158             {
159                 key = src.m_strKey;
160             }
161         };
162
163         // Less predicate
164         struct my_less {
165             bool operator()( Foo const& v1, Foo const& v2 ) const
166             { return v1.m_strKey < v2.m_strKey ; }
167
168             bool operator()( Foo const& v, std::string const& s ) const
169             { return v.m_strKey < s ; }
170
171             bool operator()( std::string const& s, Foo const& v ) const
172             { return s < v.m_strKey ; }
173
174             // Support comparing std::string and char const *
175             bool operator()( std::string const& s, char const * p ) const
176             { return s.compare(p) < 0 ; }
177
178             bool operator()( Foo const& v, char const * p ) const
179             { return v.m_strKey.compare(p) < 0 ; }
180
181             bool operator()( char const * p, std::string const& s ) const
182             { return s.compare(p) > 0; }
183
184             bool operator()( char const * p, Foo const& v ) const
185             { return v.m_strKey.compare(p) > 0; }
186         };
187
188         // Tree traits for our set
189         // It is necessary to specify only those typedefs that differ from
190         // cds::intrusive::ellen_bintree::traits defaults.
191         struct set_traits: public cds::intrusive::ellen_bintree::traits
192         {
193             typedef cds::intrusive::ellen_bintree::base_hook< cds::opt::gc<gpb_rcu> > > hook;
194             typedef my_key_extractor    key_extractor;
195             typedef my_less             less;
196             typedef cds::atomicity::item_counter item_counter;
197         };
198         \endcode
199
200         Now we declare \p %EllenBinTree set and use it:
201         \code
202         typedef cds::intrusive::EllenBinTree< gpb_rcu, std::string, Foo, set_traits >   set_type;
203
204         set_type    theSet;
205         // ...
206         \endcode
207
208         Instead of declaring \p set_traits type traits we can use option-based syntax with 
209         \p ellen_bintree::make_traits metafunction, for example:
210         \code
211         typedef cds::intrusive::EllenBinTree< gpb_rcu, std::string, Foo,
212             typename cds::intrusive::ellen_bintree::make_traits<
213                 cds::opt::hook< cds::intrusive::ellen_bintree::base_hook< cds::opt::gc<gpb_rcu> > >
214                 ,cds::intrusive::ellen_bintree::key_extractor< my_key_extractor >
215                 ,cds::opt::less< my_less >
216                 ,cds::opt::item_counter< cds::atomicity::item_counter >
217             >::type
218         >   set_type2;
219         \endcode
220
221         Functionally, \p set_type and \p set_type2 are equivalent.
222
223         <b>Member-hooked tree</b>
224
225         Sometimes, we cannot use base hook, for example, when the \p Foo structure is external.
226         In such case we can use member hook feature.
227         \code
228         #include <cds/urcu/general_buffered.h>
229         #include <cds/intrusive/ellen_bintree_rcu.h>
230
231         // Struct Foo is external and its declaration cannot be modified.
232         struct Foo {
233             std::string     m_strKey    ;   // The key
234             //...                           // other non-key data
235         };
236
237         // RCU type we use
238         typedef cds::urcu::gc< cds::urcu::general_buffered<> >  gpb_rcu;
239
240         // Foo wrapper
241         struct MyFoo
242         {
243             Foo     m_foo;
244             cds::intrusive:ellen_bintree::node< gpb_rcu >   set_hook;   // member hook
245         };
246
247         // Key extractor functor
248         struct member_key_extractor
249         {
250             void operator ()( std::string& key, MyFoo const& src ) const
251             {
252                 key = src.m_foo.m_strKey;
253             }
254         };
255
256         // Less predicate
257         struct member_less {
258             bool operator()( MyFoo const& v1, MyFoo const& v2 ) const
259             { return v1.m_foo.m_strKey < v2.m_foo.m_strKey ; }
260
261             bool operator()( MyFoo const& v, std::string const& s ) const
262             { return v.m_foo.m_strKey < s ; }
263
264             bool operator()( std::string const& s, MyFoo const& v ) const
265             { return s < v.m_foo.m_strKey ; }
266
267             // Support comparing std::string and char const *
268             bool operator()( std::string const& s, char const * p ) const
269             { return s.compare(p) < 0 ; }
270
271             bool operator()( MyFoo const& v, char const * p ) const
272             { return v.m_foo.m_strKey.compare(p) < 0 ; }
273
274             bool operator()( char const * p, std::string const& s ) const
275             { return s.compare(p) > 0; }
276
277             bool operator()( char const * p, MyFoo const& v ) const
278             { return v.m_foo.m_strKey.compare(p) > 0; }
279         };
280
281         // Tree traits for our member-based set
282         struct member_set_traits: public cds::intrusive::ellen_bintree::traits
283         {
284             cds::intrusive::ellen_bintree::member_hook< offsetof(MyFoo, set_hook), cds::opt::gc<gpb_rcu> > > hook;
285             typedef member_key_extractor    key_extractor;
286             typedef member_less             less;
287             typedef cds::atomicity::item_counter item_counter;
288         };
289
290         // Tree containing MyFoo objects
291         typedef cds::intrusive::EllenBinTree< gpb_rcu, std::string, MyFoo, member_set_traits >   member_set_type;
292
293         member_set_type    theMemberSet;
294         \endcode
295
296         <b>Multiple containers</b>
297
298         Sometimes we need that our \p Foo struct should be used in several different containers.
299         Suppose, \p Foo struct has two key fields:
300         \code
301         struct Foo {
302             std::string m_strKey    ;   // string key
303             int         m_nKey      ;   // int key
304             //...                       // other non-key data fields
305         };
306         \endcode
307
308         We want to build two intrusive \p %EllenBinTree sets: one indexed on \p Foo::m_strKey field,
309         another indexed on \p Foo::m_nKey field. To decide such case we should use a tag option for
310         tree's hook:
311         \code
312         #include <cds/urcu/general_buffered.h>
313         #include <cds/intrusive/ellen_bintree_rcu.h>
314
315         // RCU type we use
316         typedef cds::urcu::gc< cds::urcu::general_buffered<> >  gpb_rcu;
317
318         // Declare tag structs
319         struct int_tag      ;   // int key tag
320         struct string_tag   ;   // string key tag
321
322         // Foo struct is derived from two ellen_bintree::node class
323         // with different tags
324         struct Foo
325             : public cds::intrusive::ellen_bintree::node< gpb_rcu, cds::opt::tag< string_tag > >
326             , public cds::intrusive::ellen_bintree::node< gpb_rcu >, cds::opt::tag< int_tag >
327         {
328             std::string m_strKey    ;   // string key
329             int         m_nKey      ;   // int key
330             //...                       // other non-key data fields
331         };
332
333         // String key extractor functor
334         struct string_key_extractor
335         {
336             void operator ()( std::string& key, Foo const& src ) const
337             {
338                 key = src.m_strKey;
339             }
340         };
341
342         // Int key extractor functor
343         struct int_key_extractor
344         {
345             void operator ()( int& key, Foo const& src ) const
346             {
347                 key = src.m_nKey;
348             }
349         };
350
351         // String less predicate
352         struct string_less {
353             bool operator()( Foo const& v1, Foo const& v2 ) const
354             { return v1.m_strKey < v2.m_strKey ; }
355
356             bool operator()( Foo const& v, std::string const& s ) const
357             { return v.m_strKey < s ; }
358
359             bool operator()( std::string const& s, Foo const& v ) const
360             { return s < v.m_strKey ; }
361
362             // Support comparing std::string and char const *
363             bool operator()( std::string const& s, char const * p ) const
364             { return s.compare(p) < 0 ; }
365
366             bool operator()( Foo const& v, char const * p ) const
367             { return v.m_strKey.compare(p) < 0 ; }
368
369             bool operator()( char const * p, std::string const& s ) const
370             { return s.compare(p) > 0; }
371
372             bool operator()( char const * p, Foo const& v ) const
373             { return v.m_strKey.compare(p) > 0; }
374         };
375
376         // Int less predicate
377         struct int_less {
378             bool operator()( Foo const& v1, Foo const& v2 ) const
379             { return v1.m_nKey < v2.m_nKey ; }
380
381             bool operator()( Foo const& v, int n ) const
382             { return v.m_nKey < n ; }
383
384             bool operator()( int n, Foo const& v ) const
385             { return n < v.m_nKey ; }
386         };
387
388         // Type traits for string-indexed set
389         struct string_set_traits: public cds::intrusive::ellen_bintree::traits
390         {
391             typedef cds::intrusive::ellen_bintree::base_hook< cds::opt::gc<gpb_rcu> >, cds::opt::tag< string_tag > > hook;
392             typedef string_key_extractor    key_extractor;
393             typedef string_less             less;
394             typedef cds::atomicity::item_counter item_counter;
395         };
396
397         // Type traits for int-indexed set
398         struct int_set_traits: public cds::intrusive::ellen_bintree::traits
399         {
400             typedef cds::intrusive::ellen_bintree::base_hook< cds::opt::gc<gpb_rcu> >, cds::opt::tag< int_tag > > hook;
401             typedef int_key_extractor    key_extractor;
402             typedef int_less             less;
403             typedef cds::atomicity::item_counter item_counter;
404         };
405
406         // Declare string-indexed set
407         typedef cds::intrusive::EllenBinTree< gpb_rcu, std::string, Foo, string_set_traits >   string_set_type;
408         string_set_type theStringSet;
409
410         // Declare int-indexed set
411         typedef cds::intrusive::EllenBinTree< gpb_rcu, int, Foo, int_set_traits >   int_set_type;
412         int_set_type    theIntSet;
413
414         // Now we can use theStringSet and theIntSet in our program
415         // ...
416         \endcode
417     */
418     template < class RCU,
419         typename Key,
420         typename T,
421 #ifdef CDS_DOXYGEN_INVOKED
422         class Traits = ellen_bintree::traits
423 #else
424         class Traits
425 #endif
426     >
427     class EllenBinTree< cds::urcu::gc<RCU>, Key, T, Traits >
428     {
429     public:
430         typedef cds::urcu::gc<RCU>  gc;   ///< RCU Garbage collector
431         typedef Key     key_type;         ///< type of a key stored in internal nodes; key is a part of \p value_type
432         typedef T       value_type;       ///< type of value stored in the binary tree
433         typedef Traits  traits;           ///< Traits template parameter
434
435         typedef typename traits::hook    hook;      ///< hook type
436         typedef typename hook::node_type node_type; ///< node type
437
438         typedef typename traits::disposer disposer;   ///< leaf node disposer
439
440     protected:
441         //@cond
442         typedef ellen_bintree::base_node< gc >                      tree_node; ///< Base type of tree node
443         typedef node_type                                           leaf_node; ///< Leaf node type
444         typedef ellen_bintree::internal_node< key_type, leaf_node > internal_node; ///< Internal node type
445         typedef ellen_bintree::update_desc< leaf_node, internal_node> update_desc; ///< Update descriptor
446         typedef typename update_desc::update_ptr                    update_ptr; ///< Marked pointer to update descriptor
447         //@endcond
448
449     public:
450         typedef cds::urcu::exempt_ptr< gc, value_type, value_type, disposer, void > exempt_ptr; ///< pointer to extracted node
451
452     public:
453 #   ifdef CDS_DOXYGEN_INVOKED
454         typedef implementation_defined key_comparator;    ///< key compare functor based on \p Traits::compare and \p Traits::less
455         typedef typename get_node_traits< value_type, node_type, hook>::type node_traits; ///< Node traits
456 #   else
457         typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;
458         struct node_traits: public get_node_traits< value_type, node_type, hook>::type
459         {
460             static internal_node const& to_internal_node( tree_node const& n )
461             {
462                 assert( n.is_internal() );
463                 return static_cast<internal_node const&>( n );
464             }
465
466             static leaf_node const& to_leaf_node( tree_node const& n )
467             {
468                 assert( n.is_leaf() );
469                 return static_cast<leaf_node const&>( n );
470             }
471         };
472 #   endif
473
474         typedef typename traits::item_counter  item_counter;   ///< Item counting policy used
475         typedef typename traits::memory_model  memory_model;   ///< Memory ordering. See cds::opt::memory_model option
476         typedef typename traits::stat          stat;           ///< internal statistics type
477         typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
478         typedef typename traits::key_extractor      key_extractor;      ///< key extracting functor
479
480         typedef typename traits::node_allocator        node_allocator;  ///< Internal node allocator
481         typedef typename traits::update_desc_allocator update_desc_allocator; ///< Update descriptor allocator
482
483         typedef typename gc::scoped_lock    rcu_lock;   ///< RCU scoped lock
484
485         static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions do not require external locking
486
487     protected:
488         //@cond
489         typedef ellen_bintree::details::compare< key_type, value_type, key_comparator, node_traits > node_compare;
490
491         typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock >   check_deadlock_policy;
492
493         typedef cds::details::Allocator< internal_node, node_allocator >        cxx_node_allocator;
494         typedef cds::details::Allocator< update_desc, update_desc_allocator >   cxx_update_desc_allocator;
495
496         struct search_result {
497             internal_node *     pGrandParent;
498             internal_node *     pParent;
499             leaf_node *         pLeaf;
500             update_ptr          updParent;
501             update_ptr          updGrandParent;
502             bool                bRightLeaf      ; // true if pLeaf is right child of pParent, false otherwise
503             bool                bRightParent    ; // true if pParent is right child of pGrandParent, false otherwise
504
505             search_result()
506                 :pGrandParent( nullptr )
507                 , pParent( nullptr )
508                 , pLeaf( nullptr )
509                 ,bRightLeaf( false )
510                 ,bRightParent( false )
511             {}
512         };
513         //@endcond
514
515     protected:
516         //@cond
517         internal_node       m_Root;     ///< Tree root node (key= Infinite2)
518         leaf_node           m_LeafInf1;
519         leaf_node           m_LeafInf2;
520         //@endcond
521
522         item_counter        m_ItemCounter;  ///< item counter
523         mutable stat        m_Stat;         ///< internal statistics
524
525     protected:
526         //@cond
527         static void free_leaf_node( value_type * p )
528         {
529             disposer()( p );
530         }
531
532         internal_node * alloc_internal_node() const
533         {
534             m_Stat.onInternalNodeCreated();
535             internal_node * pNode = cxx_node_allocator().New();
536             //pNode->clean();
537             return pNode;
538         }
539
540         static void free_internal_node( internal_node * pNode )
541         {
542             cxx_node_allocator().Delete( pNode );
543         }
544
545         struct internal_node_deleter {
546             void operator()( internal_node * p) const
547             {
548                 free_internal_node( p );
549             }
550         };
551
552         typedef std::unique_ptr< internal_node, internal_node_deleter>  unique_internal_node_ptr;
553
554         update_desc * alloc_update_desc() const
555         {
556             m_Stat.onUpdateDescCreated();
557             return cxx_update_desc_allocator().New();
558         }
559
560         static void free_update_desc( update_desc * pDesc )
561         {
562             cxx_update_desc_allocator().Delete( pDesc );
563         }
564
565         class retired_list
566         {
567             update_desc *   pUpdateHead;
568             tree_node *     pNodeHead;
569
570         private:
571             class forward_iterator
572             {
573                 update_desc *   m_pUpdate;
574                 tree_node *     m_pNode;
575
576             public:
577                 forward_iterator( retired_list const& l )
578                     : m_pUpdate( l.pUpdateHead )
579                     , m_pNode( l.pNodeHead )
580                 {}
581
582                 forward_iterator()
583                     : m_pUpdate( nullptr )
584                     , m_pNode( nullptr )
585                 {}
586
587                 cds::urcu::retired_ptr operator *()
588                 {
589                     if ( m_pUpdate ) {
590                         return cds::urcu::retired_ptr( reinterpret_cast<void *>( m_pUpdate ),
591                             reinterpret_cast<cds::urcu::free_retired_ptr_func>( free_update_desc ) );
592                     }
593                     if ( m_pNode ) {
594                         if ( m_pNode->is_leaf() ) {
595                             return cds::urcu::retired_ptr( reinterpret_cast<void *>( node_traits::to_value_ptr( static_cast<leaf_node *>( m_pNode ))),
596                                 reinterpret_cast< cds::urcu::free_retired_ptr_func>( free_leaf_node ) );
597                         }
598                         else {
599                             return cds::urcu::retired_ptr( reinterpret_cast<void *>( static_cast<internal_node *>( m_pNode ) ),
600                                 reinterpret_cast<cds::urcu::free_retired_ptr_func>( free_internal_node ) );
601                         }
602                     }
603                     return cds::urcu::retired_ptr( nullptr,
604                         reinterpret_cast<cds::urcu::free_retired_ptr_func>( free_update_desc ) );
605                 }
606
607                 void operator ++()
608                 {
609                     if ( m_pUpdate ) {
610                         m_pUpdate = m_pUpdate->pNextRetire;
611                         return;
612                     }
613                     if ( m_pNode )
614                         m_pNode = m_pNode->m_pNextRetired;
615                 }
616
617                 friend bool operator ==( forward_iterator const& i1, forward_iterator const& i2 )
618                 {
619                     return i1.m_pUpdate == i2.m_pUpdate && i1.m_pNode == i2.m_pNode;
620                 }
621                 friend bool operator !=( forward_iterator const& i1, forward_iterator const& i2 )
622                 {
623                     return !( i1 == i2 );
624                 }
625             };
626
627         public:
628             retired_list()
629                 : pUpdateHead( nullptr )
630                 , pNodeHead( nullptr )
631             {}
632
633             ~retired_list()
634             {
635                 gc::batch_retire( forward_iterator(*this), forward_iterator() );
636             }
637
638             void push( update_desc * p )
639             {
640                 p->pNextRetire = pUpdateHead;
641                 pUpdateHead = p;
642             }
643
644             void push( tree_node * p )
645             {
646                 p->m_pNextRetired = pNodeHead;
647                 pNodeHead = p;
648             }
649         };
650
651         void retire_node( tree_node * pNode, retired_list& rl ) const
652         {
653             if ( pNode->is_leaf() ) {
654                 assert( static_cast<leaf_node *>( pNode ) != &m_LeafInf1 );
655                 assert( static_cast<leaf_node *>( pNode ) != &m_LeafInf2 );
656             }
657             else {
658                 assert( static_cast<internal_node *>( pNode ) != &m_Root );
659                 m_Stat.onInternalNodeDeleted();
660             }
661             rl.push( pNode );
662         }
663
664         void retire_update_desc( update_desc * p, retired_list& rl, bool bDirect ) const
665         {
666             m_Stat.onUpdateDescDeleted();
667             if ( bDirect )
668                 free_update_desc( p );
669             else
670                 rl.push( p );
671         }
672
673         void make_empty_tree()
674         {
675             m_Root.infinite_key( 2 );
676             m_LeafInf1.infinite_key( 1 );
677             m_LeafInf2.infinite_key( 2 );
678             m_Root.m_pLeft.store( &m_LeafInf1, memory_model::memory_order_relaxed );
679             m_Root.m_pRight.store( &m_LeafInf2, memory_model::memory_order_release );
680         }
681         //@endcond
682
683     public:
684         /// Default constructor
685         EllenBinTree()
686         {
687             static_assert( !std::is_same< key_extractor, opt::none >::value, "The key extractor option must be specified" );
688             make_empty_tree();
689         }
690
691         /// Clears the tree
692         ~EllenBinTree()
693         {
694             unsafe_clear();
695         }
696
697         /// Inserts new node
698         /**
699             The function inserts \p val in the tree if it does not contain
700             an item with key equal to \p val.
701
702             The function applies RCU lock internally.
703
704             Returns \p true if \p val is placed into the set, \p false otherwise.
705         */
706         bool insert( value_type& val )
707         {
708             return insert( val, []( value_type& ) {} );
709         }
710
711         /// Inserts new node
712         /**
713             This function is intended for derived non-intrusive containers.
714
715             The function allows to split creating of new item into two part:
716             - create item with key only
717             - insert new item into the tree
718             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
719
720             The functor signature is:
721             \code
722                 void func( value_type& val );
723             \endcode
724             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
725             \p val no any other changes could be made on this tree's item by concurrent threads.
726             The user-defined functor is called only if the inserting is success.
727
728             RCU \p synchronize method can be called. RCU should not be locked.
729         */
730         template <typename Func>
731         bool insert( value_type& val, Func f )
732         {
733             check_deadlock_policy::check();
734
735             unique_internal_node_ptr pNewInternal;
736             retired_list updRetire;
737
738             {
739                 rcu_lock l;
740
741                 search_result res;
742                 for ( ;; ) {
743                     if ( search( res, val, node_compare() )) {
744                         if ( pNewInternal.get() )
745                             m_Stat.onInternalNodeDeleted() ;    // unique_internal_node_ptr deletes internal node
746                         m_Stat.onInsertFailed();
747                         return false;
748                     }
749
750                     if ( res.updParent.bits() != update_desc::Clean )
751                         help( res.updParent, updRetire );
752                     else {
753                         if ( !pNewInternal.get() )
754                             pNewInternal.reset( alloc_internal_node() );
755
756                         if ( try_insert( val, pNewInternal.get(), res, updRetire )) {
757                             f( val );
758                             pNewInternal.release()  ;   // internal node is linked into the tree and should not be deleted
759                             break;
760                         }
761                     }
762
763                     m_Stat.onInsertRetry();
764                 }
765             }
766
767             ++m_ItemCounter;
768             m_Stat.onInsertSuccess();
769
770             return true;
771         }
772
773         /// Ensures that the \p val exists in the tree
774         /**
775             The operation performs inserting or changing data with lock-free manner.
776
777             If the item \p val is not found in the tree, then \p val is inserted into the tree.
778             Otherwise, the functor \p func is called with item found.
779             The functor signature is:
780             \code
781                 void func( bool bNew, value_type& item, value_type& val );
782             \endcode
783             with arguments:
784             - \p bNew - \p true if the item has been inserted, \p false otherwise
785             - \p item - item of the tree
786             - \p val - argument \p val passed into the \p ensure function
787             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
788             refer to the same thing.
789
790             The functor can change non-key fields of the \p item; however, \p func must guarantee
791             that during changing no any other modifications could be made on this item by concurrent threads.
792
793             RCU \p synchronize method can be called. RCU should not be locked.
794
795             Returns <tt>std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
796             \p second is \p true if new item has been added or \p false if the item with \p key
797             already is in the tree.
798
799             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
800         */
801         template <typename Func>
802         std::pair<bool, bool> ensure( value_type& val, Func func )
803         {
804             check_deadlock_policy::check();
805
806             unique_internal_node_ptr pNewInternal;
807             retired_list updRetire;
808
809             {
810                 rcu_lock l;
811
812                 search_result res;
813                 for ( ;; ) {
814                     if ( search( res, val, node_compare() )) {
815                         func( false, *node_traits::to_value_ptr( res.pLeaf ), val );
816                         if ( pNewInternal.get() )
817                             m_Stat.onInternalNodeDeleted() ;    // unique_internal_node_ptr deletes internal node
818                         m_Stat.onEnsureExist();
819                         return std::make_pair( true, false );
820                     }
821
822                     if ( res.updParent.bits() != update_desc::Clean )
823                         help( res.updParent, updRetire );
824                     else {
825                         if ( !pNewInternal.get() )
826                             pNewInternal.reset( alloc_internal_node() );
827
828                         if ( try_insert( val, pNewInternal.get(), res, updRetire )) {
829                             func( true, val, val );
830                             pNewInternal.release()  ;   // internal node is linked into the tree and should not be deleted
831                             break;
832                         }
833                     }
834                     m_Stat.onEnsureRetry();
835                 }
836             }
837
838             ++m_ItemCounter;
839             m_Stat.onEnsureNew();
840
841             return std::make_pair( true, true );
842         }
843
844         /// Unlinks the item \p val from the tree
845         /**
846             The function searches the item \p val in the tree and unlink it from the tree
847             if it is found and is equal to \p val.
848
849             Difference between \ref erase and \p unlink functions: \p erase finds <i>a key</i>
850             and deletes the item found. \p unlink finds an item by key and deletes it
851             only if \p val is an item of the tree, i.e. the pointer to item found
852             is equal to <tt> &val </tt>.
853
854             RCU \p synchronize method can be called. RCU should not be locked.
855
856             The \ref disposer specified in \p Traits class template parameter is called
857             by garbage collector \p GC asynchronously.
858
859             The function returns \p true if success and \p false otherwise.
860         */
861         bool unlink( value_type& val )
862         {
863             return erase_( val, node_compare(),
864                 []( value_type const& v, leaf_node const& n ) -> bool { return &v == node_traits::to_value_ptr( n ); },
865                 [](value_type const&) {} );
866         }
867
868         /// Deletes the item from the tree
869         /** \anchor cds_intrusive_EllenBinTree_rcu_erase
870             The function searches an item with key equal to \p key in the tree,
871             unlinks it from the tree, and returns \p true.
872             If the item with key equal to \p key is not found the function return \p false.
873
874             Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
875
876             RCU \p synchronize method can be called. RCU should not be locked.
877         */
878         template <typename Q>
879         bool erase( const Q& key )
880         {
881             return erase_( key, node_compare(),
882                 []( Q const&, leaf_node const& ) -> bool { return true; },
883                 [](value_type const&) {} );
884         }
885
886         /// Delete the item from the tree with comparing functor \p pred
887         /**
888             The function is an analog of \ref cds_intrusive_EllenBinTree_rcu_erase "erase(Q const&)"
889             but \p pred predicate is used for key comparing.
890             \p Less has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_rcu_less
891             "Predicate requirements".
892             \p pred must imply the same element order as the comparator used for building the tree.
893         */
894         template <typename Q, typename Less>
895         bool erase_with( const Q& key, Less pred )
896         {
897             typedef ellen_bintree::details::compare<
898                 key_type,
899                 value_type,
900                 opt::details::make_comparator_from_less<Less>,
901                 node_traits
902             > compare_functor;
903
904             return erase_( key, compare_functor(),
905                 []( Q const&, leaf_node const& ) -> bool { return true; },
906                 [](value_type const&) {} );
907         }
908
909         /// Deletes the item from the tree
910         /** \anchor cds_intrusive_EllenBinTree_rcu_erase_func
911             The function searches an item with key equal to \p key in the tree,
912             call \p f functor with item found, unlinks it from the tree, and returns \p true.
913             The \ref disposer specified in \p Traits class template parameter is called
914             by garbage collector \p GC asynchronously.
915
916             The \p Func interface is
917             \code
918             struct functor {
919                 void operator()( value_type const& item );
920             };
921             \endcode
922
923             If the item with key equal to \p key is not found the function return \p false.
924
925             Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
926
927             RCU \p synchronize method can be called. RCU should not be locked.
928         */
929         template <typename Q, typename Func>
930         bool erase( Q const& key, Func f )
931         {
932             return erase_( key, node_compare(),
933                 []( Q const&, leaf_node const& ) -> bool { return true; },
934                 f );
935         }
936
937         /// Delete the item from the tree with comparing functor \p pred
938         /**
939             The function is an analog of \ref cds_intrusive_EllenBinTree_rcu_erase_func "erase(Q const&, Func)"
940             but \p pred predicate is used for key comparing.
941             \p Less has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_rcu_less
942             "Predicate requirements".
943             \p pred must imply the same element order as the comparator used for building the tree.
944         */
945         template <typename Q, typename Less, typename Func>
946         bool erase_with( Q const& key, Less pred, Func f )
947         {
948             typedef ellen_bintree::details::compare<
949                 key_type,
950                 value_type,
951                 opt::details::make_comparator_from_less<Less>,
952                 node_traits
953             > compare_functor;
954
955             return erase_( key, compare_functor(),
956                 []( Q const&, leaf_node const& ) -> bool { return true; },
957                 f );
958         }
959
960         /// Extracts an item with minimal key from the tree
961         /**
962             The function searches an item with minimal key, unlinks it, and returns pointer to an item found in \p result parameter.
963             If the tree is empty the function returns \p false.
964
965             @note Due the concurrent nature of the tree, the function extracts <i>nearly</i> minimum key.
966             It means that the function gets leftmost leaf of the tree and tries to unlink it.
967             During unlinking, a concurrent thread may insert an item with key less than leftmost item's key.
968             So, the function returns the item with minimum key at the moment of tree traversing.
969
970             RCU \p synchronize method can be called. RCU should NOT be locked.
971             The function does not call the disposer for the item found.
972             The disposer will be implicitly invoked when \p result object is destroyed or when
973             <tt>result.release()</tt> is called, see cds::urcu::exempt_ptr for explanation.
974             @note Before reusing \p result object you should call its \p release() method.
975         */
976         bool extract_min(exempt_ptr& result)
977         {
978             return extract_min_(result);
979         }
980
981         /// Extracts an item with maximal key from the tree
982         /**
983             The function searches an item with maximal key, unlinks it, and returns pointer to an item found in \p result prameter.
984             If the tree is empty the function returns \p false.
985
986             @note Due the concurrent nature of the tree, the function extracts <i>nearly</i> maximal key.
987             It means that the function gets rightmost leaf of the tree and tries to unlink it.
988             During unlinking, a concurrent thread may insert an item with key great than rightmost item's key.
989             So, the function returns the item with maximum key at the moment of tree traversing.
990
991             RCU \p synchronize method can be called. RCU should NOT be locked.
992             The function does not call the disposer for the item found.
993             The disposer will be implicitly invoked when \p result object is destroyed or when
994             <tt>result.release()</tt> is called, see cds::urcu::exempt_ptr for explanation.
995             @note Before reusing \p result object you should call its \p release() method.
996         */
997         bool extract_max(exempt_ptr& result)
998         {
999             return extract_max_(result);
1000         }
1001
1002         /// Extracts an item from the tree
1003         /** \anchor cds_intrusive_EllenBinTree_rcu_extract
1004             The function searches an item with key equal to \p key in the tree,
1005             unlinks it, and returns pointer to an item found in \p result parameter.
1006             If the item with the key equal to \p key is not found the function returns \p false.
1007
1008             RCU \p synchronize method can be called. RCU should NOT be locked.
1009             The function does not call the disposer for the item found.
1010             The disposer will be implicitly invoked when \p result object is destroyed or when
1011             <tt>result.release()</tt> is called, see cds::urcu::exempt_ptr for explanation.
1012             @note Before reusing \p result object you should call its \p release() method.
1013         */
1014         template <typename Q>
1015         bool extract( exempt_ptr& result, Q const& key )
1016         {
1017             return extract_( result, key, node_compare() );
1018         }
1019
1020         /// Extracts an item from the set using \p pred for searching
1021         /**
1022             The function is an analog of \ref cds_intrusive_EllenBinTree_rcu_extract "extract(exempt_ptr&, Q const&)"
1023             but \p pred is used for key compare.
1024             \p Less has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_rcu_less
1025             "predicate requirements".
1026             \p pred must imply the same element order as the comparator used for building the tree.
1027         */
1028         template <typename Q, typename Less>
1029         bool extract_with( exempt_ptr& dest,  Q const& key, Less pred )
1030         {
1031             return extract_with_( dest, key, pred );
1032         }
1033
1034         /// Finds the key \p key
1035         /** @anchor cds_intrusive_EllenBinTree_rcu_find_val
1036             The function searches the item with key equal to \p key
1037             and returns \p true if it is found, and \p false otherwise.
1038
1039             Note the hash functor specified for class \p Traits template parameter
1040             should accept a parameter of type \p Q that can be not the same as \p value_type.
1041
1042             The function applies RCU lock internally.
1043         */
1044         template <typename Q>
1045         bool find( Q const& key ) const
1046         {
1047             rcu_lock l;
1048             search_result    res;
1049             if ( search( res, key, node_compare() )) {
1050                 m_Stat.onFindSuccess();
1051                 return true;
1052             }
1053
1054             m_Stat.onFindFailed();
1055             return false;
1056         }
1057
1058         /// Finds the key \p key with comparing functor \p pred
1059         /**
1060             The function is an analog of \ref cds_intrusive_EllenBinTree_rcu_find_val "find(Q const&)"
1061             but \p pred is used for key compare.
1062             \p Less functor has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_rcu_less
1063             "Predicate requirements".
1064             \p pred must imply the same element order as the comparator used for building the tree.
1065             \p pred should accept arguments of type \p Q, \p key_type, \p value_type in any combination.
1066         */
1067         template <typename Q, typename Less>
1068         bool find_with( Q const& key, Less pred ) const
1069         {
1070             typedef ellen_bintree::details::compare<
1071                 key_type,
1072                 value_type,
1073                 opt::details::make_comparator_from_less<Less>,
1074                 node_traits
1075             > compare_functor;
1076
1077             rcu_lock l;
1078             search_result    res;
1079             if ( search( res, key, compare_functor() )) {
1080                 m_Stat.onFindSuccess();
1081                 return true;
1082             }
1083             m_Stat.onFindFailed();
1084             return false;
1085         }
1086
1087         /// Finds the key \p key
1088         /** @anchor cds_intrusive_EllenBinTree_rcu_find_func
1089             The function searches the item with key equal to \p key and calls the functor \p f for item found.
1090             The interface of \p Func functor is:
1091             \code
1092             struct functor {
1093                 void operator()( value_type& item, Q& key );
1094             };
1095             \endcode
1096             where \p item is the item found, \p key is the <tt>find</tt> function argument.
1097
1098             The functor can change non-key fields of \p item. Note that the functor is only guarantee
1099             that \p item cannot be disposed during functor is executing.
1100             The functor does not serialize simultaneous access to the tree \p item. If such access is
1101             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
1102
1103             The function applies RCU lock internally.
1104
1105             The function returns \p true if \p key is found, \p false otherwise.
1106         */
1107         template <typename Q, typename Func>
1108         bool find( Q& key, Func f ) const
1109         {
1110             return find_( key, f );
1111         }
1112         //@cond
1113         template <typename Q, typename Func>
1114         bool find( Q const& key, Func f ) const
1115         {
1116             return find_( key, f );
1117         }
1118         //@endcond
1119
1120         /// Finds the key \p key with comparing functor \p pred
1121         /**
1122             The function is an analog of \ref cds_intrusive_EllenBinTree_rcu_find_func "find(Q&, Func)"
1123             but \p pred is used for key comparison.
1124             \p Less functor has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_rcu_less
1125             "Predicate requirements".
1126             \p pred must imply the same element order as the comparator used for building the tree.
1127         */
1128         template <typename Q, typename Less, typename Func>
1129         bool find_with( Q& key, Less pred, Func f ) const
1130         {
1131             return find_with_( key, pred, f );
1132         }
1133         //@cond
1134         template <typename Q, typename Less, typename Func>
1135         bool find_with( Q const& key, Less pred, Func f ) const
1136         {
1137             return find_with_( key, pred, f );
1138         }
1139         //@endcond
1140
1141         /// Finds \p key and return the item found
1142         /** \anchor cds_intrusive_EllenBinTree_rcu_get
1143             The function searches the item with key equal to \p key and returns the pointer to item found.
1144             If \p key is not found it returns \p nullptr.
1145
1146             RCU should be locked before call the function.
1147             Returned pointer is valid while RCU is locked.
1148         */
1149         template <typename Q>
1150         value_type * get( Q const& key ) const
1151         {
1152             return get_( key, node_compare() );
1153         }
1154
1155         /// Finds \p key with \p pred predicate and return the item found
1156         /**
1157             The function is an analog of \ref cds_intrusive_EllenBinTree_rcu_get "get(Q const&)"
1158             but \p pred is used for comparing the keys.
1159
1160             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
1161             in any order.
1162             \p pred must imply the same element order as the comparator used for building the tree.
1163         */
1164         template <typename Q, typename Less>
1165         value_type * get_with( Q const& key, Less pred ) const
1166         {
1167             typedef ellen_bintree::details::compare<
1168                 key_type,
1169                 value_type,
1170                 opt::details::make_comparator_from_less<Less>,
1171                 node_traits
1172             > compare_functor;
1173
1174             return get_( key, compare_functor());
1175         }
1176
1177         /// Checks if the tree is empty
1178         bool empty() const
1179         {
1180             return m_Root.m_pLeft.load( memory_model::memory_order_relaxed )->is_leaf();
1181         }
1182
1183         /// Clears the tree (thread safe, not atomic)
1184         /**
1185             The function unlink all items from the tree.
1186             The function is thread safe but not atomic: in multi-threaded environment with parallel insertions
1187             this sequence
1188             \code
1189             set.clear();
1190             assert( set.empty() );
1191             \endcode
1192             the assertion could be raised.
1193
1194             For each leaf the \ref disposer will be called after unlinking.
1195
1196             RCU \p synchronize method can be called. RCU should not be locked.
1197         */
1198         void clear()
1199         {
1200             exempt_ptr ep;
1201             while ( extract_min(ep) )
1202                 ep.release();
1203         }
1204
1205         /// Clears the tree (not thread safe)
1206         /**
1207             This function is not thread safe and may be called only when no other thread deals with the tree.
1208             The function is used in the tree destructor.
1209         */
1210         void unsafe_clear()
1211         {
1212             rcu_lock l;
1213
1214             while ( true ) {
1215                 internal_node * pParent = nullptr;
1216                 internal_node * pGrandParent = nullptr;
1217                 tree_node *     pLeaf = const_cast<internal_node *>( &m_Root );
1218
1219                 // Get leftmost leaf
1220                 while ( pLeaf->is_internal() ) {
1221                     pGrandParent = pParent;
1222                     pParent = static_cast<internal_node *>( pLeaf );
1223                     pLeaf = pParent->m_pLeft.load( memory_model::memory_order_relaxed );
1224                 }
1225
1226                 if ( pLeaf->infinite_key()) {
1227                     // The tree is empty
1228                     return;
1229                 }
1230
1231                 // Remove leftmost leaf and its parent node
1232                 assert( pGrandParent );
1233                 assert( pParent );
1234                 assert( pLeaf->is_leaf() );
1235
1236                 pGrandParent->m_pLeft.store( pParent->m_pRight.load( memory_model::memory_order_relaxed ), memory_model::memory_order_relaxed );
1237                 free_leaf_node( node_traits::to_value_ptr( static_cast<leaf_node *>( pLeaf ) ) );
1238                 free_internal_node( pParent );
1239             }
1240         }
1241
1242         /// Returns item count in the tree
1243         /**
1244             Only leaf nodes containing user data are counted.
1245
1246             The value returned depends on item counter type provided by \p Traits template parameter.
1247             If it is \p atomicity::empty_item_counter this function always returns 0.
1248
1249             The function is not suitable for checking the tree emptiness, use \p empty()
1250             member function for that.
1251         */
1252         size_t size() const
1253         {
1254             return m_ItemCounter;
1255         }
1256
1257         /// Returns const reference to internal statistics
1258         stat const& statistics() const
1259         {
1260             return m_Stat;
1261         }
1262
1263         /// Checks internal consistency (not atomic, not thread-safe)
1264         /**
1265             The debugging function to check internal consistency of the tree.
1266         */
1267         bool check_consistency() const
1268         {
1269             return check_consistency( &m_Root );
1270         }
1271
1272     protected:
1273         //@cond
1274
1275         bool check_consistency( internal_node const * pRoot ) const
1276         {
1277             tree_node * pLeft  = pRoot->m_pLeft.load( atomics::memory_order_relaxed );
1278             tree_node * pRight = pRoot->m_pRight.load( atomics::memory_order_relaxed );
1279             assert( pLeft );
1280             assert( pRight );
1281
1282             if ( node_compare()( *pLeft, *pRoot ) < 0
1283                 && node_compare()( *pRoot, *pRight ) <= 0
1284                 && node_compare()( *pLeft, *pRight ) < 0 )
1285             {
1286                 bool bRet = true;
1287                 if ( pLeft->is_internal() )
1288                     bRet = check_consistency( static_cast<internal_node *>( pLeft ) );
1289                 assert( bRet );
1290
1291                 if ( bRet && pRight->is_internal() )
1292                     bRet = bRet && check_consistency( static_cast<internal_node *>( pRight ));
1293                 assert( bRet );
1294
1295                 return bRet;
1296             }
1297             return false;
1298         }
1299
1300         void help( update_ptr pUpdate, retired_list& rl )
1301         {
1302             /*
1303             switch ( pUpdate.bits() ) {
1304                 case update_desc::IFlag:
1305                     help_insert( pUpdate.ptr() );
1306                     m_Stat.onHelpInsert();
1307                     break;
1308                 case update_desc::DFlag:
1309                     //help_delete( pUpdate.ptr(), rl );
1310                     //m_Stat.onHelpDelete();
1311                     break;
1312                 case update_desc::Mark:
1313                     //help_marked( pUpdate.ptr() );
1314                     //m_Stat.onHelpMark();
1315                     break;
1316             }
1317             */
1318         }
1319
1320         void help_insert( update_desc * pOp )
1321         {
1322             assert( gc::is_locked() );
1323
1324             tree_node * pLeaf = static_cast<tree_node *>( pOp->iInfo.pLeaf );
1325             if ( pOp->iInfo.bRightLeaf ) {
1326                 pOp->iInfo.pParent->m_pRight.compare_exchange_strong( pLeaf, static_cast<tree_node *>( pOp->iInfo.pNew ),
1327                     memory_model::memory_order_release, atomics::memory_order_relaxed );
1328             }
1329             else {
1330                 pOp->iInfo.pParent->m_pLeft.compare_exchange_strong( pLeaf, static_cast<tree_node *>( pOp->iInfo.pNew ),
1331                     memory_model::memory_order_release, atomics::memory_order_relaxed );
1332             }
1333
1334             update_ptr cur( pOp, update_desc::IFlag );
1335             pOp->iInfo.pParent->m_pUpdate.compare_exchange_strong( cur, pOp->iInfo.pParent->null_update_desc(),
1336                       memory_model::memory_order_release, atomics::memory_order_relaxed );
1337         }
1338
1339         bool check_delete_precondition( search_result& res )
1340         {
1341             assert( res.pGrandParent != nullptr );
1342
1343             return
1344                 static_cast<internal_node *>( res.bRightParent
1345                     ? res.pGrandParent->m_pRight.load(memory_model::memory_order_relaxed)
1346                     : res.pGrandParent->m_pLeft.load(memory_model::memory_order_relaxed)
1347                 ) == res.pParent
1348                 &&
1349                 static_cast<leaf_node *>( res.bRightLeaf
1350                     ? res.pParent->m_pRight.load(memory_model::memory_order_relaxed)
1351                     : res.pParent->m_pLeft.load(memory_model::memory_order_relaxed)
1352                 ) == res.pLeaf;
1353         }
1354
1355         bool help_delete( update_desc * pOp, retired_list& rl )
1356         {
1357             assert( gc::is_locked() );
1358
1359             update_ptr pUpdate( pOp->dInfo.pUpdateParent );
1360             update_ptr pMark( pOp, update_desc::Mark );
1361             if ( pOp->dInfo.pParent->m_pUpdate.compare_exchange_strong( pUpdate, pMark,
1362                     memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1363             {
1364                 help_marked( pOp );
1365                 retire_node( pOp->dInfo.pParent, rl );
1366                 // For extract operations the leaf should NOT be disposed
1367                 if ( pOp->dInfo.bDisposeLeaf )
1368                     retire_node( pOp->dInfo.pLeaf, rl );
1369                 retire_update_desc( pOp, rl, false );
1370
1371                 return true;
1372             }
1373             else if ( pUpdate == pMark ) {
1374                 // some other thread is processing help_marked()
1375                 help_marked( pOp );
1376                 m_Stat.onHelpMark();
1377                 return true;
1378             }
1379             else {
1380                 // pUpdate has been changed by CAS
1381                 help( pUpdate, rl );
1382
1383                 // Undo grandparent dInfo
1384                 update_ptr pDel( pOp, update_desc::DFlag );
1385                 if ( pOp->dInfo.pGrandParent->m_pUpdate.compare_exchange_strong( pDel, pOp->dInfo.pGrandParent->null_update_desc(),
1386                     memory_model::memory_order_release, atomics::memory_order_relaxed ))
1387                 {
1388                     retire_update_desc( pOp, rl, false );
1389                 }
1390                 return false;
1391             }
1392         }
1393
1394         void help_marked( update_desc * pOp )
1395         {
1396             assert( gc::is_locked() );
1397
1398             tree_node * p = pOp->dInfo.pParent;
1399             if ( pOp->dInfo.bRightParent ) {
1400                 pOp->dInfo.pGrandParent->m_pRight.compare_exchange_strong( p,
1401                     pOp->dInfo.bRightLeaf
1402                         ? pOp->dInfo.pParent->m_pLeft.load( memory_model::memory_order_acquire )
1403                         : pOp->dInfo.pParent->m_pRight.load( memory_model::memory_order_acquire ),
1404                     memory_model::memory_order_release, atomics::memory_order_relaxed );
1405             }
1406             else {
1407                 pOp->dInfo.pGrandParent->m_pLeft.compare_exchange_strong( p,
1408                     pOp->dInfo.bRightLeaf
1409                         ? pOp->dInfo.pParent->m_pLeft.load( memory_model::memory_order_acquire )
1410                         : pOp->dInfo.pParent->m_pRight.load( memory_model::memory_order_acquire ),
1411                     memory_model::memory_order_release, atomics::memory_order_relaxed );
1412             }
1413
1414             update_ptr upd( pOp, update_desc::DFlag );
1415             pOp->dInfo.pGrandParent->m_pUpdate.compare_exchange_strong( upd, pOp->dInfo.pGrandParent->null_update_desc(),
1416                 memory_model::memory_order_release, atomics::memory_order_relaxed );
1417         }
1418
1419         template <typename KeyValue, typename Compare>
1420         bool search( search_result& res, KeyValue const& key, Compare cmp ) const
1421         {
1422             assert( gc::is_locked() );
1423
1424             internal_node * pParent;
1425             internal_node * pGrandParent = nullptr;
1426             tree_node *     pLeaf;
1427             update_ptr      updParent;
1428             update_ptr      updGrandParent;
1429             bool bRightLeaf;
1430             bool bRightParent = false;
1431
1432             int nCmp = 0;
1433
1434         retry:
1435             pParent = nullptr;
1436             pLeaf = const_cast<internal_node *>( &m_Root );
1437             updParent = nullptr;
1438             bRightLeaf = false;
1439             while ( pLeaf->is_internal() ) {
1440                 pGrandParent = pParent;
1441                 pParent = static_cast<internal_node *>( pLeaf );
1442                 bRightParent = bRightLeaf;
1443                 updGrandParent = updParent;
1444                 updParent = pParent->m_pUpdate.load( memory_model::memory_order_acquire );
1445
1446                 switch ( updParent.bits() ) {
1447                     case update_desc::DFlag:
1448                     case update_desc::Mark:
1449                         m_Stat.onSearchRetry();
1450                         goto retry;
1451                 }
1452
1453                 nCmp = cmp( key, *pParent );
1454                 bRightLeaf = nCmp >= 0;
1455                 pLeaf = nCmp < 0 ? pParent->m_pLeft.load( memory_model::memory_order_acquire )
1456                                  : pParent->m_pRight.load( memory_model::memory_order_acquire );
1457             }
1458
1459             assert( pLeaf->is_leaf() );
1460             nCmp = cmp( key, *static_cast<leaf_node *>(pLeaf) );
1461
1462             res.pGrandParent    = pGrandParent;
1463             res.pParent         = pParent;
1464             res.pLeaf           = static_cast<leaf_node *>( pLeaf );
1465             res.updParent       = updParent;
1466             res.updGrandParent  = updGrandParent;
1467             res.bRightParent    = bRightParent;
1468             res.bRightLeaf      = bRightLeaf;
1469
1470             return nCmp == 0;
1471         }
1472
1473         bool search_min( search_result& res ) const
1474         {
1475             assert( gc::is_locked() );
1476
1477             internal_node * pParent;
1478             internal_node * pGrandParent = nullptr;
1479             tree_node *     pLeaf;
1480             update_ptr      updParent;
1481             update_ptr      updGrandParent;
1482
1483         retry:
1484             pParent = nullptr;
1485             pLeaf = const_cast<internal_node *>( &m_Root );
1486             while ( pLeaf->is_internal() ) {
1487                 pGrandParent = pParent;
1488                 pParent = static_cast<internal_node *>( pLeaf );
1489                 updGrandParent = updParent;
1490                 updParent = pParent->m_pUpdate.load( memory_model::memory_order_acquire );
1491
1492                 switch ( updParent.bits() ) {
1493                     case update_desc::DFlag:
1494                     case update_desc::Mark:
1495                         m_Stat.onSearchRetry();
1496                         goto retry;
1497                 }
1498
1499                 pLeaf = pParent->m_pLeft.load( memory_model::memory_order_acquire );
1500             }
1501
1502             if ( pLeaf->infinite_key())
1503                 return false;
1504
1505             res.pGrandParent    = pGrandParent;
1506             res.pParent         = pParent;
1507             assert( pLeaf->is_leaf() );
1508             res.pLeaf           = static_cast<leaf_node *>( pLeaf );
1509             res.updParent       = updParent;
1510             res.updGrandParent  = updGrandParent;
1511             res.bRightParent    = false;
1512             res.bRightLeaf      = false;
1513
1514             return true;
1515         }
1516
1517         bool search_max( search_result& res ) const
1518         {
1519             assert( gc::is_locked() );
1520
1521             internal_node * pParent;
1522             internal_node * pGrandParent = nullptr;
1523             tree_node *     pLeaf;
1524             update_ptr      updParent;
1525             update_ptr      updGrandParent;
1526             bool bRightLeaf;
1527             bool bRightParent = false;
1528
1529         retry:
1530             pParent = nullptr;
1531             pLeaf = const_cast<internal_node *>( &m_Root );
1532             bRightLeaf = false;
1533             while ( pLeaf->is_internal() ) {
1534                 pGrandParent = pParent;
1535                 pParent = static_cast<internal_node *>( pLeaf );
1536                 bRightParent = bRightLeaf;
1537                 updGrandParent = updParent;
1538                 updParent = pParent->m_pUpdate.load( memory_model::memory_order_acquire );
1539
1540                 switch ( updParent.bits() ) {
1541                     case update_desc::DFlag:
1542                     case update_desc::Mark:
1543                         m_Stat.onSearchRetry();
1544                         goto retry;
1545                 }
1546
1547                 if ( pParent->infinite_key()) {
1548                     pLeaf = pParent->m_pLeft.load( memory_model::memory_order_acquire );
1549                     bRightLeaf = false;
1550                 }
1551                 else {
1552                     pLeaf = pParent->m_pRight.load( memory_model::memory_order_acquire );
1553                     bRightLeaf = true;
1554                 }
1555             }
1556
1557             if ( pLeaf->infinite_key())
1558                 return false;
1559
1560             res.pGrandParent    = pGrandParent;
1561             res.pParent         = pParent;
1562             assert( pLeaf->is_leaf() );
1563             res.pLeaf           = static_cast<leaf_node *>( pLeaf );
1564             res.updParent       = updParent;
1565             res.updGrandParent  = updGrandParent;
1566             res.bRightParent    = bRightParent;
1567             res.bRightLeaf      = bRightLeaf;
1568
1569             return true;
1570         }
1571
1572         template <typename Q, typename Compare, typename Equal, typename Func>
1573         bool erase_( Q const& val, Compare cmp, Equal eq, Func f )
1574         {
1575             check_deadlock_policy::check();
1576
1577             retired_list updRetire;
1578             update_desc * pOp = nullptr;
1579             search_result res;
1580
1581             {
1582                 rcu_lock l;
1583                 for ( ;; ) {
1584                     if ( !search( res, val, cmp ) || !eq( val, *res.pLeaf ) ) {
1585                         if ( pOp )
1586                             retire_update_desc( pOp, updRetire, false );
1587                         m_Stat.onEraseFailed();
1588                         return false;
1589                     }
1590
1591                     if ( res.updGrandParent.bits() != update_desc::Clean )
1592                         help( res.updGrandParent, updRetire );
1593                     else if ( res.updParent.bits() != update_desc::Clean )
1594                         help( res.updParent, updRetire );
1595                     else {
1596                         if ( !pOp )
1597                             pOp = alloc_update_desc();
1598                         if ( check_delete_precondition( res ) ) {
1599                             pOp->dInfo.pGrandParent = res.pGrandParent;
1600                             pOp->dInfo.pParent = res.pParent;
1601                             pOp->dInfo.pLeaf = res.pLeaf;
1602                             pOp->dInfo.bDisposeLeaf = true;
1603                             pOp->dInfo.pUpdateParent = res.updParent.ptr();
1604                             pOp->dInfo.bRightParent = res.bRightParent;
1605                             pOp->dInfo.bRightLeaf = res.bRightLeaf;
1606
1607                             update_ptr updGP( res.updGrandParent.ptr() );
1608                             if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
1609                                 memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1610                             {
1611                                 if ( help_delete( pOp, updRetire )) {
1612                                     // res.pLeaf is not deleted yet since RCU is blocked
1613                                     f( *node_traits::to_value_ptr( res.pLeaf ));
1614                                     break;
1615                                 }
1616                                 pOp = nullptr;
1617                             }
1618                             else {
1619                                 // updGP has been changed by CAS
1620                                 help( updGP, updRetire );
1621                             }
1622                         }
1623                     }
1624
1625                     m_Stat.onEraseRetry();
1626                 }
1627             }
1628
1629             --m_ItemCounter;
1630             m_Stat.onEraseSuccess();
1631             return true;
1632         }
1633
1634         template <typename ExemptPtr, typename Q, typename Less>
1635         bool extract_with_( ExemptPtr& dest,  Q const& val, Less pred )
1636         {
1637             typedef ellen_bintree::details::compare<
1638                 key_type,
1639                 value_type,
1640                 opt::details::make_comparator_from_less<Less>,
1641                 node_traits
1642             > compare_functor;
1643
1644             return extract_( dest, val, compare_functor() );
1645         }
1646
1647         template <typename ExemptPtr, typename Q, typename Compare>
1648         bool extract_( ExemptPtr& ptr, Q const& val, Compare cmp )
1649         {
1650             check_deadlock_policy::check();
1651
1652             retired_list updRetire;
1653             update_desc * pOp = nullptr;
1654             search_result res;
1655
1656             {
1657                 rcu_lock l;
1658                 for ( ;; ) {
1659                     if ( !search( res, val, cmp ) ) {
1660                         if ( pOp )
1661                             retire_update_desc( pOp, updRetire, false );
1662                         m_Stat.onEraseFailed();
1663                         return false;
1664                     }
1665
1666                     if ( res.updGrandParent.bits() != update_desc::Clean )
1667                         help( res.updGrandParent, updRetire );
1668                     else if ( res.updParent.bits() != update_desc::Clean )
1669                         help( res.updParent, updRetire );
1670                     else {
1671                         if ( !pOp )
1672                             pOp = alloc_update_desc();
1673                         if ( check_delete_precondition( res )) {
1674                             pOp->dInfo.pGrandParent = res.pGrandParent;
1675                             pOp->dInfo.pParent = res.pParent;
1676                             pOp->dInfo.pLeaf = res.pLeaf;
1677                             pOp->dInfo.bDisposeLeaf = false;
1678                             pOp->dInfo.pUpdateParent = res.updParent.ptr();
1679                             pOp->dInfo.bRightParent = res.bRightParent;
1680                             pOp->dInfo.bRightLeaf = res.bRightLeaf;
1681
1682                             update_ptr updGP( res.updGrandParent.ptr() );
1683                             if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
1684                                 memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1685                             {
1686                                 if ( help_delete( pOp, updRetire )) {
1687                                     ptr = node_traits::to_value_ptr( res.pLeaf );
1688                                     break;
1689                                 }
1690                                 pOp = nullptr;
1691                             }
1692                             else {
1693                                 // updGP has been changed by CAS
1694                                 help( updGP, updRetire );
1695                             }
1696                         }
1697                     }
1698
1699                     m_Stat.onEraseRetry();
1700                 }
1701             }
1702
1703             --m_ItemCounter;
1704             m_Stat.onEraseSuccess();
1705             return true;
1706         }
1707
1708
1709         template <typename ExemptPtr>
1710         bool extract_max_( ExemptPtr& result )
1711         {
1712             check_deadlock_policy::check();
1713
1714             retired_list updRetire;
1715             update_desc * pOp = nullptr;
1716             search_result res;
1717
1718             {
1719                 rcu_lock l;
1720                 for ( ;; ) {
1721                     if ( !search_max( res )) {
1722                         // Tree is empty
1723                         if ( pOp )
1724                             retire_update_desc( pOp, updRetire, false );
1725                         m_Stat.onExtractMaxFailed();
1726                         return false;
1727                     }
1728
1729                     if ( res.updGrandParent.bits() != update_desc::Clean )
1730                         help( res.updGrandParent, updRetire );
1731                     else if ( res.updParent.bits() != update_desc::Clean )
1732                         help( res.updParent, updRetire );
1733                     else {
1734                         if ( !pOp )
1735                             pOp = alloc_update_desc();
1736                         if ( check_delete_precondition( res ) ) {
1737                             pOp->dInfo.pGrandParent = res.pGrandParent;
1738                             pOp->dInfo.pParent = res.pParent;
1739                             pOp->dInfo.pLeaf = res.pLeaf;
1740                             pOp->dInfo.bDisposeLeaf = false;
1741                             pOp->dInfo.pUpdateParent = res.updParent.ptr();
1742                             pOp->dInfo.bRightParent = res.bRightParent;
1743                             pOp->dInfo.bRightLeaf = res.bRightLeaf;
1744
1745                             update_ptr updGP( res.updGrandParent.ptr() );
1746                             if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
1747                                 memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1748                             {
1749                                 if ( help_delete( pOp, updRetire )) {
1750                                     result = node_traits::to_value_ptr( res.pLeaf );
1751                                     break;
1752                                 }
1753                                 pOp = nullptr;
1754                             }
1755                             else {
1756                                 // updGP has been changed by CAS
1757                                 help( updGP, updRetire );
1758                             }
1759                         }
1760                     }
1761                     m_Stat.onExtractMaxRetry();
1762                 }
1763             }
1764
1765             --m_ItemCounter;
1766             m_Stat.onExtractMaxSuccess();
1767             return true;
1768         }
1769
1770         template <typename ExemptPtr>
1771         bool extract_min_(ExemptPtr& result)
1772         {
1773             check_deadlock_policy::check();
1774
1775             retired_list updRetire;
1776             update_desc * pOp = nullptr;
1777             search_result res;
1778
1779             {
1780                 rcu_lock l;
1781                 for ( ;; ) {
1782                     if ( !search_min( res )) {
1783                         // Tree is empty
1784                         if ( pOp )
1785                             retire_update_desc( pOp, updRetire, false );
1786                         m_Stat.onExtractMinFailed();
1787                         return false;
1788                     }
1789
1790                     if ( res.updGrandParent.bits() != update_desc::Clean )
1791                         help( res.updGrandParent, updRetire );
1792                     else if ( res.updParent.bits() != update_desc::Clean )
1793                         help( res.updParent, updRetire );
1794                     else {
1795                         if ( !pOp )
1796                             pOp = alloc_update_desc();
1797                         if ( check_delete_precondition( res ) ) {
1798                             pOp->dInfo.pGrandParent = res.pGrandParent;
1799                             pOp->dInfo.pParent = res.pParent;
1800                             pOp->dInfo.pLeaf = res.pLeaf;
1801                             pOp->dInfo.bDisposeLeaf = false;
1802                             pOp->dInfo.pUpdateParent = res.updParent.ptr();
1803                             pOp->dInfo.bRightParent = res.bRightParent;
1804                             pOp->dInfo.bRightLeaf = res.bRightLeaf;
1805
1806                             update_ptr updGP( res.updGrandParent.ptr() );
1807                             if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
1808                                 memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1809                             {
1810                                 if ( help_delete( pOp, updRetire )) {
1811                                     result = node_traits::to_value_ptr( res.pLeaf );
1812                                     break;
1813                                 }
1814                                 pOp = nullptr;
1815                             }
1816                             else {
1817                                 // updGP has been changed by CAS
1818                                 help( updGP, updRetire );
1819                             }
1820                         }
1821                     }
1822
1823                     m_Stat.onExtractMinRetry();
1824                 }
1825             }
1826
1827             --m_ItemCounter;
1828             m_Stat.onExtractMinSuccess();
1829             return true;
1830         }
1831
1832         template <typename Q, typename Less, typename Func>
1833         bool find_with_( Q& val, Less pred, Func f ) const
1834         {
1835             typedef ellen_bintree::details::compare<
1836                 key_type,
1837                 value_type,
1838                 opt::details::make_comparator_from_less<Less>,
1839                 node_traits
1840             > compare_functor;
1841
1842             rcu_lock l;
1843             search_result    res;
1844             if ( search( res, val, compare_functor() )) {
1845                 assert( res.pLeaf );
1846                 f( *node_traits::to_value_ptr( res.pLeaf ), val );
1847
1848                 m_Stat.onFindSuccess();
1849                 return true;
1850             }
1851
1852             m_Stat.onFindFailed();
1853             return false;
1854         }
1855
1856         template <typename Q, typename Func>
1857         bool find_( Q& key, Func f ) const
1858         {
1859             rcu_lock l;
1860             search_result    res;
1861             if ( search( res, key, node_compare() )) {
1862                 assert( res.pLeaf );
1863                 f( *node_traits::to_value_ptr( res.pLeaf ), key );
1864
1865                 m_Stat.onFindSuccess();
1866                 return true;
1867             }
1868
1869             m_Stat.onFindFailed();
1870             return false;
1871         }
1872
1873         template <typename Q, typename Compare>
1874         value_type * get_( Q const& key, Compare cmp ) const
1875         {
1876             assert( gc::is_locked());
1877
1878             search_result    res;
1879             if ( search( res, key, cmp )) {
1880                 m_Stat.onFindSuccess();
1881                 return node_traits::to_value_ptr( res.pLeaf );
1882             }
1883
1884             m_Stat.onFindFailed();
1885             return nullptr;
1886         }
1887
1888
1889         bool try_insert( value_type& val, internal_node * pNewInternal, search_result& res, retired_list& updRetire )
1890         {
1891             assert( gc::is_locked() );
1892             assert( res.updParent.bits() == update_desc::Clean );
1893
1894             // check search result
1895             if ( static_cast<leaf_node *>( res.bRightLeaf
1896                 ? res.pParent->m_pRight.load( memory_model::memory_order_relaxed )
1897                 : res.pParent->m_pLeft.load( memory_model::memory_order_relaxed ) ) == res.pLeaf )
1898             {
1899                 leaf_node * pNewLeaf = node_traits::to_node_ptr( val );
1900
1901                 int nCmp = node_compare()( val, *res.pLeaf );
1902                 if ( nCmp < 0 ) {
1903                     if ( res.pGrandParent ) {
1904                         pNewInternal->infinite_key( 0 );
1905                         key_extractor()( pNewInternal->m_Key, *node_traits::to_value_ptr( res.pLeaf ) );
1906                         assert( !res.pLeaf->infinite_key() );
1907                     }
1908                     else {
1909                         assert( res.pLeaf->infinite_key() == tree_node::key_infinite1 );
1910                         pNewInternal->infinite_key( 1 );
1911                     }
1912                     pNewInternal->m_pLeft.store( static_cast<tree_node *>(pNewLeaf), memory_model::memory_order_relaxed );
1913                     pNewInternal->m_pRight.store( static_cast<tree_node *>(res.pLeaf), memory_model::memory_order_release );
1914                 }
1915                 else {
1916                     assert( !res.pLeaf->is_internal() );
1917                     pNewInternal->infinite_key( 0 );
1918
1919                     key_extractor()( pNewInternal->m_Key, val );
1920                     pNewInternal->m_pLeft.store( static_cast<tree_node *>(res.pLeaf), memory_model::memory_order_relaxed );
1921                     pNewInternal->m_pRight.store( static_cast<tree_node *>(pNewLeaf), memory_model::memory_order_release );
1922                     assert( !res.pLeaf->infinite_key());
1923                 }
1924
1925                 update_desc * pOp = alloc_update_desc();
1926
1927                 pOp->iInfo.pParent = res.pParent;
1928                 pOp->iInfo.pNew = pNewInternal;
1929                 pOp->iInfo.pLeaf = res.pLeaf;
1930                 pOp->iInfo.bRightLeaf = res.bRightLeaf;
1931
1932                 update_ptr updCur( res.updParent.ptr() );
1933                 if ( res.pParent->m_pUpdate.compare_exchange_strong( updCur, update_ptr( pOp, update_desc::IFlag ),
1934                     memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1935                 {
1936                     // do insert
1937                     help_insert( pOp );
1938                     retire_update_desc( pOp, updRetire, false );
1939                     return true;
1940                 }
1941                 else {
1942                     // updCur has been updated by CAS
1943                     help( updCur, updRetire );
1944                     retire_update_desc( pOp, updRetire, true );
1945                 }
1946             }
1947             return false;
1948         }
1949
1950         //@endcond
1951     };
1952
1953 }} // namespace cds::intrusive
1954
1955 #endif  // #ifndef __CDS_INTRUSIVE_ELLEN_BINTREE_RCU_H