avltree_algorithms.hpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Daniel K. O. 2005.
  4. // (C) Copyright Ion Gaztanaga 2007-2014
  5. //
  6. // Distributed under the Boost Software License, Version 1.0.
  7. // (See accompanying file LICENSE_1_0.txt or copy at
  8. // http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. // See http://www.boost.org/libs/intrusive for documentation.
  11. //
  12. /////////////////////////////////////////////////////////////////////////////
  13. #ifndef BOOST_INTRUSIVE_AVLTREE_ALGORITHMS_HPP
  14. #define BOOST_INTRUSIVE_AVLTREE_ALGORITHMS_HPP
  15. #include <boost/intrusive/detail/config_begin.hpp>
  16. #include <boost/intrusive/intrusive_fwd.hpp>
  17. #include <cstddef>
  18. #include <boost/intrusive/detail/assert.hpp>
  19. #include <boost/intrusive/detail/algo_type.hpp>
  20. #include <boost/intrusive/detail/ebo_functor_holder.hpp>
  21. #include <boost/intrusive/bstree_algorithms.hpp>
  22. #if defined(BOOST_HAS_PRAGMA_ONCE)
  23. # pragma once
  24. #endif
  25. namespace boost {
  26. namespace intrusive {
  27. /// @cond
  28. template<class NodeTraits, class F>
  29. struct avltree_node_cloner
  30. //Use public inheritance to avoid MSVC bugs with closures
  31. : public detail::ebo_functor_holder<F>
  32. {
  33. typedef typename NodeTraits::node_ptr node_ptr;
  34. typedef detail::ebo_functor_holder<F> base_t;
  35. BOOST_INTRUSIVE_FORCEINLINE avltree_node_cloner(F f)
  36. : base_t(f)
  37. {}
  38. BOOST_INTRUSIVE_FORCEINLINE node_ptr operator()(const node_ptr & p)
  39. {
  40. node_ptr n = base_t::get()(p);
  41. NodeTraits::set_balance(n, NodeTraits::get_balance(p));
  42. return n;
  43. }
  44. BOOST_INTRUSIVE_FORCEINLINE node_ptr operator()(const node_ptr & p) const
  45. {
  46. node_ptr n = base_t::get()(p);
  47. NodeTraits::set_balance(n, NodeTraits::get_balance(p));
  48. return n;
  49. }
  50. };
  51. namespace detail {
  52. template<class ValueTraits, class NodePtrCompare, class ExtraChecker>
  53. struct avltree_node_checker
  54. : public bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker>
  55. {
  56. typedef bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> base_checker_t;
  57. typedef ValueTraits value_traits;
  58. typedef typename value_traits::node_traits node_traits;
  59. typedef typename node_traits::const_node_ptr const_node_ptr;
  60. struct return_type
  61. : public base_checker_t::return_type
  62. {
  63. return_type() : height(0) {}
  64. int height;
  65. };
  66. avltree_node_checker(const NodePtrCompare& comp, ExtraChecker extra_checker)
  67. : base_checker_t(comp, extra_checker)
  68. {}
  69. void operator () (const const_node_ptr& p,
  70. const return_type& check_return_left, const return_type& check_return_right,
  71. return_type& check_return)
  72. {
  73. const int height_diff = check_return_right.height - check_return_left.height; (void)height_diff;
  74. BOOST_INTRUSIVE_INVARIANT_ASSERT(
  75. (height_diff == -1 && node_traits::get_balance(p) == node_traits::negative()) ||
  76. (height_diff == 0 && node_traits::get_balance(p) == node_traits::zero()) ||
  77. (height_diff == 1 && node_traits::get_balance(p) == node_traits::positive())
  78. );
  79. check_return.height = 1 +
  80. (check_return_left.height > check_return_right.height ? check_return_left.height : check_return_right.height);
  81. base_checker_t::operator()(p, check_return_left, check_return_right, check_return);
  82. }
  83. };
  84. } // namespace detail
  85. /// @endcond
  86. //! avltree_algorithms is configured with a NodeTraits class, which encapsulates the
  87. //! information about the node to be manipulated. NodeTraits must support the
  88. //! following interface:
  89. //!
  90. //! <b>Typedefs</b>:
  91. //!
  92. //! <tt>node</tt>: The type of the node that forms the binary search tree
  93. //!
  94. //! <tt>node_ptr</tt>: A pointer to a node
  95. //!
  96. //! <tt>const_node_ptr</tt>: A pointer to a const node
  97. //!
  98. //! <tt>balance</tt>: The type of the balance factor
  99. //!
  100. //! <b>Static functions</b>:
  101. //!
  102. //! <tt>static node_ptr get_parent(const_node_ptr n);</tt>
  103. //!
  104. //! <tt>static void set_parent(node_ptr n, node_ptr parent);</tt>
  105. //!
  106. //! <tt>static node_ptr get_left(const_node_ptr n);</tt>
  107. //!
  108. //! <tt>static void set_left(node_ptr n, node_ptr left);</tt>
  109. //!
  110. //! <tt>static node_ptr get_right(const_node_ptr n);</tt>
  111. //!
  112. //! <tt>static void set_right(node_ptr n, node_ptr right);</tt>
  113. //!
  114. //! <tt>static balance get_balance(const_node_ptr n);</tt>
  115. //!
  116. //! <tt>static void set_balance(node_ptr n, balance b);</tt>
  117. //!
  118. //! <tt>static balance negative();</tt>
  119. //!
  120. //! <tt>static balance zero();</tt>
  121. //!
  122. //! <tt>static balance positive();</tt>
  123. template<class NodeTraits>
  124. class avltree_algorithms
  125. #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  126. : public bstree_algorithms<NodeTraits>
  127. #endif
  128. {
  129. public:
  130. typedef typename NodeTraits::node node;
  131. typedef NodeTraits node_traits;
  132. typedef typename NodeTraits::node_ptr node_ptr;
  133. typedef typename NodeTraits::const_node_ptr const_node_ptr;
  134. typedef typename NodeTraits::balance balance;
  135. /// @cond
  136. private:
  137. typedef bstree_algorithms<NodeTraits> bstree_algo;
  138. /// @endcond
  139. public:
  140. //! This type is the information that will be
  141. //! filled by insert_unique_check
  142. typedef typename bstree_algo::insert_commit_data insert_commit_data;
  143. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  144. //! @copydoc ::boost::intrusive::bstree_algorithms::get_header(const const_node_ptr&)
  145. static node_ptr get_header(const const_node_ptr & n);
  146. //! @copydoc ::boost::intrusive::bstree_algorithms::begin_node
  147. static node_ptr begin_node(const const_node_ptr & header);
  148. //! @copydoc ::boost::intrusive::bstree_algorithms::end_node
  149. static node_ptr end_node(const const_node_ptr & header);
  150. //! @copydoc ::boost::intrusive::bstree_algorithms::swap_tree
  151. static void swap_tree(node_ptr header1, node_ptr header2);
  152. #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  153. //! @copydoc ::boost::intrusive::bstree_algorithms::swap_nodes(node_ptr,node_ptr)
  154. static void swap_nodes(node_ptr node1, node_ptr node2)
  155. {
  156. if(node1 == node2)
  157. return;
  158. node_ptr header1(bstree_algo::get_header(node1)), header2(bstree_algo::get_header(node2));
  159. swap_nodes(node1, header1, node2, header2);
  160. }
  161. //! @copydoc ::boost::intrusive::bstree_algorithms::swap_nodes(node_ptr,node_ptr,node_ptr,node_ptr)
  162. static void swap_nodes(node_ptr node1, node_ptr header1, node_ptr node2, node_ptr header2)
  163. {
  164. if(node1 == node2) return;
  165. bstree_algo::swap_nodes(node1, header1, node2, header2);
  166. //Swap balance
  167. balance c = NodeTraits::get_balance(node1);
  168. NodeTraits::set_balance(node1, NodeTraits::get_balance(node2));
  169. NodeTraits::set_balance(node2, c);
  170. }
  171. //! @copydoc ::boost::intrusive::bstree_algorithms::replace_node(node_ptr,node_ptr)
  172. static void replace_node(node_ptr node_to_be_replaced, node_ptr new_node)
  173. {
  174. if(node_to_be_replaced == new_node)
  175. return;
  176. replace_node(node_to_be_replaced, bstree_algo::get_header(node_to_be_replaced), new_node);
  177. }
  178. //! @copydoc ::boost::intrusive::bstree_algorithms::replace_node(node_ptr,node_ptr,node_ptr)
  179. static void replace_node(node_ptr node_to_be_replaced, node_ptr header, node_ptr new_node)
  180. {
  181. bstree_algo::replace_node(node_to_be_replaced, header, new_node);
  182. NodeTraits::set_balance(new_node, NodeTraits::get_balance(node_to_be_replaced));
  183. }
  184. //! @copydoc ::boost::intrusive::bstree_algorithms::unlink(node_ptr)
  185. static void unlink(node_ptr node)
  186. {
  187. node_ptr x = NodeTraits::get_parent(node);
  188. if(x){
  189. while(!is_header(x))
  190. x = NodeTraits::get_parent(x);
  191. erase(x, node);
  192. }
  193. }
  194. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  195. //! @copydoc ::boost::intrusive::bstree_algorithms::unlink_leftmost_without_rebalance
  196. static node_ptr unlink_leftmost_without_rebalance(const node_ptr & header);
  197. //! @copydoc ::boost::intrusive::bstree_algorithms::unique(const const_node_ptr&)
  198. static bool unique(const const_node_ptr & node);
  199. //! @copydoc ::boost::intrusive::bstree_algorithms::size(const const_node_ptr&)
  200. static std::size_t size(const const_node_ptr & header);
  201. //! @copydoc ::boost::intrusive::bstree_algorithms::next_node(const node_ptr&)
  202. static node_ptr next_node(const node_ptr & node);
  203. //! @copydoc ::boost::intrusive::bstree_algorithms::prev_node(const node_ptr&)
  204. static node_ptr prev_node(const node_ptr & node);
  205. //! @copydoc ::boost::intrusive::bstree_algorithms::init(node_ptr)
  206. static void init(const node_ptr & node);
  207. #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  208. //! <b>Requires</b>: node must not be part of any tree.
  209. //!
  210. //! <b>Effects</b>: Initializes the header to represent an empty tree.
  211. //! unique(header) == true.
  212. //!
  213. //! <b>Complexity</b>: Constant.
  214. //!
  215. //! <b>Throws</b>: Nothing.
  216. //!
  217. //! <b>Nodes</b>: If node is inserted in a tree, this function corrupts the tree.
  218. static void init_header(node_ptr header)
  219. {
  220. bstree_algo::init_header(header);
  221. NodeTraits::set_balance(header, NodeTraits::zero());
  222. }
  223. //! @copydoc ::boost::intrusive::bstree_algorithms::erase(node_ptr,node_ptr)
  224. static node_ptr erase(node_ptr header, node_ptr z)
  225. {
  226. typename bstree_algo::data_for_rebalance info;
  227. bstree_algo::erase(header, z, info);
  228. rebalance_after_erasure(header, z, info);
  229. return z;
  230. }
  231. //! @copydoc ::boost::intrusive::bstree_algorithms::transfer_unique
  232. template<class NodePtrCompare>
  233. static bool transfer_unique
  234. (node_ptr header1, NodePtrCompare comp, node_ptr header2, node_ptr z)
  235. {
  236. typename bstree_algo::data_for_rebalance info;
  237. bool const transferred = bstree_algo::transfer_unique(header1, comp, header2, z, info);
  238. if(transferred){
  239. rebalance_after_erasure(header2, z, info);
  240. rebalance_after_insertion(header1, z);
  241. }
  242. return transferred;
  243. }
  244. //! @copydoc ::boost::intrusive::bstree_algorithms::transfer_equal
  245. template<class NodePtrCompare>
  246. static void transfer_equal
  247. (node_ptr header1, NodePtrCompare comp, node_ptr header2, node_ptr z)
  248. {
  249. typename bstree_algo::data_for_rebalance info;
  250. bstree_algo::transfer_equal(header1, comp, header2, z, info);
  251. rebalance_after_erasure(header2, z, info);
  252. rebalance_after_insertion(header1, z);
  253. }
  254. //! @copydoc ::boost::intrusive::bstree_algorithms::clone(const const_node_ptr&,node_ptr,Cloner,Disposer)
  255. template <class Cloner, class Disposer>
  256. static void clone
  257. (const const_node_ptr & source_header, node_ptr target_header, Cloner cloner, Disposer disposer)
  258. {
  259. avltree_node_cloner<NodeTraits, Cloner> new_cloner(cloner);
  260. bstree_algo::clone(source_header, target_header, new_cloner, disposer);
  261. }
  262. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  263. //! @copydoc ::boost::intrusive::bstree_algorithms::clear_and_dispose(const node_ptr&,Disposer)
  264. template<class Disposer>
  265. static void clear_and_dispose(const node_ptr & header, Disposer disposer);
  266. //! @copydoc ::boost::intrusive::bstree_algorithms::lower_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  267. template<class KeyType, class KeyNodePtrCompare>
  268. static node_ptr lower_bound
  269. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
  270. //! @copydoc ::boost::intrusive::bstree_algorithms::upper_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  271. template<class KeyType, class KeyNodePtrCompare>
  272. static node_ptr upper_bound
  273. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
  274. //! @copydoc ::boost::intrusive::bstree_algorithms::find(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  275. template<class KeyType, class KeyNodePtrCompare>
  276. static node_ptr find
  277. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
  278. //! @copydoc ::boost::intrusive::bstree_algorithms::equal_range(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  279. template<class KeyType, class KeyNodePtrCompare>
  280. static std::pair<node_ptr, node_ptr> equal_range
  281. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
  282. //! @copydoc ::boost::intrusive::bstree_algorithms::bounded_range(const const_node_ptr&,const KeyType&,const KeyType&,KeyNodePtrCompare,bool,bool)
  283. template<class KeyType, class KeyNodePtrCompare>
  284. static std::pair<node_ptr, node_ptr> bounded_range
  285. (const const_node_ptr & header, const KeyType &lower_key, const KeyType &upper_key, KeyNodePtrCompare comp
  286. , bool left_closed, bool right_closed);
  287. //! @copydoc ::boost::intrusive::bstree_algorithms::count(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  288. template<class KeyType, class KeyNodePtrCompare>
  289. static std::size_t count(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
  290. #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  291. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_equal_upper_bound(node_ptr,node_ptr,NodePtrCompare)
  292. template<class NodePtrCompare>
  293. static node_ptr insert_equal_upper_bound
  294. (node_ptr h, node_ptr new_node, NodePtrCompare comp)
  295. {
  296. bstree_algo::insert_equal_upper_bound(h, new_node, comp);
  297. rebalance_after_insertion(h, new_node);
  298. return new_node;
  299. }
  300. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_equal_lower_bound(node_ptr,node_ptr,NodePtrCompare)
  301. template<class NodePtrCompare>
  302. static node_ptr insert_equal_lower_bound
  303. (node_ptr h, node_ptr new_node, NodePtrCompare comp)
  304. {
  305. bstree_algo::insert_equal_lower_bound(h, new_node, comp);
  306. rebalance_after_insertion(h, new_node);
  307. return new_node;
  308. }
  309. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_equal(node_ptr,node_ptr,node_ptr,NodePtrCompare)
  310. template<class NodePtrCompare>
  311. static node_ptr insert_equal
  312. (node_ptr header, node_ptr hint, node_ptr new_node, NodePtrCompare comp)
  313. {
  314. bstree_algo::insert_equal(header, hint, new_node, comp);
  315. rebalance_after_insertion(header, new_node);
  316. return new_node;
  317. }
  318. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_before(node_ptr,node_ptr,node_ptr)
  319. static node_ptr insert_before
  320. (node_ptr header, node_ptr pos, node_ptr new_node)
  321. {
  322. bstree_algo::insert_before(header, pos, new_node);
  323. rebalance_after_insertion(header, new_node);
  324. return new_node;
  325. }
  326. //! @copydoc ::boost::intrusive::bstree_algorithms::push_back(node_ptr,node_ptr)
  327. static void push_back(node_ptr header, node_ptr new_node)
  328. {
  329. bstree_algo::push_back(header, new_node);
  330. rebalance_after_insertion(header, new_node);
  331. }
  332. //! @copydoc ::boost::intrusive::bstree_algorithms::push_front(node_ptr,node_ptr)
  333. static void push_front(node_ptr header, node_ptr new_node)
  334. {
  335. bstree_algo::push_front(header, new_node);
  336. rebalance_after_insertion(header, new_node);
  337. }
  338. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  339. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_unique_check(const const_node_ptr&,const KeyType&,KeyNodePtrCompare,insert_commit_data&)
  340. template<class KeyType, class KeyNodePtrCompare>
  341. static std::pair<node_ptr, bool> insert_unique_check
  342. (const const_node_ptr & header, const KeyType &key
  343. ,KeyNodePtrCompare comp, insert_commit_data &commit_data);
  344. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_unique_check(const const_node_ptr&,const node_ptr&,const KeyType&,KeyNodePtrCompare,insert_commit_data&)
  345. template<class KeyType, class KeyNodePtrCompare>
  346. static std::pair<node_ptr, bool> insert_unique_check
  347. (const const_node_ptr & header, const node_ptr &hint, const KeyType &key
  348. ,KeyNodePtrCompare comp, insert_commit_data &commit_data);
  349. #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  350. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_unique_commit(node_ptr,node_ptr,const insert_commit_data &)
  351. static void insert_unique_commit
  352. (node_ptr header, node_ptr new_value, const insert_commit_data &commit_data)
  353. {
  354. bstree_algo::insert_unique_commit(header, new_value, commit_data);
  355. rebalance_after_insertion(header, new_value);
  356. }
  357. //! @copydoc ::boost::intrusive::bstree_algorithms::is_header
  358. static bool is_header(const const_node_ptr & p)
  359. { return NodeTraits::get_balance(p) == NodeTraits::zero() && bstree_algo::is_header(p); }
  360. /// @cond
  361. static bool verify(const node_ptr &header)
  362. {
  363. std::size_t height;
  364. std::size_t count;
  365. return verify_recursion(NodeTraits::get_parent(header), count, height);
  366. }
  367. private:
  368. static bool verify_recursion(node_ptr n, std::size_t &count, std::size_t &height)
  369. {
  370. if (!n){
  371. count = 0;
  372. height = 0;
  373. return true;
  374. }
  375. std::size_t leftcount, rightcount;
  376. std::size_t leftheight, rightheight;
  377. if(!verify_recursion(NodeTraits::get_left (n), leftcount, leftheight) ||
  378. !verify_recursion(NodeTraits::get_right(n), rightcount, rightheight) ){
  379. return false;
  380. }
  381. count = 1u + leftcount + rightcount;
  382. height = 1u + (leftheight > rightheight ? leftheight : rightheight);
  383. //If equal height, balance must be zero
  384. if(rightheight == leftheight){
  385. if(NodeTraits::get_balance(n) != NodeTraits::zero()){
  386. BOOST_ASSERT(0);
  387. return false;
  388. }
  389. }
  390. //If right is taller than left, then the difference must be at least 1 and the balance positive
  391. else if(rightheight > leftheight){
  392. if(rightheight - leftheight > 1 ){
  393. BOOST_ASSERT(0);
  394. return false;
  395. }
  396. else if(NodeTraits::get_balance(n) != NodeTraits::positive()){
  397. BOOST_ASSERT(0);
  398. return false;
  399. }
  400. }
  401. //If left is taller than right, then the difference must be at least 1 and the balance negative
  402. else{
  403. if(leftheight - rightheight > 1 ){
  404. BOOST_ASSERT(0);
  405. return false;
  406. }
  407. else if(NodeTraits::get_balance(n) != NodeTraits::negative()){
  408. BOOST_ASSERT(0);
  409. return false;
  410. }
  411. }
  412. return true;
  413. }
  414. static void rebalance_after_erasure
  415. ( node_ptr header, node_ptr z, const typename bstree_algo::data_for_rebalance &info)
  416. {
  417. if(info.y != z){
  418. NodeTraits::set_balance(info.y, NodeTraits::get_balance(z));
  419. }
  420. //Rebalance avltree
  421. rebalance_after_erasure_restore_invariants(header, info.x, info.x_parent);
  422. }
  423. static void rebalance_after_erasure_restore_invariants(node_ptr header, node_ptr x, node_ptr x_parent)
  424. {
  425. for ( node_ptr root = NodeTraits::get_parent(header)
  426. ; x != root
  427. ; root = NodeTraits::get_parent(header), x_parent = NodeTraits::get_parent(x)) {
  428. const balance x_parent_balance = NodeTraits::get_balance(x_parent);
  429. //Don't cache x_is_leftchild or similar because x can be null and
  430. //equal to both x_parent_left and x_parent_right
  431. const node_ptr x_parent_left (NodeTraits::get_left(x_parent));
  432. const node_ptr x_parent_right(NodeTraits::get_right(x_parent));
  433. if(x_parent_balance == NodeTraits::zero()){
  434. NodeTraits::set_balance( x_parent, x == x_parent_right ? NodeTraits::negative() : NodeTraits::positive() );
  435. break; // the height didn't change, let's stop here
  436. }
  437. else if(x_parent_balance == NodeTraits::negative()){
  438. if (x == x_parent_left) { ////x is left child or x and sibling are null
  439. NodeTraits::set_balance(x_parent, NodeTraits::zero()); // balanced
  440. x = x_parent;
  441. }
  442. else {
  443. // x is right child (x_parent_left is the left child)
  444. BOOST_INTRUSIVE_INVARIANT_ASSERT(x_parent_left);
  445. if (NodeTraits::get_balance(x_parent_left) == NodeTraits::positive()) {
  446. // x_parent_left MUST have a right child
  447. BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_right(x_parent_left));
  448. x = avl_rotate_left_right(x_parent, x_parent_left, header);
  449. }
  450. else {
  451. avl_rotate_right(x_parent, x_parent_left, header);
  452. x = x_parent_left;
  453. }
  454. // if changed from negative to NodeTraits::positive(), no need to check above
  455. if (NodeTraits::get_balance(x) == NodeTraits::positive()){
  456. break;
  457. }
  458. }
  459. }
  460. else if(x_parent_balance == NodeTraits::positive()){
  461. if (x == x_parent_right) { //x is right child or x and sibling are null
  462. NodeTraits::set_balance(x_parent, NodeTraits::zero()); // balanced
  463. x = x_parent;
  464. }
  465. else {
  466. // x is left child (x_parent_right is the right child)
  467. BOOST_INTRUSIVE_INVARIANT_ASSERT(x_parent_right);
  468. if (NodeTraits::get_balance(x_parent_right) == NodeTraits::negative()) {
  469. // x_parent_right MUST have then a left child
  470. BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(x_parent_right));
  471. x = avl_rotate_right_left(x_parent, x_parent_right, header);
  472. }
  473. else {
  474. avl_rotate_left(x_parent, x_parent_right, header);
  475. x = x_parent_right;
  476. }
  477. // if changed from NodeTraits::positive() to negative, no need to check above
  478. if (NodeTraits::get_balance(x) == NodeTraits::negative()){
  479. break;
  480. }
  481. }
  482. }
  483. else{
  484. BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached
  485. }
  486. }
  487. }
  488. static void rebalance_after_insertion(node_ptr header, node_ptr x)
  489. {
  490. NodeTraits::set_balance(x, NodeTraits::zero());
  491. // Rebalance.
  492. for(node_ptr root = NodeTraits::get_parent(header); x != root; root = NodeTraits::get_parent(header)){
  493. node_ptr const x_parent(NodeTraits::get_parent(x));
  494. node_ptr const x_parent_left(NodeTraits::get_left(x_parent));
  495. const balance x_parent_balance = NodeTraits::get_balance(x_parent);
  496. const bool x_is_leftchild(x == x_parent_left);
  497. if(x_parent_balance == NodeTraits::zero()){
  498. // if x is left, parent will have parent->bal_factor = negative
  499. // else, parent->bal_factor = NodeTraits::positive()
  500. NodeTraits::set_balance( x_parent, x_is_leftchild ? NodeTraits::negative() : NodeTraits::positive() );
  501. x = x_parent;
  502. }
  503. else if(x_parent_balance == NodeTraits::positive()){
  504. // if x is a left child, parent->bal_factor = zero
  505. if (x_is_leftchild)
  506. NodeTraits::set_balance(x_parent, NodeTraits::zero());
  507. else{ // x is a right child, needs rebalancing
  508. if (NodeTraits::get_balance(x) == NodeTraits::negative())
  509. avl_rotate_right_left(x_parent, x, header);
  510. else
  511. avl_rotate_left(x_parent, x, header);
  512. }
  513. break;
  514. }
  515. else if(x_parent_balance == NodeTraits::negative()){
  516. // if x is a left child, needs rebalancing
  517. if (x_is_leftchild) {
  518. if (NodeTraits::get_balance(x) == NodeTraits::positive())
  519. avl_rotate_left_right(x_parent, x, header);
  520. else
  521. avl_rotate_right(x_parent, x, header);
  522. }
  523. else
  524. NodeTraits::set_balance(x_parent, NodeTraits::zero());
  525. break;
  526. }
  527. else{
  528. BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached
  529. }
  530. }
  531. }
  532. static void left_right_balancing(node_ptr a, node_ptr b, node_ptr c)
  533. {
  534. // balancing...
  535. const balance c_balance = NodeTraits::get_balance(c);
  536. const balance zero_balance = NodeTraits::zero();
  537. const balance posi_balance = NodeTraits::positive();
  538. const balance nega_balance = NodeTraits::negative();
  539. NodeTraits::set_balance(c, zero_balance);
  540. if(c_balance == nega_balance){
  541. NodeTraits::set_balance(a, posi_balance);
  542. NodeTraits::set_balance(b, zero_balance);
  543. }
  544. else if(c_balance == zero_balance){
  545. NodeTraits::set_balance(a, zero_balance);
  546. NodeTraits::set_balance(b, zero_balance);
  547. }
  548. else if(c_balance == posi_balance){
  549. NodeTraits::set_balance(a, zero_balance);
  550. NodeTraits::set_balance(b, nega_balance);
  551. }
  552. else{
  553. BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached
  554. }
  555. }
  556. static node_ptr avl_rotate_left_right(const node_ptr a, const node_ptr a_oldleft, node_ptr hdr)
  557. { // [note: 'a_oldleft' is 'b']
  558. // | | //
  559. // a(-2) c //
  560. // / \ / \ //
  561. // / \ ==> / \ //
  562. // (pos)b [g] b a //
  563. // / \ / \ / \ //
  564. // [d] c [d] e f [g] //
  565. // / \ //
  566. // e f //
  567. const node_ptr c = NodeTraits::get_right(a_oldleft);
  568. bstree_algo::rotate_left_no_parent_fix(a_oldleft, c);
  569. //No need to link c with a [NodeTraits::set_parent(c, a) + NodeTraits::set_left(a, c)]
  570. //as c is not root and another rotation is coming
  571. bstree_algo::rotate_right(a, c, NodeTraits::get_parent(a), hdr);
  572. left_right_balancing(a, a_oldleft, c);
  573. return c;
  574. }
  575. static node_ptr avl_rotate_right_left(const node_ptr a, const node_ptr a_oldright, node_ptr hdr)
  576. { // [note: 'a_oldright' is 'b']
  577. // | | //
  578. // a(pos) c //
  579. // / \ / \ //
  580. // / \ / \ //
  581. // [d] b(neg) ==> a b //
  582. // / \ / \ / \ //
  583. // c [g] [d] e f [g] //
  584. // / \ //
  585. // e f //
  586. const node_ptr c (NodeTraits::get_left(a_oldright));
  587. bstree_algo::rotate_right_no_parent_fix(a_oldright, c);
  588. //No need to link c with a [NodeTraits::set_parent(c, a) + NodeTraits::set_right(a, c)]
  589. //as c is not root and another rotation is coming.
  590. bstree_algo::rotate_left(a, c, NodeTraits::get_parent(a), hdr);
  591. left_right_balancing(a_oldright, a, c);
  592. return c;
  593. }
  594. static void avl_rotate_left(node_ptr x, node_ptr x_oldright, node_ptr hdr)
  595. {
  596. bstree_algo::rotate_left(x, x_oldright, NodeTraits::get_parent(x), hdr);
  597. // reset the balancing factor
  598. if (NodeTraits::get_balance(x_oldright) == NodeTraits::positive()) {
  599. NodeTraits::set_balance(x, NodeTraits::zero());
  600. NodeTraits::set_balance(x_oldright, NodeTraits::zero());
  601. }
  602. else { // this doesn't happen during insertions
  603. NodeTraits::set_balance(x, NodeTraits::positive());
  604. NodeTraits::set_balance(x_oldright, NodeTraits::negative());
  605. }
  606. }
  607. static void avl_rotate_right(node_ptr x, node_ptr x_oldleft, node_ptr hdr)
  608. {
  609. bstree_algo::rotate_right(x, x_oldleft, NodeTraits::get_parent(x), hdr);
  610. // reset the balancing factor
  611. if (NodeTraits::get_balance(x_oldleft) == NodeTraits::negative()) {
  612. NodeTraits::set_balance(x, NodeTraits::zero());
  613. NodeTraits::set_balance(x_oldleft, NodeTraits::zero());
  614. }
  615. else { // this doesn't happen during insertions
  616. NodeTraits::set_balance(x, NodeTraits::negative());
  617. NodeTraits::set_balance(x_oldleft, NodeTraits::positive());
  618. }
  619. }
  620. /// @endcond
  621. };
  622. /// @cond
  623. template<class NodeTraits>
  624. struct get_algo<AvlTreeAlgorithms, NodeTraits>
  625. {
  626. typedef avltree_algorithms<NodeTraits> type;
  627. };
  628. template <class ValueTraits, class NodePtrCompare, class ExtraChecker>
  629. struct get_node_checker<AvlTreeAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker>
  630. {
  631. typedef detail::avltree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type;
  632. };
  633. /// @endcond
  634. } //namespace intrusive
  635. } //namespace boost
  636. #include <boost/intrusive/detail/config_end.hpp>
  637. #endif //BOOST_INTRUSIVE_AVLTREE_ALGORITHMS_HPP