c0cc2ff37faf6ca7e0d136ec162546ab1b4ef54c
[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         typedef typename traits::back_off back_off;   ///< back-off strategy
440
441     protected:
442         //@cond
443         typedef ellen_bintree::base_node< gc >                      tree_node; ///< Base type of tree node
444         typedef node_type                                           leaf_node; ///< Leaf node type
445         typedef ellen_bintree::internal_node< key_type, leaf_node > internal_node; ///< Internal node type
446         typedef ellen_bintree::update_desc< leaf_node, internal_node> update_desc; ///< Update descriptor
447         typedef typename update_desc::update_ptr                    update_ptr; ///< Marked pointer to update descriptor
448         //@endcond
449
450     public:
451         using exempt_ptr = cds::urcu::exempt_ptr< gc, value_type, value_type, disposer, void >; ///< pointer to extracted node
452
453     public:
454 #   ifdef CDS_DOXYGEN_INVOKED
455         typedef implementation_defined key_comparator;    ///< key compare functor based on \p Traits::compare and \p Traits::less
456         typedef typename get_node_traits< value_type, node_type, hook>::type node_traits; ///< Node traits
457 #   else
458         typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;
459         struct node_traits: public get_node_traits< value_type, node_type, hook>::type
460         {
461             static internal_node const& to_internal_node( tree_node const& n )
462             {
463                 assert( n.is_internal() );
464                 return static_cast<internal_node const&>( n );
465             }
466
467             static leaf_node const& to_leaf_node( tree_node const& n )
468             {
469                 assert( n.is_leaf() );
470                 return static_cast<leaf_node const&>( n );
471             }
472         };
473 #   endif
474
475         typedef typename traits::item_counter  item_counter;   ///< Item counting policy used
476         typedef typename traits::memory_model  memory_model;   ///< Memory ordering. See cds::opt::memory_model option
477         typedef typename traits::stat          stat;           ///< internal statistics type
478         typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
479         typedef typename traits::key_extractor      key_extractor;      ///< key extracting functor
480
481         typedef typename traits::node_allocator        node_allocator;  ///< Internal node allocator
482         typedef typename traits::update_desc_allocator update_desc_allocator; ///< Update descriptor allocator
483
484         typedef typename gc::scoped_lock    rcu_lock;   ///< RCU scoped lock
485
486         static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions do not require external locking
487
488     protected:
489         //@cond
490         typedef ellen_bintree::details::compare< key_type, value_type, key_comparator, node_traits > node_compare;
491
492         typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock >   check_deadlock_policy;
493
494         typedef cds::details::Allocator< internal_node, node_allocator >        cxx_node_allocator;
495         typedef cds::details::Allocator< update_desc, update_desc_allocator >   cxx_update_desc_allocator;
496
497         struct search_result {
498             internal_node *     pGrandParent;
499             internal_node *     pParent;
500             leaf_node *         pLeaf;
501             update_ptr          updParent;
502             update_ptr          updGrandParent;
503             bool                bRightLeaf      ; // true if pLeaf is right child of pParent, false otherwise
504             bool                bRightParent    ; // true if pParent is right child of pGrandParent, false otherwise
505
506             search_result()
507                 :pGrandParent( nullptr )
508                 , pParent( nullptr )
509                 , pLeaf( nullptr )
510                 ,bRightLeaf( false )
511                 ,bRightParent( false )
512             {}
513         };
514         //@endcond
515
516     protected:
517         //@cond
518         internal_node       m_Root;     ///< Tree root node (key= Infinite2)
519         leaf_node           m_LeafInf1;
520         leaf_node           m_LeafInf2;
521         //@endcond
522
523         item_counter        m_ItemCounter;  ///< item counter
524         mutable stat        m_Stat;         ///< internal statistics
525
526     protected:
527         //@cond
528         static void free_leaf_node( value_type * p )
529         {
530             disposer()( p );
531         }
532
533         internal_node * alloc_internal_node() const
534         {
535             m_Stat.onInternalNodeCreated();
536             internal_node * pNode = cxx_node_allocator().New();
537             //pNode->clean();
538             return pNode;
539         }
540
541         static void free_internal_node( internal_node * pNode )
542         {
543             cxx_node_allocator().Delete( pNode );
544         }
545
546         struct internal_node_deleter {
547             void operator()( internal_node * p) const
548             {
549                 free_internal_node( p );
550             }
551         };
552
553         typedef std::unique_ptr< internal_node, internal_node_deleter>  unique_internal_node_ptr;
554
555         update_desc * alloc_update_desc() const
556         {
557             m_Stat.onUpdateDescCreated();
558             return cxx_update_desc_allocator().New();
559         }
560
561         static void free_update_desc( update_desc * pDesc )
562         {
563             cxx_update_desc_allocator().Delete( pDesc );
564         }
565
566         class retired_list
567         {
568             update_desc *   pUpdateHead;
569             tree_node *     pNodeHead;
570
571         private:
572             class forward_iterator
573             {
574                 update_desc *   m_pUpdate;
575                 tree_node *     m_pNode;
576
577             public:
578                 forward_iterator( retired_list const& l )
579                     : m_pUpdate( l.pUpdateHead )
580                     , m_pNode( l.pNodeHead )
581                 {}
582
583                 forward_iterator()
584                     : m_pUpdate( nullptr )
585                     , m_pNode( nullptr )
586                 {}
587
588                 cds::urcu::retired_ptr operator *()
589                 {
590                     if ( m_pUpdate ) {
591                         return cds::urcu::retired_ptr( reinterpret_cast<void *>( m_pUpdate ),
592                             reinterpret_cast<cds::urcu::free_retired_ptr_func>( free_update_desc ) );
593                     }
594                     if ( m_pNode ) {
595                         if ( m_pNode->is_leaf() ) {
596                             return cds::urcu::retired_ptr( reinterpret_cast<void *>( node_traits::to_value_ptr( static_cast<leaf_node *>( m_pNode ))),
597                                 reinterpret_cast< cds::urcu::free_retired_ptr_func>( free_leaf_node ) );
598                         }
599                         else {
600                             return cds::urcu::retired_ptr( reinterpret_cast<void *>( static_cast<internal_node *>( m_pNode ) ),
601                                 reinterpret_cast<cds::urcu::free_retired_ptr_func>( free_internal_node ) );
602                         }
603                     }
604                     return cds::urcu::retired_ptr( nullptr,
605                         reinterpret_cast<cds::urcu::free_retired_ptr_func>( free_update_desc ) );
606                 }
607
608                 void operator ++()
609                 {
610                     if ( m_pUpdate ) {
611                         m_pUpdate = m_pUpdate->pNextRetire;
612                         return;
613                     }
614                     if ( m_pNode )
615                         m_pNode = m_pNode->m_pNextRetired;
616                 }
617
618                 friend bool operator ==( forward_iterator const& i1, forward_iterator const& i2 )
619                 {
620                     return i1.m_pUpdate == i2.m_pUpdate && i1.m_pNode == i2.m_pNode;
621                 }
622                 friend bool operator !=( forward_iterator const& i1, forward_iterator const& i2 )
623                 {
624                     return !( i1 == i2 );
625                 }
626             };
627
628         public:
629             retired_list()
630                 : pUpdateHead( nullptr )
631                 , pNodeHead( nullptr )
632             {}
633
634             ~retired_list()
635             {
636                 gc::batch_retire( forward_iterator(*this), forward_iterator() );
637             }
638
639             void push( update_desc * p )
640             {
641                 p->pNextRetire = pUpdateHead;
642                 pUpdateHead = p;
643             }
644
645             void push( tree_node * p )
646             {
647                 p->m_pNextRetired = pNodeHead;
648                 pNodeHead = p;
649             }
650         };
651
652         void retire_node( tree_node * pNode, retired_list& rl ) const
653         {
654             if ( pNode->is_leaf() ) {
655                 assert( static_cast<leaf_node *>( pNode ) != &m_LeafInf1 );
656                 assert( static_cast<leaf_node *>( pNode ) != &m_LeafInf2 );
657             }
658             else {
659                 assert( static_cast<internal_node *>( pNode ) != &m_Root );
660                 m_Stat.onInternalNodeDeleted();
661             }
662             rl.push( pNode );
663         }
664
665         void retire_update_desc( update_desc * p, retired_list& rl, bool bDirect ) const
666         {
667             m_Stat.onUpdateDescDeleted();
668             if ( bDirect )
669                 free_update_desc( p );
670             else
671                 rl.push( p );
672         }
673
674         void make_empty_tree()
675         {
676             m_Root.infinite_key( 2 );
677             m_LeafInf1.infinite_key( 1 );
678             m_LeafInf2.infinite_key( 2 );
679             m_Root.m_pLeft.store( &m_LeafInf1, memory_model::memory_order_relaxed );
680             m_Root.m_pRight.store( &m_LeafInf2, memory_model::memory_order_release );
681         }
682         //@endcond
683
684     public:
685         /// Default constructor
686         EllenBinTree()
687         {
688             static_assert( !std::is_same< key_extractor, opt::none >::value, "The key extractor option must be specified" );
689             make_empty_tree();
690         }
691
692         /// Clears the tree
693         ~EllenBinTree()
694         {
695             unsafe_clear();
696         }
697
698         /// Inserts new node
699         /**
700             The function inserts \p val in the tree if it does not contain
701             an item with key equal to \p val.
702
703             The function applies RCU lock internally.
704
705             Returns \p true if \p val is placed into the set, \p false otherwise.
706         */
707         bool insert( value_type& val )
708         {
709             return insert( val, []( value_type& ) {} );
710         }
711
712         /// Inserts new node
713         /**
714             This function is intended for derived non-intrusive containers.
715
716             The function allows to split creating of new item into two part:
717             - create item with key only
718             - insert new item into the tree
719             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
720
721             The functor signature is:
722             \code
723                 void func( value_type& val );
724             \endcode
725             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
726             \p val no any other changes could be made on this tree's item by concurrent threads.
727             The user-defined functor is called only if the inserting is success.
728
729             RCU \p synchronize method can be called. RCU should not be locked.
730         */
731         template <typename Func>
732         bool insert( value_type& val, Func f )
733         {
734             check_deadlock_policy::check();
735
736             unique_internal_node_ptr pNewInternal;
737             retired_list updRetire;
738             back_off bkoff;
739
740             {
741                 rcu_lock l;
742
743                 search_result res;
744                 for ( ;; ) {
745                     if ( search( res, val, node_compare() )) {
746                         if ( pNewInternal.get() )
747                             m_Stat.onInternalNodeDeleted() ;    // unique_internal_node_ptr deletes internal node
748                         m_Stat.onInsertFailed();
749                         return false;
750                     }
751
752                     if ( res.updParent.bits() != update_desc::Clean )
753                         help( res.updParent, updRetire );
754                     else {
755                         if ( !pNewInternal.get() )
756                             pNewInternal.reset( alloc_internal_node() );
757
758                         if ( try_insert( val, pNewInternal.get(), res, updRetire )) {
759                             f( val );
760                             pNewInternal.release()  ;   // internal node is linked into the tree and should not be deleted
761                             break;
762                         }
763                     }
764
765                     bkoff();
766                     m_Stat.onInsertRetry();
767                 }
768             }
769
770             ++m_ItemCounter;
771             m_Stat.onInsertSuccess();
772
773             return true;
774         }
775
776         /// Ensures that the \p val exists in the tree
777         /**
778             The operation performs inserting or changing data with lock-free manner.
779
780             If the item \p val is not found in the tree, then \p val is inserted into the tree.
781             Otherwise, the functor \p func is called with item found.
782             The functor signature is:
783             \code
784                 void func( bool bNew, value_type& item, value_type& val );
785             \endcode
786             with arguments:
787             - \p bNew - \p true if the item has been inserted, \p false otherwise
788             - \p item - item of the tree
789             - \p val - argument \p val passed into the \p ensure function
790             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
791             refer to the same thing.
792
793             The functor can change non-key fields of the \p item; however, \p func must guarantee
794             that during changing no any other modifications could be made on this item by concurrent threads.
795
796             RCU \p synchronize method can be called. RCU should not be locked.
797
798             Returns <tt>std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
799             \p second is \p true if new item has been added or \p false if the item with \p key
800             already is in the tree.
801
802             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
803         */
804         template <typename Func>
805         std::pair<bool, bool> ensure( value_type& val, Func func )
806         {
807             check_deadlock_policy::check();
808
809             unique_internal_node_ptr pNewInternal;
810             retired_list updRetire;
811             back_off bkoff;
812
813             {
814                 rcu_lock l;
815
816                 search_result res;
817                 for ( ;; ) {
818                     if ( search( res, val, node_compare() )) {
819                         func( false, *node_traits::to_value_ptr( res.pLeaf ), val );
820                         if ( pNewInternal.get() )
821                             m_Stat.onInternalNodeDeleted() ;    // unique_internal_node_ptr deletes internal node
822                         m_Stat.onEnsureExist();
823                         return std::make_pair( true, false );
824                     }
825
826                     if ( res.updParent.bits() != update_desc::Clean )
827                         help( res.updParent, updRetire );
828                     else {
829                         if ( !pNewInternal.get() )
830                             pNewInternal.reset( alloc_internal_node() );
831
832                         if ( try_insert( val, pNewInternal.get(), res, updRetire )) {
833                             func( true, val, val );
834                             pNewInternal.release()  ;   // internal node is linked into the tree and should not be deleted
835                             break;
836                         }
837                     }
838
839                     bkoff();
840                     m_Stat.onEnsureRetry();
841                 }
842             }
843
844             ++m_ItemCounter;
845             m_Stat.onEnsureNew();
846
847             return std::make_pair( true, true );
848         }
849
850         /// Unlinks the item \p val from the tree
851         /**
852             The function searches the item \p val in the tree and unlink it from the tree
853             if it is found and is equal to \p val.
854
855             Difference between \ref erase and \p unlink functions: \p erase finds <i>a key</i>
856             and deletes the item found. \p unlink finds an item by key and deletes it
857             only if \p val is an item of the tree, i.e. the pointer to item found
858             is equal to <tt> &val </tt>.
859
860             RCU \p synchronize method can be called. RCU should not be locked.
861
862             The \ref disposer specified in \p Traits class template parameter is called
863             by garbage collector \p GC asynchronously.
864
865             The function returns \p true if success and \p false otherwise.
866         */
867         bool unlink( value_type& val )
868         {
869             return erase_( val, node_compare(),
870                 []( value_type const& v, leaf_node const& n ) -> bool { return &v == node_traits::to_value_ptr( n ); },
871                 [](value_type const&) {} );
872         }
873
874         /// Deletes the item from the tree
875         /** \anchor cds_intrusive_EllenBinTree_rcu_erase
876             The function searches an item with key equal to \p key in the tree,
877             unlinks it from the tree, and returns \p true.
878             If the item with key equal to \p key is not found the function return \p false.
879
880             Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
881
882             RCU \p synchronize method can be called. RCU should not be locked.
883         */
884         template <typename Q>
885         bool erase( const Q& key )
886         {
887             return erase_( key, node_compare(),
888                 []( Q const&, leaf_node const& ) -> bool { return true; },
889                 [](value_type const&) {} );
890         }
891
892         /// Delete the item from the tree with comparing functor \p pred
893         /**
894             The function is an analog of \ref cds_intrusive_EllenBinTree_rcu_erase "erase(Q const&)"
895             but \p pred predicate is used for key comparing.
896             \p Less has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_rcu_less
897             "Predicate requirements".
898             \p pred must imply the same element order as the comparator used for building the tree.
899         */
900         template <typename Q, typename Less>
901         bool erase_with( const Q& key, Less pred )
902         {
903             CDS_UNUSED( pred );
904             typedef ellen_bintree::details::compare<
905                 key_type,
906                 value_type,
907                 opt::details::make_comparator_from_less<Less>,
908                 node_traits
909             > compare_functor;
910
911             return erase_( key, compare_functor(),
912                 []( Q const&, leaf_node const& ) -> bool { return true; },
913                 [](value_type const&) {} );
914         }
915
916         /// Deletes the item from the tree
917         /** \anchor cds_intrusive_EllenBinTree_rcu_erase_func
918             The function searches an item with key equal to \p key in the tree,
919             call \p f functor with item found, unlinks it from the tree, and returns \p true.
920             The \ref disposer specified in \p Traits class template parameter is called
921             by garbage collector \p GC asynchronously.
922
923             The \p Func interface is
924             \code
925             struct functor {
926                 void operator()( value_type const& item );
927             };
928             \endcode
929
930             If the item with key equal to \p key is not found the function return \p false.
931
932             Note the hash functor should accept a parameter of type \p Q that can be not the same as \p value_type.
933
934             RCU \p synchronize method can be called. RCU should not be locked.
935         */
936         template <typename Q, typename Func>
937         bool erase( Q const& key, Func f )
938         {
939             return erase_( key, node_compare(),
940                 []( Q const&, leaf_node const& ) -> bool { return true; },
941                 f );
942         }
943
944         /// Delete the item from the tree with comparing functor \p pred
945         /**
946             The function is an analog of \ref cds_intrusive_EllenBinTree_rcu_erase_func "erase(Q const&, Func)"
947             but \p pred predicate is used for key comparing.
948             \p Less has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_rcu_less
949             "Predicate requirements".
950             \p pred must imply the same element order as the comparator used for building the tree.
951         */
952         template <typename Q, typename Less, typename Func>
953         bool erase_with( Q const& key, Less pred, Func f )
954         {
955             CDS_UNUSED( pred );
956             typedef ellen_bintree::details::compare<
957                 key_type,
958                 value_type,
959                 opt::details::make_comparator_from_less<Less>,
960                 node_traits
961             > compare_functor;
962
963             return erase_( key, compare_functor(),
964                 []( Q const&, leaf_node const& ) -> bool { return true; },
965                 f );
966         }
967
968         /// Extracts an item with minimal key from the tree
969         /**
970             The function searches an item with minimal key, unlinks it, and returns 
971             \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the leftmost item.
972             If the tree is empty the function returns empty \p exempt_ptr.
973
974             @note Due the concurrent nature of the tree, the function extracts <i>nearly</i> minimum key.
975             It means that the function gets leftmost leaf of the tree and tries to unlink it.
976             During unlinking, a concurrent thread may insert an item with key less than leftmost item's key.
977             So, the function returns the item with minimum key at the moment of tree traversing.
978
979             RCU \p synchronize method can be called. RCU should NOT be locked.
980             The function does not call the disposer for the item found.
981             The disposer will be implicitly invoked when the returned object is destroyed or when
982             its \p release() member function is called.
983         */
984         exempt_ptr extract_min()
985         {
986             return exempt_ptr( extract_min_() );
987         }
988
989         /// Extracts an item with maximal key from the tree
990         /**
991             The function searches an item with maximal key, unlinks it, and returns 
992             \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the rightmost item.
993             If the tree is empty the function returns empty \p exempt_ptr.
994
995             @note Due the concurrent nature of the tree, the function extracts <i>nearly</i> maximal key.
996             It means that the function gets rightmost leaf of the tree and tries to unlink it.
997             During unlinking, a concurrent thread may insert an item with key great than rightmost item's key.
998             So, the function returns the item with maximum key at the moment of tree traversing.
999
1000             RCU \p synchronize method can be called. RCU should NOT be locked.
1001             The function does not call the disposer for the item found.
1002             The disposer will be implicitly invoked when the returned object is destroyed or when
1003             its \p release() member function is called.
1004         */
1005         exempt_ptr extract_max()
1006         {
1007             return exempt_ptr( extract_max_() );
1008         }
1009
1010         /// Extracts an item from the tree
1011         /** \anchor cds_intrusive_EllenBinTree_rcu_extract
1012             The function searches an item with key equal to \p key in the tree,
1013             unlinks it, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to an item found.
1014             If the item with the key equal to \p key is not found the function returns empty \p exempt_ptr.
1015
1016             RCU \p synchronize method can be called. RCU should NOT be locked.
1017             The function does not call the disposer for the item found.
1018             The disposer will be implicitly invoked when the returned object is destroyed or when
1019             its \p release() member function is called.
1020         */
1021         template <typename Q>
1022         exempt_ptr extract( Q const& key )
1023         {
1024             return exempt_ptr( extract_( key, node_compare() ));
1025         }
1026
1027         /// Extracts an item from the set using \p pred for searching
1028         /**
1029             The function is an analog of \ref cds_intrusive_EllenBinTree_rcu_extract "extract(exempt_ptr&, Q const&)"
1030             but \p pred is used for key compare.
1031             \p Less has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_rcu_less
1032             "predicate requirements".
1033             \p pred must imply the same element order as the comparator used for building the tree.
1034         */
1035         template <typename Q, typename Less>
1036         exempt_ptr extract_with( Q const& key, Less pred )
1037         {
1038             return exempt_ptr( extract_with_( key, pred ));
1039         }
1040
1041         /// Finds the key \p key
1042         /** @anchor cds_intrusive_EllenBinTree_rcu_find_val
1043             The function searches the item with key equal to \p key
1044             and returns \p true if it is found, and \p false otherwise.
1045
1046             Note the hash functor specified for class \p Traits template parameter
1047             should accept a parameter of type \p Q that can be not the same as \p value_type.
1048
1049             The function applies RCU lock internally.
1050         */
1051         template <typename Q>
1052         bool find( Q const& key ) const
1053         {
1054             rcu_lock l;
1055             search_result    res;
1056             if ( search( res, key, node_compare() )) {
1057                 m_Stat.onFindSuccess();
1058                 return true;
1059             }
1060
1061             m_Stat.onFindFailed();
1062             return false;
1063         }
1064
1065         /// Finds the key \p key with comparing functor \p pred
1066         /**
1067             The function is an analog of \ref cds_intrusive_EllenBinTree_rcu_find_val "find(Q const&)"
1068             but \p pred is used for key compare.
1069             \p Less functor has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_rcu_less
1070             "Predicate requirements".
1071             \p pred must imply the same element order as the comparator used for building the tree.
1072             \p pred should accept arguments of type \p Q, \p key_type, \p value_type in any combination.
1073         */
1074         template <typename Q, typename Less>
1075         bool find_with( Q const& key, Less pred ) const
1076         {
1077             CDS_UNUSED( pred );
1078             typedef ellen_bintree::details::compare<
1079                 key_type,
1080                 value_type,
1081                 opt::details::make_comparator_from_less<Less>,
1082                 node_traits
1083             > compare_functor;
1084
1085             rcu_lock l;
1086             search_result    res;
1087             if ( search( res, key, compare_functor() )) {
1088                 m_Stat.onFindSuccess();
1089                 return true;
1090             }
1091             m_Stat.onFindFailed();
1092             return false;
1093         }
1094
1095         /// Finds the key \p key
1096         /** @anchor cds_intrusive_EllenBinTree_rcu_find_func
1097             The function searches the item with key equal to \p key and calls the functor \p f for item found.
1098             The interface of \p Func functor is:
1099             \code
1100             struct functor {
1101                 void operator()( value_type& item, Q& key );
1102             };
1103             \endcode
1104             where \p item is the item found, \p key is the <tt>find</tt> function argument.
1105
1106             The functor can change non-key fields of \p item. Note that the functor is only guarantee
1107             that \p item cannot be disposed during functor is executing.
1108             The functor does not serialize simultaneous access to the tree \p item. If such access is
1109             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
1110
1111             The function applies RCU lock internally.
1112
1113             The function returns \p true if \p key is found, \p false otherwise.
1114         */
1115         template <typename Q, typename Func>
1116         bool find( Q& key, Func f ) const
1117         {
1118             return find_( key, f );
1119         }
1120         //@cond
1121         template <typename Q, typename Func>
1122         bool find( Q const& key, Func f ) const
1123         {
1124             return find_( key, f );
1125         }
1126         //@endcond
1127
1128         /// Finds the key \p key with comparing functor \p pred
1129         /**
1130             The function is an analog of \ref cds_intrusive_EllenBinTree_rcu_find_func "find(Q&, Func)"
1131             but \p pred is used for key comparison.
1132             \p Less functor has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_rcu_less
1133             "Predicate requirements".
1134             \p pred must imply the same element order as the comparator used for building the tree.
1135         */
1136         template <typename Q, typename Less, typename Func>
1137         bool find_with( Q& key, Less pred, Func f ) const
1138         {
1139             return find_with_( key, pred, f );
1140         }
1141         //@cond
1142         template <typename Q, typename Less, typename Func>
1143         bool find_with( Q const& key, Less pred, Func f ) const
1144         {
1145             return find_with_( key, pred, f );
1146         }
1147         //@endcond
1148
1149         /// Finds \p key and return the item found
1150         /** \anchor cds_intrusive_EllenBinTree_rcu_get
1151             The function searches the item with key equal to \p key and returns the pointer to item found.
1152             If \p key is not found it returns \p nullptr.
1153
1154             RCU should be locked before call the function.
1155             Returned pointer is valid while RCU is locked.
1156         */
1157         template <typename Q>
1158         value_type * get( Q const& key ) const
1159         {
1160             return get_( key, node_compare() );
1161         }
1162
1163         /// Finds \p key with \p pred predicate and return the item found
1164         /**
1165             The function is an analog of \ref cds_intrusive_EllenBinTree_rcu_get "get(Q const&)"
1166             but \p pred is used for comparing the keys.
1167
1168             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
1169             in any order.
1170             \p pred must imply the same element order as the comparator used for building the tree.
1171         */
1172         template <typename Q, typename Less>
1173         value_type * get_with( Q const& key, Less pred ) const
1174         {
1175             CDS_UNUSED( pred );
1176             typedef ellen_bintree::details::compare<
1177                 key_type,
1178                 value_type,
1179                 opt::details::make_comparator_from_less<Less>,
1180                 node_traits
1181             > compare_functor;
1182
1183             return get_( key, compare_functor());
1184         }
1185
1186         /// Checks if the tree is empty
1187         bool empty() const
1188         {
1189             return m_Root.m_pLeft.load( memory_model::memory_order_relaxed )->is_leaf();
1190         }
1191
1192         /// Clears the tree (thread safe, not atomic)
1193         /**
1194             The function unlink all items from the tree.
1195             The function is thread safe but not atomic: in multi-threaded environment with parallel insertions
1196             this sequence
1197             \code
1198             set.clear();
1199             assert( set.empty() );
1200             \endcode
1201             the assertion could be raised.
1202
1203             For each leaf the \ref disposer will be called after unlinking.
1204
1205             RCU \p synchronize method can be called. RCU should not be locked.
1206         */
1207         void clear()
1208         {
1209             for ( exempt_ptr ep = extract_min(); !ep.empty(); ep = extract_min() )
1210                 ep.release();
1211         }
1212
1213         /// Clears the tree (not thread safe)
1214         /**
1215             This function is not thread safe and may be called only when no other thread deals with the tree.
1216             The function is used in the tree destructor.
1217         */
1218         void unsafe_clear()
1219         {
1220             rcu_lock l;
1221
1222             while ( true ) {
1223                 internal_node * pParent = nullptr;
1224                 internal_node * pGrandParent = nullptr;
1225                 tree_node *     pLeaf = const_cast<internal_node *>( &m_Root );
1226
1227                 // Get leftmost leaf
1228                 while ( pLeaf->is_internal() ) {
1229                     pGrandParent = pParent;
1230                     pParent = static_cast<internal_node *>( pLeaf );
1231                     pLeaf = pParent->m_pLeft.load( memory_model::memory_order_relaxed );
1232                 }
1233
1234                 if ( pLeaf->infinite_key()) {
1235                     // The tree is empty
1236                     return;
1237                 }
1238
1239                 // Remove leftmost leaf and its parent node
1240                 assert( pGrandParent );
1241                 assert( pParent );
1242                 assert( pLeaf->is_leaf() );
1243
1244                 pGrandParent->m_pLeft.store( pParent->m_pRight.load( memory_model::memory_order_relaxed ), memory_model::memory_order_relaxed );
1245                 free_leaf_node( node_traits::to_value_ptr( static_cast<leaf_node *>( pLeaf ) ) );
1246                 free_internal_node( pParent );
1247             }
1248         }
1249
1250         /// Returns item count in the tree
1251         /**
1252             Only leaf nodes containing user data are counted.
1253
1254             The value returned depends on item counter type provided by \p Traits template parameter.
1255             If it is \p atomicity::empty_item_counter this function always returns 0.
1256
1257             The function is not suitable for checking the tree emptiness, use \p empty()
1258             member function for that.
1259         */
1260         size_t size() const
1261         {
1262             return m_ItemCounter;
1263         }
1264
1265         /// Returns const reference to internal statistics
1266         stat const& statistics() const
1267         {
1268             return m_Stat;
1269         }
1270
1271         /// Checks internal consistency (not atomic, not thread-safe)
1272         /**
1273             The debugging function to check internal consistency of the tree.
1274         */
1275         bool check_consistency() const
1276         {
1277             return check_consistency( &m_Root );
1278         }
1279
1280     protected:
1281         //@cond
1282
1283         bool check_consistency( internal_node const * pRoot ) const
1284         {
1285             tree_node * pLeft  = pRoot->m_pLeft.load( atomics::memory_order_relaxed );
1286             tree_node * pRight = pRoot->m_pRight.load( atomics::memory_order_relaxed );
1287             assert( pLeft );
1288             assert( pRight );
1289
1290             if ( node_compare()( *pLeft, *pRoot ) < 0
1291                 && node_compare()( *pRoot, *pRight ) <= 0
1292                 && node_compare()( *pLeft, *pRight ) < 0 )
1293             {
1294                 bool bRet = true;
1295                 if ( pLeft->is_internal() )
1296                     bRet = check_consistency( static_cast<internal_node *>( pLeft ) );
1297                 assert( bRet );
1298
1299                 if ( bRet && pRight->is_internal() )
1300                     bRet = bRet && check_consistency( static_cast<internal_node *>( pRight ));
1301                 assert( bRet );
1302
1303                 return bRet;
1304             }
1305             return false;
1306         }
1307
1308         void help( update_ptr /*pUpdate*/, retired_list& /*rl*/ )
1309         {
1310             /*
1311             switch ( pUpdate.bits() ) {
1312                 case update_desc::IFlag:
1313                     help_insert( pUpdate.ptr() );
1314                     m_Stat.onHelpInsert();
1315                     break;
1316                 case update_desc::DFlag:
1317                     //help_delete( pUpdate.ptr(), rl );
1318                     //m_Stat.onHelpDelete();
1319                     break;
1320                 case update_desc::Mark:
1321                     //help_marked( pUpdate.ptr() );
1322                     //m_Stat.onHelpMark();
1323                     break;
1324             }
1325             */
1326         }
1327
1328         void help_insert( update_desc * pOp )
1329         {
1330             assert( gc::is_locked() );
1331
1332             tree_node * pLeaf = static_cast<tree_node *>( pOp->iInfo.pLeaf );
1333             if ( pOp->iInfo.bRightLeaf ) {
1334                 pOp->iInfo.pParent->m_pRight.compare_exchange_strong( pLeaf, static_cast<tree_node *>( pOp->iInfo.pNew ),
1335                     memory_model::memory_order_release, atomics::memory_order_relaxed );
1336             }
1337             else {
1338                 pOp->iInfo.pParent->m_pLeft.compare_exchange_strong( pLeaf, static_cast<tree_node *>( pOp->iInfo.pNew ),
1339                     memory_model::memory_order_release, atomics::memory_order_relaxed );
1340             }
1341
1342             update_ptr cur( pOp, update_desc::IFlag );
1343             pOp->iInfo.pParent->m_pUpdate.compare_exchange_strong( cur, pOp->iInfo.pParent->null_update_desc(),
1344                       memory_model::memory_order_release, atomics::memory_order_relaxed );
1345         }
1346
1347         bool check_delete_precondition( search_result& res )
1348         {
1349             assert( res.pGrandParent != nullptr );
1350
1351             return
1352                 static_cast<internal_node *>( res.bRightParent
1353                     ? res.pGrandParent->m_pRight.load(memory_model::memory_order_relaxed)
1354                     : res.pGrandParent->m_pLeft.load(memory_model::memory_order_relaxed)
1355                 ) == res.pParent
1356                 &&
1357                 static_cast<leaf_node *>( res.bRightLeaf
1358                     ? res.pParent->m_pRight.load(memory_model::memory_order_relaxed)
1359                     : res.pParent->m_pLeft.load(memory_model::memory_order_relaxed)
1360                 ) == res.pLeaf;
1361         }
1362
1363         bool help_delete( update_desc * pOp, retired_list& rl )
1364         {
1365             assert( gc::is_locked() );
1366
1367             update_ptr pUpdate( pOp->dInfo.pUpdateParent );
1368             update_ptr pMark( pOp, update_desc::Mark );
1369             if ( pOp->dInfo.pParent->m_pUpdate.compare_exchange_strong( pUpdate, pMark,
1370                     memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1371             {
1372                 help_marked( pOp );
1373                 retire_node( pOp->dInfo.pParent, rl );
1374                 // For extract operations the leaf should NOT be disposed
1375                 if ( pOp->dInfo.bDisposeLeaf )
1376                     retire_node( pOp->dInfo.pLeaf, rl );
1377                 retire_update_desc( pOp, rl, false );
1378
1379                 return true;
1380             }
1381             else if ( pUpdate == pMark ) {
1382                 // some other thread is processing help_marked()
1383                 help_marked( pOp );
1384                 m_Stat.onHelpMark();
1385                 return true;
1386             }
1387             else {
1388                 // pUpdate has been changed by CAS
1389                 help( pUpdate, rl );
1390
1391                 // Undo grandparent dInfo
1392                 update_ptr pDel( pOp, update_desc::DFlag );
1393                 if ( pOp->dInfo.pGrandParent->m_pUpdate.compare_exchange_strong( pDel, pOp->dInfo.pGrandParent->null_update_desc(),
1394                     memory_model::memory_order_release, atomics::memory_order_relaxed ))
1395                 {
1396                     retire_update_desc( pOp, rl, false );
1397                 }
1398                 return false;
1399             }
1400         }
1401
1402         void help_marked( update_desc * pOp )
1403         {
1404             assert( gc::is_locked() );
1405
1406             tree_node * p = pOp->dInfo.pParent;
1407             if ( pOp->dInfo.bRightParent ) {
1408                 pOp->dInfo.pGrandParent->m_pRight.compare_exchange_strong( p,
1409                     pOp->dInfo.bRightLeaf
1410                         ? pOp->dInfo.pParent->m_pLeft.load( memory_model::memory_order_acquire )
1411                         : pOp->dInfo.pParent->m_pRight.load( memory_model::memory_order_acquire ),
1412                     memory_model::memory_order_release, atomics::memory_order_relaxed );
1413             }
1414             else {
1415                 pOp->dInfo.pGrandParent->m_pLeft.compare_exchange_strong( p,
1416                     pOp->dInfo.bRightLeaf
1417                         ? pOp->dInfo.pParent->m_pLeft.load( memory_model::memory_order_acquire )
1418                         : pOp->dInfo.pParent->m_pRight.load( memory_model::memory_order_acquire ),
1419                     memory_model::memory_order_release, atomics::memory_order_relaxed );
1420             }
1421
1422             update_ptr upd( pOp, update_desc::DFlag );
1423             pOp->dInfo.pGrandParent->m_pUpdate.compare_exchange_strong( upd, pOp->dInfo.pGrandParent->null_update_desc(),
1424                 memory_model::memory_order_release, atomics::memory_order_relaxed );
1425         }
1426
1427         template <typename KeyValue, typename Compare>
1428         bool search( search_result& res, KeyValue const& key, Compare cmp ) const
1429         {
1430             assert( gc::is_locked() );
1431
1432             internal_node * pParent;
1433             internal_node * pGrandParent = nullptr;
1434             tree_node *     pLeaf;
1435             update_ptr      updParent;
1436             update_ptr      updGrandParent;
1437             bool bRightLeaf;
1438             bool bRightParent = false;
1439
1440             int nCmp = 0;
1441
1442         retry:
1443             pParent = nullptr;
1444             pLeaf = const_cast<internal_node *>( &m_Root );
1445             updParent = nullptr;
1446             bRightLeaf = false;
1447             while ( pLeaf->is_internal() ) {
1448                 pGrandParent = pParent;
1449                 pParent = static_cast<internal_node *>( pLeaf );
1450                 bRightParent = bRightLeaf;
1451                 updGrandParent = updParent;
1452                 updParent = pParent->m_pUpdate.load( memory_model::memory_order_acquire );
1453
1454                 switch ( updParent.bits() ) {
1455                     case update_desc::DFlag:
1456                     case update_desc::Mark:
1457                         m_Stat.onSearchRetry();
1458                         goto retry;
1459                 }
1460
1461                 nCmp = cmp( key, *pParent );
1462                 bRightLeaf = nCmp >= 0;
1463                 pLeaf = nCmp < 0 ? pParent->m_pLeft.load( memory_model::memory_order_acquire )
1464                                  : pParent->m_pRight.load( memory_model::memory_order_acquire );
1465             }
1466
1467             assert( pLeaf->is_leaf() );
1468             nCmp = cmp( key, *static_cast<leaf_node *>(pLeaf) );
1469
1470             res.pGrandParent    = pGrandParent;
1471             res.pParent         = pParent;
1472             res.pLeaf           = static_cast<leaf_node *>( pLeaf );
1473             res.updParent       = updParent;
1474             res.updGrandParent  = updGrandParent;
1475             res.bRightParent    = bRightParent;
1476             res.bRightLeaf      = bRightLeaf;
1477
1478             return nCmp == 0;
1479         }
1480
1481         bool search_min( search_result& res ) const
1482         {
1483             assert( gc::is_locked() );
1484
1485             internal_node * pParent;
1486             internal_node * pGrandParent = nullptr;
1487             tree_node *     pLeaf;
1488             update_ptr      updParent;
1489             update_ptr      updGrandParent;
1490
1491         retry:
1492             pParent = nullptr;
1493             pLeaf = const_cast<internal_node *>( &m_Root );
1494             while ( pLeaf->is_internal() ) {
1495                 pGrandParent = pParent;
1496                 pParent = static_cast<internal_node *>( pLeaf );
1497                 updGrandParent = updParent;
1498                 updParent = pParent->m_pUpdate.load( memory_model::memory_order_acquire );
1499
1500                 switch ( updParent.bits() ) {
1501                     case update_desc::DFlag:
1502                     case update_desc::Mark:
1503                         m_Stat.onSearchRetry();
1504                         goto retry;
1505                 }
1506
1507                 pLeaf = pParent->m_pLeft.load( memory_model::memory_order_acquire );
1508             }
1509
1510             if ( pLeaf->infinite_key())
1511                 return false;
1512
1513             res.pGrandParent    = pGrandParent;
1514             res.pParent         = pParent;
1515             assert( pLeaf->is_leaf() );
1516             res.pLeaf           = static_cast<leaf_node *>( pLeaf );
1517             res.updParent       = updParent;
1518             res.updGrandParent  = updGrandParent;
1519             res.bRightParent    = false;
1520             res.bRightLeaf      = false;
1521
1522             return true;
1523         }
1524
1525         bool search_max( search_result& res ) const
1526         {
1527             assert( gc::is_locked() );
1528
1529             internal_node * pParent;
1530             internal_node * pGrandParent = nullptr;
1531             tree_node *     pLeaf;
1532             update_ptr      updParent;
1533             update_ptr      updGrandParent;
1534             bool bRightLeaf;
1535             bool bRightParent = false;
1536
1537         retry:
1538             pParent = nullptr;
1539             pLeaf = const_cast<internal_node *>( &m_Root );
1540             bRightLeaf = false;
1541             while ( pLeaf->is_internal() ) {
1542                 pGrandParent = pParent;
1543                 pParent = static_cast<internal_node *>( pLeaf );
1544                 bRightParent = bRightLeaf;
1545                 updGrandParent = updParent;
1546                 updParent = pParent->m_pUpdate.load( memory_model::memory_order_acquire );
1547
1548                 switch ( updParent.bits() ) {
1549                     case update_desc::DFlag:
1550                     case update_desc::Mark:
1551                         m_Stat.onSearchRetry();
1552                         goto retry;
1553                 }
1554
1555                 if ( pParent->infinite_key()) {
1556                     pLeaf = pParent->m_pLeft.load( memory_model::memory_order_acquire );
1557                     bRightLeaf = false;
1558                 }
1559                 else {
1560                     pLeaf = pParent->m_pRight.load( memory_model::memory_order_acquire );
1561                     bRightLeaf = true;
1562                 }
1563             }
1564
1565             if ( pLeaf->infinite_key())
1566                 return false;
1567
1568             res.pGrandParent    = pGrandParent;
1569             res.pParent         = pParent;
1570             assert( pLeaf->is_leaf() );
1571             res.pLeaf           = static_cast<leaf_node *>( pLeaf );
1572             res.updParent       = updParent;
1573             res.updGrandParent  = updGrandParent;
1574             res.bRightParent    = bRightParent;
1575             res.bRightLeaf      = bRightLeaf;
1576
1577             return true;
1578         }
1579
1580         template <typename Q, typename Compare, typename Equal, typename Func>
1581         bool erase_( Q const& val, Compare cmp, Equal eq, Func f )
1582         {
1583             check_deadlock_policy::check();
1584
1585             retired_list updRetire;
1586             update_desc * pOp = nullptr;
1587             search_result res;
1588             back_off bkoff;
1589
1590             {
1591                 rcu_lock l;
1592                 for ( ;; ) {
1593                     if ( !search( res, val, cmp ) || !eq( val, *res.pLeaf ) ) {
1594                         if ( pOp )
1595                             retire_update_desc( pOp, updRetire, false );
1596                         m_Stat.onEraseFailed();
1597                         return false;
1598                     }
1599
1600                     if ( res.updGrandParent.bits() != update_desc::Clean )
1601                         help( res.updGrandParent, updRetire );
1602                     else if ( res.updParent.bits() != update_desc::Clean )
1603                         help( res.updParent, updRetire );
1604                     else {
1605                         if ( !pOp )
1606                             pOp = alloc_update_desc();
1607                         if ( check_delete_precondition( res ) ) {
1608                             pOp->dInfo.pGrandParent = res.pGrandParent;
1609                             pOp->dInfo.pParent = res.pParent;
1610                             pOp->dInfo.pLeaf = res.pLeaf;
1611                             pOp->dInfo.bDisposeLeaf = true;
1612                             pOp->dInfo.pUpdateParent = res.updParent.ptr();
1613                             pOp->dInfo.bRightParent = res.bRightParent;
1614                             pOp->dInfo.bRightLeaf = res.bRightLeaf;
1615
1616                             update_ptr updGP( res.updGrandParent.ptr() );
1617                             if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
1618                                 memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1619                             {
1620                                 if ( help_delete( pOp, updRetire )) {
1621                                     // res.pLeaf is not deleted yet since RCU is blocked
1622                                     f( *node_traits::to_value_ptr( res.pLeaf ));
1623                                     break;
1624                                 }
1625                                 pOp = nullptr;
1626                             }
1627                             else {
1628                                 // updGP has been changed by CAS
1629                                 help( updGP, updRetire );
1630                             }
1631                         }
1632                     }
1633
1634                     bkoff();
1635                     m_Stat.onEraseRetry();
1636                 }
1637             }
1638
1639             --m_ItemCounter;
1640             m_Stat.onEraseSuccess();
1641             return true;
1642         }
1643
1644         template <typename Q, typename Less>
1645         value_type * extract_with_( Q const& val, Less /*pred*/ )
1646         {
1647             CDS_UNUSED( pred );
1648             typedef ellen_bintree::details::compare<
1649                 key_type,
1650                 value_type,
1651                 opt::details::make_comparator_from_less<Less>,
1652                 node_traits
1653             > compare_functor;
1654
1655             return extract_( val, compare_functor() );
1656         }
1657
1658         template <typename Q, typename Compare>
1659         value_type * extract_( Q const& val, Compare cmp )
1660         {
1661             check_deadlock_policy::check();
1662
1663             retired_list updRetire;
1664             update_desc * pOp = nullptr;
1665             search_result res;
1666             back_off bkoff;
1667             value_type * pResult;
1668
1669             {
1670                 rcu_lock l;
1671                 for ( ;; ) {
1672                     if ( !search( res, val, cmp ) ) {
1673                         if ( pOp )
1674                             retire_update_desc( pOp, updRetire, false );
1675                         m_Stat.onEraseFailed();
1676                         return nullptr;
1677                     }
1678
1679                     if ( res.updGrandParent.bits() != update_desc::Clean )
1680                         help( res.updGrandParent, updRetire );
1681                     else if ( res.updParent.bits() != update_desc::Clean )
1682                         help( res.updParent, updRetire );
1683                     else {
1684                         if ( !pOp )
1685                             pOp = alloc_update_desc();
1686                         if ( check_delete_precondition( res )) {
1687                             pOp->dInfo.pGrandParent = res.pGrandParent;
1688                             pOp->dInfo.pParent = res.pParent;
1689                             pOp->dInfo.pLeaf = res.pLeaf;
1690                             pOp->dInfo.bDisposeLeaf = false;
1691                             pOp->dInfo.pUpdateParent = res.updParent.ptr();
1692                             pOp->dInfo.bRightParent = res.bRightParent;
1693                             pOp->dInfo.bRightLeaf = res.bRightLeaf;
1694
1695                             update_ptr updGP( res.updGrandParent.ptr() );
1696                             if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
1697                                 memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1698                             {
1699                                 if ( help_delete( pOp, updRetire )) {
1700                                     pResult = node_traits::to_value_ptr( res.pLeaf );
1701                                     break;
1702                                 }
1703                                 pOp = nullptr;
1704                             }
1705                             else {
1706                                 // updGP has been changed by CAS
1707                                 help( updGP, updRetire );
1708                             }
1709                         }
1710                     }
1711
1712                     bkoff();
1713                     m_Stat.onEraseRetry();
1714                 }
1715             }
1716
1717             --m_ItemCounter;
1718             m_Stat.onEraseSuccess();
1719             return pResult;
1720         }
1721
1722
1723         value_type * extract_max_()
1724         {
1725             check_deadlock_policy::check();
1726
1727             retired_list updRetire;
1728             update_desc * pOp = nullptr;
1729             search_result res;
1730             back_off bkoff;
1731             value_type * pResult;
1732
1733             {
1734                 rcu_lock l;
1735                 for ( ;; ) {
1736                     if ( !search_max( res )) {
1737                         // Tree is empty
1738                         if ( pOp )
1739                             retire_update_desc( pOp, updRetire, false );
1740                         m_Stat.onExtractMaxFailed();
1741                         return nullptr;
1742                     }
1743
1744                     if ( res.updGrandParent.bits() != update_desc::Clean )
1745                         help( res.updGrandParent, updRetire );
1746                     else if ( res.updParent.bits() != update_desc::Clean )
1747                         help( res.updParent, updRetire );
1748                     else {
1749                         if ( !pOp )
1750                             pOp = alloc_update_desc();
1751                         if ( check_delete_precondition( res ) ) {
1752                             pOp->dInfo.pGrandParent = res.pGrandParent;
1753                             pOp->dInfo.pParent = res.pParent;
1754                             pOp->dInfo.pLeaf = res.pLeaf;
1755                             pOp->dInfo.bDisposeLeaf = false;
1756                             pOp->dInfo.pUpdateParent = res.updParent.ptr();
1757                             pOp->dInfo.bRightParent = res.bRightParent;
1758                             pOp->dInfo.bRightLeaf = res.bRightLeaf;
1759
1760                             update_ptr updGP( res.updGrandParent.ptr() );
1761                             if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
1762                                 memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1763                             {
1764                                 if ( help_delete( pOp, updRetire )) {
1765                                     pResult = node_traits::to_value_ptr( res.pLeaf );
1766                                     break;
1767                                 }
1768                                 pOp = nullptr;
1769                             }
1770                             else {
1771                                 // updGP has been changed by CAS
1772                                 help( updGP, updRetire );
1773                             }
1774                         }
1775                     }
1776
1777                     bkoff();
1778                     m_Stat.onExtractMaxRetry();
1779                 }
1780             }
1781
1782             --m_ItemCounter;
1783             m_Stat.onExtractMaxSuccess();
1784             return pResult;
1785         }
1786
1787         value_type * extract_min_()
1788         {
1789             check_deadlock_policy::check();
1790
1791             retired_list updRetire;
1792             update_desc * pOp = nullptr;
1793             search_result res;
1794             back_off bkoff;
1795             value_type * pResult;
1796
1797             {
1798                 rcu_lock l;
1799                 for ( ;; ) {
1800                     if ( !search_min( res )) {
1801                         // Tree is empty
1802                         if ( pOp )
1803                             retire_update_desc( pOp, updRetire, false );
1804                         m_Stat.onExtractMinFailed();
1805                         return nullptr;
1806                     }
1807
1808                     if ( res.updGrandParent.bits() != update_desc::Clean )
1809                         help( res.updGrandParent, updRetire );
1810                     else if ( res.updParent.bits() != update_desc::Clean )
1811                         help( res.updParent, updRetire );
1812                     else {
1813                         if ( !pOp )
1814                             pOp = alloc_update_desc();
1815                         if ( check_delete_precondition( res ) ) {
1816                             pOp->dInfo.pGrandParent = res.pGrandParent;
1817                             pOp->dInfo.pParent = res.pParent;
1818                             pOp->dInfo.pLeaf = res.pLeaf;
1819                             pOp->dInfo.bDisposeLeaf = false;
1820                             pOp->dInfo.pUpdateParent = res.updParent.ptr();
1821                             pOp->dInfo.bRightParent = res.bRightParent;
1822                             pOp->dInfo.bRightLeaf = res.bRightLeaf;
1823
1824                             update_ptr updGP( res.updGrandParent.ptr() );
1825                             if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
1826                                 memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1827                             {
1828                                 if ( help_delete( pOp, updRetire )) {
1829                                     pResult = node_traits::to_value_ptr( res.pLeaf );
1830                                     break;
1831                                 }
1832                                 pOp = nullptr;
1833                             }
1834                             else {
1835                                 // updGP has been changed by CAS
1836                                 help( updGP, updRetire );
1837                             }
1838                         }
1839                     }
1840
1841                     bkoff();
1842                     m_Stat.onExtractMinRetry();
1843                 }
1844             }
1845
1846             --m_ItemCounter;
1847             m_Stat.onExtractMinSuccess();
1848             return pResult;
1849         }
1850
1851         template <typename Q, typename Less, typename Func>
1852         bool find_with_( Q& val, Less /*pred*/, Func f ) const
1853         {
1854             CDS_UNUSED( pred );
1855             typedef ellen_bintree::details::compare<
1856                 key_type,
1857                 value_type,
1858                 opt::details::make_comparator_from_less<Less>,
1859                 node_traits
1860             > compare_functor;
1861
1862             rcu_lock l;
1863             search_result    res;
1864             if ( search( res, val, compare_functor() )) {
1865                 assert( res.pLeaf );
1866                 f( *node_traits::to_value_ptr( res.pLeaf ), val );
1867
1868                 m_Stat.onFindSuccess();
1869                 return true;
1870             }
1871
1872             m_Stat.onFindFailed();
1873             return false;
1874         }
1875
1876         template <typename Q, typename Func>
1877         bool find_( Q& key, Func f ) const
1878         {
1879             rcu_lock l;
1880             search_result    res;
1881             if ( search( res, key, node_compare() )) {
1882                 assert( res.pLeaf );
1883                 f( *node_traits::to_value_ptr( res.pLeaf ), key );
1884
1885                 m_Stat.onFindSuccess();
1886                 return true;
1887             }
1888
1889             m_Stat.onFindFailed();
1890             return false;
1891         }
1892
1893         template <typename Q, typename Compare>
1894         value_type * get_( Q const& key, Compare cmp ) const
1895         {
1896             assert( gc::is_locked());
1897
1898             search_result    res;
1899             if ( search( res, key, cmp )) {
1900                 m_Stat.onFindSuccess();
1901                 return node_traits::to_value_ptr( res.pLeaf );
1902             }
1903
1904             m_Stat.onFindFailed();
1905             return nullptr;
1906         }
1907
1908
1909         bool try_insert( value_type& val, internal_node * pNewInternal, search_result& res, retired_list& updRetire )
1910         {
1911             assert( gc::is_locked() );
1912             assert( res.updParent.bits() == update_desc::Clean );
1913
1914             // check search result
1915             if ( static_cast<leaf_node *>( res.bRightLeaf
1916                 ? res.pParent->m_pRight.load( memory_model::memory_order_relaxed )
1917                 : res.pParent->m_pLeft.load( memory_model::memory_order_relaxed ) ) == res.pLeaf )
1918             {
1919                 leaf_node * pNewLeaf = node_traits::to_node_ptr( val );
1920
1921                 int nCmp = node_compare()( val, *res.pLeaf );
1922                 if ( nCmp < 0 ) {
1923                     if ( res.pGrandParent ) {
1924                         pNewInternal->infinite_key( 0 );
1925                         key_extractor()( pNewInternal->m_Key, *node_traits::to_value_ptr( res.pLeaf ) );
1926                         assert( !res.pLeaf->infinite_key() );
1927                     }
1928                     else {
1929                         assert( res.pLeaf->infinite_key() == tree_node::key_infinite1 );
1930                         pNewInternal->infinite_key( 1 );
1931                     }
1932                     pNewInternal->m_pLeft.store( static_cast<tree_node *>(pNewLeaf), memory_model::memory_order_relaxed );
1933                     pNewInternal->m_pRight.store( static_cast<tree_node *>(res.pLeaf), memory_model::memory_order_release );
1934                 }
1935                 else {
1936                     assert( !res.pLeaf->is_internal() );
1937                     pNewInternal->infinite_key( 0 );
1938
1939                     key_extractor()( pNewInternal->m_Key, val );
1940                     pNewInternal->m_pLeft.store( static_cast<tree_node *>(res.pLeaf), memory_model::memory_order_relaxed );
1941                     pNewInternal->m_pRight.store( static_cast<tree_node *>(pNewLeaf), memory_model::memory_order_release );
1942                     assert( !res.pLeaf->infinite_key());
1943                 }
1944
1945                 update_desc * pOp = alloc_update_desc();
1946
1947                 pOp->iInfo.pParent = res.pParent;
1948                 pOp->iInfo.pNew = pNewInternal;
1949                 pOp->iInfo.pLeaf = res.pLeaf;
1950                 pOp->iInfo.bRightLeaf = res.bRightLeaf;
1951
1952                 update_ptr updCur( res.updParent.ptr() );
1953                 if ( res.pParent->m_pUpdate.compare_exchange_strong( updCur, update_ptr( pOp, update_desc::IFlag ),
1954                     memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
1955                 {
1956                     // do insert
1957                     help_insert( pOp );
1958                     retire_update_desc( pOp, updRetire, false );
1959                     return true;
1960                 }
1961                 else {
1962                     // updCur has been updated by CAS
1963                     help( updCur, updRetire );
1964                     retire_update_desc( pOp, updRetire, true );
1965                 }
1966             }
1967             return false;
1968         }
1969
1970         //@endcond
1971     };
1972
1973 }} // namespace cds::intrusive
1974
1975 #endif  // #ifndef __CDS_INTRUSIVE_ELLEN_BINTREE_RCU_H