RedBlackTree.h (24239B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 // Portions of this file were originally under the following license: 8 // 9 // Copyright (C) 2008 Jason Evans <jasone@FreeBSD.org>. 10 // All rights reserved. 11 // 12 // Redistribution and use in source and binary forms, with or without 13 // modification, are permitted provided that the following conditions 14 // are met: 15 // 1. Redistributions of source code must retain the above copyright 16 // notice(s), this list of conditions and the following disclaimer 17 // unmodified other than the allowable addition of one or more 18 // copyright notices. 19 // 2. Redistributions in binary form must reproduce the above copyright 20 // notice(s), this list of conditions and the following disclaimer in 21 // the documentation and/or other materials provided with the 22 // distribution. 23 // 24 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 25 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 28 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 31 // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 33 // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 34 // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 // 36 // **************************************************************************** 37 // 38 // C++ template implementation of left-leaning red-black trees. 39 // 40 // All operations are done non-recursively. Parent pointers are not used, and 41 // color bits are stored in the least significant bit of right-child pointers, 42 // thus making node linkage as compact as is possible for red-black trees. 43 // 44 // The RedBlackTree template expects two type arguments: the type of the nodes, 45 // containing a RedBlackTreeNode, and a trait providing two methods: 46 // - a GetTreeNode method that returns a reference to the RedBlackTreeNode 47 // corresponding to a given node with the following signature: 48 // static RedBlackTreeNode<T>& GetTreeNode(T*) 49 // - a Compare function with the following signature: 50 // static Order Compare(T* aNode, T* aOther) 51 // ^^^^^ 52 // or aKey 53 // 54 // Interpretation of comparision function return values: 55 // 56 // Order::eLess: aNode < aOther 57 // Order::eEqual: aNode == aOther 58 // Order::eGreater: aNode > aOther 59 // 60 // In all cases, the aNode or aKey argument is the first argument to the 61 // comparison function, which makes it possible to write comparison functions 62 // that treat the first argument specially. 63 // 64 // *************************************************************************** 65 66 #ifndef RB_H_ 67 #define RB_H_ 68 69 #include "mozilla/Alignment.h" 70 #include "mozilla/Assertions.h" 71 #include "Utils.h" 72 73 enum NodeColor { 74 Black = 0, 75 Red = 1, 76 }; 77 78 // Node structure. 79 template <typename T> 80 class RedBlackTreeNode { 81 T* mLeft; 82 // The lowest bit is the color 83 T* mRightAndColor; 84 85 public: 86 T* Left() { return mLeft; } 87 88 void SetLeft(T* aValue) { mLeft = aValue; } 89 90 T* Right() { 91 return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(mRightAndColor) & 92 uintptr_t(~1)); 93 } 94 95 void SetRight(T* aValue) { 96 mRightAndColor = reinterpret_cast<T*>( 97 (reinterpret_cast<uintptr_t>(aValue) & uintptr_t(~1)) | Color()); 98 } 99 100 NodeColor Color() { 101 #pragma GCC diagnostic push 102 #pragma GCC diagnostic ignored "-Wuninitialized" 103 return static_cast<NodeColor>(reinterpret_cast<uintptr_t>(mRightAndColor) & 104 1); 105 #pragma GCC diagnostic pop 106 } 107 108 bool IsBlack() { return Color() == NodeColor::Black; } 109 110 bool IsRed() { return Color() == NodeColor::Red; } 111 112 void SetColor(NodeColor aColor) { 113 mRightAndColor = reinterpret_cast<T*>( 114 (reinterpret_cast<uintptr_t>(mRightAndColor) & uintptr_t(~1)) | aColor); 115 } 116 }; 117 118 // Tree structure. 119 template <typename T, typename Trait> 120 class RedBlackTree { 121 public: 122 constexpr RedBlackTree() : mRoot(nullptr) {} 123 124 T* First(T* aStart = nullptr) { return First(TreeNode(aStart)).Get(); } 125 126 T* Last(T* aStart = nullptr) { return Last(TreeNode(aStart)).Get(); } 127 128 T* Next(T* aNode) { return Next(TreeNode(aNode)).Get(); } 129 130 T* Prev(T* aNode) { return Prev(TreeNode(aNode)).Get(); } 131 132 T* Search(T* aKey) { return Search(TreeNode(aKey)).Get(); } 133 134 // Find a match if it exists. Otherwise, find the next greater node, if one 135 // exists. 136 T* SearchOrNext(T* aKey) { return SearchOrNext(TreeNode(aKey)).Get(); } 137 138 void Insert(T* aNode) { Insert(TreeNode(aNode)); } 139 140 void Remove(T* aNode) { Remove(TreeNode(aNode)); } 141 142 // Helper class to avoid having all the tree traversal code further below 143 // have to use Trait::GetTreeNode and do manual null pointer checks, adding 144 // visual noise. Practically speaking TreeNode(nullptr) acts as a virtual 145 // sentinel, that loops back to itself for Left() and Right() and is always 146 // black. 147 class TreeNode { 148 public: 149 constexpr TreeNode() : mNode(nullptr) {} 150 151 MOZ_IMPLICIT TreeNode(T* aNode) : mNode(aNode) {} 152 153 TreeNode& operator=(TreeNode aOther) { 154 mNode = aOther.mNode; 155 return *this; 156 } 157 158 TreeNode Left() { 159 return TreeNode(mNode ? Trait::GetTreeNode(mNode).Left() : nullptr); 160 } 161 162 void SetLeft(TreeNode aNode) { 163 MOZ_RELEASE_ASSERT(mNode); 164 Trait::GetTreeNode(mNode).SetLeft(aNode.mNode); 165 } 166 167 TreeNode Right() { 168 return TreeNode(mNode ? Trait::GetTreeNode(mNode).Right() : nullptr); 169 } 170 171 void SetRight(TreeNode aNode) { 172 MOZ_RELEASE_ASSERT(mNode); 173 Trait::GetTreeNode(mNode).SetRight(aNode.mNode); 174 } 175 176 NodeColor Color() { 177 return mNode ? Trait::GetTreeNode(mNode).Color() : NodeColor::Black; 178 } 179 180 bool IsRed() { return Color() == NodeColor::Red; } 181 182 bool IsBlack() { return Color() == NodeColor::Black; } 183 184 void SetColor(NodeColor aColor) { 185 MOZ_RELEASE_ASSERT(mNode); 186 Trait::GetTreeNode(mNode).SetColor(aColor); 187 } 188 189 T* Get() { return mNode; } 190 191 MOZ_IMPLICIT operator bool() { return !!mNode; } 192 193 bool operator==(TreeNode& aOther) { return mNode == aOther.mNode; } 194 195 private: 196 T* mNode; 197 }; 198 199 private: 200 // Ideally we'd use a TreeNode for mRoot, but we need RedBlackTree to stay 201 // a POD type to avoid a static initializer for gArenas. 202 T* mRoot; 203 204 TreeNode First(TreeNode aStart) { 205 TreeNode ret; 206 for (ret = aStart ? aStart : mRoot; ret.Left(); ret = ret.Left()) { 207 } 208 return ret; 209 } 210 211 TreeNode Last(TreeNode aStart) { 212 TreeNode ret; 213 for (ret = aStart ? aStart : mRoot; ret.Right(); ret = ret.Right()) { 214 } 215 return ret; 216 } 217 218 TreeNode Next(TreeNode aNode) { 219 TreeNode ret; 220 if (aNode.Right()) { 221 ret = First(aNode.Right()); 222 } else { 223 TreeNode rbp_n_t = mRoot; 224 MOZ_ASSERT(rbp_n_t); 225 ret = nullptr; 226 while (true) { 227 Order rbp_n_cmp = Trait::Compare(aNode.Get(), rbp_n_t.Get()); 228 if (rbp_n_cmp == Order::eLess) { 229 ret = rbp_n_t; 230 rbp_n_t = rbp_n_t.Left(); 231 } else if (rbp_n_cmp == Order::eGreater) { 232 rbp_n_t = rbp_n_t.Right(); 233 } else { 234 break; 235 } 236 MOZ_ASSERT(rbp_n_t); 237 } 238 } 239 return ret; 240 } 241 242 TreeNode Prev(TreeNode aNode) { 243 TreeNode ret; 244 if (aNode.Left()) { 245 ret = Last(aNode.Left()); 246 } else { 247 TreeNode rbp_p_t = mRoot; 248 MOZ_ASSERT(rbp_p_t); 249 ret = nullptr; 250 while (true) { 251 Order rbp_p_cmp = Trait::Compare(aNode.Get(), rbp_p_t.Get()); 252 if (rbp_p_cmp == Order::eLess) { 253 rbp_p_t = rbp_p_t.Left(); 254 } else if (rbp_p_cmp == Order::eGreater) { 255 ret = rbp_p_t; 256 rbp_p_t = rbp_p_t.Right(); 257 } else { 258 break; 259 } 260 MOZ_ASSERT(rbp_p_t); 261 } 262 } 263 return ret; 264 } 265 266 TreeNode Search(TreeNode aKey) { 267 TreeNode ret = mRoot; 268 Order rbp_se_cmp; 269 while (ret && (rbp_se_cmp = Trait::Compare(aKey.Get(), ret.Get())) != 270 Order::eEqual) { 271 if (rbp_se_cmp == Order::eLess) { 272 ret = ret.Left(); 273 } else { 274 ret = ret.Right(); 275 } 276 } 277 return ret; 278 } 279 280 TreeNode SearchOrNext(TreeNode aKey) { 281 TreeNode ret = nullptr; 282 TreeNode rbp_ns_t = mRoot; 283 while (rbp_ns_t) { 284 Order rbp_ns_cmp = Trait::Compare(aKey.Get(), rbp_ns_t.Get()); 285 if (rbp_ns_cmp == Order::eLess) { 286 ret = rbp_ns_t; 287 rbp_ns_t = rbp_ns_t.Left(); 288 } else if (rbp_ns_cmp == Order::eGreater) { 289 rbp_ns_t = rbp_ns_t.Right(); 290 } else { 291 ret = rbp_ns_t; 292 break; 293 } 294 } 295 return ret; 296 } 297 298 void Insert(TreeNode aNode) { 299 // rbp_i_s is only used as a placeholder for its RedBlackTreeNode. Use 300 // AlignedStorage2 to avoid running the TreeNode base class constructor. 301 mozilla::AlignedStorage2<T> rbp_i_s; 302 TreeNode rbp_i_g, rbp_i_p, rbp_i_c, rbp_i_t, rbp_i_u; 303 Order rbp_i_cmp = Order::eEqual; 304 rbp_i_g = nullptr; 305 rbp_i_p = rbp_i_s.addr(); 306 rbp_i_p.SetLeft(mRoot); 307 rbp_i_p.SetRight(nullptr); 308 rbp_i_p.SetColor(NodeColor::Black); 309 rbp_i_c = mRoot; 310 // Iteratively search down the tree for the insertion point, 311 // splitting 4-nodes as they are encountered. At the end of each 312 // iteration, rbp_i_g->rbp_i_p->rbp_i_c is a 3-level path down 313 // the tree, assuming a sufficiently deep tree. 314 while (rbp_i_c) { 315 rbp_i_t = rbp_i_c.Left(); 316 rbp_i_u = rbp_i_t.Left(); 317 if (rbp_i_t.IsRed() && rbp_i_u.IsRed()) { 318 // rbp_i_c is the top of a logical 4-node, so split it. 319 // This iteration does not move down the tree, due to the 320 // disruptiveness of node splitting. 321 // 322 // Rotate right. 323 rbp_i_t = RotateRight(rbp_i_c); 324 // Pass red links up one level. 325 rbp_i_u = rbp_i_t.Left(); 326 rbp_i_u.SetColor(NodeColor::Black); 327 if (rbp_i_p.Left() == rbp_i_c) { 328 rbp_i_p.SetLeft(rbp_i_t); 329 rbp_i_c = rbp_i_t; 330 } else { 331 // rbp_i_c was the right child of rbp_i_p, so rotate 332 // left in order to maintain the left-leaning invariant. 333 MOZ_ASSERT(rbp_i_p.Right() == rbp_i_c); 334 rbp_i_p.SetRight(rbp_i_t); 335 rbp_i_u = LeanLeft(rbp_i_p); 336 if (rbp_i_g.Left() == rbp_i_p) { 337 rbp_i_g.SetLeft(rbp_i_u); 338 } else { 339 MOZ_ASSERT(rbp_i_g.Right() == rbp_i_p); 340 rbp_i_g.SetRight(rbp_i_u); 341 } 342 rbp_i_p = rbp_i_u; 343 rbp_i_cmp = Trait::Compare(aNode.Get(), rbp_i_p.Get()); 344 if (rbp_i_cmp == Order::eLess) { 345 rbp_i_c = rbp_i_p.Left(); 346 } else { 347 MOZ_ASSERT(rbp_i_cmp == Order::eGreater); 348 rbp_i_c = rbp_i_p.Right(); 349 } 350 continue; 351 } 352 } 353 rbp_i_g = rbp_i_p; 354 rbp_i_p = rbp_i_c; 355 rbp_i_cmp = Trait::Compare(aNode.Get(), rbp_i_c.Get()); 356 if (rbp_i_cmp == Order::eLess) { 357 rbp_i_c = rbp_i_c.Left(); 358 } else { 359 MOZ_ASSERT(rbp_i_cmp == Order::eGreater); 360 rbp_i_c = rbp_i_c.Right(); 361 } 362 } 363 // rbp_i_p now refers to the node under which to insert. 364 aNode.SetLeft(nullptr); 365 aNode.SetRight(nullptr); 366 aNode.SetColor(NodeColor::Red); 367 if (rbp_i_cmp == Order::eGreater) { 368 rbp_i_p.SetRight(aNode); 369 rbp_i_t = LeanLeft(rbp_i_p); 370 if (rbp_i_g.Left() == rbp_i_p) { 371 rbp_i_g.SetLeft(rbp_i_t); 372 } else if (rbp_i_g.Right() == rbp_i_p) { 373 rbp_i_g.SetRight(rbp_i_t); 374 } 375 } else { 376 rbp_i_p.SetLeft(aNode); 377 } 378 // Update the root and make sure that it is black. 379 TreeNode root = TreeNode(rbp_i_s.addr()).Left(); 380 root.SetColor(NodeColor::Black); 381 mRoot = root.Get(); 382 } 383 384 void Remove(TreeNode aNode) { 385 // rbp_r_s is only used as a placeholder for its RedBlackTreeNode. Use 386 // AlignedStorage2 to avoid running the TreeNode base class constructor. 387 mozilla::AlignedStorage2<T> rbp_r_s; 388 TreeNode rbp_r_p, rbp_r_c, rbp_r_xp, rbp_r_t, rbp_r_u; 389 Order rbp_r_cmp; 390 rbp_r_p = TreeNode(rbp_r_s.addr()); 391 rbp_r_p.SetLeft(mRoot); 392 rbp_r_p.SetRight(nullptr); 393 rbp_r_p.SetColor(NodeColor::Black); 394 rbp_r_c = mRoot; 395 rbp_r_xp = nullptr; 396 // Iterate down the tree, but always transform 2-nodes to 3- or 397 // 4-nodes in order to maintain the invariant that the current 398 // node is not a 2-node. This allows simple deletion once a leaf 399 // is reached. Handle the root specially though, since there may 400 // be no way to convert it from a 2-node to a 3-node. 401 rbp_r_cmp = Trait::Compare(aNode.Get(), rbp_r_c.Get()); 402 if (rbp_r_cmp == Order::eLess) { 403 rbp_r_t = rbp_r_c.Left(); 404 rbp_r_u = rbp_r_t.Left(); 405 if (rbp_r_t.IsBlack() && rbp_r_u.IsBlack()) { 406 // Apply standard transform to prepare for left move. 407 rbp_r_t = MoveRedLeft(rbp_r_c); 408 rbp_r_t.SetColor(NodeColor::Black); 409 rbp_r_p.SetLeft(rbp_r_t); 410 rbp_r_c = rbp_r_t; 411 } else { 412 // Move left. 413 rbp_r_p = rbp_r_c; 414 rbp_r_c = rbp_r_c.Left(); 415 } 416 } else { 417 if (rbp_r_cmp == Order::eEqual) { 418 MOZ_ASSERT(aNode == rbp_r_c); 419 if (!rbp_r_c.Right()) { 420 // Delete root node (which is also a leaf node). 421 if (rbp_r_c.Left()) { 422 rbp_r_t = LeanRight(rbp_r_c); 423 rbp_r_t.SetRight(nullptr); 424 } else { 425 rbp_r_t = nullptr; 426 } 427 rbp_r_p.SetLeft(rbp_r_t); 428 } else { 429 // This is the node we want to delete, but we will 430 // instead swap it with its successor and delete the 431 // successor. Record enough information to do the 432 // swap later. rbp_r_xp is the aNode's parent. 433 rbp_r_xp = rbp_r_p; 434 rbp_r_cmp = Order::eGreater; // Note that deletion is incomplete. 435 } 436 } 437 if (rbp_r_cmp == Order::eGreater) { 438 if (rbp_r_c.Right().Left().IsBlack()) { 439 rbp_r_t = rbp_r_c.Left(); 440 if (rbp_r_t.IsRed()) { 441 // Standard transform. 442 rbp_r_t = MoveRedRight(rbp_r_c); 443 } else { 444 // Root-specific transform. 445 rbp_r_c.SetColor(NodeColor::Red); 446 rbp_r_u = rbp_r_t.Left(); 447 if (rbp_r_u.IsRed()) { 448 rbp_r_u.SetColor(NodeColor::Black); 449 rbp_r_t = RotateRight(rbp_r_c); 450 rbp_r_u = RotateLeft(rbp_r_c); 451 rbp_r_t.SetRight(rbp_r_u); 452 } else { 453 rbp_r_t.SetColor(NodeColor::Red); 454 rbp_r_t = RotateLeft(rbp_r_c); 455 } 456 } 457 rbp_r_p.SetLeft(rbp_r_t); 458 rbp_r_c = rbp_r_t; 459 } else { 460 // Move right. 461 rbp_r_p = rbp_r_c; 462 rbp_r_c = rbp_r_c.Right(); 463 } 464 } 465 } 466 if (rbp_r_cmp != Order::eEqual) { 467 while (true) { 468 MOZ_ASSERT(rbp_r_p); 469 rbp_r_cmp = Trait::Compare(aNode.Get(), rbp_r_c.Get()); 470 if (rbp_r_cmp == Order::eLess) { 471 rbp_r_t = rbp_r_c.Left(); 472 if (!rbp_r_t) { 473 // rbp_r_c now refers to the successor node to 474 // relocate, and rbp_r_xp/aNode refer to the 475 // context for the relocation. 476 if (rbp_r_xp.Left() == aNode) { 477 rbp_r_xp.SetLeft(rbp_r_c); 478 } else { 479 MOZ_ASSERT(rbp_r_xp.Right() == (aNode)); 480 rbp_r_xp.SetRight(rbp_r_c); 481 } 482 rbp_r_c.SetLeft(aNode.Left()); 483 rbp_r_c.SetRight(aNode.Right()); 484 rbp_r_c.SetColor(aNode.Color()); 485 if (rbp_r_p.Left() == rbp_r_c) { 486 rbp_r_p.SetLeft(nullptr); 487 } else { 488 MOZ_ASSERT(rbp_r_p.Right() == rbp_r_c); 489 rbp_r_p.SetRight(nullptr); 490 } 491 break; 492 } 493 rbp_r_u = rbp_r_t.Left(); 494 if (rbp_r_t.IsBlack() && rbp_r_u.IsBlack()) { 495 rbp_r_t = MoveRedLeft(rbp_r_c); 496 if (rbp_r_p.Left() == rbp_r_c) { 497 rbp_r_p.SetLeft(rbp_r_t); 498 } else { 499 rbp_r_p.SetRight(rbp_r_t); 500 } 501 rbp_r_c = rbp_r_t; 502 } else { 503 rbp_r_p = rbp_r_c; 504 rbp_r_c = rbp_r_c.Left(); 505 } 506 } else { 507 // Check whether to delete this node (it has to be 508 // the correct node and a leaf node). 509 if (rbp_r_cmp == Order::eEqual) { 510 MOZ_ASSERT(aNode == rbp_r_c); 511 if (!rbp_r_c.Right()) { 512 // Delete leaf node. 513 if (rbp_r_c.Left()) { 514 rbp_r_t = LeanRight(rbp_r_c); 515 rbp_r_t.SetRight(nullptr); 516 } else { 517 rbp_r_t = nullptr; 518 } 519 if (rbp_r_p.Left() == rbp_r_c) { 520 rbp_r_p.SetLeft(rbp_r_t); 521 } else { 522 rbp_r_p.SetRight(rbp_r_t); 523 } 524 break; 525 } 526 // This is the node we want to delete, but we 527 // will instead swap it with its successor 528 // and delete the successor. Record enough 529 // information to do the swap later. 530 // rbp_r_xp is aNode's parent. 531 rbp_r_xp = rbp_r_p; 532 } 533 rbp_r_t = rbp_r_c.Right(); 534 rbp_r_u = rbp_r_t.Left(); 535 if (rbp_r_u.IsBlack()) { 536 rbp_r_t = MoveRedRight(rbp_r_c); 537 if (rbp_r_p.Left() == rbp_r_c) { 538 rbp_r_p.SetLeft(rbp_r_t); 539 } else { 540 rbp_r_p.SetRight(rbp_r_t); 541 } 542 rbp_r_c = rbp_r_t; 543 } else { 544 rbp_r_p = rbp_r_c; 545 rbp_r_c = rbp_r_c.Right(); 546 } 547 } 548 } 549 } 550 // Update root. 551 mRoot = TreeNode(rbp_r_s.addr()).Left().Get(); 552 aNode.SetLeft(nullptr); 553 aNode.SetRight(nullptr); 554 aNode.SetColor(NodeColor::Black); 555 } 556 557 TreeNode RotateLeft(TreeNode aNode) { 558 TreeNode node = aNode.Right(); 559 aNode.SetRight(node.Left()); 560 node.SetLeft(aNode); 561 return node; 562 } 563 564 TreeNode RotateRight(TreeNode aNode) { 565 TreeNode node = aNode.Left(); 566 aNode.SetLeft(node.Right()); 567 node.SetRight(aNode); 568 return node; 569 } 570 571 TreeNode LeanLeft(TreeNode aNode) { 572 TreeNode node = RotateLeft(aNode); 573 NodeColor color = aNode.Color(); 574 node.SetColor(color); 575 aNode.SetColor(NodeColor::Red); 576 return node; 577 } 578 579 TreeNode LeanRight(TreeNode aNode) { 580 TreeNode node = RotateRight(aNode); 581 NodeColor color = aNode.Color(); 582 node.SetColor(color); 583 aNode.SetColor(NodeColor::Red); 584 return node; 585 } 586 587 TreeNode MoveRedLeft(TreeNode aNode) { 588 TreeNode node; 589 TreeNode rbp_mrl_t, rbp_mrl_u; 590 rbp_mrl_t = aNode.Left(); 591 rbp_mrl_t.SetColor(NodeColor::Red); 592 rbp_mrl_t = aNode.Right(); 593 rbp_mrl_u = rbp_mrl_t.Left(); 594 if (rbp_mrl_u.IsRed()) { 595 rbp_mrl_u = RotateRight(rbp_mrl_t); 596 aNode.SetRight(rbp_mrl_u); 597 node = RotateLeft(aNode); 598 rbp_mrl_t = aNode.Right(); 599 if (rbp_mrl_t.IsRed()) { 600 rbp_mrl_t.SetColor(NodeColor::Black); 601 aNode.SetColor(NodeColor::Red); 602 rbp_mrl_t = RotateLeft(aNode); 603 node.SetLeft(rbp_mrl_t); 604 } else { 605 aNode.SetColor(NodeColor::Black); 606 } 607 } else { 608 aNode.SetColor(NodeColor::Red); 609 node = RotateLeft(aNode); 610 } 611 return node; 612 } 613 614 TreeNode MoveRedRight(TreeNode aNode) { 615 TreeNode node; 616 TreeNode rbp_mrr_t; 617 rbp_mrr_t = aNode.Left(); 618 if (rbp_mrr_t.IsRed()) { 619 TreeNode rbp_mrr_u, rbp_mrr_v; 620 rbp_mrr_u = rbp_mrr_t.Right(); 621 rbp_mrr_v = rbp_mrr_u.Left(); 622 if (rbp_mrr_v.IsRed()) { 623 rbp_mrr_u.SetColor(aNode.Color()); 624 rbp_mrr_v.SetColor(NodeColor::Black); 625 rbp_mrr_u = RotateLeft(rbp_mrr_t); 626 aNode.SetLeft(rbp_mrr_u); 627 node = RotateRight(aNode); 628 rbp_mrr_t = RotateLeft(aNode); 629 node.SetRight(rbp_mrr_t); 630 } else { 631 rbp_mrr_t.SetColor(aNode.Color()); 632 rbp_mrr_u.SetColor(NodeColor::Red); 633 node = RotateRight(aNode); 634 rbp_mrr_t = RotateLeft(aNode); 635 node.SetRight(rbp_mrr_t); 636 } 637 aNode.SetColor(NodeColor::Red); 638 } else { 639 rbp_mrr_t.SetColor(NodeColor::Red); 640 rbp_mrr_t = rbp_mrr_t.Left(); 641 if (rbp_mrr_t.IsRed()) { 642 rbp_mrr_t.SetColor(NodeColor::Black); 643 node = RotateRight(aNode); 644 rbp_mrr_t = RotateLeft(aNode); 645 node.SetRight(rbp_mrr_t); 646 } else { 647 node = RotateLeft(aNode); 648 } 649 } 650 return node; 651 } 652 653 // The iterator simulates recursion via an array of pointers that store the 654 // current path. This is critical to performance, since a series of calls to 655 // rb_{next,prev}() would require time proportional to (n lg n), whereas this 656 // implementation only requires time proportional to (n). 657 // 658 // Since the iterator caches a path down the tree, any tree modification may 659 // cause the cached path to become invalid. Don't modify the tree during an 660 // iteration. 661 662 // Size the path arrays such that they are always large enough, even if a 663 // tree consumes all of memory. Since each node must contain a minimum of 664 // two pointers, there can never be more nodes than: 665 // 666 // 1 << ((sizeof(void*)<<3) - (log2(sizeof(void*))+1)) 667 // 668 // Since the depth of a tree is limited to 3*lg(#nodes), the maximum depth 669 // is: 670 // 671 // (3 * ((sizeof(void*)<<3) - (log2(sizeof(void*))+1))) 672 // 673 // This works out to a maximum depth of 87 and 180 for 32- and 64-bit 674 // systems, respectively (approximately 348 and 1440 bytes, respectively). 675 public: 676 class Iterator { 677 TreeNode mPath[3 * ((sizeof(void*) << 3) - (LOG2(sizeof(void*)) + 1))]; 678 679 // Depth always points to the next empty place in mPath. Therefore 680 // mDepth == 0 means there are no items in mPath, 681 // mDepth != 0 means that mPath[mDepth-1] is safe to dereference. 682 unsigned mDepth; 683 684 public: 685 explicit Iterator(RedBlackTree<T, Trait>* aTree) : mDepth(0) { 686 // Initialize the path to contain the left spine. 687 if (aTree->mRoot) { 688 TreeNode node; 689 mPath[mDepth++] = aTree->mRoot; 690 while ((node = mPath[mDepth - 1].Left())) { 691 mPath[mDepth++] = node; 692 } 693 } 694 } 695 696 template <typename Iterator> 697 class Item { 698 Iterator* mIterator; 699 T* mItem; 700 701 public: 702 Item(Iterator* aIterator, T* aItem) 703 : mIterator(aIterator), mItem(aItem) {} 704 705 bool operator!=(const Item& aOther) const { 706 return (mIterator != aOther.mIterator) || (mItem != aOther.mItem); 707 } 708 709 T* operator*() const { return mItem; } 710 711 const Item& operator++() { 712 mItem = mIterator->Next(); 713 return *this; 714 } 715 }; 716 717 Item<Iterator> begin() { return Item<Iterator>(this, Current()); } 718 719 Item<Iterator> end() { return Item<Iterator>(this, nullptr); } 720 721 T* Next() { 722 TreeNode node; 723 if ((node = mPath[mDepth - 1].Right())) { 724 // The successor is the left-most node in the right subtree. 725 mPath[mDepth++] = node; 726 while ((node = mPath[mDepth - 1].Left())) { 727 mPath[mDepth++] = node; 728 } 729 } else { 730 // The successor is above the current node. Unwind until a 731 // left-leaning edge is removed from the path, of the path is empty. 732 for (mDepth--; mDepth > 0; mDepth--) { 733 if (mPath[mDepth - 1].Left() == mPath[mDepth]) { 734 break; 735 } 736 } 737 } 738 return Current(); 739 } 740 741 T* Current() { return mDepth > 0 ? mPath[mDepth - 1].Get() : nullptr; } 742 743 bool NotDone() { return !!mDepth; } 744 }; 745 746 Iterator iter() { return Iterator(this); } 747 }; 748 749 #endif // RB_H_