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 13 #ifndef BOOST_INTRUSIVE_BSTREE_ALGORITHMS_HPP 14 #define BOOST_INTRUSIVE_BSTREE_ALGORITHMS_HPP 15 16 #include <cstddef> 17 #include <boost/intrusive/detail/config_begin.hpp> 18 #include <boost/intrusive/intrusive_fwd.hpp> 19 #include <boost/intrusive/detail/bstree_algorithms_base.hpp> 20 #include <boost/intrusive/detail/assert.hpp> 21 #include <boost/intrusive/detail/uncast.hpp> 22 #include <boost/intrusive/detail/math.hpp> 23 #include <boost/intrusive/detail/algo_type.hpp> 24 25 #include <boost/intrusive/detail/minimal_pair_header.hpp> 26 27 #if defined(BOOST_HAS_PRAGMA_ONCE) 28 # pragma once 29 #endif 30 31 namespace boost { 32 namespace intrusive { 33 34 /// @cond 35 36 //! This type is the information that will be filled by insert_unique_check 37 template <class NodePtr> 38 struct insert_commit_data_t 39 { insert_commit_data_tboost::intrusive::insert_commit_data_t40 BOOST_INTRUSIVE_FORCEINLINE insert_commit_data_t() 41 : link_left(false), node() 42 {} 43 bool link_left; 44 NodePtr node; 45 }; 46 47 template <class NodePtr> 48 struct data_for_rebalance_t 49 { 50 NodePtr x; 51 NodePtr x_parent; 52 NodePtr y; 53 }; 54 55 namespace detail { 56 57 template<class ValueTraits, class NodePtrCompare, class ExtraChecker> 58 struct bstree_node_checker 59 : public ExtraChecker 60 { 61 typedef ExtraChecker base_checker_t; 62 typedef ValueTraits value_traits; 63 typedef typename value_traits::node_traits node_traits; 64 typedef typename node_traits::const_node_ptr const_node_ptr; 65 66 struct return_type 67 : public base_checker_t::return_type 68 { return_typeboost::intrusive::detail::bstree_node_checker::return_type69 BOOST_INTRUSIVE_FORCEINLINE return_type() 70 : min_key_node_ptr(const_node_ptr()), max_key_node_ptr(const_node_ptr()), node_count(0) 71 {} 72 73 const_node_ptr min_key_node_ptr; 74 const_node_ptr max_key_node_ptr; 75 size_t node_count; 76 }; 77 bstree_node_checkerboost::intrusive::detail::bstree_node_checker78 BOOST_INTRUSIVE_FORCEINLINE bstree_node_checker(const NodePtrCompare& comp, ExtraChecker extra_checker) 79 : base_checker_t(extra_checker), comp_(comp) 80 {} 81 operator ()boost::intrusive::detail::bstree_node_checker82 void operator () (const const_node_ptr& p, 83 const return_type& check_return_left, const return_type& check_return_right, 84 return_type& check_return) 85 { 86 if (check_return_left.max_key_node_ptr) 87 BOOST_INTRUSIVE_INVARIANT_ASSERT(!comp_(p, check_return_left.max_key_node_ptr)); 88 if (check_return_right.min_key_node_ptr) 89 BOOST_INTRUSIVE_INVARIANT_ASSERT(!comp_(check_return_right.min_key_node_ptr, p)); 90 check_return.min_key_node_ptr = node_traits::get_left(p)? check_return_left.min_key_node_ptr : p; 91 check_return.max_key_node_ptr = node_traits::get_right(p)? check_return_right.max_key_node_ptr : p; 92 check_return.node_count = check_return_left.node_count + check_return_right.node_count + 1; 93 base_checker_t::operator()(p, check_return_left, check_return_right, check_return); 94 } 95 96 const NodePtrCompare comp_; 97 }; 98 99 } // namespace detail 100 101 /// @endcond 102 103 104 105 //! This is an implementation of a binary search tree. 106 //! A node in the search tree has references to its children and its parent. This 107 //! is to allow traversal of the whole tree from a given node making the 108 //! implementation of iterator a pointer to a node. 109 //! At the top of the tree a node is used specially. This node's parent pointer 110 //! is pointing to the root of the tree. Its left pointer points to the 111 //! leftmost node in the tree and the right pointer to the rightmost one. 112 //! This node is used to represent the end-iterator. 113 //! 114 //! +---------+ 115 //! header------------------------------>| | 116 //! | | 117 //! +----------(left)--------| |--------(right)---------+ 118 //! | +---------+ | 119 //! | | | 120 //! | | (parent) | 121 //! | | | 122 //! | | | 123 //! | +---------+ | 124 //! root of tree ..|......................> | | | 125 //! | | D | | 126 //! | | | | 127 //! | +-------+---------+-------+ | 128 //! | | | | 129 //! | | | | 130 //! | | | | 131 //! | | | | 132 //! | | | | 133 //! | +---------+ +---------+ | 134 //! | | | | | | 135 //! | | B | | F | | 136 //! | | | | | | 137 //! | +--+---------+--+ +--+---------+--+ | 138 //! | | | | | | 139 //! | | | | | | 140 //! | | | | | | 141 //! | +---+-----+ +-----+---+ +---+-----+ +-----+---+ | 142 //! +-->| | | | | | | |<--+ 143 //! | A | | C | | E | | G | 144 //! | | | | | | | | 145 //! +---------+ +---------+ +---------+ +---------+ 146 //! 147 //! bstree_algorithms is configured with a NodeTraits class, which encapsulates the 148 //! information about the node to be manipulated. NodeTraits must support the 149 //! following interface: 150 //! 151 //! <b>Typedefs</b>: 152 //! 153 //! <tt>node</tt>: The type of the node that forms the binary search tree 154 //! 155 //! <tt>node_ptr</tt>: A pointer to a node 156 //! 157 //! <tt>const_node_ptr</tt>: A pointer to a const node 158 //! 159 //! <b>Static functions</b>: 160 //! 161 //! <tt>static node_ptr get_parent(const_node_ptr n);</tt> 162 //! 163 //! <tt>static void set_parent(node_ptr n, node_ptr parent);</tt> 164 //! 165 //! <tt>static node_ptr get_left(const_node_ptr n);</tt> 166 //! 167 //! <tt>static void set_left(node_ptr n, node_ptr left);</tt> 168 //! 169 //! <tt>static node_ptr get_right(const_node_ptr n);</tt> 170 //! 171 //! <tt>static void set_right(node_ptr n, node_ptr right);</tt> 172 template<class NodeTraits> 173 class bstree_algorithms : public bstree_algorithms_base<NodeTraits> 174 { 175 public: 176 typedef typename NodeTraits::node node; 177 typedef NodeTraits node_traits; 178 typedef typename NodeTraits::node_ptr node_ptr; 179 typedef typename NodeTraits::const_node_ptr const_node_ptr; 180 typedef insert_commit_data_t<node_ptr> insert_commit_data; 181 typedef data_for_rebalance_t<node_ptr> data_for_rebalance; 182 183 /// @cond 184 typedef bstree_algorithms<NodeTraits> this_type; 185 typedef bstree_algorithms_base<NodeTraits> base_type; 186 private: 187 template<class Disposer> 188 struct dispose_subtree_disposer 189 { dispose_subtree_disposerboost::intrusive::bstree_algorithms::dispose_subtree_disposer190 BOOST_INTRUSIVE_FORCEINLINE dispose_subtree_disposer(Disposer &disp, const node_ptr & subtree) 191 : disposer_(&disp), subtree_(subtree) 192 {} 193 releaseboost::intrusive::bstree_algorithms::dispose_subtree_disposer194 BOOST_INTRUSIVE_FORCEINLINE void release() 195 { disposer_ = 0; } 196 ~dispose_subtree_disposerboost::intrusive::bstree_algorithms::dispose_subtree_disposer197 BOOST_INTRUSIVE_FORCEINLINE ~dispose_subtree_disposer() 198 { 199 if(disposer_){ 200 dispose_subtree(subtree_, *disposer_); 201 } 202 } 203 Disposer *disposer_; 204 const node_ptr subtree_; 205 }; 206 207 /// @endcond 208 209 public: 210 //! <b>Requires</b>: 'header' is the header node of a tree. 211 //! 212 //! <b>Effects</b>: Returns the first node of the tree, the header if the tree is empty. 213 //! 214 //! <b>Complexity</b>: Constant time. 215 //! 216 //! <b>Throws</b>: Nothing. begin_node(const const_node_ptr & header)217 BOOST_INTRUSIVE_FORCEINLINE static node_ptr begin_node(const const_node_ptr & header) 218 { return node_traits::get_left(header); } 219 220 //! <b>Requires</b>: 'header' is the header node of a tree. 221 //! 222 //! <b>Effects</b>: Returns the header of the tree. 223 //! 224 //! <b>Complexity</b>: Constant time. 225 //! 226 //! <b>Throws</b>: Nothing. end_node(const const_node_ptr & header)227 BOOST_INTRUSIVE_FORCEINLINE static node_ptr end_node(const const_node_ptr & header) 228 { return detail::uncast(header); } 229 230 //! <b>Requires</b>: 'header' is the header node of a tree. 231 //! 232 //! <b>Effects</b>: Returns the root of the tree if any, header otherwise 233 //! 234 //! <b>Complexity</b>: Constant time. 235 //! 236 //! <b>Throws</b>: Nothing. root_node(const const_node_ptr & header)237 BOOST_INTRUSIVE_FORCEINLINE static node_ptr root_node(const const_node_ptr & header) 238 { 239 node_ptr p = node_traits::get_parent(header); 240 return p ? p : detail::uncast(header); 241 } 242 243 //! <b>Requires</b>: 'node' is a node of the tree or a node initialized 244 //! by init(...) or init_node. 245 //! 246 //! <b>Effects</b>: Returns true if the node is initialized by init() or init_node(). 247 //! 248 //! <b>Complexity</b>: Constant time. 249 //! 250 //! <b>Throws</b>: Nothing. unique(const const_node_ptr & node)251 BOOST_INTRUSIVE_FORCEINLINE static bool unique(const const_node_ptr & node) 252 { return !NodeTraits::get_parent(node); } 253 254 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) 255 //! <b>Requires</b>: 'node' is a node of the tree or a header node. 256 //! 257 //! <b>Effects</b>: Returns the header of the tree. 258 //! 259 //! <b>Complexity</b>: Logarithmic. 260 //! 261 //! <b>Throws</b>: Nothing. 262 static node_ptr get_header(const const_node_ptr & node); 263 #endif 264 265 //! <b>Requires</b>: node1 and node2 can't be header nodes 266 //! of two trees. 267 //! 268 //! <b>Effects</b>: Swaps two nodes. After the function node1 will be inserted 269 //! in the position node2 before the function. node2 will be inserted in the 270 //! position node1 had before the function. 271 //! 272 //! <b>Complexity</b>: Logarithmic. 273 //! 274 //! <b>Throws</b>: Nothing. 275 //! 276 //! <b>Note</b>: This function will break container ordering invariants if 277 //! node1 and node2 are not equivalent according to the ordering rules. 278 //! 279 //!Experimental function swap_nodes(node_ptr node1,node_ptr node2)280 static void swap_nodes(node_ptr node1, node_ptr node2) 281 { 282 if(node1 == node2) 283 return; 284 285 node_ptr header1(base_type::get_header(node1)), header2(base_type::get_header(node2)); 286 swap_nodes(node1, header1, node2, header2); 287 } 288 289 //! <b>Requires</b>: node1 and node2 can't be header nodes 290 //! of two trees with header header1 and header2. 291 //! 292 //! <b>Effects</b>: Swaps two nodes. After the function node1 will be inserted 293 //! in the position node2 before the function. node2 will be inserted in the 294 //! position node1 had before the function. 295 //! 296 //! <b>Complexity</b>: Constant. 297 //! 298 //! <b>Throws</b>: Nothing. 299 //! 300 //! <b>Note</b>: This function will break container ordering invariants if 301 //! node1 and node2 are not equivalent according to the ordering rules. 302 //! 303 //!Experimental function swap_nodes(node_ptr node1,node_ptr header1,node_ptr node2,node_ptr header2)304 static void swap_nodes(node_ptr node1, node_ptr header1, node_ptr node2, node_ptr header2) 305 { 306 if(node1 == node2) 307 return; 308 309 //node1 and node2 must not be header nodes 310 //BOOST_INTRUSIVE_INVARIANT_ASSERT((header1 != node1 && header2 != node2)); 311 if(header1 != header2){ 312 //Update header1 if necessary 313 if(node1 == NodeTraits::get_left(header1)){ 314 NodeTraits::set_left(header1, node2); 315 } 316 317 if(node1 == NodeTraits::get_right(header1)){ 318 NodeTraits::set_right(header1, node2); 319 } 320 321 if(node1 == NodeTraits::get_parent(header1)){ 322 NodeTraits::set_parent(header1, node2); 323 } 324 325 //Update header2 if necessary 326 if(node2 == NodeTraits::get_left(header2)){ 327 NodeTraits::set_left(header2, node1); 328 } 329 330 if(node2 == NodeTraits::get_right(header2)){ 331 NodeTraits::set_right(header2, node1); 332 } 333 334 if(node2 == NodeTraits::get_parent(header2)){ 335 NodeTraits::set_parent(header2, node1); 336 } 337 } 338 else{ 339 //If both nodes are from the same tree 340 //Update header if necessary 341 if(node1 == NodeTraits::get_left(header1)){ 342 NodeTraits::set_left(header1, node2); 343 } 344 else if(node2 == NodeTraits::get_left(header2)){ 345 NodeTraits::set_left(header2, node1); 346 } 347 348 if(node1 == NodeTraits::get_right(header1)){ 349 NodeTraits::set_right(header1, node2); 350 } 351 else if(node2 == NodeTraits::get_right(header2)){ 352 NodeTraits::set_right(header2, node1); 353 } 354 355 if(node1 == NodeTraits::get_parent(header1)){ 356 NodeTraits::set_parent(header1, node2); 357 } 358 else if(node2 == NodeTraits::get_parent(header2)){ 359 NodeTraits::set_parent(header2, node1); 360 } 361 362 //Adjust data in nodes to be swapped 363 //so that final link swap works as expected 364 if(node1 == NodeTraits::get_parent(node2)){ 365 NodeTraits::set_parent(node2, node2); 366 367 if(node2 == NodeTraits::get_right(node1)){ 368 NodeTraits::set_right(node1, node1); 369 } 370 else{ 371 NodeTraits::set_left(node1, node1); 372 } 373 } 374 else if(node2 == NodeTraits::get_parent(node1)){ 375 NodeTraits::set_parent(node1, node1); 376 377 if(node1 == NodeTraits::get_right(node2)){ 378 NodeTraits::set_right(node2, node2); 379 } 380 else{ 381 NodeTraits::set_left(node2, node2); 382 } 383 } 384 } 385 386 //Now swap all the links 387 node_ptr temp; 388 //swap left link 389 temp = NodeTraits::get_left(node1); 390 NodeTraits::set_left(node1, NodeTraits::get_left(node2)); 391 NodeTraits::set_left(node2, temp); 392 //swap right link 393 temp = NodeTraits::get_right(node1); 394 NodeTraits::set_right(node1, NodeTraits::get_right(node2)); 395 NodeTraits::set_right(node2, temp); 396 //swap parent link 397 temp = NodeTraits::get_parent(node1); 398 NodeTraits::set_parent(node1, NodeTraits::get_parent(node2)); 399 NodeTraits::set_parent(node2, temp); 400 401 //Now adjust adjacent nodes for newly inserted node 1 402 if((temp = NodeTraits::get_left(node1))){ 403 NodeTraits::set_parent(temp, node1); 404 } 405 if((temp = NodeTraits::get_right(node1))){ 406 NodeTraits::set_parent(temp, node1); 407 } 408 if((temp = NodeTraits::get_parent(node1)) && 409 //The header has been already updated so avoid it 410 temp != header2){ 411 if(NodeTraits::get_left(temp) == node2){ 412 NodeTraits::set_left(temp, node1); 413 } 414 if(NodeTraits::get_right(temp) == node2){ 415 NodeTraits::set_right(temp, node1); 416 } 417 } 418 //Now adjust adjacent nodes for newly inserted node 2 419 if((temp = NodeTraits::get_left(node2))){ 420 NodeTraits::set_parent(temp, node2); 421 } 422 if((temp = NodeTraits::get_right(node2))){ 423 NodeTraits::set_parent(temp, node2); 424 } 425 if((temp = NodeTraits::get_parent(node2)) && 426 //The header has been already updated so avoid it 427 temp != header1){ 428 if(NodeTraits::get_left(temp) == node1){ 429 NodeTraits::set_left(temp, node2); 430 } 431 if(NodeTraits::get_right(temp) == node1){ 432 NodeTraits::set_right(temp, node2); 433 } 434 } 435 } 436 437 //! <b>Requires</b>: node_to_be_replaced must be inserted in a tree 438 //! and new_node must not be inserted in a tree. 439 //! 440 //! <b>Effects</b>: Replaces node_to_be_replaced in its position in the 441 //! tree with new_node. The tree does not need to be rebalanced 442 //! 443 //! <b>Complexity</b>: Logarithmic. 444 //! 445 //! <b>Throws</b>: Nothing. 446 //! 447 //! <b>Note</b>: This function will break container ordering invariants if 448 //! new_node is not equivalent to node_to_be_replaced according to the 449 //! ordering rules. This function is faster than erasing and inserting 450 //! the node, since no rebalancing and comparison is needed. Experimental function replace_node(node_ptr node_to_be_replaced,node_ptr new_node)451 BOOST_INTRUSIVE_FORCEINLINE static void replace_node(node_ptr node_to_be_replaced, node_ptr new_node) 452 { 453 if(node_to_be_replaced == new_node) 454 return; 455 replace_node(node_to_be_replaced, base_type::get_header(node_to_be_replaced), new_node); 456 } 457 458 //! <b>Requires</b>: node_to_be_replaced must be inserted in a tree 459 //! with header "header" and new_node must not be inserted in a tree. 460 //! 461 //! <b>Effects</b>: Replaces node_to_be_replaced in its position in the 462 //! tree with new_node. The tree does not need to be rebalanced 463 //! 464 //! <b>Complexity</b>: Constant. 465 //! 466 //! <b>Throws</b>: Nothing. 467 //! 468 //! <b>Note</b>: This function will break container ordering invariants if 469 //! new_node is not equivalent to node_to_be_replaced according to the 470 //! ordering rules. This function is faster than erasing and inserting 471 //! the node, since no rebalancing or comparison is needed. Experimental function replace_node(node_ptr node_to_be_replaced,node_ptr header,node_ptr new_node)472 static void replace_node(node_ptr node_to_be_replaced, node_ptr header, node_ptr new_node) 473 { 474 if(node_to_be_replaced == new_node) 475 return; 476 477 //Update header if necessary 478 if(node_to_be_replaced == NodeTraits::get_left(header)){ 479 NodeTraits::set_left(header, new_node); 480 } 481 482 if(node_to_be_replaced == NodeTraits::get_right(header)){ 483 NodeTraits::set_right(header, new_node); 484 } 485 486 if(node_to_be_replaced == NodeTraits::get_parent(header)){ 487 NodeTraits::set_parent(header, new_node); 488 } 489 490 //Now set data from the original node 491 node_ptr temp; 492 NodeTraits::set_left(new_node, NodeTraits::get_left(node_to_be_replaced)); 493 NodeTraits::set_right(new_node, NodeTraits::get_right(node_to_be_replaced)); 494 NodeTraits::set_parent(new_node, NodeTraits::get_parent(node_to_be_replaced)); 495 496 //Now adjust adjacent nodes for newly inserted node 497 if((temp = NodeTraits::get_left(new_node))){ 498 NodeTraits::set_parent(temp, new_node); 499 } 500 if((temp = NodeTraits::get_right(new_node))){ 501 NodeTraits::set_parent(temp, new_node); 502 } 503 if((temp = NodeTraits::get_parent(new_node)) && 504 //The header has been already updated so avoid it 505 temp != header){ 506 if(NodeTraits::get_left(temp) == node_to_be_replaced){ 507 NodeTraits::set_left(temp, new_node); 508 } 509 if(NodeTraits::get_right(temp) == node_to_be_replaced){ 510 NodeTraits::set_right(temp, new_node); 511 } 512 } 513 } 514 515 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) 516 //! <b>Requires</b>: 'node' is a node from the tree except the header. 517 //! 518 //! <b>Effects</b>: Returns the next node of the tree. 519 //! 520 //! <b>Complexity</b>: Average constant time. 521 //! 522 //! <b>Throws</b>: Nothing. 523 static node_ptr next_node(const node_ptr & node); 524 525 //! <b>Requires</b>: 'node' is a node from the tree except the leftmost node. 526 //! 527 //! <b>Effects</b>: Returns the previous node of the tree. 528 //! 529 //! <b>Complexity</b>: Average constant time. 530 //! 531 //! <b>Throws</b>: Nothing. 532 static node_ptr prev_node(const node_ptr & node); 533 534 //! <b>Requires</b>: 'node' is a node of a tree but not the header. 535 //! 536 //! <b>Effects</b>: Returns the minimum node of the subtree starting at p. 537 //! 538 //! <b>Complexity</b>: Logarithmic to the size of the subtree. 539 //! 540 //! <b>Throws</b>: Nothing. 541 static node_ptr minimum(node_ptr node); 542 543 //! <b>Requires</b>: 'node' is a node of a tree but not the header. 544 //! 545 //! <b>Effects</b>: Returns the maximum node of the subtree starting at p. 546 //! 547 //! <b>Complexity</b>: Logarithmic to the size of the subtree. 548 //! 549 //! <b>Throws</b>: Nothing. 550 static node_ptr maximum(node_ptr node); 551 #endif 552 553 //! <b>Requires</b>: 'node' must not be part of any tree. 554 //! 555 //! <b>Effects</b>: After the function unique(node) == true. 556 //! 557 //! <b>Complexity</b>: Constant. 558 //! 559 //! <b>Throws</b>: Nothing. 560 //! 561 //! <b>Nodes</b>: If node is inserted in a tree, this function corrupts the tree. init(node_ptr node)562 BOOST_INTRUSIVE_FORCEINLINE static void init(node_ptr node) 563 { 564 NodeTraits::set_parent(node, node_ptr()); 565 NodeTraits::set_left(node, node_ptr()); 566 NodeTraits::set_right(node, node_ptr()); 567 } 568 569 //! <b>Effects</b>: Returns true if node is in the same state as if called init(node) 570 //! 571 //! <b>Complexity</b>: Constant. 572 //! 573 //! <b>Throws</b>: Nothing. inited(const const_node_ptr & node)574 BOOST_INTRUSIVE_FORCEINLINE static bool inited(const const_node_ptr & node) 575 { 576 return !NodeTraits::get_parent(node) && 577 !NodeTraits::get_left(node) && 578 !NodeTraits::get_right(node) ; 579 } 580 581 //! <b>Requires</b>: node must not be part of any tree. 582 //! 583 //! <b>Effects</b>: Initializes the header to represent an empty tree. 584 //! unique(header) == true. 585 //! 586 //! <b>Complexity</b>: Constant. 587 //! 588 //! <b>Throws</b>: Nothing. 589 //! 590 //! <b>Nodes</b>: If node is inserted in a tree, this function corrupts the tree. init_header(node_ptr header)591 BOOST_INTRUSIVE_FORCEINLINE static void init_header(node_ptr header) 592 { 593 NodeTraits::set_parent(header, node_ptr()); 594 NodeTraits::set_left(header, header); 595 NodeTraits::set_right(header, header); 596 } 597 598 //! <b>Requires</b>: "disposer" must be an object function 599 //! taking a node_ptr parameter and shouldn't throw. 600 //! 601 //! <b>Effects</b>: Empties the target tree calling 602 //! <tt>void disposer::operator()(const node_ptr &)</tt> for every node of the tree 603 //! except the header. 604 //! 605 //! <b>Complexity</b>: Linear to the number of element of the source tree plus the. 606 //! number of elements of tree target tree when calling this function. 607 //! 608 //! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed. 609 template<class Disposer> clear_and_dispose(const node_ptr & header,Disposer disposer)610 static void clear_and_dispose(const node_ptr & header, Disposer disposer) 611 { 612 node_ptr source_root = NodeTraits::get_parent(header); 613 if(!source_root) 614 return; 615 dispose_subtree(source_root, disposer); 616 init_header(header); 617 } 618 619 //! <b>Requires</b>: header is the header of a tree. 620 //! 621 //! <b>Effects</b>: Unlinks the leftmost node from the tree, and 622 //! updates the header link to the new leftmost node. 623 //! 624 //! <b>Complexity</b>: Average complexity is constant time. 625 //! 626 //! <b>Throws</b>: Nothing. 627 //! 628 //! <b>Notes</b>: This function breaks the tree and the tree can 629 //! only be used for more unlink_leftmost_without_rebalance calls. 630 //! This function is normally used to achieve a step by step 631 //! controlled destruction of the tree. unlink_leftmost_without_rebalance(node_ptr header)632 static node_ptr unlink_leftmost_without_rebalance(node_ptr header) 633 { 634 node_ptr leftmost = NodeTraits::get_left(header); 635 if (leftmost == header) 636 return node_ptr(); 637 node_ptr leftmost_parent(NodeTraits::get_parent(leftmost)); 638 node_ptr leftmost_right (NodeTraits::get_right(leftmost)); 639 bool is_root = leftmost_parent == header; 640 641 if (leftmost_right){ 642 NodeTraits::set_parent(leftmost_right, leftmost_parent); 643 NodeTraits::set_left(header, base_type::minimum(leftmost_right)); 644 645 if (is_root) 646 NodeTraits::set_parent(header, leftmost_right); 647 else 648 NodeTraits::set_left(NodeTraits::get_parent(header), leftmost_right); 649 } 650 else if (is_root){ 651 NodeTraits::set_parent(header, node_ptr()); 652 NodeTraits::set_left(header, header); 653 NodeTraits::set_right(header, header); 654 } 655 else{ 656 NodeTraits::set_left(leftmost_parent, node_ptr()); 657 NodeTraits::set_left(header, leftmost_parent); 658 } 659 return leftmost; 660 } 661 662 //! <b>Requires</b>: node is a node of the tree but it's not the header. 663 //! 664 //! <b>Effects</b>: Returns the number of nodes of the subtree. 665 //! 666 //! <b>Complexity</b>: Linear time. 667 //! 668 //! <b>Throws</b>: Nothing. size(const const_node_ptr & header)669 static std::size_t size(const const_node_ptr & header) 670 { 671 node_ptr beg(begin_node(header)); 672 node_ptr end(end_node(header)); 673 std::size_t i = 0; 674 for(;beg != end; beg = base_type::next_node(beg)) ++i; 675 return i; 676 } 677 678 //! <b>Requires</b>: header1 and header2 must be the header nodes 679 //! of two trees. 680 //! 681 //! <b>Effects</b>: Swaps two trees. After the function header1 will contain 682 //! links to the second tree and header2 will have links to the first tree. 683 //! 684 //! <b>Complexity</b>: Constant. 685 //! 686 //! <b>Throws</b>: Nothing. swap_tree(node_ptr header1,node_ptr header2)687 static void swap_tree(node_ptr header1, node_ptr header2) 688 { 689 if(header1 == header2) 690 return; 691 692 node_ptr tmp; 693 694 //Parent swap 695 tmp = NodeTraits::get_parent(header1); 696 NodeTraits::set_parent(header1, NodeTraits::get_parent(header2)); 697 NodeTraits::set_parent(header2, tmp); 698 //Left swap 699 tmp = NodeTraits::get_left(header1); 700 NodeTraits::set_left(header1, NodeTraits::get_left(header2)); 701 NodeTraits::set_left(header2, tmp); 702 //Right swap 703 tmp = NodeTraits::get_right(header1); 704 NodeTraits::set_right(header1, NodeTraits::get_right(header2)); 705 NodeTraits::set_right(header2, tmp); 706 707 //Now test parent 708 node_ptr h1_parent(NodeTraits::get_parent(header1)); 709 if(h1_parent){ 710 NodeTraits::set_parent(h1_parent, header1); 711 } 712 else{ 713 NodeTraits::set_left(header1, header1); 714 NodeTraits::set_right(header1, header1); 715 } 716 717 node_ptr h2_parent(NodeTraits::get_parent(header2)); 718 if(h2_parent){ 719 NodeTraits::set_parent(h2_parent, header2); 720 } 721 else{ 722 NodeTraits::set_left(header2, header2); 723 NodeTraits::set_right(header2, header2); 724 } 725 } 726 727 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) 728 //! <b>Requires</b>: p is a node of a tree. 729 //! 730 //! <b>Effects</b>: Returns true if p is the header of the tree. 731 //! 732 //! <b>Complexity</b>: Constant. 733 //! 734 //! <b>Throws</b>: Nothing. 735 static bool is_header(const const_node_ptr & p); 736 #endif 737 738 //! <b>Requires</b>: "header" must be the header node of a tree. 739 //! KeyNodePtrCompare is a function object that induces a strict weak 740 //! ordering compatible with the strict weak ordering used to create the 741 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. 742 //! 743 //! <b>Effects</b>: Returns a node_ptr to the first element that is equivalent to 744 //! "key" according to "comp" or "header" if that element does not exist. 745 //! 746 //! <b>Complexity</b>: Logarithmic. 747 //! 748 //! <b>Throws</b>: If "comp" throws. 749 template<class KeyType, class KeyNodePtrCompare> find(const const_node_ptr & header,const KeyType & key,KeyNodePtrCompare comp)750 static node_ptr find 751 (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) 752 { 753 node_ptr end = detail::uncast(header); 754 node_ptr y = lower_bound(header, key, comp); 755 return (y == end || comp(key, y)) ? end : y; 756 } 757 758 //! <b>Requires</b>: "header" must be the header node of a tree. 759 //! KeyNodePtrCompare is a function object that induces a strict weak 760 //! ordering compatible with the strict weak ordering used to create the 761 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. 762 //! 'lower_key' must not be greater than 'upper_key' according to 'comp'. If 763 //! 'lower_key' == 'upper_key', ('left_closed' || 'right_closed') must be true. 764 //! 765 //! <b>Effects</b>: Returns an a pair with the following criteria: 766 //! 767 //! first = lower_bound(lower_key) if left_closed, upper_bound(lower_key) otherwise 768 //! 769 //! second = upper_bound(upper_key) if right_closed, lower_bound(upper_key) otherwise 770 //! 771 //! <b>Complexity</b>: Logarithmic. 772 //! 773 //! <b>Throws</b>: If "comp" throws. 774 //! 775 //! <b>Note</b>: This function can be more efficient than calling upper_bound 776 //! and lower_bound for lower_key and upper_key. 777 //! 778 //! <b>Note</b>: Experimental function, the interface might change. 779 template< class KeyType, class KeyNodePtrCompare> bounded_range(const const_node_ptr & header,const KeyType & lower_key,const KeyType & upper_key,KeyNodePtrCompare comp,bool left_closed,bool right_closed)780 static std::pair<node_ptr, node_ptr> bounded_range 781 ( const const_node_ptr & header 782 , const KeyType &lower_key 783 , const KeyType &upper_key 784 , KeyNodePtrCompare comp 785 , bool left_closed 786 , bool right_closed) 787 { 788 node_ptr y = detail::uncast(header); 789 node_ptr x = NodeTraits::get_parent(header); 790 791 while(x){ 792 //If x is less than lower_key the target 793 //range is on the right part 794 if(comp(x, lower_key)){ 795 //Check for invalid input range 796 BOOST_INTRUSIVE_INVARIANT_ASSERT(comp(x, upper_key)); 797 x = NodeTraits::get_right(x); 798 } 799 //If the upper_key is less than x, the target 800 //range is on the left part 801 else if(comp(upper_key, x)){ 802 y = x; 803 x = NodeTraits::get_left(x); 804 } 805 else{ 806 //x is inside the bounded range(lower_key <= x <= upper_key), 807 //so we must split lower and upper searches 808 // 809 //Sanity check: if lower_key and upper_key are equal, then both left_closed and right_closed can't be false 810 BOOST_INTRUSIVE_INVARIANT_ASSERT(left_closed || right_closed || comp(lower_key, x) || comp(x, upper_key)); 811 return std::pair<node_ptr,node_ptr>( 812 left_closed 813 //If left_closed, then comp(x, lower_key) is already the lower_bound 814 //condition so we save one comparison and go to the next level 815 //following traditional lower_bound algo 816 ? lower_bound_loop(NodeTraits::get_left(x), x, lower_key, comp) 817 //If left-open, comp(x, lower_key) is not the upper_bound algo 818 //condition so we must recheck current 'x' node with upper_bound algo 819 : upper_bound_loop(x, y, lower_key, comp) 820 , 821 right_closed 822 //If right_closed, then comp(upper_key, x) is already the upper_bound 823 //condition so we can save one comparison and go to the next level 824 //following lower_bound algo 825 ? upper_bound_loop(NodeTraits::get_right(x), y, upper_key, comp) 826 //If right-open, comp(upper_key, x) is not the lower_bound algo 827 //condition so we must recheck current 'x' node with lower_bound algo 828 : lower_bound_loop(x, y, upper_key, comp) 829 ); 830 } 831 } 832 return std::pair<node_ptr,node_ptr> (y, y); 833 } 834 835 //! <b>Requires</b>: "header" must be the header node of a tree. 836 //! KeyNodePtrCompare is a function object that induces a strict weak 837 //! ordering compatible with the strict weak ordering used to create the 838 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. 839 //! 840 //! <b>Effects</b>: Returns the number of elements with a key equivalent to "key" 841 //! according to "comp". 842 //! 843 //! <b>Complexity</b>: Logarithmic. 844 //! 845 //! <b>Throws</b>: If "comp" throws. 846 template<class KeyType, class KeyNodePtrCompare> count(const const_node_ptr & header,const KeyType & key,KeyNodePtrCompare comp)847 static std::size_t count 848 (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) 849 { 850 std::pair<node_ptr, node_ptr> ret = equal_range(header, key, comp); 851 std::size_t n = 0; 852 while(ret.first != ret.second){ 853 ++n; 854 ret.first = base_type::next_node(ret.first); 855 } 856 return n; 857 } 858 859 //! <b>Requires</b>: "header" must be the header node of a tree. 860 //! KeyNodePtrCompare is a function object that induces a strict weak 861 //! ordering compatible with the strict weak ordering used to create the 862 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. 863 //! 864 //! <b>Effects</b>: Returns an a pair of node_ptr delimiting a range containing 865 //! all elements that are equivalent to "key" according to "comp" or an 866 //! empty range that indicates the position where those elements would be 867 //! if there are no equivalent elements. 868 //! 869 //! <b>Complexity</b>: Logarithmic. 870 //! 871 //! <b>Throws</b>: If "comp" throws. 872 template<class KeyType, class KeyNodePtrCompare> equal_range(const const_node_ptr & header,const KeyType & key,KeyNodePtrCompare comp)873 BOOST_INTRUSIVE_FORCEINLINE static std::pair<node_ptr, node_ptr> equal_range 874 (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) 875 { 876 return bounded_range(header, key, key, comp, true, true); 877 } 878 879 //! <b>Requires</b>: "header" must be the header node of a tree. 880 //! KeyNodePtrCompare is a function object that induces a strict weak 881 //! ordering compatible with the strict weak ordering used to create the 882 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. 883 //! 884 //! <b>Effects</b>: Returns an a pair of node_ptr delimiting a range containing 885 //! the first element that is equivalent to "key" according to "comp" or an 886 //! empty range that indicates the position where that element would be 887 //! if there are no equivalent elements. 888 //! 889 //! <b>Complexity</b>: Logarithmic. 890 //! 891 //! <b>Throws</b>: If "comp" throws. 892 template<class KeyType, class KeyNodePtrCompare> lower_bound_range(const const_node_ptr & header,const KeyType & key,KeyNodePtrCompare comp)893 static std::pair<node_ptr, node_ptr> lower_bound_range 894 (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) 895 { 896 node_ptr const lb(lower_bound(header, key, comp)); 897 std::pair<node_ptr, node_ptr> ret_ii(lb, lb); 898 if(lb != header && !comp(key, lb)){ 899 ret_ii.second = base_type::next_node(ret_ii.second); 900 } 901 return ret_ii; 902 } 903 904 //! <b>Requires</b>: "header" must be the header node of a tree. 905 //! KeyNodePtrCompare is a function object that induces a strict weak 906 //! ordering compatible with the strict weak ordering used to create the 907 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. 908 //! 909 //! <b>Effects</b>: Returns a node_ptr to the first element that is 910 //! not less than "key" according to "comp" or "header" if that element does 911 //! not exist. 912 //! 913 //! <b>Complexity</b>: Logarithmic. 914 //! 915 //! <b>Throws</b>: If "comp" throws. 916 template<class KeyType, class KeyNodePtrCompare> lower_bound(const const_node_ptr & header,const KeyType & key,KeyNodePtrCompare comp)917 BOOST_INTRUSIVE_FORCEINLINE static node_ptr lower_bound 918 (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) 919 { 920 return lower_bound_loop(NodeTraits::get_parent(header), detail::uncast(header), key, comp); 921 } 922 923 //! <b>Requires</b>: "header" must be the header node of a tree. 924 //! KeyNodePtrCompare is a function object that induces a strict weak 925 //! ordering compatible with the strict weak ordering used to create the 926 //! the tree. KeyNodePtrCompare can compare KeyType with tree's node_ptrs. 927 //! 928 //! <b>Effects</b>: Returns a node_ptr to the first element that is greater 929 //! than "key" according to "comp" or "header" if that element does not exist. 930 //! 931 //! <b>Complexity</b>: Logarithmic. 932 //! 933 //! <b>Throws</b>: If "comp" throws. 934 template<class KeyType, class KeyNodePtrCompare> upper_bound(const const_node_ptr & header,const KeyType & key,KeyNodePtrCompare comp)935 BOOST_INTRUSIVE_FORCEINLINE static node_ptr upper_bound 936 (const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp) 937 { 938 return upper_bound_loop(NodeTraits::get_parent(header), detail::uncast(header), key, comp); 939 } 940 941 //! <b>Requires</b>: "header" must be the header node of a tree. 942 //! "commit_data" must have been obtained from a previous call to 943 //! "insert_unique_check". No objects should have been inserted or erased 944 //! from the set between the "insert_unique_check" that filled "commit_data" 945 //! and the call to "insert_commit". 946 //! 947 //! 948 //! <b>Effects</b>: Inserts new_node in the set using the information obtained 949 //! from the "commit_data" that a previous "insert_check" filled. 950 //! 951 //! <b>Complexity</b>: Constant time. 952 //! 953 //! <b>Throws</b>: Nothing. 954 //! 955 //! <b>Notes</b>: This function has only sense if a "insert_unique_check" has been 956 //! previously executed to fill "commit_data". No value should be inserted or 957 //! erased between the "insert_check" and "insert_commit" calls. insert_unique_commit(node_ptr header,node_ptr new_value,const insert_commit_data & commit_data)958 BOOST_INTRUSIVE_FORCEINLINE static void insert_unique_commit 959 (node_ptr header, node_ptr new_value, const insert_commit_data &commit_data) 960 { return insert_commit(header, new_value, commit_data); } 961 962 //! <b>Requires</b>: "header" must be the header node of a tree. 963 //! KeyNodePtrCompare is a function object that induces a strict weak 964 //! ordering compatible with the strict weak ordering used to create the 965 //! the tree. NodePtrCompare compares KeyType with a node_ptr. 966 //! 967 //! <b>Effects</b>: Checks if there is an equivalent node to "key" in the 968 //! tree according to "comp" and obtains the needed information to realize 969 //! a constant-time node insertion if there is no equivalent node. 970 //! 971 //! <b>Returns</b>: If there is an equivalent value 972 //! returns a pair containing a node_ptr to the already present node 973 //! and false. If there is not equivalent key can be inserted returns true 974 //! in the returned pair's boolean and fills "commit_data" that is meant to 975 //! be used with the "insert_commit" function to achieve a constant-time 976 //! insertion function. 977 //! 978 //! <b>Complexity</b>: Average complexity is at most logarithmic. 979 //! 980 //! <b>Throws</b>: If "comp" throws. 981 //! 982 //! <b>Notes</b>: This function is used to improve performance when constructing 983 //! a node is expensive and the user does not want to have two equivalent nodes 984 //! in the tree: if there is an equivalent value 985 //! the constructed object must be discarded. Many times, the part of the 986 //! node that is used to impose the order is much cheaper to construct 987 //! than the node and this function offers the possibility to use that part 988 //! to check if the insertion will be successful. 989 //! 990 //! If the check is successful, the user can construct the node and use 991 //! "insert_commit" to insert the node in constant-time. This gives a total 992 //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). 993 //! 994 //! "commit_data" remains valid for a subsequent "insert_unique_commit" only 995 //! if no more objects are inserted or erased from the set. 996 template<class KeyType, class KeyNodePtrCompare> insert_unique_check(const const_node_ptr & header,const KeyType & key,KeyNodePtrCompare comp,insert_commit_data & commit_data,std::size_t * pdepth=0)997 static std::pair<node_ptr, bool> insert_unique_check 998 (const const_node_ptr & header, const KeyType &key 999 ,KeyNodePtrCompare comp, insert_commit_data &commit_data 1000 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED 1001 , std::size_t *pdepth = 0 1002 #endif 1003 ) 1004 { 1005 std::size_t depth = 0; 1006 node_ptr h(detail::uncast(header)); 1007 node_ptr y(h); 1008 node_ptr x(NodeTraits::get_parent(y)); 1009 node_ptr prev = node_ptr(); 1010 1011 //Find the upper bound, cache the previous value and if we should 1012 //store it in the left or right node 1013 bool left_child = true; 1014 while(x){ 1015 ++depth; 1016 y = x; 1017 x = (left_child = comp(key, x)) ? 1018 NodeTraits::get_left(x) : (prev = y, NodeTraits::get_right(x)); 1019 } 1020 1021 if(pdepth) *pdepth = depth; 1022 1023 //Since we've found the upper bound there is no other value with the same key if: 1024 // - There is no previous node 1025 // - The previous node is less than the key 1026 const bool not_present = !prev || comp(prev, key); 1027 if(not_present){ 1028 commit_data.link_left = left_child; 1029 commit_data.node = y; 1030 } 1031 return std::pair<node_ptr, bool>(prev, not_present); 1032 } 1033 1034 //! <b>Requires</b>: "header" must be the header node of a tree. 1035 //! KeyNodePtrCompare is a function object that induces a strict weak 1036 //! ordering compatible with the strict weak ordering used to create the 1037 //! the tree. NodePtrCompare compares KeyType with a node_ptr. 1038 //! "hint" is node from the "header"'s tree. 1039 //! 1040 //! <b>Effects</b>: Checks if there is an equivalent node to "key" in the 1041 //! tree according to "comp" using "hint" as a hint to where it should be 1042 //! inserted and obtains the needed information to realize 1043 //! a constant-time node insertion if there is no equivalent node. 1044 //! If "hint" is the upper_bound the function has constant time 1045 //! complexity (two comparisons in the worst case). 1046 //! 1047 //! <b>Returns</b>: If there is an equivalent value 1048 //! returns a pair containing a node_ptr to the already present node 1049 //! and false. If there is not equivalent key can be inserted returns true 1050 //! in the returned pair's boolean and fills "commit_data" that is meant to 1051 //! be used with the "insert_commit" function to achieve a constant-time 1052 //! insertion function. 1053 //! 1054 //! <b>Complexity</b>: Average complexity is at most logarithmic, but it is 1055 //! amortized constant time if new_node should be inserted immediately before "hint". 1056 //! 1057 //! <b>Throws</b>: If "comp" throws. 1058 //! 1059 //! <b>Notes</b>: This function is used to improve performance when constructing 1060 //! a node is expensive and the user does not want to have two equivalent nodes 1061 //! in the tree: if there is an equivalent value 1062 //! the constructed object must be discarded. Many times, the part of the 1063 //! node that is used to impose the order is much cheaper to construct 1064 //! than the node and this function offers the possibility to use that part 1065 //! to check if the insertion will be successful. 1066 //! 1067 //! If the check is successful, the user can construct the node and use 1068 //! "insert_commit" to insert the node in constant-time. This gives a total 1069 //! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)). 1070 //! 1071 //! "commit_data" remains valid for a subsequent "insert_unique_commit" only 1072 //! if no more objects are inserted or erased from the set. 1073 template<class KeyType, class KeyNodePtrCompare> insert_unique_check(const const_node_ptr & header,const node_ptr & hint,const KeyType & key,KeyNodePtrCompare comp,insert_commit_data & commit_data,std::size_t * pdepth=0)1074 static std::pair<node_ptr, bool> insert_unique_check 1075 (const const_node_ptr & header, const node_ptr &hint, const KeyType &key 1076 ,KeyNodePtrCompare comp, insert_commit_data &commit_data 1077 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED 1078 , std::size_t *pdepth = 0 1079 #endif 1080 ) 1081 { 1082 //hint must be bigger than the key 1083 if(hint == header || comp(key, hint)){ 1084 node_ptr prev(hint); 1085 //Previous value should be less than the key 1086 if(hint == begin_node(header) || comp((prev = base_type::prev_node(hint)), key)){ 1087 commit_data.link_left = unique(header) || !NodeTraits::get_left(hint); 1088 commit_data.node = commit_data.link_left ? hint : prev; 1089 if(pdepth){ 1090 *pdepth = commit_data.node == header ? 0 : depth(commit_data.node) + 1; 1091 } 1092 return std::pair<node_ptr, bool>(node_ptr(), true); 1093 } 1094 } 1095 //Hint was wrong, use hintless insertion 1096 return insert_unique_check(header, key, comp, commit_data, pdepth); 1097 } 1098 1099 //! <b>Requires</b>: "header" must be the header node of a tree. 1100 //! NodePtrCompare is a function object that induces a strict weak 1101 //! ordering compatible with the strict weak ordering used to create the 1102 //! the tree. NodePtrCompare compares two node_ptrs. "hint" is node from 1103 //! the "header"'s tree. 1104 //! 1105 //! <b>Effects</b>: Inserts new_node into the tree, using "hint" as a hint to 1106 //! where it will be inserted. If "hint" is the upper_bound 1107 //! the insertion takes constant time (two comparisons in the worst case). 1108 //! 1109 //! <b>Complexity</b>: Logarithmic in general, but it is amortized 1110 //! constant time if new_node is inserted immediately before "hint". 1111 //! 1112 //! <b>Throws</b>: If "comp" throws. 1113 template<class NodePtrCompare> insert_equal(node_ptr h,node_ptr hint,node_ptr new_node,NodePtrCompare comp,std::size_t * pdepth=0)1114 static node_ptr insert_equal 1115 (node_ptr h, node_ptr hint, node_ptr new_node, NodePtrCompare comp 1116 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED 1117 , std::size_t *pdepth = 0 1118 #endif 1119 ) 1120 { 1121 insert_commit_data commit_data; 1122 insert_equal_check(h, hint, new_node, comp, commit_data, pdepth); 1123 insert_commit(h, new_node, commit_data); 1124 return new_node; 1125 } 1126 1127 //! <b>Requires</b>: "h" must be the header node of a tree. 1128 //! NodePtrCompare is a function object that induces a strict weak 1129 //! ordering compatible with the strict weak ordering used to create the 1130 //! the tree. NodePtrCompare compares two node_ptrs. 1131 //! 1132 //! <b>Effects</b>: Inserts new_node into the tree before the upper bound 1133 //! according to "comp". 1134 //! 1135 //! <b>Complexity</b>: Average complexity for insert element is at 1136 //! most logarithmic. 1137 //! 1138 //! <b>Throws</b>: If "comp" throws. 1139 template<class NodePtrCompare> insert_equal_upper_bound(node_ptr h,node_ptr new_node,NodePtrCompare comp,std::size_t * pdepth=0)1140 static node_ptr insert_equal_upper_bound 1141 (node_ptr h, node_ptr new_node, NodePtrCompare comp 1142 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED 1143 , std::size_t *pdepth = 0 1144 #endif 1145 ) 1146 { 1147 insert_commit_data commit_data; 1148 insert_equal_upper_bound_check(h, new_node, comp, commit_data, pdepth); 1149 insert_commit(h, new_node, commit_data); 1150 return new_node; 1151 } 1152 1153 //! <b>Requires</b>: "h" must be the header node of a tree. 1154 //! NodePtrCompare is a function object that induces a strict weak 1155 //! ordering compatible with the strict weak ordering used to create the 1156 //! the tree. NodePtrCompare compares two node_ptrs. 1157 //! 1158 //! <b>Effects</b>: Inserts new_node into the tree before the lower bound 1159 //! according to "comp". 1160 //! 1161 //! <b>Complexity</b>: Average complexity for insert element is at 1162 //! most logarithmic. 1163 //! 1164 //! <b>Throws</b>: If "comp" throws. 1165 template<class NodePtrCompare> insert_equal_lower_bound(node_ptr h,node_ptr new_node,NodePtrCompare comp,std::size_t * pdepth=0)1166 static node_ptr insert_equal_lower_bound 1167 (node_ptr h, node_ptr new_node, NodePtrCompare comp 1168 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED 1169 , std::size_t *pdepth = 0 1170 #endif 1171 ) 1172 { 1173 insert_commit_data commit_data; 1174 insert_equal_lower_bound_check(h, new_node, comp, commit_data, pdepth); 1175 insert_commit(h, new_node, commit_data); 1176 return new_node; 1177 } 1178 1179 //! <b>Requires</b>: "header" must be the header node of a tree. 1180 //! "pos" must be a valid iterator or header (end) node. 1181 //! "pos" must be an iterator pointing to the successor to "new_node" 1182 //! once inserted according to the order of already inserted nodes. This function does not 1183 //! check "pos" and this precondition must be guaranteed by the caller. 1184 //! 1185 //! <b>Effects</b>: Inserts new_node into the tree before "pos". 1186 //! 1187 //! <b>Complexity</b>: Constant-time. 1188 //! 1189 //! <b>Throws</b>: Nothing. 1190 //! 1191 //! <b>Note</b>: If "pos" is not the successor of the newly inserted "new_node" 1192 //! tree invariants might be broken. insert_before(node_ptr header,node_ptr pos,node_ptr new_node,std::size_t * pdepth=0)1193 static node_ptr insert_before 1194 (node_ptr header, node_ptr pos, node_ptr new_node 1195 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED 1196 , std::size_t *pdepth = 0 1197 #endif 1198 ) 1199 { 1200 insert_commit_data commit_data; 1201 insert_before_check(header, pos, commit_data, pdepth); 1202 insert_commit(header, new_node, commit_data); 1203 return new_node; 1204 } 1205 1206 //! <b>Requires</b>: "header" must be the header node of a tree. 1207 //! "new_node" must be, according to the used ordering no less than the 1208 //! greatest inserted key. 1209 //! 1210 //! <b>Effects</b>: Inserts new_node into the tree before "pos". 1211 //! 1212 //! <b>Complexity</b>: Constant-time. 1213 //! 1214 //! <b>Throws</b>: Nothing. 1215 //! 1216 //! <b>Note</b>: If "new_node" is less than the greatest inserted key 1217 //! tree invariants are broken. This function is slightly faster than 1218 //! using "insert_before". push_back(node_ptr header,node_ptr new_node,std::size_t * pdepth=0)1219 static void push_back 1220 (node_ptr header, node_ptr new_node 1221 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED 1222 , std::size_t *pdepth = 0 1223 #endif 1224 ) 1225 { 1226 insert_commit_data commit_data; 1227 push_back_check(header, commit_data, pdepth); 1228 insert_commit(header, new_node, commit_data); 1229 } 1230 1231 //! <b>Requires</b>: "header" must be the header node of a tree. 1232 //! "new_node" must be, according to the used ordering, no greater than the 1233 //! lowest inserted key. 1234 //! 1235 //! <b>Effects</b>: Inserts new_node into the tree before "pos". 1236 //! 1237 //! <b>Complexity</b>: Constant-time. 1238 //! 1239 //! <b>Throws</b>: Nothing. 1240 //! 1241 //! <b>Note</b>: If "new_node" is greater than the lowest inserted key 1242 //! tree invariants are broken. This function is slightly faster than 1243 //! using "insert_before". push_front(node_ptr header,node_ptr new_node,std::size_t * pdepth=0)1244 static void push_front 1245 (node_ptr header, node_ptr new_node 1246 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED 1247 , std::size_t *pdepth = 0 1248 #endif 1249 ) 1250 { 1251 insert_commit_data commit_data; 1252 push_front_check(header, commit_data, pdepth); 1253 insert_commit(header, new_node, commit_data); 1254 } 1255 1256 //! <b>Requires</b>: 'node' can't be a header node. 1257 //! 1258 //! <b>Effects</b>: Calculates the depth of a node: the depth of a 1259 //! node is the length (number of edges) of the path from the root 1260 //! to that node. (The root node is at depth 0.) 1261 //! 1262 //! <b>Complexity</b>: Logarithmic to the number of nodes in the tree. 1263 //! 1264 //! <b>Throws</b>: Nothing. depth(const_node_ptr node)1265 static std::size_t depth(const_node_ptr node) 1266 { 1267 std::size_t depth = 0; 1268 node_ptr p_parent; 1269 while(node != NodeTraits::get_parent(p_parent = NodeTraits::get_parent(node))){ 1270 ++depth; 1271 node = p_parent; 1272 } 1273 return depth; 1274 } 1275 1276 //! <b>Requires</b>: "cloner" must be a function 1277 //! object taking a node_ptr and returning a new cloned node of it. "disposer" must 1278 //! take a node_ptr and shouldn't throw. 1279 //! 1280 //! <b>Effects</b>: First empties target tree calling 1281 //! <tt>void disposer::operator()(const node_ptr &)</tt> for every node of the tree 1282 //! except the header. 1283 //! 1284 //! Then, duplicates the entire tree pointed by "source_header" cloning each 1285 //! source node with <tt>node_ptr Cloner::operator()(const node_ptr &)</tt> to obtain 1286 //! the nodes of the target tree. If "cloner" throws, the cloned target nodes 1287 //! are disposed using <tt>void disposer(const node_ptr &)</tt>. 1288 //! 1289 //! <b>Complexity</b>: Linear to the number of element of the source tree plus the 1290 //! number of elements of tree target tree when calling this function. 1291 //! 1292 //! <b>Throws</b>: If cloner functor throws. If this happens target nodes are disposed. 1293 template <class Cloner, class Disposer> clone(const const_node_ptr & source_header,node_ptr target_header,Cloner cloner,Disposer disposer)1294 static void clone 1295 (const const_node_ptr & source_header, node_ptr target_header, Cloner cloner, Disposer disposer) 1296 { 1297 if(!unique(target_header)){ 1298 clear_and_dispose(target_header, disposer); 1299 } 1300 1301 node_ptr leftmost, rightmost; 1302 node_ptr new_root = clone_subtree 1303 (source_header, target_header, cloner, disposer, leftmost, rightmost); 1304 1305 //Now update header node 1306 NodeTraits::set_parent(target_header, new_root); 1307 NodeTraits::set_left (target_header, leftmost); 1308 NodeTraits::set_right (target_header, rightmost); 1309 } 1310 1311 //! <b>Requires</b>: header must be the header of a tree, z a node 1312 //! of that tree and z != header. 1313 //! 1314 //! <b>Effects</b>: Erases node "z" from the tree with header "header". 1315 //! 1316 //! <b>Complexity</b>: Amortized constant time. 1317 //! 1318 //! <b>Throws</b>: Nothing. erase(node_ptr header,node_ptr z)1319 BOOST_INTRUSIVE_FORCEINLINE static void erase(node_ptr header, node_ptr z) 1320 { 1321 data_for_rebalance ignored; 1322 erase(header, z, ignored); 1323 } 1324 1325 //! <b>Requires</b>: header1 and header2 must be the headers of trees tree1 and tree2 1326 //! respectively, z a non-header node of tree1. NodePtrCompare is the comparison 1327 //! function of tree1.. 1328 //! 1329 //! <b>Effects</b>: Transfers node "z" from tree1 to tree2 if tree1 does not contain 1330 //! a node that is equivalent to z. 1331 //! 1332 //! <b>Returns</b>: True if the node was trasferred, false otherwise. 1333 //! 1334 //! <b>Complexity</b>: Logarithmic. 1335 //! 1336 //! <b>Throws</b>: If the comparison throws. 1337 template<class NodePtrCompare> transfer_unique(node_ptr header1,NodePtrCompare comp,node_ptr header2,node_ptr z)1338 BOOST_INTRUSIVE_FORCEINLINE static bool transfer_unique 1339 (node_ptr header1, NodePtrCompare comp, node_ptr header2, node_ptr z) 1340 { 1341 data_for_rebalance ignored; 1342 return transfer_unique(header1, comp, header2, z, ignored); 1343 } 1344 1345 //! <b>Requires</b>: header1 and header2 must be the headers of trees tree1 and tree2 1346 //! respectively, z a non-header node of tree1. NodePtrCompare is the comparison 1347 //! function of tree1.. 1348 //! 1349 //! <b>Effects</b>: Transfers node "z" from tree1 to tree2. 1350 //! 1351 //! <b>Complexity</b>: Logarithmic. 1352 //! 1353 //! <b>Throws</b>: If the comparison throws. 1354 template<class NodePtrCompare> transfer_equal(node_ptr header1,NodePtrCompare comp,node_ptr header2,node_ptr z)1355 BOOST_INTRUSIVE_FORCEINLINE static void transfer_equal 1356 (node_ptr header1, NodePtrCompare comp, node_ptr header2, node_ptr z) 1357 { 1358 data_for_rebalance ignored; 1359 transfer_equal(header1, comp, header2, z, ignored); 1360 } 1361 1362 //! <b>Requires</b>: node is a tree node but not the header. 1363 //! 1364 //! <b>Effects</b>: Unlinks the node and rebalances the tree. 1365 //! 1366 //! <b>Complexity</b>: Average complexity is constant time. 1367 //! 1368 //! <b>Throws</b>: Nothing. unlink(node_ptr node)1369 static void unlink(node_ptr node) 1370 { 1371 node_ptr x = NodeTraits::get_parent(node); 1372 if(x){ 1373 while(!base_type::is_header(x)) 1374 x = NodeTraits::get_parent(x); 1375 erase(x, node); 1376 } 1377 } 1378 1379 //! <b>Requires</b>: header must be the header of a tree. 1380 //! 1381 //! <b>Effects</b>: Rebalances the tree. 1382 //! 1383 //! <b>Throws</b>: Nothing. 1384 //! 1385 //! <b>Complexity</b>: Linear. rebalance(node_ptr header)1386 static void rebalance(node_ptr header) 1387 { 1388 node_ptr root = NodeTraits::get_parent(header); 1389 if(root){ 1390 rebalance_subtree(root); 1391 } 1392 } 1393 1394 //! <b>Requires</b>: old_root is a node of a tree. It shall not be null. 1395 //! 1396 //! <b>Effects</b>: Rebalances the subtree rooted at old_root. 1397 //! 1398 //! <b>Returns</b>: The new root of the subtree. 1399 //! 1400 //! <b>Throws</b>: Nothing. 1401 //! 1402 //! <b>Complexity</b>: Linear. rebalance_subtree(node_ptr old_root)1403 static node_ptr rebalance_subtree(node_ptr old_root) 1404 { 1405 //Taken from: 1406 //"Tree rebalancing in optimal time and space" 1407 //Quentin F. Stout and Bette L. Warren 1408 1409 //To avoid irregularities in the algorithm (old_root can be a 1410 //left or right child or even the root of the tree) just put the 1411 //root as the right child of its parent. Before doing this backup 1412 //information to restore the original relationship after 1413 //the algorithm is applied. 1414 node_ptr super_root = NodeTraits::get_parent(old_root); 1415 BOOST_INTRUSIVE_INVARIANT_ASSERT(super_root); 1416 1417 //Get root info 1418 node_ptr super_root_right_backup = NodeTraits::get_right(super_root); 1419 bool super_root_is_header = NodeTraits::get_parent(super_root) == old_root; 1420 bool old_root_is_right = is_right_child(old_root); 1421 NodeTraits::set_right(super_root, old_root); 1422 1423 std::size_t size; 1424 subtree_to_vine(super_root, size); 1425 vine_to_subtree(super_root, size); 1426 node_ptr new_root = NodeTraits::get_right(super_root); 1427 1428 //Recover root 1429 if(super_root_is_header){ 1430 NodeTraits::set_right(super_root, super_root_right_backup); 1431 NodeTraits::set_parent(super_root, new_root); 1432 } 1433 else if(old_root_is_right){ 1434 NodeTraits::set_right(super_root, new_root); 1435 } 1436 else{ 1437 NodeTraits::set_right(super_root, super_root_right_backup); 1438 NodeTraits::set_left(super_root, new_root); 1439 } 1440 return new_root; 1441 } 1442 1443 //! <b>Effects</b>: Asserts the integrity of the container with additional checks provided by the user. 1444 //! 1445 //! <b>Requires</b>: header must be the header of a tree. 1446 //! 1447 //! <b>Complexity</b>: Linear time. 1448 //! 1449 //! <b>Note</b>: The method might not have effect when asserts are turned off (e.g., with NDEBUG). 1450 //! Experimental function, interface might change in future versions. 1451 template<class Checker> check(const const_node_ptr & header,Checker checker,typename Checker::return_type & checker_return)1452 static void check(const const_node_ptr& header, Checker checker, typename Checker::return_type& checker_return) 1453 { 1454 const_node_ptr root_node_ptr = NodeTraits::get_parent(header); 1455 if (!root_node_ptr){ 1456 // check left&right header pointers 1457 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(header) == header); 1458 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_right(header) == header); 1459 } 1460 else{ 1461 // check parent pointer of root node 1462 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_parent(root_node_ptr) == header); 1463 // check subtree from root 1464 check_subtree(root_node_ptr, checker, checker_return); 1465 // check left&right header pointers 1466 const_node_ptr p = root_node_ptr; 1467 while (NodeTraits::get_left(p)) { p = NodeTraits::get_left(p); } 1468 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_left(header) == p); 1469 p = root_node_ptr; 1470 while (NodeTraits::get_right(p)) { p = NodeTraits::get_right(p); } 1471 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_right(header) == p); 1472 } 1473 } 1474 1475 protected: 1476 1477 template<class NodePtrCompare> transfer_unique(node_ptr header1,NodePtrCompare comp,node_ptr header2,node_ptr z,data_for_rebalance & info)1478 static bool transfer_unique 1479 (node_ptr header1, NodePtrCompare comp, node_ptr header2, node_ptr z, data_for_rebalance &info) 1480 { 1481 insert_commit_data commit_data; 1482 bool const transferable = insert_unique_check(header1, z, comp, commit_data).second; 1483 if(transferable){ 1484 erase(header2, z, info); 1485 insert_commit(header1, z, commit_data); 1486 } 1487 return transferable; 1488 } 1489 1490 template<class NodePtrCompare> transfer_equal(node_ptr header1,NodePtrCompare comp,node_ptr header2,node_ptr z,data_for_rebalance & info)1491 static void transfer_equal 1492 (node_ptr header1, NodePtrCompare comp, node_ptr header2, node_ptr z, data_for_rebalance &info) 1493 { 1494 insert_commit_data commit_data; 1495 insert_equal_upper_bound_check(header1, z, comp, commit_data); 1496 erase(header2, z, info); 1497 insert_commit(header1, z, commit_data); 1498 } 1499 erase(node_ptr header,node_ptr z,data_for_rebalance & info)1500 static void erase(node_ptr header, node_ptr z, data_for_rebalance &info) 1501 { 1502 node_ptr y(z); 1503 node_ptr x; 1504 const node_ptr z_left(NodeTraits::get_left(z)); 1505 const node_ptr z_right(NodeTraits::get_right(z)); 1506 1507 if(!z_left){ 1508 x = z_right; // x might be null. 1509 } 1510 else if(!z_right){ // z has exactly one non-null child. y == z. 1511 x = z_left; // x is not null. 1512 BOOST_ASSERT(x); 1513 } 1514 else{ //make y != z 1515 // y = find z's successor 1516 y = base_type::minimum(z_right); 1517 x = NodeTraits::get_right(y); // x might be null. 1518 } 1519 1520 node_ptr x_parent; 1521 const node_ptr z_parent(NodeTraits::get_parent(z)); 1522 const bool z_is_leftchild(NodeTraits::get_left(z_parent) == z); 1523 1524 if(y != z){ //has two children and y is the minimum of z 1525 //y is z's successor and it has a null left child. 1526 //x is the right child of y (it can be null) 1527 //Relink y in place of z and link x with y's old parent 1528 NodeTraits::set_parent(z_left, y); 1529 NodeTraits::set_left(y, z_left); 1530 if(y != z_right){ 1531 //Link y with the right tree of z 1532 NodeTraits::set_right(y, z_right); 1533 NodeTraits::set_parent(z_right, y); 1534 //Link x with y's old parent (y must be a left child) 1535 x_parent = NodeTraits::get_parent(y); 1536 BOOST_ASSERT(NodeTraits::get_left(x_parent) == y); 1537 if(x) 1538 NodeTraits::set_parent(x, x_parent); 1539 //Since y was the successor and not the right child of z, it must be a left child 1540 NodeTraits::set_left(x_parent, x); 1541 } 1542 else{ //y was the right child of y so no need to fix x's position 1543 x_parent = y; 1544 } 1545 NodeTraits::set_parent(y, z_parent); 1546 this_type::set_child(header, y, z_parent, z_is_leftchild); 1547 } 1548 else { // z has zero or one child, x is one child (it can be null) 1549 //Just link x to z's parent 1550 x_parent = z_parent; 1551 if(x) 1552 NodeTraits::set_parent(x, z_parent); 1553 this_type::set_child(header, x, z_parent, z_is_leftchild); 1554 1555 //Now update leftmost/rightmost in case z was one of them 1556 if(NodeTraits::get_left(header) == z){ 1557 //z_left must be null because z is the leftmost 1558 BOOST_ASSERT(!z_left); 1559 NodeTraits::set_left(header, !z_right ? 1560 z_parent : // makes leftmost == header if z == root 1561 base_type::minimum(z_right)); 1562 } 1563 if(NodeTraits::get_right(header) == z){ 1564 //z_right must be null because z is the rightmost 1565 BOOST_ASSERT(!z_right); 1566 NodeTraits::set_right(header, !z_left ? 1567 z_parent : // makes rightmost == header if z == root 1568 base_type::maximum(z_left)); 1569 } 1570 } 1571 1572 //If z had 0/1 child, y == z and one of its children (and maybe null) 1573 //If z had 2 children, y is the successor of z and x is the right child of y 1574 info.x = x; 1575 info.y = y; 1576 //If z had 0/1 child, x_parent is the new parent of the old right child of y (z's successor) 1577 //If z had 2 children, x_parent is the new parent of y (z_parent) 1578 BOOST_ASSERT(!x || NodeTraits::get_parent(x) == x_parent); 1579 info.x_parent = x_parent; 1580 } 1581 1582 //! <b>Requires</b>: node is a node of the tree but it's not the header. 1583 //! 1584 //! <b>Effects</b>: Returns the number of nodes of the subtree. 1585 //! 1586 //! <b>Complexity</b>: Linear time. 1587 //! 1588 //! <b>Throws</b>: Nothing. subtree_size(const const_node_ptr & subtree)1589 static std::size_t subtree_size(const const_node_ptr & subtree) 1590 { 1591 std::size_t count = 0; 1592 if (subtree){ 1593 node_ptr n = detail::uncast(subtree); 1594 node_ptr m = NodeTraits::get_left(n); 1595 while(m){ 1596 n = m; 1597 m = NodeTraits::get_left(n); 1598 } 1599 1600 while(1){ 1601 ++count; 1602 node_ptr n_right(NodeTraits::get_right(n)); 1603 if(n_right){ 1604 n = n_right; 1605 m = NodeTraits::get_left(n); 1606 while(m){ 1607 n = m; 1608 m = NodeTraits::get_left(n); 1609 } 1610 } 1611 else { 1612 do{ 1613 if (n == subtree){ 1614 return count; 1615 } 1616 m = n; 1617 n = NodeTraits::get_parent(n); 1618 }while(NodeTraits::get_left(n) != m); 1619 } 1620 } 1621 } 1622 return count; 1623 } 1624 1625 //! <b>Requires</b>: p is a node of a tree. 1626 //! 1627 //! <b>Effects</b>: Returns true if p is a left child. 1628 //! 1629 //! <b>Complexity</b>: Constant. 1630 //! 1631 //! <b>Throws</b>: Nothing. is_left_child(const node_ptr & p)1632 BOOST_INTRUSIVE_FORCEINLINE static bool is_left_child(const node_ptr & p) 1633 { return NodeTraits::get_left(NodeTraits::get_parent(p)) == p; } 1634 1635 //! <b>Requires</b>: p is a node of a tree. 1636 //! 1637 //! <b>Effects</b>: Returns true if p is a right child. 1638 //! 1639 //! <b>Complexity</b>: Constant. 1640 //! 1641 //! <b>Throws</b>: Nothing. is_right_child(const node_ptr & p)1642 BOOST_INTRUSIVE_FORCEINLINE static bool is_right_child(const node_ptr & p) 1643 { return NodeTraits::get_right(NodeTraits::get_parent(p)) == p; } 1644 insert_before_check(node_ptr header,node_ptr pos,insert_commit_data & commit_data,std::size_t * pdepth=0)1645 static void insert_before_check 1646 (node_ptr header, node_ptr pos 1647 , insert_commit_data &commit_data 1648 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED 1649 , std::size_t *pdepth = 0 1650 #endif 1651 ) 1652 { 1653 node_ptr prev(pos); 1654 if(pos != NodeTraits::get_left(header)) 1655 prev = base_type::prev_node(pos); 1656 bool link_left = unique(header) || !NodeTraits::get_left(pos); 1657 commit_data.link_left = link_left; 1658 commit_data.node = link_left ? pos : prev; 1659 if(pdepth){ 1660 *pdepth = commit_data.node == header ? 0 : depth(commit_data.node) + 1; 1661 } 1662 } 1663 push_back_check(node_ptr header,insert_commit_data & commit_data,std::size_t * pdepth=0)1664 static void push_back_check 1665 (node_ptr header, insert_commit_data &commit_data 1666 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED 1667 , std::size_t *pdepth = 0 1668 #endif 1669 ) 1670 { 1671 node_ptr prev(NodeTraits::get_right(header)); 1672 if(pdepth){ 1673 *pdepth = prev == header ? 0 : depth(prev) + 1; 1674 } 1675 commit_data.link_left = false; 1676 commit_data.node = prev; 1677 } 1678 push_front_check(node_ptr header,insert_commit_data & commit_data,std::size_t * pdepth=0)1679 static void push_front_check 1680 (node_ptr header, insert_commit_data &commit_data 1681 #ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED 1682 , std::size_t *pdepth = 0 1683 #endif 1684 ) 1685 { 1686 node_ptr pos(NodeTraits::get_left(header)); 1687 if(pdepth){ 1688 *pdepth = pos == header ? 0 : depth(pos) + 1; 1689 } 1690 commit_data.link_left = true; 1691 commit_data.node = pos; 1692 } 1693 1694 template<class NodePtrCompare> insert_equal_check(node_ptr header,node_ptr hint,node_ptr new_node,NodePtrCompare comp,insert_commit_data & commit_data,std::size_t * pdepth=0)1695 static void insert_equal_check 1696 (node_ptr header, node_ptr hint, node_ptr new_node, NodePtrCompare comp 1697 , insert_commit_data &commit_data 1698 /// @cond 1699 , std::size_t *pdepth = 0 1700 /// @endcond 1701 ) 1702 { 1703 if(hint == header || !comp(hint, new_node)){ 1704 node_ptr prev(hint); 1705 if(hint == NodeTraits::get_left(header) || 1706 !comp(new_node, (prev = base_type::prev_node(hint)))){ 1707 bool link_left = unique(header) || !NodeTraits::get_left(hint); 1708 commit_data.link_left = link_left; 1709 commit_data.node = link_left ? hint : prev; 1710 if(pdepth){ 1711 *pdepth = commit_data.node == header ? 0 : depth(commit_data.node) + 1; 1712 } 1713 } 1714 else{ 1715 insert_equal_upper_bound_check(header, new_node, comp, commit_data, pdepth); 1716 } 1717 } 1718 else{ 1719 insert_equal_lower_bound_check(header, new_node, comp, commit_data, pdepth); 1720 } 1721 } 1722 1723 template<class NodePtrCompare> insert_equal_upper_bound_check(node_ptr h,node_ptr new_node,NodePtrCompare comp,insert_commit_data & commit_data,std::size_t * pdepth=0)1724 static void insert_equal_upper_bound_check 1725 (node_ptr h, node_ptr new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0) 1726 { 1727 std::size_t depth = 0; 1728 node_ptr y(h); 1729 node_ptr x(NodeTraits::get_parent(y)); 1730 1731 while(x){ 1732 ++depth; 1733 y = x; 1734 x = comp(new_node, x) ? 1735 NodeTraits::get_left(x) : NodeTraits::get_right(x); 1736 } 1737 if(pdepth) *pdepth = depth; 1738 commit_data.link_left = (y == h) || comp(new_node, y); 1739 commit_data.node = y; 1740 } 1741 1742 template<class NodePtrCompare> insert_equal_lower_bound_check(node_ptr h,node_ptr new_node,NodePtrCompare comp,insert_commit_data & commit_data,std::size_t * pdepth=0)1743 static void insert_equal_lower_bound_check 1744 (node_ptr h, node_ptr new_node, NodePtrCompare comp, insert_commit_data & commit_data, std::size_t *pdepth = 0) 1745 { 1746 std::size_t depth = 0; 1747 node_ptr y(h); 1748 node_ptr x(NodeTraits::get_parent(y)); 1749 1750 while(x){ 1751 ++depth; 1752 y = x; 1753 x = !comp(x, new_node) ? 1754 NodeTraits::get_left(x) : NodeTraits::get_right(x); 1755 } 1756 if(pdepth) *pdepth = depth; 1757 commit_data.link_left = (y == h) || !comp(y, new_node); 1758 commit_data.node = y; 1759 } 1760 insert_commit(node_ptr header,node_ptr new_node,const insert_commit_data & commit_data)1761 static void insert_commit 1762 (node_ptr header, node_ptr new_node, const insert_commit_data &commit_data) 1763 { 1764 //Check if commit_data has not been initialized by a insert_unique_check call. 1765 BOOST_INTRUSIVE_INVARIANT_ASSERT(commit_data.node != node_ptr()); 1766 node_ptr parent_node(commit_data.node); 1767 if(parent_node == header){ 1768 NodeTraits::set_parent(header, new_node); 1769 NodeTraits::set_right(header, new_node); 1770 NodeTraits::set_left(header, new_node); 1771 } 1772 else if(commit_data.link_left){ 1773 NodeTraits::set_left(parent_node, new_node); 1774 if(parent_node == NodeTraits::get_left(header)) 1775 NodeTraits::set_left(header, new_node); 1776 } 1777 else{ 1778 NodeTraits::set_right(parent_node, new_node); 1779 if(parent_node == NodeTraits::get_right(header)) 1780 NodeTraits::set_right(header, new_node); 1781 } 1782 NodeTraits::set_parent(new_node, parent_node); 1783 NodeTraits::set_right(new_node, node_ptr()); 1784 NodeTraits::set_left(new_node, node_ptr()); 1785 } 1786 1787 //Fix header and own's parent data when replacing x with own, providing own's old data with parent set_child(node_ptr header,node_ptr new_child,node_ptr new_parent,const bool link_left)1788 static void set_child(node_ptr header, node_ptr new_child, node_ptr new_parent, const bool link_left) 1789 { 1790 if(new_parent == header) 1791 NodeTraits::set_parent(header, new_child); 1792 else if(link_left) 1793 NodeTraits::set_left(new_parent, new_child); 1794 else 1795 NodeTraits::set_right(new_parent, new_child); 1796 } 1797 1798 // rotate p to left (no header and p's parent fixup) rotate_left_no_parent_fix(node_ptr p,node_ptr p_right)1799 static void rotate_left_no_parent_fix(node_ptr p, node_ptr p_right) 1800 { 1801 node_ptr p_right_left(NodeTraits::get_left(p_right)); 1802 NodeTraits::set_right(p, p_right_left); 1803 if(p_right_left){ 1804 NodeTraits::set_parent(p_right_left, p); 1805 } 1806 NodeTraits::set_left(p_right, p); 1807 NodeTraits::set_parent(p, p_right); 1808 } 1809 1810 // rotate p to left (with header and p's parent fixup) rotate_left(node_ptr p,node_ptr p_right,node_ptr p_parent,node_ptr header)1811 static void rotate_left(node_ptr p, node_ptr p_right, node_ptr p_parent, node_ptr header) 1812 { 1813 const bool p_was_left(NodeTraits::get_left(p_parent) == p); 1814 rotate_left_no_parent_fix(p, p_right); 1815 NodeTraits::set_parent(p_right, p_parent); 1816 set_child(header, p_right, p_parent, p_was_left); 1817 } 1818 1819 // rotate p to right (no header and p's parent fixup) rotate_right_no_parent_fix(node_ptr p,node_ptr p_left)1820 static void rotate_right_no_parent_fix(node_ptr p, node_ptr p_left) 1821 { 1822 node_ptr p_left_right(NodeTraits::get_right(p_left)); 1823 NodeTraits::set_left(p, p_left_right); 1824 if(p_left_right){ 1825 NodeTraits::set_parent(p_left_right, p); 1826 } 1827 NodeTraits::set_right(p_left, p); 1828 NodeTraits::set_parent(p, p_left); 1829 } 1830 1831 // rotate p to right (with header and p's parent fixup) rotate_right(node_ptr p,node_ptr p_left,node_ptr p_parent,node_ptr header)1832 static void rotate_right(node_ptr p, node_ptr p_left, node_ptr p_parent, node_ptr header) 1833 { 1834 const bool p_was_left(NodeTraits::get_left(p_parent) == p); 1835 rotate_right_no_parent_fix(p, p_left); 1836 NodeTraits::set_parent(p_left, p_parent); 1837 set_child(header, p_left, p_parent, p_was_left); 1838 } 1839 1840 private: 1841 subtree_to_vine(node_ptr vine_tail,std::size_t & size)1842 static void subtree_to_vine(node_ptr vine_tail, std::size_t &size) 1843 { 1844 //Inspired by LibAVL: 1845 //It uses a clever optimization for trees with parent pointers. 1846 //No parent pointer is updated when transforming a tree to a vine as 1847 //most of them will be overriten during compression rotations. 1848 //A final pass must be made after the rebalancing to updated those 1849 //pointers not updated by tree_to_vine + compression calls 1850 std::size_t len = 0; 1851 node_ptr remainder = NodeTraits::get_right(vine_tail); 1852 while(remainder){ 1853 node_ptr tempptr = NodeTraits::get_left(remainder); 1854 if(!tempptr){ //move vine-tail down one 1855 vine_tail = remainder; 1856 remainder = NodeTraits::get_right(remainder); 1857 ++len; 1858 } 1859 else{ //rotate 1860 NodeTraits::set_left(remainder, NodeTraits::get_right(tempptr)); 1861 NodeTraits::set_right(tempptr, remainder); 1862 remainder = tempptr; 1863 NodeTraits::set_right(vine_tail, tempptr); 1864 } 1865 } 1866 size = len; 1867 } 1868 compress_subtree(node_ptr scanner,std::size_t count)1869 static void compress_subtree(node_ptr scanner, std::size_t count) 1870 { 1871 while(count--){ //compress "count" spine nodes in the tree with pseudo-root scanner 1872 node_ptr child = NodeTraits::get_right(scanner); 1873 node_ptr child_right = NodeTraits::get_right(child); 1874 NodeTraits::set_right(scanner, child_right); 1875 //Avoid setting the parent of child_right 1876 scanner = child_right; 1877 node_ptr scanner_left = NodeTraits::get_left(scanner); 1878 NodeTraits::set_right(child, scanner_left); 1879 if(scanner_left) 1880 NodeTraits::set_parent(scanner_left, child); 1881 NodeTraits::set_left(scanner, child); 1882 NodeTraits::set_parent(child, scanner); 1883 } 1884 } 1885 vine_to_subtree(node_ptr super_root,std::size_t count)1886 static void vine_to_subtree(node_ptr super_root, std::size_t count) 1887 { 1888 const std::size_t one_szt = 1u; 1889 std::size_t leaf_nodes = count + one_szt - std::size_t(one_szt << detail::floor_log2(count + one_szt)); 1890 compress_subtree(super_root, leaf_nodes); //create deepest leaves 1891 std::size_t vine_nodes = count - leaf_nodes; 1892 while(vine_nodes > 1){ 1893 vine_nodes /= 2; 1894 compress_subtree(super_root, vine_nodes); 1895 } 1896 1897 //Update parents of nodes still in the in the original vine line 1898 //as those have not been updated by subtree_to_vine or compress_subtree 1899 for ( node_ptr q = super_root, p = NodeTraits::get_right(super_root) 1900 ; p 1901 ; q = p, p = NodeTraits::get_right(p)){ 1902 NodeTraits::set_parent(p, q); 1903 } 1904 } 1905 1906 //! <b>Requires</b>: "n" must be a node inserted in a tree. 1907 //! 1908 //! <b>Effects</b>: Returns a pointer to the header node of the tree. 1909 //! 1910 //! <b>Complexity</b>: Logarithmic. 1911 //! 1912 //! <b>Throws</b>: Nothing. get_root(const node_ptr & node)1913 static node_ptr get_root(const node_ptr & node) 1914 { 1915 BOOST_INTRUSIVE_INVARIANT_ASSERT((!inited(node))); 1916 node_ptr x = NodeTraits::get_parent(node); 1917 if(x){ 1918 while(!base_type::is_header(x)){ 1919 x = NodeTraits::get_parent(x); 1920 } 1921 return x; 1922 } 1923 else{ 1924 return node; 1925 } 1926 } 1927 1928 template <class Cloner, class Disposer> clone_subtree(const const_node_ptr & source_parent,node_ptr target_parent,Cloner cloner,Disposer disposer,node_ptr & leftmost_out,node_ptr & rightmost_out)1929 static node_ptr clone_subtree 1930 (const const_node_ptr &source_parent, node_ptr target_parent 1931 , Cloner cloner, Disposer disposer 1932 , node_ptr &leftmost_out, node_ptr &rightmost_out 1933 ) 1934 { 1935 node_ptr target_sub_root = target_parent; 1936 node_ptr source_root = NodeTraits::get_parent(source_parent); 1937 if(!source_root){ 1938 leftmost_out = rightmost_out = source_root; 1939 } 1940 else{ 1941 //We'll calculate leftmost and rightmost nodes while iterating 1942 node_ptr current = source_root; 1943 node_ptr insertion_point = target_sub_root = cloner(current); 1944 1945 //We'll calculate leftmost and rightmost nodes while iterating 1946 node_ptr leftmost = target_sub_root; 1947 node_ptr rightmost = target_sub_root; 1948 1949 //First set the subroot 1950 NodeTraits::set_left(target_sub_root, node_ptr()); 1951 NodeTraits::set_right(target_sub_root, node_ptr()); 1952 NodeTraits::set_parent(target_sub_root, target_parent); 1953 1954 dispose_subtree_disposer<Disposer> rollback(disposer, target_sub_root); 1955 while(true) { 1956 //First clone left nodes 1957 if( NodeTraits::get_left(current) && 1958 !NodeTraits::get_left(insertion_point)) { 1959 current = NodeTraits::get_left(current); 1960 node_ptr temp = insertion_point; 1961 //Clone and mark as leaf 1962 insertion_point = cloner(current); 1963 NodeTraits::set_left (insertion_point, node_ptr()); 1964 NodeTraits::set_right (insertion_point, node_ptr()); 1965 //Insert left 1966 NodeTraits::set_parent(insertion_point, temp); 1967 NodeTraits::set_left (temp, insertion_point); 1968 //Update leftmost 1969 if(rightmost == target_sub_root) 1970 leftmost = insertion_point; 1971 } 1972 //Then clone right nodes 1973 else if( NodeTraits::get_right(current) && 1974 !NodeTraits::get_right(insertion_point)){ 1975 current = NodeTraits::get_right(current); 1976 node_ptr temp = insertion_point; 1977 //Clone and mark as leaf 1978 insertion_point = cloner(current); 1979 NodeTraits::set_left (insertion_point, node_ptr()); 1980 NodeTraits::set_right (insertion_point, node_ptr()); 1981 //Insert right 1982 NodeTraits::set_parent(insertion_point, temp); 1983 NodeTraits::set_right (temp, insertion_point); 1984 //Update rightmost 1985 rightmost = insertion_point; 1986 } 1987 //If not, go up 1988 else if(current == source_root){ 1989 break; 1990 } 1991 else{ 1992 //Branch completed, go up searching more nodes to clone 1993 current = NodeTraits::get_parent(current); 1994 insertion_point = NodeTraits::get_parent(insertion_point); 1995 } 1996 } 1997 rollback.release(); 1998 leftmost_out = leftmost; 1999 rightmost_out = rightmost; 2000 } 2001 return target_sub_root; 2002 } 2003 2004 template<class Disposer> dispose_subtree(node_ptr x,Disposer disposer)2005 static void dispose_subtree(node_ptr x, Disposer disposer) 2006 { 2007 while (x){ 2008 node_ptr save(NodeTraits::get_left(x)); 2009 if (save) { 2010 // Right rotation 2011 NodeTraits::set_left(x, NodeTraits::get_right(save)); 2012 NodeTraits::set_right(save, x); 2013 } 2014 else { 2015 save = NodeTraits::get_right(x); 2016 init(x); 2017 disposer(x); 2018 } 2019 x = save; 2020 } 2021 } 2022 2023 template<class KeyType, class KeyNodePtrCompare> lower_bound_loop(node_ptr x,node_ptr y,const KeyType & key,KeyNodePtrCompare comp)2024 static node_ptr lower_bound_loop 2025 (node_ptr x, node_ptr y, const KeyType &key, KeyNodePtrCompare comp) 2026 { 2027 while(x){ 2028 if(comp(x, key)){ 2029 x = NodeTraits::get_right(x); 2030 } 2031 else{ 2032 y = x; 2033 x = NodeTraits::get_left(x); 2034 } 2035 } 2036 return y; 2037 } 2038 2039 template<class KeyType, class KeyNodePtrCompare> upper_bound_loop(node_ptr x,node_ptr y,const KeyType & key,KeyNodePtrCompare comp)2040 static node_ptr upper_bound_loop 2041 (node_ptr x, node_ptr y, const KeyType &key, KeyNodePtrCompare comp) 2042 { 2043 while(x){ 2044 if(comp(key, x)){ 2045 y = x; 2046 x = NodeTraits::get_left(x); 2047 } 2048 else{ 2049 x = NodeTraits::get_right(x); 2050 } 2051 } 2052 return y; 2053 } 2054 2055 template<class Checker> check_subtree(const const_node_ptr & node,Checker checker,typename Checker::return_type & check_return)2056 static void check_subtree(const const_node_ptr& node, Checker checker, typename Checker::return_type& check_return) 2057 { 2058 const_node_ptr left = NodeTraits::get_left(node); 2059 const_node_ptr right = NodeTraits::get_right(node); 2060 typename Checker::return_type check_return_left; 2061 typename Checker::return_type check_return_right; 2062 if (left) 2063 { 2064 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_parent(left) == node); 2065 check_subtree(left, checker, check_return_left); 2066 } 2067 if (right) 2068 { 2069 BOOST_INTRUSIVE_INVARIANT_ASSERT(NodeTraits::get_parent(right) == node); 2070 check_subtree(right, checker, check_return_right); 2071 } 2072 checker(node, check_return_left, check_return_right, check_return); 2073 } 2074 }; 2075 2076 /// @cond 2077 2078 template<class NodeTraits> 2079 struct get_algo<BsTreeAlgorithms, NodeTraits> 2080 { 2081 typedef bstree_algorithms<NodeTraits> type; 2082 }; 2083 2084 template <class ValueTraits, class NodePtrCompare, class ExtraChecker> 2085 struct get_node_checker<BsTreeAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker> 2086 { 2087 typedef detail::bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type; 2088 }; 2089 2090 /// @endcond 2091 2092 } //namespace intrusive 2093 } //namespace boost 2094 2095 #include <boost/intrusive/detail/config_end.hpp> 2096 2097 #endif //BOOST_INTRUSIVE_BSTREE_ALGORITHMS_HPP 2098