BronsonAVLTreeMap: docfix
[libcds.git] / cds / container / impl / bronson_avltree_map_rcu.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef CDSLIB_CONTAINER_IMPL_BRONSON_AVLTREE_MAP_RCU_H
32 #define CDSLIB_CONTAINER_IMPL_BRONSON_AVLTREE_MAP_RCU_H
33
34 #include <type_traits> // is_base_of
35 #include <cds/container/details/bronson_avltree_base.h>
36 #include <cds/urcu/details/check_deadlock.h>
37 #include <cds/urcu/exempt_ptr.h>
38
39 namespace cds { namespace container {
40
41     /// Bronson et al AVL-tree (RCU specialization for pointers)
42     /** @ingroup cds_nonintrusive_map
43         @ingroup cds_nonintrusive_tree
44         @headerfile cds/container/bronson_avltree_map_rcu.h
45         @anchor cds_container_BronsonAVLTreeMap_rcu_ptr
46
47         This is the specialization of \ref cds_container_BronsonAVLTreeMap_rcu "RCU-based Bronson et al AVL-tree"
48         for "key -> value pointer" map. This specialization stores the pointer to user-allocated values instead of the copy
49         of the value. When a tree node is removed, the algorithm does not free the value pointer directly, instead, it call
50         the disposer functor provided by \p Traits template parameter.
51
52         <b>Template arguments</b>:
53         - \p RCU - one of \ref cds_urcu_gc "RCU type"
54         - \p Key - key type
55         - \p T - value type to be stored in tree's nodes. Note, the specialization stores the pointer to user-allocated
56             value, not the copy.
57         - \p Traits - tree traits, default is \p bronson_avltree::traits
58             It is possible to declare option-based tree with \p bronson_avltree::make_traits metafunction
59             instead of \p Traits template argument.
60
61         @note Before including <tt><cds/container/bronson_avltree_map_rcu.h></tt> you should include appropriate RCU header file,
62         see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
63     */
64     template <
65         typename RCU,
66         typename Key,
67         typename T,
68 #   ifdef CDS_DOXYGEN_INVOKED
69         typename Traits = bronson_avltree::traits
70 #else
71         typename Traits
72 #endif
73     >
74     class BronsonAVLTreeMap< cds::urcu::gc<RCU>, Key, T*, Traits >
75     {
76     public:
77         typedef cds::urcu::gc<RCU>  gc;   ///< RCU Garbage collector
78         typedef Key     key_type;    ///< type of a key stored in the map
79         typedef T *     mapped_type; ///< type of value stored in the map
80         typedef Traits  traits;      ///< Traits template parameter
81
82 #   ifdef CDS_DOXYGEN_INVOKED
83         typedef implementation_defined key_comparator;    ///< key compare functor based on \p Traits::compare and \p Traits::less
84 #   else
85         typedef typename opt::details::make_comparator< key_type, traits >::type key_comparator;
86 #endif
87         typedef typename traits::item_counter           item_counter;       ///< Item counting policy
88         typedef typename traits::memory_model           memory_model;       ///< Memory ordering, see \p cds::opt::memory_model option
89         typedef typename traits::node_allocator         node_allocator_type; ///< allocator for maintaining internal nodes
90         typedef typename traits::stat                   stat;               ///< internal statistics
91         typedef typename traits::rcu_check_deadlock     rcu_check_deadlock; ///< Deadlock checking policy
92         typedef typename traits::back_off               back_off;           ///< Back-off strategy
93         typedef typename traits::disposer               disposer;           ///< Value disposer
94         typedef typename traits::sync_monitor           sync_monitor;       ///< @ref cds_sync_monitor "Synchronization monitor" type for node-level locking
95
96         /// Enabled or disabled @ref bronson_avltree::relaxed_insert "relaxed insertion"
97         static CDS_CONSTEXPR bool const c_bRelaxedInsert = traits::relaxed_insert;
98
99         /// Group of \p extract_xxx functions does not require external locking
100         static CDS_CONSTEXPR const bool c_bExtractLockExternal = false;
101
102 #   ifdef CDS_DOXYGEN_INVOKED
103         /// Returned pointer to \p mapped_type of extracted node
104         typedef cds::urcu::exempt_ptr< gc, T, T, disposer, void > exempt_ptr;
105 #   else
106         typedef cds::urcu::exempt_ptr< gc,
107             typename std::remove_pointer<mapped_type>::type,
108             typename std::remove_pointer<mapped_type>::type,
109             disposer,
110             void
111         > exempt_ptr;
112 #   endif
113
114         typedef typename gc::scoped_lock    rcu_lock;  ///< RCU scoped lock
115
116     protected:
117         //@cond
118         typedef bronson_avltree::node< key_type, mapped_type, sync_monitor > node_type;
119         typedef typename node_type::version_type version_type;
120
121         typedef cds::details::Allocator< node_type, node_allocator_type > cxx_allocator;
122         typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock >   check_deadlock_policy;
123
124         enum class find_result
125         {
126             not_found,
127             found,
128             retry
129         };
130
131         struct update_flags
132         {
133             enum {
134                 allow_insert = 1,
135                 allow_update = 2,
136                 //allow_remove = 4,
137
138                 retry = 1024,
139
140                 failed = 0,
141                 result_inserted = allow_insert,
142                 result_updated = allow_update,
143                 result_removed = 4
144             };
145         };
146
147         enum node_condition
148         {
149             nothing_required = -3,
150             rebalance_required = -2,
151             unlink_required = -1
152         };
153
154         enum direction {
155             left_child = -1,
156             right_child = 1
157         };
158
159         typedef typename sync_monitor::template scoped_lock<node_type> node_scoped_lock;
160         //@endcond
161
162     protected:
163         //@cond
164         template <typename K>
165         static node_type * alloc_node( K&& key, int nHeight, version_type version, node_type * pParent, node_type * pLeft, node_type * pRight )
166         {
167             return cxx_allocator().New( std::forward<K>( key ), nHeight, version, pParent, pLeft, pRight );
168         }
169
170         static void free_node( node_type * pNode )
171         {
172             // Free node without disposer
173             assert( !pNode->is_valued( memory_model::memory_order_relaxed ));
174             assert( pNode->m_SyncMonitorInjection.check_free());
175             cxx_allocator().Delete( pNode );
176         }
177
178         static void free_value( mapped_type pVal )
179         {
180             disposer()(pVal);
181         }
182
183         static node_type * child( node_type * pNode, int nDir, atomics::memory_order order )
184         {
185             return pNode->child( nDir, order );
186         }
187
188         static node_type * parent( node_type * pNode, atomics::memory_order order )
189         {
190             return pNode->parent( order );
191         }
192
193         // RCU safe disposer
194         class rcu_disposer
195         {
196             node_type *     m_pRetiredList;     ///< head of retired node list
197             mapped_type     m_pRetiredValue;    ///< value retired
198
199         public:
200             rcu_disposer()
201                 : m_pRetiredList( nullptr )
202                 , m_pRetiredValue( nullptr )
203             {}
204
205             ~rcu_disposer()
206             {
207                 clean();
208             }
209
210             void dispose( node_type * pNode )
211             {
212                 assert( !pNode->is_valued( memory_model::memory_order_relaxed ));
213                 pNode->m_pNextRemoved = m_pRetiredList;
214                 m_pRetiredList = pNode;
215             }
216
217             void dispose_value( mapped_type pVal )
218             {
219                 assert( m_pRetiredValue == nullptr );
220                 m_pRetiredValue = pVal;
221             }
222
223         private:
224             struct internal_disposer
225             {
226                 void operator()( node_type * p ) const
227                 {
228                     free_node( p );
229                 }
230             };
231
232             void clean()
233             {
234                 assert( !gc::is_locked());
235
236                 // TODO: use RCU::batch_retire
237
238                 // Dispose nodes
239                 for ( node_type * p = m_pRetiredList; p; ) {
240                     node_type * pNext = static_cast<node_type *>( p->m_pNextRemoved );
241                     // Value already disposed
242                     gc::template retire_ptr<internal_disposer>( p );
243                     p = pNext;
244                 }
245
246                 // Dispose value
247                 if ( m_pRetiredValue  )
248                     gc::template retire_ptr<disposer>( m_pRetiredValue );
249             }
250         };
251
252         //@endcond
253
254     protected:
255         //@cond
256         typename node_type::base_class m_Root;
257         node_type *             m_pRoot;
258         item_counter            m_ItemCounter;
259         mutable sync_monitor    m_Monitor;
260         mutable stat            m_stat;
261         //@endcond
262
263     public:
264         /// Creates empty map
265         BronsonAVLTreeMap()
266             : m_pRoot( static_cast<node_type *>( &m_Root ))
267         {}
268
269         /// Destroys the map
270         ~BronsonAVLTreeMap()
271         {
272             unsafe_clear();
273         }
274
275         /// Inserts new node
276         /**
277             The \p key_type should be constructible from a value of type \p K.
278
279             RCU \p synchronize() can be called. RCU should not be locked.
280
281             Returns \p true if inserting successful, \p false otherwise.
282         */
283         template <typename K>
284         bool insert( K const& key, mapped_type pVal )
285         {
286             return do_update(key, key_comparator(),
287                 [pVal]( node_type * pNode ) -> mapped_type
288                 {
289                     assert( pNode->m_pValue.load( memory_model::memory_order_relaxed ) == nullptr );
290                     CDS_UNUSED( pNode );
291                     return pVal;
292                 },
293                 update_flags::allow_insert
294             ) == update_flags::result_inserted;
295         }
296
297         /// Updates the value for \p key
298         /**
299             The operation performs inserting or updating the value for \p key with lock-free manner.
300             If \p bInsert is \p false, only updating of existing node is possible.
301
302             If \p key is not found and inserting is allowed (i.e. \p bInsert is \p true),
303             then the new node created from \p key will be inserted into the map; note that in this case the \ref key_type should be
304             constructible from type \p K.
305             Otherwise, the value for \p key will be changed to \p pVal.
306
307             RCU \p synchronize() method can be called. RCU should not be locked.
308
309             Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
310             \p second is \p true if new node has been added or \p false if the node with \p key
311             already exists.
312         */
313         template <typename K>
314         std::pair<bool, bool> update( K const& key, mapped_type pVal, bool bInsert = true )
315         {
316             int result = do_update( key, key_comparator(),
317                 [pVal]( node_type * ) -> mapped_type
318                 {
319                     return pVal;
320                 },
321                 update_flags::allow_update | (bInsert ? update_flags::allow_insert : 0)
322             );
323             return std::make_pair( result != 0, (result & update_flags::result_inserted) != 0 );
324         }
325
326         //@endcond
327
328         /// Delete \p key from the map
329         /**
330             RCU \p synchronize() method can be called. RCU should not be locked.
331
332             Return \p true if \p key is found and deleted, \p false otherwise
333         */
334         template <typename K>
335         bool erase( K const& key )
336         {
337             return do_remove(
338                 key,
339                 key_comparator(),
340                 []( key_type const&, mapped_type pVal, rcu_disposer& disp ) -> bool { disp.dispose_value( pVal ); return true; }
341             );
342         }
343
344         /// Deletes the item from the map using \p pred predicate for searching
345         /**
346             The function is an analog of \p erase(K const&)
347             but \p pred is used for key comparing.
348             \p Less functor has the interface like \p std::less.
349             \p Less must imply the same element order as the comparator used for building the map.
350         */
351         template <typename K, typename Less>
352         bool erase_with( K const& key, Less pred )
353         {
354             CDS_UNUSED( pred );
355             return do_remove(
356                 key,
357                 cds::opt::details::make_comparator_from_less<Less>(),
358                 []( key_type const&, mapped_type pVal, rcu_disposer& disp ) -> bool { disp.dispose_value( pVal ); return true;  }
359             );
360         }
361
362         /// Delete \p key from the map
363         /**
364             The function searches an item with key \p key, calls \p f functor
365             and deletes the item. If \p key is not found, the functor is not called.
366
367             The functor \p Func interface:
368             \code
369             struct functor {
370                 void operator()( key_type const& key, std::remove_pointer<mapped_type>::type& val) { ... }
371             };
372             \endcode
373
374             RCU \p synchronize method can be called. RCU should not be locked.
375
376             Return \p true if key is found and deleted, \p false otherwise
377         */
378         template <typename K, typename Func>
379         bool erase( K const& key, Func f )
380         {
381             return do_remove(
382                 key,
383                 key_comparator(),
384                 [&f]( key_type const& key, mapped_type pVal, rcu_disposer& disp ) -> bool {
385                     assert( pVal );
386                     f( key, *pVal );
387                     disp.dispose_value(pVal);
388                     return true;
389                 }
390             );
391         }
392
393         /// Deletes the item from the map using \p pred predicate for searching
394         /**
395             The function is an analog of \p erase(K const&, Func)
396             but \p pred is used for key comparing.
397             \p Less functor has the interface like \p std::less.
398             \p Less must imply the same element order as the comparator used for building the map.
399         */
400         template <typename K, typename Less, typename Func>
401         bool erase_with( K const& key, Less pred, Func f )
402         {
403             CDS_UNUSED( pred );
404             return do_remove(
405                 key,
406                 cds::opt::details::make_comparator_from_less<Less>(),
407                 [&f]( key_type const& key, mapped_type pVal, rcu_disposer& disp ) -> bool {
408                     assert( pVal );
409                     f( key, *pVal );
410                     disp.dispose_value(pVal);
411                     return true;
412                 }
413             );
414         }
415
416         /// Extracts a value with minimal key from the map
417         /**
418             Returns \p exempt_ptr to the leftmost item.
419             If the tree is empty, returns empty \p exempt_ptr.
420
421             Note that the function returns only the value for minimal key.
422             To retrieve its key use \p extract_min( Func ) member function.
423
424             @note Due the concurrent nature of the map, the function extracts <i>nearly</i> minimum key.
425             It means that the function gets leftmost leaf of the tree and tries to unlink it.
426             During unlinking, a concurrent thread may insert an item with key less than leftmost item's key.
427             So, the function returns the item with minimum key at the moment of tree traversing.
428
429             RCU \p synchronize method can be called. RCU should NOT be locked.
430             The function does not free the item.
431             The deallocator will be implicitly invoked when the returned object is destroyed or when
432             its \p release() member function is called.
433         */
434         exempt_ptr extract_min()
435         {
436             return exempt_ptr(do_extract_min( []( key_type const& ) {}));
437         }
438
439         /// Extracts minimal key and corresponding value
440         /**
441             Returns \p exempt_ptr to the leftmost item.
442             If the tree is empty, returns empty \p exempt_ptr.
443
444             \p Func functor is used to store minimal key.
445             \p Func has the following signature:
446             \code
447             struct functor {
448                 void operator()( key_type const& key );
449             };
450             \endcode
451             If the tree is empty, \p f is not called.
452             Otherwise, it is called with minimal key, the pointer to corresponding value is returned
453             as \p exempt_ptr.
454
455             @note Due the concurrent nature of the map, the function extracts <i>nearly</i> minimum key.
456             It means that the function gets leftmost leaf of the tree and tries to unlink it.
457             During unlinking, a concurrent thread may insert an item with key less than leftmost item's key.
458             So, the function returns the item with minimum key at the moment of tree traversing.
459
460             RCU \p synchronize method can be called. RCU should NOT be locked.
461             The function does not free the item.
462             The deallocator will be implicitly invoked when the returned object is destroyed or when
463             its \p release() member function is called.
464         */
465         template <typename Func>
466         exempt_ptr extract_min( Func f )
467         {
468             return exempt_ptr(do_extract_min( [&f]( key_type const& key ) { f(key); }));
469         }
470
471         /// Extracts minimal key and corresponding value
472         /**
473             This function is a shortcut for the following call:
474             \code
475             key_type key;
476             exempt_ptr xp = theTree.extract_min( [&key]( key_type const& k ) { key = k; } );
477             \endcode
478             \p key_type should be copy-assignable. The copy of minimal key
479             is returned in \p min_key argument.
480         */
481         typename std::enable_if< std::is_copy_assignable<key_type>::value, exempt_ptr >::type
482         extract_min_key( key_type& min_key )
483         {
484             return exempt_ptr(do_extract_min( [&min_key]( key_type const& key ) { min_key = key; }));
485         }
486
487         /// Extracts a value with maximal key from the tree
488         /**
489             Returns \p exempt_ptr pointer to the rightmost item.
490             If the set is empty, returns empty \p exempt_ptr.
491
492             Note that the function returns only the value for maximal key.
493             To retrieve its key use \p extract_max( Func ) member function.
494
495             @note Due the concurrent nature of the map, the function extracts <i>nearly</i> maximal key.
496             It means that the function gets rightmost leaf of the tree and tries to unlink it.
497             During unlinking, a concurrent thread may insert an item with key greater than rightmost item's key.
498             So, the function returns the item with maximum key at the moment of tree traversing.
499
500             RCU \p synchronize method can be called. RCU should NOT be locked.
501             The function does not free the item.
502             The deallocator will be implicitly invoked when the returned object is destroyed or when
503             its \p release() is called.
504         */
505         exempt_ptr extract_max()
506         {
507             return exempt_ptr(do_extract_max( []( key_type const& ) {}));
508         }
509
510         /// Extracts the maximal key and corresponding value
511         /**
512             Returns \p exempt_ptr pointer to the rightmost item.
513             If the set is empty, returns empty \p exempt_ptr.
514
515             \p Func functor is used to store maximal key.
516             \p Func has the following signature:
517             \code
518                 struct functor {
519                     void operator()( key_type const& key );
520                 };
521             \endcode
522             If the tree is empty, \p f is not called.
523             Otherwise, it is called with maximal key, the pointer to corresponding value is returned
524             as \p exempt_ptr.
525
526             @note Due the concurrent nature of the map, the function extracts <i>nearly</i> maximal key.
527             It means that the function gets rightmost leaf of the tree and tries to unlink it.
528             During unlinking, a concurrent thread may insert an item with key greater than rightmost item's key.
529             So, the function returns the item with maximum key at the moment of tree traversing.
530
531             RCU \p synchronize method can be called. RCU should NOT be locked.
532             The function does not free the item.
533             The deallocator will be implicitly invoked when the returned object is destroyed or when
534             its \p release() is called.
535         */
536         template <typename Func>
537         exempt_ptr extract_max( Func f )
538         {
539             return exempt_ptr(do_extract_max( [&f]( key_type const& key ) { f(key); }));
540         }
541
542         /// Extracts the maximal key and corresponding value
543         /**
544             This function is a shortcut for the following call:
545             \code
546                 key_type key;
547                 exempt_ptr xp = theTree.extract_max( [&key]( key_type const& k ) { key = k; } );
548             \endcode
549             \p key_type should be copy-assignable. The copy of maximal key
550             is returned in \p max_key argument.
551         */
552         typename std::enable_if< std::is_copy_assignable<key_type>::value, exempt_ptr >::type
553         extract_max_key( key_type& max_key )
554         {
555             return exempt_ptr(do_extract_max( [&max_key]( key_type const& key ) { max_key = key; }));
556         }
557
558         /// Extracts an item from the map
559         /**
560             The function searches an item with key equal to \p key in the tree,
561             unlinks it, and returns \p exempt_ptr pointer to a value found.
562             If \p key is not found the function returns an empty \p exempt_ptr.
563
564             RCU \p synchronize method can be called. RCU should NOT be locked.
565             The function does not destroy the value found.
566             The disposer will be implicitly invoked when the returned object is destroyed or when
567             its \p release() member function is called.
568         */
569         template <typename Q>
570         exempt_ptr extract( Q const& key )
571         {
572             return exempt_ptr(do_extract( key ));
573         }
574
575
576         /// Extracts an item from the map using \p pred for searching
577         /**
578             The function is an analog of \p extract(Q const&)
579             but \p pred is used for key compare.
580             \p Less has the interface like \p std::less.
581             \p pred must imply the same element order as the comparator used for building the tree.
582         */
583         template <typename Q, typename Less>
584         exempt_ptr extract_with( Q const& key, Less pred )
585         {
586             return exempt_ptr(do_extract_with( key, pred ));
587         }
588
589         /// Find the key \p key
590         /**
591             The function searches the item with key equal to \p key and calls the functor \p f for item found.
592             The interface of \p Func functor is:
593             \code
594             struct functor {
595                 void operator()( key_type const& key, std::remove_pointer< mapped_type )::type& item );
596             };
597             \endcode
598             where \p item is the item found.
599             The functor is called under node-level lock.
600
601             The function applies RCU lock internally.
602
603             The function returns \p true if \p key is found, \p false otherwise.
604         */
605         template <typename K, typename Func>
606         bool find( K const& key, Func f )
607         {
608             return do_find( key, key_comparator(),
609                 [&f]( node_type * pNode ) -> bool {
610                     assert( pNode != nullptr );
611                     mapped_type pVal = pNode->m_pValue.load( memory_model::memory_order_relaxed );
612                     if ( pVal ) {
613                         f( pNode->m_key, *pVal );
614                         return true;
615                     }
616                     return false;
617                 }
618             );
619         }
620
621         /// Finds the key \p val using \p pred predicate for searching
622         /**
623             The function is an analog of \p find(K const&, Func)
624             but \p pred is used for key comparing.
625             \p Less functor has the interface like \p std::less.
626             \p Less must imply the same element order as the comparator used for building the map.
627         */
628         template <typename K, typename Less, typename Func>
629         bool find_with( K const& key, Less pred, Func f )
630         {
631             CDS_UNUSED( pred );
632             return do_find( key, cds::opt::details::make_comparator_from_less<Less>(),
633                 [&f]( node_type * pNode ) -> bool {
634                     assert( pNode != nullptr );
635                     mapped_type pVal = pNode->m_pValue.load( memory_model::memory_order_relaxed );
636                     if ( pVal ) {
637                         f( pNode->m_key, *pVal );
638                         return true;
639                     }
640                     return false;
641                 }
642             );
643         }
644
645         /// Checks whether the map contains \p key
646         /**
647             The function searches the item with key equal to \p key
648             and returns \p true if it is found, and \p false otherwise.
649
650             The function applies RCU lock internally.
651         */
652         template <typename K>
653         bool contains( K const& key )
654         {
655             return do_find( key, key_comparator(), []( node_type * ) -> bool { return true; });
656         }
657
658         /// Checks whether the map contains \p key using \p pred predicate for searching
659         /**
660             The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
661             \p Less functor has the interface like \p std::less.
662             \p Less must imply the same element order as the comparator used for building the set.
663         */
664         template <typename K, typename Less>
665         bool contains( K const& key, Less pred )
666         {
667             CDS_UNUSED( pred );
668             return do_find( key, cds::opt::details::make_comparator_from_less<Less>(), []( node_type * ) -> bool { return true; } );
669         }
670
671         /// Clears the tree (thread safe, not atomic)
672         /**
673             The function unlink all items from the tree.
674             The function is thread safe but not atomic: in multi-threaded environment with parallel insertions
675             this sequence
676             \code
677             set.clear();
678             assert( set.empty());
679             \endcode
680             the assertion could be raised.
681
682             For each node the \ref disposer will be called after unlinking.
683
684             RCU \p synchronize method can be called. RCU should not be locked.
685         */
686         void clear()
687         {
688             while ( extract_min());
689         }
690
691         /// Clears the tree (not thread safe)
692         /**
693             This function is not thread safe and may be called only when no other thread deals with the tree.
694             The function is used in the tree destructor.
695         */
696         void unsafe_clear()
697         {
698             clear(); // temp solution
699             //TODO
700         }
701
702         /// Checks if the map is empty
703         bool empty() const
704         {
705             return m_Root.m_pRight.load( memory_model::memory_order_relaxed ) == nullptr;
706         }
707
708         /// Returns item count in the map
709         /**
710             Only leaf nodes containing user data are counted.
711
712             The value returned depends on item counter type provided by \p Traits template parameter.
713             If it is \p atomicity::empty_item_counter this function always returns 0.
714
715             The function is not suitable for checking the tree emptiness, use \p empty()
716             member function for this purpose.
717         */
718         size_t size() const
719         {
720             return m_ItemCounter;
721         }
722
723         /// Returns const reference to internal statistics
724         stat const& statistics() const
725         {
726             return m_stat;
727         }
728
729         /// Returns reference to \p sync_monitor object
730         sync_monitor& monitor()
731         {
732             return m_Monitor;
733         }
734         //@cond
735         sync_monitor const& monitor() const
736         {
737             return m_Monitor;
738         }
739         //@endcond
740
741         /// Checks internal consistency (not atomic, not thread-safe)
742         /**
743             The debugging function to check internal consistency of the tree.
744         */
745         bool check_consistency() const
746         {
747             return check_consistency([]( size_t /*nLevel*/, size_t /*hLeft*/, size_t /*hRight*/ ){} );
748         }
749
750         /// Checks internal consistency (not atomic, not thread-safe)
751         /**
752             The debugging function to check internal consistency of the tree.
753             The functor \p Func is called if a violation of internal tree structure
754             is found:
755             \code
756             struct functor {
757                 void operator()( size_t nLevel, size_t hLeft, size_t hRight );
758             };
759             \endcode
760             where
761             - \p nLevel - the level where the violation is found
762             - \p hLeft - the height of left subtree
763             - \p hRight - the height of right subtree
764
765             The functor is called for each violation found.
766         */
767         template <typename Func>
768         bool check_consistency( Func f ) const
769         {
770             node_type * pChild = child( m_pRoot, right_child, memory_model::memory_order_acquire );
771             if ( pChild ) {
772                 size_t nErrors = 0;
773                 do_check_consistency( pChild, 1, f, nErrors );
774                 return nErrors == 0;
775             }
776             return true;
777         }
778
779     protected:
780         //@cond
781         template <typename Func>
782         size_t do_check_consistency( node_type * pNode, size_t nLevel, Func f, size_t& nErrors ) const
783         {
784             if ( pNode ) {
785                 key_comparator cmp;
786                 node_type * pLeft = child( pNode, left_child, memory_model::memory_order_acquire );
787                 node_type * pRight = child( pNode, right_child, memory_model::memory_order_acquire );
788                 if ( pLeft && cmp( pLeft->m_key, pNode->m_key ) > 0 )
789                     ++nErrors;
790                 if (  pRight && cmp( pNode->m_key, pRight->m_key ) > 0 )
791                     ++nErrors;
792
793                 size_t hLeft = do_check_consistency( pLeft, nLevel + 1, f, nErrors );
794                 size_t hRight = do_check_consistency( pRight, nLevel + 1, f, nErrors );
795
796                 if ( hLeft >= hRight ) {
797                     if ( hLeft - hRight > 1 ) {
798                         f( nLevel, hLeft, hRight );
799                         ++nErrors;
800                     }
801                     return hLeft;
802                 }
803                 else {
804                     if ( hRight - hLeft > 1 ) {
805                         f( nLevel, hLeft, hRight );
806                         ++nErrors;
807                     }
808                     return hRight;
809                 }
810             }
811             return 0;
812         }
813
814         template <typename Q, typename Compare, typename Func>
815         bool do_find( Q& key, Compare cmp, Func f ) const
816         {
817             find_result result;
818             {
819                 rcu_lock l;
820                 result = try_find( key, cmp, f, m_pRoot, right_child, 0 );
821             }
822             assert( result != find_result::retry );
823             return result == find_result::found;
824         }
825
826         template <typename K, typename Compare, typename Func>
827         int do_update( K const& key, Compare cmp, Func funcUpdate, int nFlags )
828         {
829             check_deadlock_policy::check();
830
831             rcu_disposer removed_list;
832             {
833                 rcu_lock l;
834                 return try_update_root( key, cmp, nFlags, funcUpdate, removed_list );
835             }
836         }
837
838         template <typename K, typename Compare, typename Func>
839         bool do_remove( K const& key, Compare cmp, Func func )
840         {
841             // Func must return true if the value was disposed
842             //              or false if the value was extracted
843
844             check_deadlock_policy::check();
845
846             rcu_disposer removed_list;
847             {
848                 rcu_lock l;
849                 return try_remove_root( key, cmp, func, removed_list );
850             }
851         }
852
853         template <typename Func>
854         mapped_type do_extract_min( Func f )
855         {
856             mapped_type pExtracted = nullptr;
857             do_extract_minmax(
858                 left_child,
859                 [&pExtracted, &f]( key_type const& key, mapped_type pVal, rcu_disposer& ) -> bool { f( key ); pExtracted = pVal; return false; }
860             );
861             return pExtracted;
862         }
863
864         template <typename Func>
865         mapped_type do_extract_max( Func f )
866         {
867             mapped_type pExtracted = nullptr;
868             do_extract_minmax(
869                 right_child,
870                 [&pExtracted, &f]( key_type const& key, mapped_type pVal, rcu_disposer& ) -> bool { f( key ); pExtracted = pVal; return false; }
871             );
872             return pExtracted;
873         }
874
875         template <typename Func>
876         void do_extract_minmax( int nDir, Func func )
877         {
878             check_deadlock_policy::check();
879
880             rcu_disposer removed_list;
881             {
882                 rcu_lock l;
883
884                 while ( true ) {
885                     int result;
886
887                     // get right child of root
888                     node_type * pChild = child( m_pRoot, right_child, memory_model::memory_order_acquire );
889                     if ( pChild ) {
890                         version_type nChildVersion = pChild->version( memory_model::memory_order_acquire );
891                         if ( nChildVersion & node_type::shrinking ) {
892                             m_stat.onRemoveRootWaitShrinking();
893                             pChild->template wait_until_shrink_completed<back_off>( memory_model::memory_order_acquire );
894                             result = update_flags::retry;
895                         }
896                         else if ( pChild == child( m_pRoot, right_child, memory_model::memory_order_acquire )) {
897                             result = try_extract_minmax( nDir, func, m_pRoot, pChild, nChildVersion, removed_list );
898                         }
899                         else
900                             result = update_flags::retry;
901                     }
902                     else
903                         return;
904
905                     if ( result == update_flags::retry )
906                         m_stat.onRemoveRetry();
907                     else {
908                         m_stat.onExtract( result == update_flags::result_removed );
909                         return;
910                     }
911                 }
912             }
913         }
914
915         template <typename Q>
916         mapped_type do_extract( Q const& key )
917         {
918             mapped_type pExtracted = nullptr;
919             do_remove(
920                 key,
921                 key_comparator(),
922                 [&pExtracted]( key_type const&, mapped_type pVal, rcu_disposer& ) -> bool { pExtracted = pVal; return false; }
923             );
924             m_stat.onExtract( pExtracted != nullptr );
925             return pExtracted;
926         }
927
928         template <typename Q, typename Less>
929         mapped_type do_extract_with( Q const& key, Less pred )
930         {
931             CDS_UNUSED( pred );
932             mapped_type pExtracted = nullptr;
933             do_remove(
934                 key,
935                 cds::opt::details::make_comparator_from_less<Less>(),
936                 [&pExtracted]( key_type const&, mapped_type pVal, rcu_disposer& ) -> bool { pExtracted = pVal; return false; }
937             );
938             m_stat.onExtract( pExtracted != nullptr );
939             return pExtracted;
940         }
941         //@endcond
942
943     private:
944         //@cond
945         static int height( node_type * pNode, atomics::memory_order order )
946         {
947             assert( pNode );
948             return pNode->m_nHeight.load( order );
949         }
950         static void set_height( node_type * pNode, int h, atomics::memory_order order )
951         {
952             assert( pNode );
953             pNode->m_nHeight.store( h, order );
954         }
955         static int height_null( node_type * pNode, atomics::memory_order order )
956         {
957             return pNode ? height( pNode, order ) : 0;
958         }
959
960         static CDS_CONSTEXPR int const c_stackSize = 64;
961
962         template <typename Q, typename Compare, typename Func>
963         find_result try_find( Q const& key, Compare cmp, Func f, node_type * pNode, int nDir, version_type nVersion ) const
964         {
965             assert( gc::is_locked());
966             assert( pNode );
967
968             struct stack_record
969             {
970                 node_type * pNode;
971                 version_type nVersion;
972                 int nDir;
973             };
974
975             stack_record stack[c_stackSize];
976             int pos = 0;
977             stack[0].pNode = pNode;
978             stack[0].nVersion = nVersion;
979             stack[0].nDir = nDir;
980
981             while ( pos >= 0 ) {
982                 pNode = stack[pos].pNode;
983                 nVersion = stack[pos].nVersion;
984                 nDir = stack[pos].nDir;
985
986                 while ( true ) {
987                     node_type * pChild = child( pNode, nDir, memory_model::memory_order_acquire );
988                     if ( !pChild ) {
989                         if ( pNode->version(memory_model::memory_order_acquire) != nVersion ) {
990                             --pos;
991                             m_stat.onFindRetry();
992                             break; // retry
993                         }
994                         m_stat.onFindFailed();
995                         return find_result::not_found;
996                     }
997
998                     int nCmp = cmp( key, pChild->m_key );
999                     if ( nCmp == 0 ) {
1000                         if ( pChild->is_valued( memory_model::memory_order_acquire )) {
1001                             // key found
1002                             node_scoped_lock l( m_Monitor, *pChild );
1003                             if ( child(pNode, nDir, memory_model::memory_order_acquire) == pChild ) {
1004                                 if ( pChild->is_valued( memory_model::memory_order_relaxed )) {
1005                                     if ( f( pChild )) {
1006                                         m_stat.onFindSuccess();
1007                                         return find_result::found;
1008                                     }
1009                                 }
1010                             }
1011                             else {
1012                                 m_stat.onFindRetry();
1013                                 continue;
1014                             }
1015                         }
1016                         m_stat.onFindFailed();
1017                         return find_result::not_found;
1018                     }
1019                     else {
1020                         version_type nChildVersion = pChild->version( memory_model::memory_order_acquire );
1021                         if ( nChildVersion & node_type::shrinking ) {
1022                             m_stat.onFindWaitShrinking();
1023                             pChild->template wait_until_shrink_completed<back_off>( memory_model::memory_order_acquire );
1024
1025                             if ( pNode->version(memory_model::memory_order_acquire) != nVersion ) {
1026                                 --pos;
1027                                 m_stat.onFindRetry();
1028                                 break; // retry
1029                             }
1030                         }
1031                         else if ( nChildVersion != node_type::unlinked && child( pNode, nDir, memory_model::memory_order_acquire ) == pChild )
1032                         {
1033                             if ( pNode->version(memory_model::memory_order_acquire) != nVersion ) {
1034                                 --pos;
1035                                 m_stat.onFindRetry();
1036                                 break; // retry
1037                             }
1038
1039                             ++pos;
1040                             assert(pos < c_stackSize);
1041                             stack[pos].pNode = pChild;
1042                             stack[pos].nVersion = nChildVersion;
1043                             stack[pos].nDir = nCmp;
1044                             break; // child iteration
1045                         }
1046
1047                         if ( pNode->version(memory_model::memory_order_acquire) != nVersion ) {
1048                             --pos;
1049                             m_stat.onFindRetry();
1050                             break; // retry
1051                         }
1052                     }
1053                     m_stat.onFindRetry();
1054                 }
1055             }
1056             return find_result::retry;
1057         }
1058
1059         template <typename K, typename Compare, typename Func>
1060         int try_update_root( K const& key, Compare cmp, int nFlags, Func funcUpdate, rcu_disposer& disp )
1061         {
1062             assert( gc::is_locked());
1063
1064             while ( true ) {
1065                 int result;
1066
1067                 // get right child of root
1068                 node_type * pChild = child( m_pRoot, right_child, memory_model::memory_order_acquire );
1069                 if ( pChild ) {
1070                     version_type nChildVersion = pChild->version( memory_model::memory_order_acquire );
1071                     if ( nChildVersion & node_type::shrinking ) {
1072                         m_stat.onUpdateRootWaitShrinking();
1073                         pChild->template wait_until_shrink_completed<back_off>( memory_model::memory_order_acquire );
1074                         result = update_flags::retry;
1075                     }
1076                     else if ( pChild == child( m_pRoot, right_child, memory_model::memory_order_acquire ))
1077                         result = try_update( key, cmp, nFlags, funcUpdate, pChild, nChildVersion, disp );
1078                     else
1079                         result = update_flags::retry;
1080                 }
1081                 else {
1082                     // the tree is empty
1083                     if ( nFlags & update_flags::allow_insert ) {
1084                         // insert into tree as right child of the root
1085                         {
1086                             node_scoped_lock l( m_Monitor, *m_pRoot );
1087                             if ( child( m_pRoot, right_child, memory_model::memory_order_acquire ) != nullptr ) {
1088                                 result = update_flags::retry;
1089                                 continue;
1090                             }
1091
1092                             node_type * pNew = alloc_node( key, 1, 0, m_pRoot, nullptr, nullptr );
1093                             mapped_type pVal = funcUpdate( pNew );
1094                             assert( pVal != nullptr );
1095                             pNew->m_pValue.store( pVal, memory_model::memory_order_release );
1096
1097                             m_pRoot->child( pNew, right_child, memory_model::memory_order_release);
1098                             set_height( m_pRoot, 2, memory_model::memory_order_release );
1099                         }
1100
1101                         ++m_ItemCounter;
1102                         m_stat.onInsertSuccess();
1103                         return update_flags::result_inserted;
1104                     }
1105
1106                     return update_flags::failed;
1107                 }
1108
1109                 if ( result != update_flags::retry )
1110                     return result;
1111             }
1112         }
1113
1114         template <typename K, typename Compare, typename Func>
1115         bool try_remove_root( K const& key, Compare cmp, Func func, rcu_disposer& disp )
1116         {
1117             assert( gc::is_locked());
1118
1119             while ( true ) {
1120                 int result;
1121
1122                 // get right child of root
1123                 node_type * pChild = child( m_pRoot, right_child, memory_model::memory_order_acquire );
1124                 if ( pChild ) {
1125                     version_type nChildVersion = pChild->version( memory_model::memory_order_acquire );
1126                     if ( nChildVersion & node_type::shrinking ) {
1127                         m_stat.onRemoveRootWaitShrinking();
1128                         pChild->template wait_until_shrink_completed<back_off>( memory_model::memory_order_acquire );
1129                         result = update_flags::retry;
1130                     }
1131                     else if ( pChild == child( m_pRoot, right_child, memory_model::memory_order_acquire )) {
1132                         result = try_remove( key, cmp, func, m_pRoot, pChild, nChildVersion, disp );
1133                     }
1134                     else
1135                         result = update_flags::retry;
1136                 }
1137                 else
1138                     return false;
1139
1140                 if ( result == update_flags::retry )
1141                     m_stat.onRemoveRetry();
1142                 else {
1143                     m_stat.onRemove( result == update_flags::result_removed );
1144                     return result == update_flags::result_removed;
1145                 }
1146             }
1147         }
1148
1149         template <typename K, typename Compare, typename Func>
1150         int try_update( K const& key, Compare cmp, int nFlags, Func funcUpdate, node_type * pNode, version_type nVersion, rcu_disposer& disp )
1151         {
1152             assert( gc::is_locked());
1153             assert( nVersion != node_type::unlinked );
1154
1155             struct stack_record
1156             {
1157                 node_type * pNode;
1158                 version_type nVersion;
1159             };
1160
1161             stack_record stack[c_stackSize];
1162             int pos = 0;
1163             stack[0].pNode = pNode;
1164             stack[0].nVersion = nVersion;
1165
1166             while ( pos >= 0 ) {
1167                 pNode = stack[pos].pNode;
1168                 nVersion = stack[pos].nVersion;
1169
1170                 int nCmp = cmp( key, pNode->m_key );
1171                 if ( nCmp == 0 ) {
1172                     int result = try_update_node( nFlags, funcUpdate, pNode, nVersion, disp );
1173                     if ( result != update_flags::retry )
1174                         return result;
1175                     --pos;
1176                     m_stat.onUpdateRetry();
1177                     continue;
1178                 }
1179
1180                 while ( true ) {
1181                     node_type * pChild = child( pNode, nCmp, memory_model::memory_order_acquire );
1182                     if ( pNode->version(memory_model::memory_order_acquire) != nVersion ) {
1183                         --pos;
1184                         m_stat.onUpdateRetry();
1185                         break;
1186                     }
1187
1188                     if ( pChild == nullptr ) {
1189                         // insert new node
1190                         if ( nFlags & update_flags::allow_insert ) {
1191                             int result = try_insert_node( key, funcUpdate, pNode, nCmp, nVersion, disp );
1192                             if ( result != update_flags::retry )
1193                                 return result;
1194                             --pos;
1195                             m_stat.onUpdateRetry();
1196                             break;
1197                         }
1198                         else
1199                             return update_flags::failed;
1200                     }
1201                     else {
1202                         // update child
1203                         version_type nChildVersion = pChild->version( memory_model::memory_order_acquire );
1204                         if ( nChildVersion & node_type::shrinking ) {
1205                             m_stat.onUpdateWaitShrinking();
1206                             pChild->template wait_until_shrink_completed<back_off>( memory_model::memory_order_acquire );
1207                             // retry
1208                         }
1209                         else if ( pChild == child( pNode, nCmp, memory_model::memory_order_acquire )) {
1210                             // this second read is important, because it is protected by nChildVersion
1211
1212                             // validate the read that our caller took to get to node
1213                             if ( pNode->version( memory_model::memory_order_acquire ) != nVersion ) {
1214                                 --pos;
1215                                 m_stat.onUpdateRetry();
1216                                 break; // retry
1217                             }
1218                             // At this point we know that the traversal our parent took to get to node is still valid.
1219                             // The recursive implementation will validate the traversal from node to
1220                             // child, so just prior to the node nVersion validation both traversals were definitely okay.
1221                             // This means that we are no longer vulnerable to node shrinks, and we don't need
1222                             // to validate node version any more.
1223                             ++pos;
1224                             assert( pos < c_stackSize );
1225                             stack[pos].pNode = pChild;
1226                             stack[pos].nVersion = nChildVersion;
1227                             assert( nChildVersion != node_type::unlinked );
1228                             break; // child iteration
1229                         }
1230                         m_stat.onUpdateRetry();
1231                     }
1232                 }
1233             }
1234             return update_flags::retry;
1235         }
1236
1237         template <typename K, typename Compare, typename Func>
1238         int try_remove( K const& key, Compare cmp, Func func, node_type * pParent, node_type * pNode, version_type nVersion, rcu_disposer& disp )
1239         {
1240             assert( gc::is_locked());
1241             assert( nVersion != node_type::unlinked );
1242
1243             struct stack_record
1244             {
1245                 node_type * pParent;
1246                 node_type * pNode;
1247                 version_type nVersion;
1248             };
1249
1250             stack_record stack[c_stackSize];
1251             int pos = 0;
1252             stack[0].pParent = pParent;
1253             stack[0].pNode = pNode;
1254             stack[0].nVersion = nVersion;
1255
1256             while ( pos >= 0 ) {
1257                 pParent = stack[pos].pParent;
1258                 pNode = stack[pos].pNode;
1259                 nVersion = stack[pos].nVersion;
1260
1261                 int nCmp = cmp( key, pNode->m_key );
1262                 if ( nCmp == 0 ) {
1263                     int result = try_remove_node( pParent, pNode, nVersion, func, disp );
1264                     if ( result != update_flags::retry )
1265                         return result;
1266                     --pos;
1267                     m_stat.onRemoveRetry();
1268                     continue;
1269                 }
1270
1271                 while ( true ) {
1272                     node_type * pChild = child( pNode, nCmp, memory_model::memory_order_acquire );
1273                     if ( pNode->version(memory_model::memory_order_acquire) != nVersion ) {
1274                         --pos;
1275                         m_stat.onRemoveRetry();
1276                         break;
1277                     }
1278
1279                     if ( pChild == nullptr )
1280                         return update_flags::failed;
1281
1282                     // update child
1283                     version_type nChildVersion = pChild->version( memory_model::memory_order_acquire );
1284                     if ( nChildVersion & node_type::shrinking ) {
1285                         m_stat.onRemoveWaitShrinking();
1286                         pChild->template wait_until_shrink_completed<back_off>( memory_model::memory_order_acquire );
1287                         // retry
1288                     }
1289                     else if ( pChild == child( pNode, nCmp, memory_model::memory_order_acquire )) {
1290                         // this second read is important, because it is protected by nChildVersion
1291
1292                         // validate the read that our caller took to get to node
1293                         if ( pNode->version(memory_model::memory_order_acquire) != nVersion ) {
1294                             --pos;
1295                             m_stat.onRemoveRetry();
1296                             break;
1297                         }
1298
1299                         // At this point we know that the traversal our parent took to get to node is still valid.
1300                         // The recursive implementation will validate the traversal from node to
1301                         // child, so just prior to the node nVersion validation both traversals were definitely okay.
1302                         // This means that we are no longer vulnerable to node shrinks, and we don't need
1303                         // to validate node version any more.
1304                         ++pos;
1305                         assert( pos < c_stackSize );
1306                         stack[pos].pParent = pNode;
1307                         stack[pos].pNode = pChild;
1308                         stack[pos].nVersion = nChildVersion;
1309                         break; // child iteration
1310                     }
1311                     m_stat.onRemoveRetry();
1312                 }
1313             }
1314             return update_flags::retry;
1315         }
1316
1317         template <typename Func>
1318         int try_extract_minmax( int nDir, Func func, node_type * pParent, node_type * pNode, version_type nVersion, rcu_disposer& disp )
1319         {
1320             assert( gc::is_locked());
1321             assert( nVersion != node_type::unlinked );
1322
1323             struct stack_record
1324             {
1325                 node_type * pParent;
1326                 node_type * pNode;
1327                 version_type nVersion;
1328             };
1329
1330             stack_record stack[c_stackSize];
1331             int pos = 0;
1332             stack[0].pParent = pParent;
1333             stack[0].pNode = pNode;
1334             stack[0].nVersion = nVersion;
1335
1336             while ( pos >= 0 ) {
1337                 pParent = stack[pos].pParent;
1338                 pNode = stack[pos].pNode;
1339                 nVersion = stack[pos].nVersion;
1340
1341                 while ( true ) {
1342                     int iterDir = nDir;
1343                     node_type * pChild = child( pNode, iterDir, memory_model::memory_order_acquire );
1344                     if ( pNode->version(memory_model::memory_order_acquire) != nVersion ) {
1345                         --pos;
1346                         m_stat.onRemoveRetry();
1347                         break;
1348                     }
1349
1350                     if ( !pChild ) {
1351                         // Found min/max
1352                         if ( pNode->is_valued( memory_model::memory_order_acquire ) ) {
1353                             int result = try_remove_node( pParent, pNode, nVersion, func, disp );
1354
1355                             if ( result == update_flags::result_removed )
1356                                 return result;
1357
1358                             --pos;
1359                             m_stat.onRemoveRetry();
1360                             break;
1361                         }
1362                         else {
1363                             // check right (for min) or left (for max) child node
1364                             iterDir = -iterDir;
1365                             pChild = child( pNode, iterDir, memory_model::memory_order_acquire );
1366                             if ( !pChild ) {
1367                                 --pos;
1368                                 m_stat.onRemoveRetry();
1369                                 break;
1370                             }
1371                         }
1372                     }
1373
1374                     version_type nChildVersion = pChild->version( memory_model::memory_order_acquire );
1375                     if ( nChildVersion & node_type::shrinking ) {
1376                         m_stat.onRemoveWaitShrinking();
1377                         pChild->template wait_until_shrink_completed<back_off>( memory_model::memory_order_acquire );
1378                         // retry
1379                     }
1380                     else if ( pChild == child( pNode, iterDir, memory_model::memory_order_acquire )) {
1381                         // this second read is important, because it is protected by nChildVersion
1382
1383                         // validate the read that our caller took to get to node
1384                         if ( pNode->version( memory_model::memory_order_acquire ) != nVersion ) {
1385                             --pos;
1386                             m_stat.onRemoveRetry();
1387                             break;
1388                         }
1389
1390                         // At this point we know that the traversal our parent took to get to node is still valid.
1391                         // The recursive implementation will validate the traversal from node to
1392                         // child, so just prior to the node nVersion validation both traversals were definitely okay.
1393                         // This means that we are no longer vulnerable to node shrinks, and we don't need
1394                         // to validate node version any more.
1395                         ++pos;
1396                         assert( pos < c_stackSize );
1397                         stack[pos].pParent = pNode;
1398                         stack[pos].pNode = pChild;
1399                         stack[pos].nVersion = nChildVersion;
1400                         break; // child iteration
1401                     }
1402                     m_stat.onRemoveRetry();
1403                 }
1404             }
1405             return update_flags::retry;
1406         }
1407
1408         template <typename K, typename Func>
1409         int try_insert_node( K const& key, Func funcUpdate, node_type * pNode, int nDir, version_type nVersion, rcu_disposer& disp )
1410         {
1411             node_type * pNew;
1412
1413             auto fnCreateNode = [&funcUpdate]( node_type * pNew ) {
1414                 mapped_type pVal = funcUpdate( pNew );
1415                 assert( pVal != nullptr );
1416                 pNew->m_pValue.store( pVal, memory_model::memory_order_release );
1417             };
1418
1419             if ( c_bRelaxedInsert ) {
1420                 if ( pNode->version( memory_model::memory_order_acquire ) != nVersion
1421                      || child( pNode, nDir, memory_model::memory_order_acquire ) != nullptr )
1422                 {
1423                     m_stat.onInsertRetry();
1424                     return update_flags::retry;
1425                 }
1426
1427                 fnCreateNode( pNew = alloc_node( key, 1, 0, pNode, nullptr, nullptr ));
1428             }
1429
1430             node_type * pDamaged;
1431             {
1432                 assert( pNode != nullptr );
1433                 node_scoped_lock l( m_Monitor, *pNode );
1434
1435                 if ( pNode->version( memory_model::memory_order_acquire ) != nVersion
1436                      || child( pNode, nDir, memory_model::memory_order_acquire ) != nullptr )
1437                 {
1438                     if ( c_bRelaxedInsert ) {
1439                         mapped_type pVal = pNew->m_pValue.load( memory_model::memory_order_relaxed );
1440                         pNew->m_pValue.store( nullptr, memory_model::memory_order_relaxed );
1441                         free_value( pVal );
1442                         free_node( pNew );
1443                         m_stat.onRelaxedInsertFailed();
1444                     }
1445
1446                     m_stat.onInsertRetry();
1447                     return update_flags::retry;
1448                 }
1449
1450                 if ( !c_bRelaxedInsert )
1451                     fnCreateNode( pNew = alloc_node( key, 1, 0, pNode, nullptr, nullptr ));
1452
1453                 pNode->child( pNew, nDir, memory_model::memory_order_release );
1454                 pDamaged = fix_height_locked( pNode );
1455             }
1456
1457             ++m_ItemCounter;
1458             m_stat.onInsertSuccess();
1459
1460             if ( pDamaged ) {
1461                 fix_height_and_rebalance( pDamaged, disp );
1462                 m_stat.onInsertRebalanceRequired();
1463             }
1464
1465             return update_flags::result_inserted;
1466         }
1467
1468         template <typename Func>
1469         int try_update_node( int nFlags, Func funcUpdate, node_type * pNode, version_type nVersion, rcu_disposer& disp )
1470         {
1471             mapped_type pOld;
1472             bool bInserted;
1473             assert( pNode != nullptr );
1474             {
1475                 node_scoped_lock l( m_Monitor, *pNode );
1476
1477                 if ( pNode->version(memory_model::memory_order_acquire) != nVersion )
1478                     return update_flags::retry;
1479
1480                 if ( pNode->is_unlinked( memory_model::memory_order_acquire )) {
1481                     m_stat.onUpdateUnlinked();
1482                     return update_flags::retry;
1483                 }
1484
1485                 if ( pNode->is_valued( memory_model::memory_order_relaxed ) && !(nFlags & update_flags::allow_update)) {
1486                     m_stat.onInsertFailed();
1487                     return update_flags::failed;
1488                 }
1489
1490                 pOld = pNode->value( memory_model::memory_order_relaxed );
1491                 bInserted = pOld == nullptr;
1492                 mapped_type pVal = funcUpdate( pNode );
1493                 if ( pVal == pOld )
1494                     pOld = nullptr;
1495                 else {
1496                     assert( pVal != nullptr );
1497                     pNode->m_pValue.store( pVal, memory_model::memory_order_release );
1498                 }
1499             }
1500
1501             if ( pOld ) {
1502                 disp.dispose_value(pOld);
1503                 m_stat.onDisposeValue();
1504             }
1505
1506             if ( bInserted ) {
1507                 ++m_ItemCounter;
1508                 m_stat.onInsertSuccess();
1509                 return update_flags::result_inserted;
1510             }
1511
1512             m_stat.onUpdateSuccess();
1513             return update_flags::result_updated;
1514         }
1515
1516         template <typename Func>
1517         int try_remove_node( node_type * pParent, node_type * pNode, version_type nVersion, Func func, rcu_disposer& disp )
1518         {
1519             assert( pParent != nullptr );
1520             assert( pNode != nullptr );
1521
1522             if ( !pNode->is_valued( memory_model::memory_order_acquire ))
1523                 return update_flags::failed;
1524
1525             if ( child( pNode, left_child, memory_model::memory_order_acquire ) == nullptr
1526               || child( pNode, right_child, memory_model::memory_order_acquire ) == nullptr )
1527             {
1528                 // pNode can be replaced with its child
1529
1530                 node_type * pDamaged;
1531                 mapped_type pOld;
1532                 {
1533                     node_scoped_lock lp( m_Monitor, *pParent );
1534                     if ( pParent->is_unlinked( memory_model::memory_order_acquire ) || parent( pNode, memory_model::memory_order_acquire ) != pParent )
1535                         return update_flags::retry;
1536
1537                     {
1538                         node_scoped_lock ln( m_Monitor, *pNode );
1539                         if ( pNode->version( memory_model::memory_order_acquire ) != nVersion )
1540                             return update_flags::retry;
1541
1542                         pOld = pNode->value( memory_model::memory_order_relaxed );
1543                         if ( !pOld )
1544                             return update_flags::failed;
1545
1546                         if ( !try_unlink_locked( pParent, pNode, disp ))
1547                             return update_flags::retry;
1548                     }
1549                     pDamaged = fix_height_locked( pParent );
1550                 }
1551
1552                 --m_ItemCounter;
1553                 if ( func( pNode->m_key, pOld, disp ))   // calls pOld disposer inside
1554                     m_stat.onDisposeValue();
1555                 else
1556                     m_stat.onExtractValue();
1557
1558                 if ( pDamaged ) {
1559                     fix_height_and_rebalance( pDamaged, disp );
1560                     m_stat.onRemoveRebalanceRequired();
1561                 }
1562             }
1563             else {
1564                 // pNode is an internal with two children
1565
1566                 mapped_type pOld;
1567                 {
1568                     node_scoped_lock ln( m_Monitor, *pNode );
1569                     pOld = pNode->value( memory_model::memory_order_relaxed );
1570                     if ( pNode->version( memory_model::memory_order_relaxed ) != nVersion )
1571                         return update_flags::retry;
1572                     if ( !pOld )
1573                         return update_flags::failed;
1574
1575                     pNode->m_pValue.store( nullptr, memory_model::memory_order_release );
1576                     m_stat.onMakeRoutingNode();
1577                 }
1578
1579                 --m_ItemCounter;
1580                 if ( func( pNode->m_key, pOld, disp ))  // calls pOld disposer inside
1581                     m_stat.onDisposeValue();
1582                 else
1583                     m_stat.onExtractValue();
1584             }
1585             return update_flags::result_removed;
1586         }
1587
1588         bool try_unlink_locked( node_type * pParent, node_type * pNode, rcu_disposer& disp )
1589         {
1590             // pParent and pNode must be locked
1591             assert( !pParent->is_unlinked(memory_model::memory_order_relaxed));
1592
1593             node_type * pParentLeft = child( pParent, left_child, memory_model::memory_order_relaxed );
1594             node_type * pParentRight = child( pParent, right_child, memory_model::memory_order_relaxed );
1595             if ( pNode != pParentLeft && pNode != pParentRight ) {
1596                 // node is no longer a child of parent
1597                 return false;
1598             }
1599
1600             assert( !pNode->is_unlinked( memory_model::memory_order_relaxed ));
1601             assert( pParent == parent( pNode, memory_model::memory_order_relaxed ));
1602
1603             node_type * pLeft = child( pNode, left_child, memory_model::memory_order_relaxed );
1604             node_type * pRight = child( pNode, right_child, memory_model::memory_order_relaxed );
1605             if ( pLeft != nullptr && pRight != nullptr ) {
1606                 // splicing is no longer possible
1607                 return false;
1608             }
1609             node_type * pSplice = pLeft ? pLeft : pRight;
1610
1611             if ( pParentLeft == pNode )
1612                 pParent->m_pLeft.store( pSplice, memory_model::memory_order_release );
1613             else
1614                 pParent->m_pRight.store( pSplice, memory_model::memory_order_release );
1615
1616             if ( pSplice )
1617                 pSplice->parent( pParent, memory_model::memory_order_release );
1618
1619             // Mark the node as unlinked
1620             pNode->version( node_type::unlinked, memory_model::memory_order_release );
1621
1622             // The value will be disposed by calling function
1623             pNode->m_pValue.store( nullptr, memory_model::memory_order_release );
1624
1625             disp.dispose( pNode );
1626             m_stat.onDisposeNode();
1627
1628             return true;
1629         }
1630
1631         //@endcond
1632
1633     private: // rotations
1634         //@cond
1635         int estimate_node_condition( node_type * pNode )
1636         {
1637             node_type * pLeft = child( pNode, left_child, memory_model::memory_order_acquire );
1638             node_type * pRight = child( pNode, right_child, memory_model::memory_order_acquire );
1639
1640             if ( (pLeft == nullptr || pRight == nullptr) && !pNode->is_valued( memory_model::memory_order_acquire ))
1641                 return unlink_required;
1642
1643             int h = height( pNode, memory_model::memory_order_acquire );
1644             int hL = height_null( pLeft, memory_model::memory_order_acquire );
1645             int hR = height_null( pRight, memory_model::memory_order_acquire );
1646
1647             int hNew = 1 + std::max( hL, hR );
1648             int nBalance = hL - hR;
1649
1650             if ( nBalance < -1 || nBalance > 1 )
1651                 return rebalance_required;
1652
1653             return h != hNew ? hNew : nothing_required;
1654         }
1655
1656         node_type * fix_height( node_type * pNode )
1657         {
1658             assert( pNode != nullptr );
1659             node_scoped_lock l( m_Monitor, *pNode );
1660             return fix_height_locked( pNode );
1661         }
1662
1663         node_type * fix_height_locked( node_type * pNode )
1664         {
1665             // pNode must be locked!!!
1666             int h = estimate_node_condition( pNode );
1667             switch ( h ) {
1668                 case rebalance_required:
1669                 case unlink_required:
1670                     return pNode;
1671                 case nothing_required:
1672                     return nullptr;
1673                 default:
1674                     set_height( pNode, h, memory_model::memory_order_release );
1675                     return parent( pNode, memory_model::memory_order_relaxed );
1676             }
1677         }
1678
1679         void fix_height_and_rebalance( node_type * pNode, rcu_disposer& disp )
1680         {
1681             while ( pNode && parent( pNode, memory_model::memory_order_acquire )) {
1682                 int nCond = estimate_node_condition( pNode );
1683                 if ( nCond == nothing_required || pNode->is_unlinked( memory_model::memory_order_acquire ))
1684                     return;
1685
1686                 if ( nCond != unlink_required && nCond != rebalance_required )
1687                     pNode = fix_height( pNode );
1688                 else {
1689                     node_type * pParent = parent( pNode, memory_model::memory_order_acquire );
1690                     assert( pParent != nullptr );
1691                     {
1692                         node_scoped_lock lp( m_Monitor, *pParent );
1693                         if ( !pParent->is_unlinked( memory_model::memory_order_relaxed ) && parent( pNode, memory_model::memory_order_acquire ) == pParent ) {
1694                             node_scoped_lock ln( m_Monitor, *pNode );
1695                             pNode = rebalance_locked( pParent, pNode, disp );
1696                         }
1697                     }
1698                 }
1699             }
1700         }
1701
1702         node_type * rebalance_locked( node_type * pParent, node_type * pNode, rcu_disposer& disp )
1703         {
1704             // pParent and pNode should be locked.
1705             // Returns a damaged node, or nullptr if no more rebalancing is necessary
1706             assert( parent( pNode, memory_model::memory_order_relaxed ) == pParent );
1707
1708             node_type * pLeft = child( pNode, left_child, memory_model::memory_order_relaxed );
1709             node_type * pRight = child( pNode, right_child, memory_model::memory_order_relaxed );
1710
1711             if ( (pLeft == nullptr || pRight == nullptr) && !pNode->is_valued( memory_model::memory_order_relaxed )) {
1712                 if ( try_unlink_locked( pParent, pNode, disp ))
1713                     return fix_height_locked( pParent );
1714                 else {
1715                     // retry needed for pNode
1716                     return pNode;
1717                 }
1718             }
1719
1720             assert( child( pParent, left_child, memory_model::memory_order_relaxed ) == pNode
1721                  || child( pParent, right_child, memory_model::memory_order_relaxed ) == pNode );
1722
1723             int h = height( pNode, memory_model::memory_order_acquire );
1724             int hL = height_null( pLeft, memory_model::memory_order_acquire );
1725             int hR = height_null( pRight, memory_model::memory_order_acquire );
1726             int hNew = 1 + std::max( hL, hR );
1727             int balance = hL - hR;
1728
1729             if ( balance > 1 )
1730                 return rebalance_to_right_locked( pParent, pNode, pLeft, hR );
1731             else if ( balance < -1 )
1732                 return rebalance_to_left_locked( pParent, pNode, pRight, hL );
1733             else if ( hNew != h ) {
1734                 set_height( pNode, hNew, memory_model::memory_order_release );
1735
1736                 // pParent is already locked
1737                 return fix_height_locked( pParent );
1738             }
1739             else
1740                 return nullptr;
1741         }
1742
1743         node_type * rebalance_to_right_locked( node_type * pParent, node_type * pNode, node_type * pLeft, int hR )
1744         {
1745             assert( parent( pNode, memory_model::memory_order_relaxed ) == pParent );
1746             assert( child( pParent, left_child, memory_model::memory_order_relaxed ) == pNode
1747                  || child( pParent, right_child, memory_model::memory_order_relaxed ) == pNode );
1748
1749             // pParent and pNode is locked yet
1750             // pNode->pLeft is too large, we will rotate-right.
1751             // If pLeft->pRight is taller than pLeft->pLeft, then we will first rotate-left pLeft.
1752
1753             {
1754                 assert( pLeft != nullptr );
1755                 node_scoped_lock l( m_Monitor, *pLeft );
1756                 if ( pNode->m_pLeft.load( memory_model::memory_order_relaxed ) != pLeft )
1757                     return pNode; // retry for pNode
1758
1759                 int hL = height( pLeft, memory_model::memory_order_acquire );
1760                 if ( hL - hR <= 1 )
1761                     return pNode; // retry
1762
1763                 node_type * pLRight = child( pLeft, right_child, memory_model::memory_order_relaxed );
1764                 int hLR = height_null( pLRight, memory_model::memory_order_acquire );
1765                 node_type * pLLeft = child( pLeft, left_child, memory_model::memory_order_relaxed );
1766                 int hLL = height_null( pLLeft, memory_model::memory_order_acquire );
1767
1768                 if ( hLL > hLR ) {
1769                     // rotate right
1770                     return rotate_right_locked( pParent, pNode, pLeft, hR, hLL, pLRight, hLR );
1771                 }
1772                 else {
1773                     if ( pLRight ) {
1774                         node_scoped_lock lr( m_Monitor, *pLRight );
1775                         if ( pLeft->m_pRight.load( memory_model::memory_order_acquire ) != pLRight )
1776                             return pNode; // retry
1777
1778                         hLR = height( pLRight, memory_model::memory_order_acquire );
1779                         if ( hLL > hLR )
1780                             return rotate_right_locked( pParent, pNode, pLeft, hR, hLL, pLRight, hLR );
1781
1782                         int hLRL = height_null( child( pLRight, left_child, memory_model::memory_order_relaxed ), memory_model::memory_order_acquire);
1783                         int balance = hLL - hLRL;
1784                         if ( balance >= -1 && balance <= 1 && !((hLL == 0 || hLRL == 0) && !pLeft->is_valued(memory_model::memory_order_relaxed))) {
1785                             // nParent.child.left won't be damaged after a double rotation
1786                             return rotate_right_over_left_locked( pParent, pNode, pLeft, hR, hLL, pLRight, hLRL );
1787                         }
1788                     }
1789                     else
1790                         return pNode; // retry
1791
1792                     // focus on pLeft, if necessary pNode will be balanced later
1793                     return rebalance_to_left_locked( pNode, pLeft, pLRight, hLL );
1794                 }
1795             }
1796         }
1797
1798         node_type * rebalance_to_left_locked( node_type * pParent, node_type * pNode, node_type * pRight, int hL )
1799         {
1800             assert( parent( pNode, memory_model::memory_order_relaxed ) == pParent );
1801             assert( child( pParent, left_child, memory_model::memory_order_relaxed ) == pNode
1802                  || child( pParent, right_child, memory_model::memory_order_relaxed ) == pNode );
1803
1804             // pParent and pNode is locked yet
1805             {
1806                 assert( pRight != nullptr );
1807                 node_scoped_lock l( m_Monitor, *pRight );
1808                 if ( pNode->m_pRight.load( memory_model::memory_order_relaxed ) != pRight )
1809                     return pNode; // retry for pNode
1810
1811                 int hR = height( pRight, memory_model::memory_order_acquire );
1812                 if ( hL - hR >= -1 )
1813                     return pNode; // retry
1814
1815                 node_type * pRLeft = child( pRight, left_child, memory_model::memory_order_relaxed );
1816                 int hRL = height_null( pRLeft, memory_model::memory_order_acquire );
1817                 node_type * pRRight = child( pRight, right_child, memory_model::memory_order_relaxed );
1818                 int hRR = height_null( pRRight, memory_model::memory_order_acquire );
1819                 if ( hRR > hRL )
1820                     return rotate_left_locked( pParent, pNode, hL, pRight, pRLeft, hRL, hRR );
1821
1822                 if ( pRLeft ) {
1823                     node_scoped_lock lrl( m_Monitor, *pRLeft );
1824                     if ( pRight->m_pLeft.load( memory_model::memory_order_acquire ) != pRLeft )
1825                         return pNode; // retry
1826
1827                     hRL = height( pRLeft, memory_model::memory_order_acquire );
1828                     if ( hRR >= hRL )
1829                         return rotate_left_locked( pParent, pNode, hL, pRight, pRLeft, hRL, hRR );
1830
1831                     node_type * pRLRight = child( pRLeft, right_child, memory_model::memory_order_relaxed );
1832                     int hRLR = height_null( pRLRight, memory_model::memory_order_acquire );
1833                     int balance = hRR - hRLR;
1834                     if ( balance >= -1 && balance <= 1 && !((hRR == 0 || hRLR == 0) && !pRight->is_valued( memory_model::memory_order_relaxed )))
1835                          return rotate_left_over_right_locked( pParent, pNode, hL, pRight, pRLeft, hRR, hRLR );
1836                 }
1837                 else
1838                     return pNode; // retry
1839                 return rebalance_to_right_locked( pNode, pRight, pRLeft, hRR );
1840             }
1841         }
1842
1843         static void begin_change( node_type * pNode, version_type version )
1844         {
1845             assert(pNode->version(memory_model::memory_order_acquire) == version );
1846             assert( (version & node_type::shrinking) == 0 );
1847             pNode->version( version | node_type::shrinking, memory_model::memory_order_release );
1848         }
1849         static void end_change( node_type * pNode, version_type version )
1850         {
1851             // Clear shrinking and unlinked flags and increment version
1852             pNode->version( (version | node_type::version_flags) + 1, memory_model::memory_order_release );
1853         }
1854
1855         node_type * rotate_right_locked( node_type * pParent, node_type * pNode, node_type * pLeft, int hR, int hLL, node_type * pLRight, int hLR )
1856         {
1857             version_type nodeVersion = pNode->version( memory_model::memory_order_relaxed );
1858             node_type * pParentLeft = child( pParent, left_child, memory_model::memory_order_relaxed );
1859
1860             begin_change( pNode, nodeVersion );
1861
1862             pNode->m_pLeft.store( pLRight, memory_model::memory_order_release );
1863             if ( pLRight != nullptr )
1864                 pLRight->parent( pNode, memory_model::memory_order_release  );
1865
1866             pLeft->m_pRight.store( pNode, memory_model::memory_order_release );
1867             pNode->parent( pLeft, memory_model::memory_order_release );
1868
1869             if ( pParentLeft == pNode )
1870                 pParent->m_pLeft.store( pLeft, memory_model::memory_order_release );
1871             else {
1872                 assert( pParent->m_pRight.load( memory_model::memory_order_relaxed ) == pNode );
1873                 pParent->m_pRight.store( pLeft, memory_model::memory_order_release );
1874             }
1875             pLeft->parent( pParent, memory_model::memory_order_release );
1876
1877             // fix up heights links
1878             int hNode = 1 + std::max( hLR, hR );
1879             set_height( pNode, hNode, memory_model::memory_order_release );
1880             set_height( pLeft, 1 + std::max( hLL, hNode ), memory_model::memory_order_release);
1881
1882             end_change( pNode, nodeVersion );
1883             m_stat.onRotateRight();
1884
1885             // We have damaged pParent, pNode (now parent.child.right), and pLeft (now
1886             // parent.child).  pNode is the deepest.  Perform as many fixes as we can
1887             // with the locks we've got.
1888
1889             // We've already fixed the height for pNode, but it might still be outside
1890             // our allowable balance range.  In that case a simple fix_height_locked()
1891             // won't help.
1892             int nodeBalance = hLR - hR;
1893             if ( nodeBalance < -1 || nodeBalance > 1 ) {
1894                 // we need another rotation at pNode
1895                 m_stat.onRotateAfterRightRotation();
1896                 return pNode;
1897             }
1898
1899             // we've fixed balance and height damage for pNode, now handle
1900             // extra-routing node damage
1901             if ( (pLRight == nullptr || hR == 0) && !pNode->is_valued(memory_model::memory_order_relaxed)) {
1902                 // we need to remove pNode and then repair
1903                 m_stat.onRemoveAfterRightRotation();
1904                 return pNode;
1905             }
1906
1907             // we've already fixed the height at pLeft, do we need a rotation here?
1908             int leftBalance = hLL - hNode;
1909             if ( leftBalance < -1 || leftBalance > 1 ) {
1910                 m_stat.onRotateAfterRightRotation();
1911                 return pLeft;
1912             }
1913
1914             // pLeft might also have routing node damage (if pLeft.left was null)
1915             if ( hLL == 0 && !pLeft->is_valued(memory_model::memory_order_acquire)) {
1916                 m_stat.onDamageAfterRightRotation();
1917                 return pLeft;
1918             }
1919
1920             // try to fix the parent height while we've still got the lock
1921             return fix_height_locked( pParent );
1922         }
1923
1924         node_type * rotate_left_locked( node_type * pParent, node_type * pNode, int hL, node_type * pRight, node_type * pRLeft, int hRL, int hRR )
1925         {
1926             version_type nodeVersion = pNode->version( memory_model::memory_order_relaxed );
1927             node_type * pParentLeft = child( pParent, left_child, memory_model::memory_order_relaxed );
1928
1929             begin_change( pNode, nodeVersion );
1930
1931             // fix up pNode links, careful to be compatible with concurrent traversal for all but pNode
1932             pNode->m_pRight.store( pRLeft, memory_model::memory_order_release );
1933             if ( pRLeft != nullptr )
1934                 pRLeft->parent( pNode, memory_model::memory_order_release );
1935
1936             pRight->m_pLeft.store( pNode, memory_model::memory_order_release );
1937             pNode->parent( pRight, memory_model::memory_order_release );
1938
1939             if ( pParentLeft == pNode )
1940                 pParent->m_pLeft.store( pRight, memory_model::memory_order_release );
1941             else {
1942                 assert( pParent->m_pRight.load( memory_model::memory_order_relaxed ) == pNode );
1943                 pParent->m_pRight.store( pRight, memory_model::memory_order_release );
1944             }
1945             pRight->parent( pParent, memory_model::memory_order_release );
1946
1947             // fix up heights
1948             int hNode = 1 + std::max( hL, hRL );
1949             set_height( pNode, hNode, memory_model::memory_order_release );
1950             set_height( pRight, 1 + std::max( hNode, hRR ), memory_model::memory_order_release);
1951
1952             end_change( pNode, nodeVersion );
1953             m_stat.onRotateLeft();
1954
1955             int nodeBalance = hRL - hL;
1956             if ( nodeBalance < -1 || nodeBalance > 1 ) {
1957                 m_stat.onRotateAfterLeftRotation();
1958                 return pNode;
1959             }
1960
1961             if ( (pRLeft == nullptr || hL == 0) && !pNode->is_valued(memory_model::memory_order_relaxed)) {
1962                 m_stat.onRemoveAfterLeftRotation();
1963                 return pNode;
1964             }
1965
1966             int rightBalance = hRR - hNode;
1967             if ( rightBalance < -1 || rightBalance > 1 ) {
1968                 m_stat.onRotateAfterLeftRotation();
1969                 return pRight;
1970             }
1971
1972             if ( hRR == 0 && !pRight->is_valued(memory_model::memory_order_acquire)) {
1973                 m_stat.onDamageAfterLeftRotation();
1974                 return pRight;
1975             }
1976
1977             return fix_height_locked( pParent );
1978         }
1979
1980         node_type * rotate_right_over_left_locked( node_type * pParent, node_type * pNode, node_type * pLeft, int hR, int hLL, node_type * pLRight, int hLRL )
1981         {
1982             version_type nodeVersion = pNode->version( memory_model::memory_order_relaxed );
1983             version_type leftVersion = pLeft->version( memory_model::memory_order_acquire );
1984
1985             node_type * pPL = child( pParent, left_child, memory_model::memory_order_relaxed );
1986             node_type * pLRL = child( pLRight, left_child, memory_model::memory_order_acquire );
1987             node_type * pLRR = child( pLRight, right_child, memory_model::memory_order_acquire );
1988             int hLRR = height_null( pLRR, memory_model::memory_order_acquire );
1989
1990             begin_change( pNode, nodeVersion );
1991             begin_change( pLeft, leftVersion );
1992
1993             // fix up pNode links, careful about the order!
1994             pNode->m_pLeft.store( pLRR, memory_model::memory_order_release );
1995             if ( pLRR != nullptr )
1996                 pLRR->parent( pNode, memory_model::memory_order_release );
1997
1998             pLeft->m_pRight.store( pLRL, memory_model::memory_order_release );
1999             if ( pLRL != nullptr )
2000                 pLRL->parent( pLeft, memory_model::memory_order_release );
2001
2002             pLRight->m_pLeft.store( pLeft, memory_model::memory_order_release );
2003             pLeft->parent( pLRight, memory_model::memory_order_release );
2004
2005             pLRight->m_pRight.store( pNode, memory_model::memory_order_release );
2006             pNode->parent( pLRight, memory_model::memory_order_release );
2007
2008             if ( pPL == pNode )
2009                 pParent->m_pLeft.store( pLRight, memory_model::memory_order_release );
2010             else {
2011                 assert( child( pParent, right_child, memory_model::memory_order_relaxed ) == pNode );
2012                 pParent->m_pRight.store( pLRight, memory_model::memory_order_release );
2013             }
2014             pLRight->parent( pParent, memory_model::memory_order_release );
2015
2016             // fix up heights
2017             int hNode = 1 + std::max( hLRR, hR );
2018             set_height( pNode, hNode, memory_model::memory_order_release );
2019             int hLeft = 1 + std::max( hLL, hLRL );
2020             set_height( pLeft, hLeft, memory_model::memory_order_release );
2021             set_height( pLRight, 1 + std::max( hLeft, hNode ), memory_model::memory_order_release);
2022
2023             end_change( pNode, nodeVersion );
2024             end_change( pLeft, leftVersion );
2025             m_stat.onRotateRightOverLeft();
2026
2027             // caller should have performed only a single rotation if pLeft was going
2028             // to end up damaged
2029             assert( hLL - hLRL <= 1 && hLRL - hLL <= 1 );
2030             assert( !((hLL == 0 || pLRL == nullptr) && !pLeft->is_valued( memory_model::memory_order_acquire )));
2031
2032             // We have damaged pParent, pLR (now parent.child), and pNode (now
2033             // parent.child.right).  pNode is the deepest.  Perform as many fixes as we
2034             // can with the locks we've got.
2035
2036             // We've already fixed the height for pNode, but it might still be outside
2037             // our allowable balance range.  In that case a simple fix_height_locked()
2038             // won't help.
2039             int nodeBalance = hLRR - hR;
2040             if ( nodeBalance < -1 || nodeBalance > 1 ) {
2041                 // we need another rotation at pNode
2042                 m_stat.onRotateAfterRLRotation();
2043                 return pNode;
2044             }
2045
2046             // pNode might also be damaged by being an unnecessary routing node
2047             if ( (pLRR == nullptr || hR == 0) && !pNode->is_valued( memory_model::memory_order_relaxed )) {
2048                 // repair involves splicing out pNode and maybe more rotations
2049                 m_stat.onRemoveAfterRLRotation();
2050                 return pNode;
2051             }
2052
2053             // we've already fixed the height at pLRight, do we need a rotation here?
2054             int balanceLR = hLeft - hNode;
2055             if ( balanceLR < -1 || balanceLR > 1 ) {
2056                 m_stat.onRotateAfterRLRotation();
2057                 return pLRight;
2058             }
2059
2060             // try to fix the parent height while we've still got the lock
2061             return fix_height_locked( pParent );
2062         }
2063
2064         node_type * rotate_left_over_right_locked( node_type * pParent, node_type * pNode, int hL, node_type * pRight, node_type * pRLeft, int hRR, int hRLR )
2065         {
2066             version_type nodeVersion = pNode->version( memory_model::memory_order_relaxed );
2067             version_type rightVersion = pRight->version( memory_model::memory_order_acquire );
2068
2069             node_type * pPL = child( pParent, left_child, memory_model::memory_order_relaxed );
2070             node_type * pRLL = child( pRLeft, left_child, memory_model::memory_order_acquire );
2071             node_type * pRLR = child( pRLeft, right_child, memory_model::memory_order_acquire );
2072             int hRLL = height_null( pRLL, memory_model::memory_order_acquire );
2073
2074             begin_change( pNode, nodeVersion );
2075             begin_change( pRight, rightVersion );
2076
2077             // fix up pNode links, careful about the order!
2078             pNode->m_pRight.store( pRLL, memory_model::memory_order_release );
2079             if ( pRLL != nullptr )
2080                 pRLL->parent( pNode, memory_model::memory_order_release );
2081
2082             pRight->m_pLeft.store( pRLR, memory_model::memory_order_release );
2083             if ( pRLR != nullptr )
2084                 pRLR->parent( pRight, memory_model::memory_order_release );
2085
2086             pRLeft->m_pRight.store( pRight, memory_model::memory_order_release );
2087             pRight->parent( pRLeft, memory_model::memory_order_release );
2088
2089             pRLeft->m_pLeft.store( pNode, memory_model::memory_order_release );
2090             pNode->parent( pRLeft, memory_model::memory_order_release );
2091
2092             if ( pPL == pNode )
2093                 pParent->m_pLeft.store( pRLeft, memory_model::memory_order_release );
2094             else {
2095                 assert( pParent->m_pRight.load( memory_model::memory_order_relaxed ) == pNode );
2096                 pParent->m_pRight.store( pRLeft, memory_model::memory_order_release );
2097             }
2098             pRLeft->parent( pParent, memory_model::memory_order_release );
2099
2100             // fix up heights
2101             int hNode = 1 + std::max( hL, hRLL );
2102             set_height( pNode, hNode, memory_model::memory_order_release );
2103             int hRight = 1 + std::max( hRLR, hRR );
2104             set_height( pRight, hRight, memory_model::memory_order_release );
2105             set_height( pRLeft, 1 + std::max( hNode, hRight ), memory_model::memory_order_release);
2106
2107             end_change( pNode, nodeVersion );
2108             end_change( pRight, rightVersion );
2109             m_stat.onRotateLeftOverRight();
2110
2111             assert( hRR - hRLR <= 1 && hRLR - hRR <= 1 );
2112
2113             int nodeBalance = hRLL - hL;
2114             if ( nodeBalance < -1 || nodeBalance > 1 ) {
2115                 m_stat.onRotateAfterLRRotation();
2116                 return pNode;
2117             }
2118
2119             if ( (pRLL == nullptr || hL == 0) && !pNode->is_valued(memory_model::memory_order_relaxed)) {
2120                 m_stat.onRemoveAfterLRRotation();
2121                 return pNode;
2122             }
2123
2124             int balRL = hRight - hNode;
2125             if ( balRL < -1 || balRL > 1 ) {
2126                 m_stat.onRotateAfterLRRotation();
2127                 return pRLeft;
2128             }
2129
2130             return fix_height_locked( pParent );
2131         }
2132
2133         //@endcond
2134     };
2135 }} // namespace cds::container
2136
2137 #endif // #ifndef CDSLIB_CONTAINER_IMPL_BRONSON_AVLTREE_MAP_RCU_H