splaytree_algorithms.hpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2007-2014
  4. //
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // See http://www.boost.org/libs/intrusive for documentation.
  10. //
  11. /////////////////////////////////////////////////////////////////////////////
  12. // The implementation of splay trees is based on the article and code published
  13. // in C++ Users Journal "Implementing Splay Trees in C++" (September 1, 2005).
  14. //
  15. // The splay code has been modified and (supposedly) improved by Ion Gaztanaga.
  16. //
  17. // Here is the copyright notice of the original file containing the splay code:
  18. //
  19. // splay_tree.h -- implementation of a STL compatible splay tree.
  20. //
  21. // Copyright (c) 2004 Ralf Mattethat
  22. //
  23. // Permission to copy, use, modify, sell and distribute this software
  24. // is granted provided this copyright notice appears in all copies.
  25. // This software is provided "as is" without express or implied
  26. // warranty, and with no claim as to its suitability for any purpose.
  27. //
  28. /////////////////////////////////////////////////////////////////////////////
  29. #ifndef BOOST_INTRUSIVE_SPLAYTREE_ALGORITHMS_HPP
  30. #define BOOST_INTRUSIVE_SPLAYTREE_ALGORITHMS_HPP
  31. #include <boost/intrusive/detail/config_begin.hpp>
  32. #include <boost/intrusive/intrusive_fwd.hpp>
  33. #include <boost/intrusive/detail/assert.hpp>
  34. #include <boost/intrusive/detail/algo_type.hpp>
  35. #include <boost/intrusive/detail/uncast.hpp>
  36. #include <boost/intrusive/bstree_algorithms.hpp>
  37. #include <cstddef>
  38. #if defined(BOOST_HAS_PRAGMA_ONCE)
  39. # pragma once
  40. #endif
  41. namespace boost {
  42. namespace intrusive {
  43. /// @cond
  44. namespace detail {
  45. template<class NodeTraits>
  46. struct splaydown_assemble_and_fix_header
  47. {
  48. typedef typename NodeTraits::node_ptr node_ptr;
  49. splaydown_assemble_and_fix_header(const node_ptr & t, const node_ptr & header, const node_ptr &leftmost, const node_ptr &rightmost)
  50. : t_(t)
  51. , null_node_(header)
  52. , l_(null_node_)
  53. , r_(null_node_)
  54. , leftmost_(leftmost)
  55. , rightmost_(rightmost)
  56. {}
  57. ~splaydown_assemble_and_fix_header()
  58. {
  59. this->assemble();
  60. //Now recover the original header except for the
  61. //splayed root node.
  62. //"t_" is the current root and "null_node_" is the header node
  63. NodeTraits::set_parent(null_node_, t_);
  64. NodeTraits::set_parent(t_, null_node_);
  65. //Recover leftmost/rightmost pointers
  66. NodeTraits::set_left (null_node_, leftmost_);
  67. NodeTraits::set_right(null_node_, rightmost_);
  68. }
  69. private:
  70. void assemble()
  71. {
  72. //procedure assemble;
  73. // left(r), right(l) := right(t), left(t);
  74. // left(t), right(t) := right(null), left(null);
  75. //end assemble;
  76. { // left(r), right(l) := right(t), left(t);
  77. node_ptr const old_t_left = NodeTraits::get_left(t_);
  78. node_ptr const old_t_right = NodeTraits::get_right(t_);
  79. NodeTraits::set_right(l_, old_t_left);
  80. NodeTraits::set_left (r_, old_t_right);
  81. if(old_t_left){
  82. NodeTraits::set_parent(old_t_left, l_);
  83. }
  84. if(old_t_right){
  85. NodeTraits::set_parent(old_t_right, r_);
  86. }
  87. }
  88. { // left(t), right(t) := right(null), left(null);
  89. node_ptr const null_right = NodeTraits::get_right(null_node_);
  90. node_ptr const null_left = NodeTraits::get_left(null_node_);
  91. NodeTraits::set_left (t_, null_right);
  92. NodeTraits::set_right(t_, null_left);
  93. if(null_right){
  94. NodeTraits::set_parent(null_right, t_);
  95. }
  96. if(null_left){
  97. NodeTraits::set_parent(null_left, t_);
  98. }
  99. }
  100. }
  101. public:
  102. node_ptr t_, null_node_, l_, r_, leftmost_, rightmost_;
  103. };
  104. } //namespace detail {
  105. /// @endcond
  106. //! A splay tree is an implementation of a binary search tree. The tree is
  107. //! self balancing using the splay algorithm as described in
  108. //!
  109. //! "Self-Adjusting Binary Search Trees
  110. //! by Daniel Dominic Sleator and Robert Endre Tarjan
  111. //! AT&T Bell Laboratories, Murray Hill, NJ
  112. //! Journal of the ACM, Vol 32, no 3, July 1985, pp 652-686
  113. //!
  114. //! splaytree_algorithms is configured with a NodeTraits class, which encapsulates the
  115. //! information about the node to be manipulated. NodeTraits must support the
  116. //! following interface:
  117. //!
  118. //! <b>Typedefs</b>:
  119. //!
  120. //! <tt>node</tt>: The type of the node that forms the binary search tree
  121. //!
  122. //! <tt>node_ptr</tt>: A pointer to a node
  123. //!
  124. //! <tt>const_node_ptr</tt>: A pointer to a const node
  125. //!
  126. //! <b>Static functions</b>:
  127. //!
  128. //! <tt>static node_ptr get_parent(const_node_ptr n);</tt>
  129. //!
  130. //! <tt>static void set_parent(node_ptr n, node_ptr parent);</tt>
  131. //!
  132. //! <tt>static node_ptr get_left(const_node_ptr n);</tt>
  133. //!
  134. //! <tt>static void set_left(node_ptr n, node_ptr left);</tt>
  135. //!
  136. //! <tt>static node_ptr get_right(const_node_ptr n);</tt>
  137. //!
  138. //! <tt>static void set_right(node_ptr n, node_ptr right);</tt>
  139. template<class NodeTraits>
  140. class splaytree_algorithms
  141. #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  142. : public bstree_algorithms<NodeTraits>
  143. #endif
  144. {
  145. /// @cond
  146. private:
  147. typedef bstree_algorithms<NodeTraits> bstree_algo;
  148. /// @endcond
  149. public:
  150. typedef typename NodeTraits::node node;
  151. typedef NodeTraits node_traits;
  152. typedef typename NodeTraits::node_ptr node_ptr;
  153. typedef typename NodeTraits::const_node_ptr const_node_ptr;
  154. //! This type is the information that will be
  155. //! filled by insert_unique_check
  156. typedef typename bstree_algo::insert_commit_data insert_commit_data;
  157. public:
  158. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  159. //! @copydoc ::boost::intrusive::bstree_algorithms::get_header(const const_node_ptr&)
  160. static node_ptr get_header(const const_node_ptr & n);
  161. //! @copydoc ::boost::intrusive::bstree_algorithms::begin_node
  162. static node_ptr begin_node(const const_node_ptr & header);
  163. //! @copydoc ::boost::intrusive::bstree_algorithms::end_node
  164. static node_ptr end_node(const const_node_ptr & header);
  165. //! @copydoc ::boost::intrusive::bstree_algorithms::swap_tree
  166. static void swap_tree(const node_ptr & header1, const node_ptr & header2);
  167. //! @copydoc ::boost::intrusive::bstree_algorithms::swap_nodes(const node_ptr&,const node_ptr&)
  168. static void swap_nodes(const node_ptr & node1, const node_ptr & node2);
  169. //! @copydoc ::boost::intrusive::bstree_algorithms::swap_nodes(const node_ptr&,const node_ptr&,const node_ptr&,const node_ptr&)
  170. static void swap_nodes(const node_ptr & node1, const node_ptr & header1, const node_ptr & node2, const node_ptr & header2);
  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. //! @copydoc ::boost::intrusive::bstree_algorithms::replace_node(const node_ptr&,const node_ptr&,const node_ptr&)
  174. static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & header, const node_ptr & new_node);
  175. //! @copydoc ::boost::intrusive::bstree_algorithms::unlink(const node_ptr&)
  176. static void unlink(const node_ptr & node);
  177. //! @copydoc ::boost::intrusive::bstree_algorithms::unlink_leftmost_without_rebalance
  178. static node_ptr unlink_leftmost_without_rebalance(const node_ptr & header);
  179. //! @copydoc ::boost::intrusive::bstree_algorithms::unique(const const_node_ptr&)
  180. static bool unique(const const_node_ptr & node);
  181. //! @copydoc ::boost::intrusive::bstree_algorithms::size(const const_node_ptr&)
  182. static std::size_t size(const const_node_ptr & header);
  183. //! @copydoc ::boost::intrusive::bstree_algorithms::next_node(const node_ptr&)
  184. static node_ptr next_node(const node_ptr & node);
  185. //! @copydoc ::boost::intrusive::bstree_algorithms::prev_node(const node_ptr&)
  186. static node_ptr prev_node(const node_ptr & node);
  187. //! @copydoc ::boost::intrusive::bstree_algorithms::init(const node_ptr&)
  188. static void init(const node_ptr & node);
  189. //! @copydoc ::boost::intrusive::bstree_algorithms::init_header(const node_ptr&)
  190. static void init_header(const node_ptr & header);
  191. #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  192. //! @copydoc ::boost::intrusive::bstree_algorithms::erase(const node_ptr&,const node_ptr&)
  193. //! Additional notes: the previous node of z is splayed to speed up range deletions.
  194. static void erase(const node_ptr & header, const node_ptr & z)
  195. {
  196. //posibility 1
  197. if(NodeTraits::get_left(z)){
  198. splay_up(bstree_algo::prev_node(z), header);
  199. }
  200. //possibility 2
  201. //if(NodeTraits::get_left(z)){
  202. // node_ptr l = NodeTraits::get_left(z);
  203. // splay_up(l, header);
  204. //}
  205. //if(NodeTraits::get_left(z)){
  206. // node_ptr l = bstree_algo::prev_node(z);
  207. // splay_up_impl(l, z);
  208. //}
  209. //possibility 4
  210. //splay_up(z, header);
  211. bstree_algo::erase(header, z);
  212. }
  213. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  214. //! @copydoc ::boost::intrusive::bstree_algorithms::clone(const const_node_ptr&,const node_ptr&,Cloner,Disposer)
  215. template <class Cloner, class Disposer>
  216. static void clone
  217. (const const_node_ptr & source_header, const node_ptr & target_header, Cloner cloner, Disposer disposer);
  218. //! @copydoc ::boost::intrusive::bstree_algorithms::clear_and_dispose(const node_ptr&,Disposer)
  219. template<class Disposer>
  220. static void clear_and_dispose(const node_ptr & header, Disposer disposer);
  221. #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  222. //! @copydoc ::boost::intrusive::bstree_algorithms::count(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  223. //! Additional notes: an element with key `key` is splayed.
  224. template<class KeyType, class KeyNodePtrCompare>
  225. static std::size_t count
  226. (const node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
  227. {
  228. std::pair<node_ptr, node_ptr> ret = equal_range(header, key, comp);
  229. std::size_t n = 0;
  230. while(ret.first != ret.second){
  231. ++n;
  232. ret.first = next_node(ret.first);
  233. }
  234. return n;
  235. }
  236. //! @copydoc ::boost::intrusive::bstree_algorithms::count(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  237. //! Additional note: no splaying is performed
  238. template<class KeyType, class KeyNodePtrCompare>
  239. static std::size_t count
  240. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
  241. { return bstree_algo::count(header, key, comp); }
  242. //! @copydoc ::boost::intrusive::bstree_algorithms::lower_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  243. //! Additional notes: the first node of the range is splayed.
  244. template<class KeyType, class KeyNodePtrCompare>
  245. static node_ptr lower_bound
  246. (const node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
  247. {
  248. splay_down(detail::uncast(header), key, comp);
  249. node_ptr y = bstree_algo::lower_bound(header, key, comp);
  250. //splay_up(y, detail::uncast(header));
  251. return y;
  252. }
  253. //! @copydoc ::boost::intrusive::bstree_algorithms::lower_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  254. //! Additional note: no splaying is performed
  255. template<class KeyType, class KeyNodePtrCompare>
  256. static node_ptr lower_bound
  257. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
  258. { return bstree_algo::lower_bound(header, key, comp); }
  259. //! @copydoc ::boost::intrusive::bstree_algorithms::upper_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  260. //! Additional notes: the first node of the range is splayed.
  261. template<class KeyType, class KeyNodePtrCompare>
  262. static node_ptr upper_bound
  263. (const node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
  264. {
  265. splay_down(detail::uncast(header), key, comp);
  266. node_ptr y = bstree_algo::upper_bound(header, key, comp);
  267. //splay_up(y, detail::uncast(header));
  268. return y;
  269. }
  270. //! @copydoc ::boost::intrusive::bstree_algorithms::upper_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  271. //! Additional note: no splaying is performed
  272. template<class KeyType, class KeyNodePtrCompare>
  273. static node_ptr upper_bound
  274. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
  275. { return bstree_algo::upper_bound(header, key, comp); }
  276. //! @copydoc ::boost::intrusive::bstree_algorithms::find(const const_node_ptr&, const KeyType&,KeyNodePtrCompare)
  277. //! Additional notes: the found node of the lower bound is splayed.
  278. template<class KeyType, class KeyNodePtrCompare>
  279. static node_ptr find
  280. (const node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
  281. {
  282. splay_down(detail::uncast(header), key, comp);
  283. return bstree_algo::find(header, key, comp);
  284. }
  285. //! @copydoc ::boost::intrusive::bstree_algorithms::find(const const_node_ptr&, const KeyType&,KeyNodePtrCompare)
  286. //! Additional note: no splaying is performed
  287. template<class KeyType, class KeyNodePtrCompare>
  288. static node_ptr find
  289. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
  290. { return bstree_algo::find(header, key, comp); }
  291. //! @copydoc ::boost::intrusive::bstree_algorithms::equal_range(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  292. //! Additional notes: the first node of the range is splayed.
  293. template<class KeyType, class KeyNodePtrCompare>
  294. static std::pair<node_ptr, node_ptr> equal_range
  295. (const node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
  296. {
  297. splay_down(detail::uncast(header), key, comp);
  298. std::pair<node_ptr, node_ptr> ret = bstree_algo::equal_range(header, key, comp);
  299. //splay_up(ret.first, detail::uncast(header));
  300. return ret;
  301. }
  302. //! @copydoc ::boost::intrusive::bstree_algorithms::equal_range(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  303. //! Additional note: no splaying is performed
  304. template<class KeyType, class KeyNodePtrCompare>
  305. static std::pair<node_ptr, node_ptr> equal_range
  306. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
  307. { return bstree_algo::equal_range(header, key, comp); }
  308. //! @copydoc ::boost::intrusive::bstree_algorithms::lower_bound_range(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  309. //! Additional notes: the first node of the range is splayed.
  310. template<class KeyType, class KeyNodePtrCompare>
  311. static std::pair<node_ptr, node_ptr> lower_bound_range
  312. (const node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
  313. {
  314. splay_down(detail::uncast(header), key, comp);
  315. std::pair<node_ptr, node_ptr> ret = bstree_algo::lower_bound_range(header, key, comp);
  316. //splay_up(ret.first, detail::uncast(header));
  317. return ret;
  318. }
  319. //! @copydoc ::boost::intrusive::bstree_algorithms::lower_bound_range(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
  320. //! Additional note: no splaying is performed
  321. template<class KeyType, class KeyNodePtrCompare>
  322. static std::pair<node_ptr, node_ptr> lower_bound_range
  323. (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp)
  324. { return bstree_algo::lower_bound_range(header, key, comp); }
  325. //! @copydoc ::boost::intrusive::bstree_algorithms::bounded_range(const const_node_ptr&,const KeyType&,const KeyType&,KeyNodePtrCompare,bool,bool)
  326. //! Additional notes: the first node of the range is splayed.
  327. template<class KeyType, class KeyNodePtrCompare>
  328. static std::pair<node_ptr, node_ptr> bounded_range
  329. (const node_ptr & header, const KeyType &lower_key, const KeyType &upper_key, KeyNodePtrCompare comp
  330. , bool left_closed, bool right_closed)
  331. {
  332. splay_down(detail::uncast(header), lower_key, comp);
  333. std::pair<node_ptr, node_ptr> ret =
  334. bstree_algo::bounded_range(header, lower_key, upper_key, comp, left_closed, right_closed);
  335. //splay_up(ret.first, detail::uncast(header));
  336. return ret;
  337. }
  338. //! @copydoc ::boost::intrusive::bstree_algorithms::bounded_range(const const_node_ptr&,const KeyType&,const KeyType&,KeyNodePtrCompare,bool,bool)
  339. //! Additional note: no splaying is performed
  340. template<class KeyType, class KeyNodePtrCompare>
  341. static std::pair<node_ptr, node_ptr> bounded_range
  342. (const const_node_ptr & header, const KeyType &lower_key, const KeyType &upper_key, KeyNodePtrCompare comp
  343. , bool left_closed, bool right_closed)
  344. { return bstree_algo::bounded_range(header, lower_key, upper_key, comp, left_closed, right_closed); }
  345. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_equal_upper_bound(const node_ptr&,const node_ptr&,NodePtrCompare)
  346. //! Additional note: the inserted node is splayed
  347. template<class NodePtrCompare>
  348. static node_ptr insert_equal_upper_bound
  349. (const node_ptr & header, const node_ptr & new_node, NodePtrCompare comp)
  350. {
  351. splay_down(header, new_node, comp);
  352. return bstree_algo::insert_equal_upper_bound(header, new_node, comp);
  353. }
  354. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_equal_lower_bound(const node_ptr&,const node_ptr&,NodePtrCompare)
  355. //! Additional note: the inserted node is splayed
  356. template<class NodePtrCompare>
  357. static node_ptr insert_equal_lower_bound
  358. (const node_ptr & header, const node_ptr & new_node, NodePtrCompare comp)
  359. {
  360. splay_down(header, new_node, comp);
  361. return bstree_algo::insert_equal_lower_bound(header, new_node, comp);
  362. }
  363. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_equal(const node_ptr&,const node_ptr&,const node_ptr&,NodePtrCompare)
  364. //! Additional note: the inserted node is splayed
  365. template<class NodePtrCompare>
  366. static node_ptr insert_equal
  367. (const node_ptr & header, const node_ptr & hint, const node_ptr & new_node, NodePtrCompare comp)
  368. {
  369. splay_down(header, new_node, comp);
  370. return bstree_algo::insert_equal(header, hint, new_node, comp);
  371. }
  372. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_before(const node_ptr&,const node_ptr&,const node_ptr&)
  373. //! Additional note: the inserted node is splayed
  374. static node_ptr insert_before
  375. (const node_ptr & header, const node_ptr & pos, const node_ptr & new_node)
  376. {
  377. bstree_algo::insert_before(header, pos, new_node);
  378. splay_up(new_node, header);
  379. return new_node;
  380. }
  381. //! @copydoc ::boost::intrusive::bstree_algorithms::push_back(const node_ptr&,const node_ptr&)
  382. //! Additional note: the inserted node is splayed
  383. static void push_back(const node_ptr & header, const node_ptr & new_node)
  384. {
  385. bstree_algo::push_back(header, new_node);
  386. splay_up(new_node, header);
  387. }
  388. //! @copydoc ::boost::intrusive::bstree_algorithms::push_front(const node_ptr&,const node_ptr&)
  389. //! Additional note: the inserted node is splayed
  390. static void push_front(const node_ptr & header, const node_ptr & new_node)
  391. {
  392. bstree_algo::push_front(header, new_node);
  393. splay_up(new_node, header);
  394. }
  395. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_unique_check(const const_node_ptr&,const KeyType&,KeyNodePtrCompare,insert_commit_data&)
  396. //! Additional note: nodes with the given key are splayed
  397. template<class KeyType, class KeyNodePtrCompare>
  398. static std::pair<node_ptr, bool> insert_unique_check
  399. (const node_ptr & header, const KeyType &key
  400. ,KeyNodePtrCompare comp, insert_commit_data &commit_data)
  401. {
  402. splay_down(header, key, comp);
  403. return bstree_algo::insert_unique_check(header, key, comp, commit_data);
  404. }
  405. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_unique_check(const const_node_ptr&,const node_ptr&,const KeyType&,KeyNodePtrCompare,insert_commit_data&)
  406. //! Additional note: nodes with the given key are splayed
  407. template<class KeyType, class KeyNodePtrCompare>
  408. static std::pair<node_ptr, bool> insert_unique_check
  409. (const node_ptr & header, const node_ptr &hint, const KeyType &key
  410. ,KeyNodePtrCompare comp, insert_commit_data &commit_data)
  411. {
  412. splay_down(header, key, comp);
  413. return bstree_algo::insert_unique_check(header, hint, key, comp, commit_data);
  414. }
  415. #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  416. //! @copydoc ::boost::intrusive::bstree_algorithms::insert_unique_commit(const node_ptr&,const node_ptr&,const insert_commit_data&)
  417. static void insert_unique_commit
  418. (const node_ptr & header, const node_ptr & new_value, const insert_commit_data &commit_data);
  419. //! @copydoc ::boost::intrusive::bstree_algorithms::is_header
  420. static bool is_header(const const_node_ptr & p);
  421. //! @copydoc ::boost::intrusive::bstree_algorithms::rebalance
  422. static void rebalance(const node_ptr & header);
  423. //! @copydoc ::boost::intrusive::bstree_algorithms::rebalance_subtree
  424. static node_ptr rebalance_subtree(const node_ptr & old_root);
  425. #endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
  426. // bottom-up splay, use data_ as parent for n | complexity : logarithmic | exception : nothrow
  427. static void splay_up(const node_ptr & node, const node_ptr & header)
  428. { priv_splay_up<true>(node, header); }
  429. // top-down splay | complexity : logarithmic | exception : strong, note A
  430. template<class KeyType, class KeyNodePtrCompare>
  431. static node_ptr splay_down(const node_ptr & header, const KeyType &key, KeyNodePtrCompare comp, bool *pfound = 0)
  432. { return priv_splay_down<true>(header, key, comp, pfound); }
  433. private:
  434. /// @cond
  435. // bottom-up splay, use data_ as parent for n | complexity : logarithmic | exception : nothrow
  436. template<bool SimpleSplay>
  437. static void priv_splay_up(const node_ptr & node, const node_ptr & header)
  438. {
  439. // If (node == header) do a splay for the right most node instead
  440. // this is to boost performance of equal_range/count on equivalent containers in the case
  441. // where there are many equal elements at the end
  442. node_ptr n((node == header) ? NodeTraits::get_right(header) : node);
  443. node_ptr t(header);
  444. if( n == t ) return;
  445. for( ;; ){
  446. node_ptr p(NodeTraits::get_parent(n));
  447. node_ptr g(NodeTraits::get_parent(p));
  448. if( p == t ) break;
  449. if( g == t ){
  450. // zig
  451. rotate(n);
  452. }
  453. else if ((NodeTraits::get_left(p) == n && NodeTraits::get_left(g) == p) ||
  454. (NodeTraits::get_right(p) == n && NodeTraits::get_right(g) == p) ){
  455. // zig-zig
  456. rotate(p);
  457. rotate(n);
  458. }
  459. else {
  460. // zig-zag
  461. rotate(n);
  462. if(!SimpleSplay){
  463. rotate(n);
  464. }
  465. }
  466. }
  467. }
  468. template<bool SimpleSplay, class KeyType, class KeyNodePtrCompare>
  469. static node_ptr priv_splay_down(const node_ptr & header, const KeyType &key, KeyNodePtrCompare comp, bool *pfound = 0)
  470. {
  471. //Most splay tree implementations use a dummy/null node to implement.
  472. //this function. This has some problems for a generic library like Intrusive:
  473. //
  474. // * The node might not have a default constructor.
  475. // * The default constructor could throw.
  476. //
  477. //We already have a header node. Leftmost and rightmost nodes of the tree
  478. //are not changed when splaying (because the invariants of the tree don't
  479. //change) We can back up them, use the header as the null node and
  480. //reassign old values after the function has been completed.
  481. node_ptr const old_root = NodeTraits::get_parent(header);
  482. node_ptr const leftmost = NodeTraits::get_left(header);
  483. node_ptr const rightmost = NodeTraits::get_right(header);
  484. if(leftmost == rightmost){ //Empty or unique node
  485. if(pfound){
  486. *pfound = old_root && !comp(key, old_root) && !comp(old_root, key);
  487. }
  488. return old_root ? old_root : header;
  489. }
  490. else{
  491. //Initialize "null node" (the header in our case)
  492. NodeTraits::set_left (header, node_ptr());
  493. NodeTraits::set_right(header, node_ptr());
  494. //Class that will backup leftmost/rightmost from header, commit the assemble(),
  495. //and will restore leftmost/rightmost to header even if "comp" throws
  496. detail::splaydown_assemble_and_fix_header<NodeTraits> commit(old_root, header, leftmost, rightmost);
  497. bool found = false;
  498. for( ;; ){
  499. if(comp(key, commit.t_)){
  500. node_ptr const t_left = NodeTraits::get_left(commit.t_);
  501. if(!t_left)
  502. break;
  503. if(comp(key, t_left)){
  504. bstree_algo::rotate_right_no_parent_fix(commit.t_, t_left);
  505. commit.t_ = t_left;
  506. if( !NodeTraits::get_left(commit.t_) )
  507. break;
  508. link_right(commit.t_, commit.r_);
  509. }
  510. else{
  511. link_right(commit.t_, commit.r_);
  512. if(!SimpleSplay && comp(t_left, key)){
  513. if( !NodeTraits::get_right(commit.t_) )
  514. break;
  515. link_left(commit.t_, commit.l_);
  516. }
  517. }
  518. }
  519. else if(comp(commit.t_, key)){
  520. node_ptr const t_right = NodeTraits::get_right(commit.t_);
  521. if(!t_right)
  522. break;
  523. if(comp(t_right, key)){
  524. bstree_algo::rotate_left_no_parent_fix(commit.t_, t_right);
  525. commit.t_ = t_right;
  526. if( !NodeTraits::get_right(commit.t_) )
  527. break;
  528. link_left(commit.t_, commit.l_);
  529. }
  530. else{
  531. link_left(commit.t_, commit.l_);
  532. if(!SimpleSplay && comp(key, t_right)){
  533. if( !NodeTraits::get_left(commit.t_) )
  534. break;
  535. link_right(commit.t_, commit.r_);
  536. }
  537. }
  538. }
  539. else{
  540. found = true;
  541. break;
  542. }
  543. }
  544. //commit.~splaydown_assemble_and_fix_header<NodeTraits>() will first
  545. //"assemble()" + link the new root & recover header's leftmost & rightmost
  546. if(pfound){
  547. *pfound = found;
  548. }
  549. return commit.t_;
  550. }
  551. }
  552. // break link to left child node and attach it to left tree pointed to by l | complexity : constant | exception : nothrow
  553. static void link_left(node_ptr & t, node_ptr & l)
  554. {
  555. //procedure link_left;
  556. // t, l, right(l) := right(t), t, t
  557. //end link_left
  558. NodeTraits::set_right(l, t);
  559. NodeTraits::set_parent(t, l);
  560. l = t;
  561. t = NodeTraits::get_right(t);
  562. }
  563. // break link to right child node and attach it to right tree pointed to by r | complexity : constant | exception : nothrow
  564. static void link_right(node_ptr & t, node_ptr & r)
  565. {
  566. //procedure link_right;
  567. // t, r, left(r) := left(t), t, t
  568. //end link_right;
  569. NodeTraits::set_left(r, t);
  570. NodeTraits::set_parent(t, r);
  571. r = t;
  572. t = NodeTraits::get_left(t);
  573. }
  574. // rotate n with its parent | complexity : constant | exception : nothrow
  575. static void rotate(const node_ptr & n)
  576. {
  577. //procedure rotate_left;
  578. // t, right(t), left(right(t)) := right(t), left(right(t)), t
  579. //end rotate_left;
  580. node_ptr p = NodeTraits::get_parent(n);
  581. node_ptr g = NodeTraits::get_parent(p);
  582. //Test if g is header before breaking tree
  583. //invariants that would make is_header invalid
  584. bool g_is_header = bstree_algo::is_header(g);
  585. if(NodeTraits::get_left(p) == n){
  586. NodeTraits::set_left(p, NodeTraits::get_right(n));
  587. if(NodeTraits::get_left(p))
  588. NodeTraits::set_parent(NodeTraits::get_left(p), p);
  589. NodeTraits::set_right(n, p);
  590. }
  591. else{ // must be ( p->right == n )
  592. NodeTraits::set_right(p, NodeTraits::get_left(n));
  593. if(NodeTraits::get_right(p))
  594. NodeTraits::set_parent(NodeTraits::get_right(p), p);
  595. NodeTraits::set_left(n, p);
  596. }
  597. NodeTraits::set_parent(p, n);
  598. NodeTraits::set_parent(n, g);
  599. if(g_is_header){
  600. if(NodeTraits::get_parent(g) == p)
  601. NodeTraits::set_parent(g, n);
  602. else{//must be ( g->right == p )
  603. BOOST_INTRUSIVE_INVARIANT_ASSERT(false);
  604. NodeTraits::set_right(g, n);
  605. }
  606. }
  607. else{
  608. if(NodeTraits::get_left(g) == p)
  609. NodeTraits::set_left(g, n);
  610. else //must be ( g->right == p )
  611. NodeTraits::set_right(g, n);
  612. }
  613. }
  614. /// @endcond
  615. };
  616. /// @cond
  617. template<class NodeTraits>
  618. struct get_algo<SplayTreeAlgorithms, NodeTraits>
  619. {
  620. typedef splaytree_algorithms<NodeTraits> type;
  621. };
  622. template <class ValueTraits, class NodePtrCompare, class ExtraChecker>
  623. struct get_node_checker<SplayTreeAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker>
  624. {
  625. typedef detail::bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type;
  626. };
  627. /// @endcond
  628. } //namespace intrusive
  629. } //namespace boost
  630. #include <boost/intrusive/detail/config_end.hpp>
  631. #endif //BOOST_INTRUSIVE_SPLAYTREE_ALGORITHMS_HPP