avltree_algorithms.hpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  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. avltree_node_cloner(F f)
  36. : base_t(f)
  37. {}
  38. 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. 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(const node_ptr & header1, const node_ptr & header2);
  152. #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  153. //! @copydoc ::boost::intrusive::bstree_algorithms::swap_nodes(const node_ptr&,const node_ptr&)
  154. static void swap_nodes(const node_ptr & node1, const 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(const node_ptr&,const node_ptr&,const node_ptr&,const node_ptr&)
  162. static void swap_nodes(const node_ptr & node1, const node_ptr & header1, const node_ptr & node2, const 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(const node_ptr&,const node_ptr&)
  172. static void replace_node(const node_ptr & node_to_be_replaced, const 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(const node_ptr&,const node_ptr&,const node_ptr&)
  179. static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & header, const 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(const node_ptr&)
  185. static void unlink(const 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(const 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(const 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(const node_ptr&,const node_ptr&)
  224. static node_ptr erase(const node_ptr & header, const node_ptr & z)
  225. {
  226. typename bstree_algo::data_for_rebalance info;
  227. bstree_algo::erase(header, z, info);
  228. if(info.y != z){
  229. NodeTraits::set_balance(info.y, NodeTraits::get_balance(z));
  230. }
  231. //Rebalance avltree
  232. rebalance_after_erasure(header, info.x, info.x_parent);
  233. return z;
  234. }
  235. //! @copydoc ::boost::intrusive::bstree_algorithms::clone(const const_node_ptr&,const node_ptr&,Cloner,Disposer)
  236. template <class Cloner, class Disposer>
  237. static void clone
  238. (const const_node_ptr & source_header, const node_ptr & target_header, Cloner cloner, Disposer disposer)
  239. {
  240. avltree_node_cloner<NodeTraits, Cloner> new_cloner(cloner);
  241. bstree_algo::clone(source_header, target_header, new_cloner, disposer);
  242. }
  243. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  244. //! @copydoc ::boost::intrusive::bstree_algorithms::clear_and_dispose(const node_ptr&,Disposer)
  245. template<class Disposer>
  246. static void clear_and_dispose(const node_ptr & header, Disposer disposer);
  247. //! @copydoc ::boost::intrusive::bstree_algorithms::lower_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  248. template<class KeyType, class KeyNodePtrCompare>
  249. static node_ptr lower_bound
  250. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
  251. //! @copydoc ::boost::intrusive::bstree_algorithms::upper_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  252. template<class KeyType, class KeyNodePtrCompare>
  253. static node_ptr upper_bound
  254. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
  255. //! @copydoc ::boost::intrusive::bstree_algorithms::find(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  256. template<class KeyType, class KeyNodePtrCompare>
  257. static node_ptr find
  258. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
  259. //! @copydoc ::boost::intrusive::bstree_algorithms::equal_range(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  260. template<class KeyType, class KeyNodePtrCompare>
  261. static std::pair<node_ptr, node_ptr> equal_range
  262. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
  263. //! @copydoc ::boost::intrusive::bstree_algorithms::bounded_range(const const_node_ptr&,const KeyType&,const KeyType&,KeyNodePtrCompare,bool,bool)
  264. template<class KeyType, class KeyNodePtrCompare>
  265. static std::pair<node_ptr, node_ptr> bounded_range
  266. (const const_node_ptr & header, const KeyType &lower_key, const KeyType &upper_key, KeyNodePtrCompare comp
  267. , bool left_closed, bool right_closed);
  268. //! @copydoc ::boost::intrusive::bstree_algorithms::count(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  269. template<class KeyType, class KeyNodePtrCompare>
  270. static std::size_t count(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
  271. #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  272. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_equal_upper_bound(const node_ptr&,const node_ptr&,NodePtrCompare)
  273. template<class NodePtrCompare>
  274. static node_ptr insert_equal_upper_bound
  275. (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp)
  276. {
  277. bstree_algo::insert_equal_upper_bound(h, new_node, comp);
  278. rebalance_after_insertion(h, new_node);
  279. return new_node;
  280. }
  281. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_equal_lower_bound(const node_ptr&,const node_ptr&,NodePtrCompare)
  282. template<class NodePtrCompare>
  283. static node_ptr insert_equal_lower_bound
  284. (const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp)
  285. {
  286. bstree_algo::insert_equal_lower_bound(h, new_node, comp);
  287. rebalance_after_insertion(h, new_node);
  288. return new_node;
  289. }
  290. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_equal(const node_ptr&,const node_ptr&,const node_ptr&,NodePtrCompare)
  291. template<class NodePtrCompare>
  292. static node_ptr insert_equal
  293. (const node_ptr & header, const node_ptr & hint, const node_ptr & new_node, NodePtrCompare comp)
  294. {
  295. bstree_algo::insert_equal(header, hint, new_node, comp);
  296. rebalance_after_insertion(header, new_node);
  297. return new_node;
  298. }
  299. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_before(const node_ptr&,const node_ptr&,const node_ptr&)
  300. static node_ptr insert_before
  301. (const node_ptr & header, const node_ptr & pos, const node_ptr & new_node)
  302. {
  303. bstree_algo::insert_before(header, pos, new_node);
  304. rebalance_after_insertion(header, new_node);
  305. return new_node;
  306. }
  307. //! @copydoc ::boost::intrusive::bstree_algorithms::push_back(const node_ptr&,const node_ptr&)
  308. static void push_back(const node_ptr & header, const node_ptr & new_node)
  309. {
  310. bstree_algo::push_back(header, new_node);
  311. rebalance_after_insertion(header, new_node);
  312. }
  313. //! @copydoc ::boost::intrusive::bstree_algorithms::push_front(const node_ptr&,const node_ptr&)
  314. static void push_front(const node_ptr & header, const node_ptr & new_node)
  315. {
  316. bstree_algo::push_front(header, new_node);
  317. rebalance_after_insertion(header, new_node);
  318. }
  319. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  320. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_unique_check(const const_node_ptr&,const KeyType&,KeyNodePtrCompare,insert_commit_data&)
  321. template<class KeyType, class KeyNodePtrCompare>
  322. static std::pair<node_ptr, bool> insert_unique_check
  323. (const const_node_ptr & header, const KeyType &key
  324. ,KeyNodePtrCompare comp, insert_commit_data &commit_data);
  325. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_unique_check(const const_node_ptr&,const node_ptr&,const KeyType&,KeyNodePtrCompare,insert_commit_data&)
  326. template<class KeyType, class KeyNodePtrCompare>
  327. static std::pair<node_ptr, bool> insert_unique_check
  328. (const const_node_ptr & header, const node_ptr &hint, const KeyType &key
  329. ,KeyNodePtrCompare comp, insert_commit_data &commit_data);
  330. #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  331. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_unique_commit(const node_ptr&,const node_ptr&,const insert_commit_data &)
  332. static void insert_unique_commit
  333. (const node_ptr & header, const node_ptr & new_value, const insert_commit_data &commit_data)
  334. {
  335. bstree_algo::insert_unique_commit(header, new_value, commit_data);
  336. rebalance_after_insertion(header, new_value);
  337. }
  338. //! @copydoc ::boost::intrusive::bstree_algorithms::is_header
  339. static bool is_header(const const_node_ptr & p)
  340. { return NodeTraits::get_balance(p) == NodeTraits::zero() && bstree_algo::is_header(p); }
  341. /// @cond
  342. static bool verify(const node_ptr &header)
  343. {
  344. std::size_t height;
  345. std::size_t count;
  346. return verify_recursion(NodeTraits::get_parent(header), count, height);
  347. }
  348. private:
  349. static bool verify_recursion(node_ptr n, std::size_t &count, std::size_t &height)
  350. {
  351. if (!n){
  352. count = 0;
  353. height = 0;
  354. return true;
  355. }
  356. std::size_t leftcount, rightcount;
  357. std::size_t leftheight, rightheight;
  358. if(!verify_recursion(NodeTraits::get_left (n), leftcount, leftheight) ||
  359. !verify_recursion(NodeTraits::get_right(n), rightcount, rightheight) ){
  360. return false;
  361. }
  362. count = 1u + leftcount + rightcount;
  363. height = 1u + (leftheight > rightheight ? leftheight : rightheight);
  364. //If equal height, balance must be zero
  365. if(rightheight == leftheight){
  366. if(NodeTraits::get_balance(n) != NodeTraits::zero()){
  367. BOOST_ASSERT(0);
  368. return false;
  369. }
  370. }
  371. //If right is taller than left, then the difference must be at least 1 and the balance positive
  372. else if(rightheight > leftheight){
  373. if(rightheight - leftheight > 1 ){
  374. BOOST_ASSERT(0);
  375. return false;
  376. }
  377. else if(NodeTraits::get_balance(n) != NodeTraits::positive()){
  378. BOOST_ASSERT(0);
  379. return false;
  380. }
  381. }
  382. //If left is taller than right, then the difference must be at least 1 and the balance negative
  383. else{
  384. if(leftheight - rightheight > 1 ){
  385. BOOST_ASSERT(0);
  386. return false;
  387. }
  388. else if(NodeTraits::get_balance(n) != NodeTraits::negative()){
  389. BOOST_ASSERT(0);
  390. return false;
  391. }
  392. }
  393. return true;
  394. }
  395. static void rebalance_after_erasure(const node_ptr & header, node_ptr x, node_ptr x_parent)
  396. {
  397. for ( node_ptr root = NodeTraits::get_parent(header)
  398. ; x != root
  399. ; root = NodeTraits::get_parent(header), x_parent = NodeTraits::get_parent(x)) {
  400. const balance x_parent_balance = NodeTraits::get_balance(x_parent);
  401. //Don't cache x_is_leftchild or similar because x can be null and
  402. //equal to both x_parent_left and x_parent_right
  403. const node_ptr x_parent_left (NodeTraits::get_left(x_parent));
  404. const node_ptr x_parent_right(NodeTraits::get_right(x_parent));
  405. if(x_parent_balance == NodeTraits::zero()){
  406. NodeTraits::set_balance( x_parent, x == x_parent_right ? NodeTraits::negative() : NodeTraits::positive() );
  407. break; // the height didn't change, let's stop here
  408. }
  409. else if(x_parent_balance == NodeTraits::negative()){
  410. if (x == x_parent_left) { ////x is left child or x and sibling are null
  411. NodeTraits::set_balance(x_parent, NodeTraits::zero()); // balanced
  412. x = x_parent;
  413. }
  414. else {
  415. // x is right child (x_parent_left is the left child)
  416. BOOST_INTRUSIVE_INVARIANT_ASSERT(x_parent_left);
  417. if (NodeTraits::get_balance(x_parent_left) == NodeTraits::positive()) {
  418. // x_parent_left MUST have a right child
  419. BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_right(x_parent_left));
  420. x = avl_rotate_left_right(x_parent, x_parent_left, header);
  421. }
  422. else {
  423. avl_rotate_right(x_parent, x_parent_left, header);
  424. x = x_parent_left;
  425. }
  426. // if changed from negative to NodeTraits::positive(), no need to check above
  427. if (NodeTraits::get_balance(x) == NodeTraits::positive()){
  428. break;
  429. }
  430. }
  431. }
  432. else if(x_parent_balance == NodeTraits::positive()){
  433. if (x == x_parent_right) { //x is right child or x and sibling are null
  434. NodeTraits::set_balance(x_parent, NodeTraits::zero()); // balanced
  435. x = x_parent;
  436. }
  437. else {
  438. // x is left child (x_parent_right is the right child)
  439. BOOST_INTRUSIVE_INVARIANT_ASSERT(x_parent_right);
  440. if (NodeTraits::get_balance(x_parent_right) == NodeTraits::negative()) {
  441. // x_parent_right MUST have then a left child
  442. BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(x_parent_right));
  443. x = avl_rotate_right_left(x_parent, x_parent_right, header);
  444. }
  445. else {
  446. avl_rotate_left(x_parent, x_parent_right, header);
  447. x = x_parent_right;
  448. }
  449. // if changed from NodeTraits::positive() to negative, no need to check above
  450. if (NodeTraits::get_balance(x) == NodeTraits::negative()){
  451. break;
  452. }
  453. }
  454. }
  455. else{
  456. BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached
  457. }
  458. }
  459. }
  460. static void rebalance_after_insertion(const node_ptr & header, node_ptr x)
  461. {
  462. NodeTraits::set_balance(x, NodeTraits::zero());
  463. // Rebalance.
  464. for(node_ptr root = NodeTraits::get_parent(header); x != root; root = NodeTraits::get_parent(header)){
  465. node_ptr const x_parent(NodeTraits::get_parent(x));
  466. node_ptr const x_parent_left(NodeTraits::get_left(x_parent));
  467. const balance x_parent_balance = NodeTraits::get_balance(x_parent);
  468. const bool x_is_leftchild(x == x_parent_left);
  469. if(x_parent_balance == NodeTraits::zero()){
  470. // if x is left, parent will have parent->bal_factor = negative
  471. // else, parent->bal_factor = NodeTraits::positive()
  472. NodeTraits::set_balance( x_parent, x_is_leftchild ? NodeTraits::negative() : NodeTraits::positive() );
  473. x = x_parent;
  474. }
  475. else if(x_parent_balance == NodeTraits::positive()){
  476. // if x is a left child, parent->bal_factor = zero
  477. if (x_is_leftchild)
  478. NodeTraits::set_balance(x_parent, NodeTraits::zero());
  479. else{ // x is a right child, needs rebalancing
  480. if (NodeTraits::get_balance(x) == NodeTraits::negative())
  481. avl_rotate_right_left(x_parent, x, header);
  482. else
  483. avl_rotate_left(x_parent, x, header);
  484. }
  485. break;
  486. }
  487. else if(x_parent_balance == NodeTraits::negative()){
  488. // if x is a left child, needs rebalancing
  489. if (x_is_leftchild) {
  490. if (NodeTraits::get_balance(x) == NodeTraits::positive())
  491. avl_rotate_left_right(x_parent, x, header);
  492. else
  493. avl_rotate_right(x_parent, x, header);
  494. }
  495. else
  496. NodeTraits::set_balance(x_parent, NodeTraits::zero());
  497. break;
  498. }
  499. else{
  500. BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached
  501. }
  502. }
  503. }
  504. static void left_right_balancing(const node_ptr & a, const node_ptr & b, const node_ptr & c)
  505. {
  506. // balancing...
  507. const balance c_balance = NodeTraits::get_balance(c);
  508. const balance zero_balance = NodeTraits::zero();
  509. const balance posi_balance = NodeTraits::positive();
  510. const balance nega_balance = NodeTraits::negative();
  511. NodeTraits::set_balance(c, zero_balance);
  512. if(c_balance == nega_balance){
  513. NodeTraits::set_balance(a, posi_balance);
  514. NodeTraits::set_balance(b, zero_balance);
  515. }
  516. else if(c_balance == zero_balance){
  517. NodeTraits::set_balance(a, zero_balance);
  518. NodeTraits::set_balance(b, zero_balance);
  519. }
  520. else if(c_balance == posi_balance){
  521. NodeTraits::set_balance(a, zero_balance);
  522. NodeTraits::set_balance(b, nega_balance);
  523. }
  524. else{
  525. BOOST_INTRUSIVE_INVARIANT_ASSERT(false); // never reached
  526. }
  527. }
  528. static node_ptr avl_rotate_left_right(const node_ptr a, const node_ptr a_oldleft, const node_ptr & hdr)
  529. { // [note: 'a_oldleft' is 'b']
  530. // | | //
  531. // a(-2) c //
  532. // / \ / \ //
  533. // / \ ==> / \ //
  534. // (pos)b [g] b a //
  535. // / \ / \ / \ //
  536. // [d] c [d] e f [g] //
  537. // / \ //
  538. // e f //
  539. const node_ptr c = NodeTraits::get_right(a_oldleft);
  540. bstree_algo::rotate_left_no_parent_fix(a_oldleft, c);
  541. //No need to link c with a [NodeTraits::set_parent(c, a) + NodeTraits::set_left(a, c)]
  542. //as c is not root and another rotation is coming
  543. bstree_algo::rotate_right(a, c, NodeTraits::get_parent(a), hdr);
  544. left_right_balancing(a, a_oldleft, c);
  545. return c;
  546. }
  547. static node_ptr avl_rotate_right_left(const node_ptr a, const node_ptr a_oldright, const node_ptr & hdr)
  548. { // [note: 'a_oldright' is 'b']
  549. // | | //
  550. // a(pos) c //
  551. // / \ / \ //
  552. // / \ / \ //
  553. // [d] b(neg) ==> a b //
  554. // / \ / \ / \ //
  555. // c [g] [d] e f [g] //
  556. // / \ //
  557. // e f //
  558. const node_ptr c (NodeTraits::get_left(a_oldright));
  559. bstree_algo::rotate_right_no_parent_fix(a_oldright, c);
  560. //No need to link c with a [NodeTraits::set_parent(c, a) + NodeTraits::set_right(a, c)]
  561. //as c is not root and another rotation is coming.
  562. bstree_algo::rotate_left(a, c, NodeTraits::get_parent(a), hdr);
  563. left_right_balancing(a_oldright, a, c);
  564. return c;
  565. }
  566. static void avl_rotate_left(const node_ptr &x, const node_ptr &x_oldright, const node_ptr & hdr)
  567. {
  568. bstree_algo::rotate_left(x, x_oldright, NodeTraits::get_parent(x), hdr);
  569. // reset the balancing factor
  570. if (NodeTraits::get_balance(x_oldright) == NodeTraits::positive()) {
  571. NodeTraits::set_balance(x, NodeTraits::zero());
  572. NodeTraits::set_balance(x_oldright, NodeTraits::zero());
  573. }
  574. else { // this doesn't happen during insertions
  575. NodeTraits::set_balance(x, NodeTraits::positive());
  576. NodeTraits::set_balance(x_oldright, NodeTraits::negative());
  577. }
  578. }
  579. static void avl_rotate_right(const node_ptr &x, const node_ptr &x_oldleft, const node_ptr & hdr)
  580. {
  581. bstree_algo::rotate_right(x, x_oldleft, NodeTraits::get_parent(x), hdr);
  582. // reset the balancing factor
  583. if (NodeTraits::get_balance(x_oldleft) == NodeTraits::negative()) {
  584. NodeTraits::set_balance(x, NodeTraits::zero());
  585. NodeTraits::set_balance(x_oldleft, NodeTraits::zero());
  586. }
  587. else { // this doesn't happen during insertions
  588. NodeTraits::set_balance(x, NodeTraits::negative());
  589. NodeTraits::set_balance(x_oldleft, NodeTraits::positive());
  590. }
  591. }
  592. /// @endcond
  593. };
  594. /// @cond
  595. template<class NodeTraits>
  596. struct get_algo<AvlTreeAlgorithms, NodeTraits>
  597. {
  598. typedef avltree_algorithms<NodeTraits> type;
  599. };
  600. template <class ValueTraits, class NodePtrCompare, class ExtraChecker>
  601. struct get_node_checker<AvlTreeAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker>
  602. {
  603. typedef detail::avltree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type;
  604. };
  605. /// @endcond
  606. } //namespace intrusive
  607. } //namespace boost
  608. #include <boost/intrusive/detail/config_end.hpp>
  609. #endif //BOOST_INTRUSIVE_AVLTREE_ALGORITHMS_HPP