Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / memory / build / rb.h
blob418d2069112d469576fe93e9948e2995c4820faf
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/. */
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.
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.
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.
36 // ****************************************************************************
38 // C++ template implementation of left-leaning red-black trees.
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.
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
54 // Interpretation of comparision function return values:
56 // Order::eLess: aNode < aOther
57 // Order::eEqual: aNode == aOther
58 // Order::eGreater: aNode > aOther
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.
64 // ***************************************************************************
66 #ifndef RB_H_
67 #define RB_H_
69 #include "mozilla/Alignment.h"
70 #include "mozilla/Assertions.h"
71 #include "Utils.h"
73 enum NodeColor {
74 Black = 0,
75 Red = 1,
78 // Node structure.
79 template <typename T>
80 class RedBlackTreeNode {
81 T* mLeft;
82 // The lowest bit is the color
83 T* mRightAndColor;
85 public:
86 T* Left() { return mLeft; }
88 void SetLeft(T* aValue) { mLeft = aValue; }
90 T* Right() {
91 return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(mRightAndColor) &
92 uintptr_t(~1));
95 void SetRight(T* aValue) {
96 mRightAndColor = reinterpret_cast<T*>(
97 (reinterpret_cast<uintptr_t>(aValue) & uintptr_t(~1)) | Color());
100 NodeColor Color() {
101 return static_cast<NodeColor>(reinterpret_cast<uintptr_t>(mRightAndColor) &
105 bool IsBlack() { return Color() == NodeColor::Black; }
107 bool IsRed() { return Color() == NodeColor::Red; }
109 void SetColor(NodeColor aColor) {
110 mRightAndColor = reinterpret_cast<T*>(
111 (reinterpret_cast<uintptr_t>(mRightAndColor) & uintptr_t(~1)) | aColor);
115 // Tree structure.
116 template <typename T, typename Trait>
117 class RedBlackTree {
118 public:
119 void Init() { mRoot = nullptr; }
121 T* First(T* aStart = nullptr) { return First(TreeNode(aStart)).Get(); }
123 T* Last(T* aStart = nullptr) { return Last(TreeNode(aStart)).Get(); }
125 T* Next(T* aNode) { return Next(TreeNode(aNode)).Get(); }
127 T* Prev(T* aNode) { return Prev(TreeNode(aNode)).Get(); }
129 T* Search(T* aKey) { return Search(TreeNode(aKey)).Get(); }
131 // Find a match if it exists. Otherwise, find the next greater node, if one
132 // exists.
133 T* SearchOrNext(T* aKey) { return SearchOrNext(TreeNode(aKey)).Get(); }
135 void Insert(T* aNode) { Insert(TreeNode(aNode)); }
137 void Remove(T* aNode) { Remove(TreeNode(aNode)); }
139 // Helper class to avoid having all the tree traversal code further below
140 // have to use Trait::GetTreeNode and do manual null pointer checks, adding
141 // visual noise. Practically speaking TreeNode(nullptr) acts as a virtual
142 // sentinel, that loops back to itself for Left() and Right() and is always
143 // black.
144 class TreeNode {
145 public:
146 constexpr TreeNode() : mNode(nullptr) {}
148 MOZ_IMPLICIT TreeNode(T* aNode) : mNode(aNode) {}
150 TreeNode& operator=(TreeNode aOther) {
151 mNode = aOther.mNode;
152 return *this;
155 TreeNode Left() {
156 return TreeNode(mNode ? Trait::GetTreeNode(mNode).Left() : nullptr);
159 void SetLeft(TreeNode aNode) {
160 MOZ_RELEASE_ASSERT(mNode);
161 Trait::GetTreeNode(mNode).SetLeft(aNode.mNode);
164 TreeNode Right() {
165 return TreeNode(mNode ? Trait::GetTreeNode(mNode).Right() : nullptr);
168 void SetRight(TreeNode aNode) {
169 MOZ_RELEASE_ASSERT(mNode);
170 Trait::GetTreeNode(mNode).SetRight(aNode.mNode);
173 NodeColor Color() {
174 return mNode ? Trait::GetTreeNode(mNode).Color() : NodeColor::Black;
177 bool IsRed() { return Color() == NodeColor::Red; }
179 bool IsBlack() { return Color() == NodeColor::Black; }
181 void SetColor(NodeColor aColor) {
182 MOZ_RELEASE_ASSERT(mNode);
183 Trait::GetTreeNode(mNode).SetColor(aColor);
186 T* Get() { return mNode; }
188 MOZ_IMPLICIT operator bool() { return !!mNode; }
190 bool operator==(TreeNode& aOther) { return mNode == aOther.mNode; }
192 private:
193 T* mNode;
196 private:
197 // Ideally we'd use a TreeNode for mRoot, but we need RedBlackTree to stay
198 // a POD type to avoid a static initializer for gArenas.
199 T* mRoot;
201 TreeNode First(TreeNode aStart) {
202 TreeNode ret;
203 for (ret = aStart ? aStart : mRoot; ret.Left(); ret = ret.Left()) {
205 return ret;
208 TreeNode Last(TreeNode aStart) {
209 TreeNode ret;
210 for (ret = aStart ? aStart : mRoot; ret.Right(); ret = ret.Right()) {
212 return ret;
215 TreeNode Next(TreeNode aNode) {
216 TreeNode ret;
217 if (aNode.Right()) {
218 ret = First(aNode.Right());
219 } else {
220 TreeNode rbp_n_t = mRoot;
221 MOZ_ASSERT(rbp_n_t);
222 ret = nullptr;
223 while (true) {
224 Order rbp_n_cmp = Trait::Compare(aNode.Get(), rbp_n_t.Get());
225 if (rbp_n_cmp == Order::eLess) {
226 ret = rbp_n_t;
227 rbp_n_t = rbp_n_t.Left();
228 } else if (rbp_n_cmp == Order::eGreater) {
229 rbp_n_t = rbp_n_t.Right();
230 } else {
231 break;
233 MOZ_ASSERT(rbp_n_t);
236 return ret;
239 TreeNode Prev(TreeNode aNode) {
240 TreeNode ret;
241 if (aNode.Left()) {
242 ret = Last(aNode.Left());
243 } else {
244 TreeNode rbp_p_t = mRoot;
245 MOZ_ASSERT(rbp_p_t);
246 ret = nullptr;
247 while (true) {
248 Order rbp_p_cmp = Trait::Compare(aNode.Get(), rbp_p_t.Get());
249 if (rbp_p_cmp == Order::eLess) {
250 rbp_p_t = rbp_p_t.Left();
251 } else if (rbp_p_cmp == Order::eGreater) {
252 ret = rbp_p_t;
253 rbp_p_t = rbp_p_t.Right();
254 } else {
255 break;
257 MOZ_ASSERT(rbp_p_t);
260 return ret;
263 TreeNode Search(TreeNode aKey) {
264 TreeNode ret = mRoot;
265 Order rbp_se_cmp;
266 while (ret && (rbp_se_cmp = Trait::Compare(aKey.Get(), ret.Get())) !=
267 Order::eEqual) {
268 if (rbp_se_cmp == Order::eLess) {
269 ret = ret.Left();
270 } else {
271 ret = ret.Right();
274 return ret;
277 TreeNode SearchOrNext(TreeNode aKey) {
278 TreeNode ret = nullptr;
279 TreeNode rbp_ns_t = mRoot;
280 while (rbp_ns_t) {
281 Order rbp_ns_cmp = Trait::Compare(aKey.Get(), rbp_ns_t.Get());
282 if (rbp_ns_cmp == Order::eLess) {
283 ret = rbp_ns_t;
284 rbp_ns_t = rbp_ns_t.Left();
285 } else if (rbp_ns_cmp == Order::eGreater) {
286 rbp_ns_t = rbp_ns_t.Right();
287 } else {
288 ret = rbp_ns_t;
289 break;
292 return ret;
295 void Insert(TreeNode aNode) {
296 // rbp_i_s is only used as a placeholder for its RedBlackTreeNode. Use
297 // AlignedStorage2 to avoid running the TreeNode base class constructor.
298 mozilla::AlignedStorage2<T> rbp_i_s;
299 TreeNode rbp_i_g, rbp_i_p, rbp_i_c, rbp_i_t, rbp_i_u;
300 Order rbp_i_cmp = Order::eEqual;
301 rbp_i_g = nullptr;
302 rbp_i_p = rbp_i_s.addr();
303 rbp_i_p.SetLeft(mRoot);
304 rbp_i_p.SetRight(nullptr);
305 rbp_i_p.SetColor(NodeColor::Black);
306 rbp_i_c = mRoot;
307 // Iteratively search down the tree for the insertion point,
308 // splitting 4-nodes as they are encountered. At the end of each
309 // iteration, rbp_i_g->rbp_i_p->rbp_i_c is a 3-level path down
310 // the tree, assuming a sufficiently deep tree.
311 while (rbp_i_c) {
312 rbp_i_t = rbp_i_c.Left();
313 rbp_i_u = rbp_i_t.Left();
314 if (rbp_i_t.IsRed() && rbp_i_u.IsRed()) {
315 // rbp_i_c is the top of a logical 4-node, so split it.
316 // This iteration does not move down the tree, due to the
317 // disruptiveness of node splitting.
319 // Rotate right.
320 rbp_i_t = RotateRight(rbp_i_c);
321 // Pass red links up one level.
322 rbp_i_u = rbp_i_t.Left();
323 rbp_i_u.SetColor(NodeColor::Black);
324 if (rbp_i_p.Left() == rbp_i_c) {
325 rbp_i_p.SetLeft(rbp_i_t);
326 rbp_i_c = rbp_i_t;
327 } else {
328 // rbp_i_c was the right child of rbp_i_p, so rotate
329 // left in order to maintain the left-leaning invariant.
330 MOZ_ASSERT(rbp_i_p.Right() == rbp_i_c);
331 rbp_i_p.SetRight(rbp_i_t);
332 rbp_i_u = LeanLeft(rbp_i_p);
333 if (rbp_i_g.Left() == rbp_i_p) {
334 rbp_i_g.SetLeft(rbp_i_u);
335 } else {
336 MOZ_ASSERT(rbp_i_g.Right() == rbp_i_p);
337 rbp_i_g.SetRight(rbp_i_u);
339 rbp_i_p = rbp_i_u;
340 rbp_i_cmp = Trait::Compare(aNode.Get(), rbp_i_p.Get());
341 if (rbp_i_cmp == Order::eLess) {
342 rbp_i_c = rbp_i_p.Left();
343 } else {
344 MOZ_ASSERT(rbp_i_cmp == Order::eGreater);
345 rbp_i_c = rbp_i_p.Right();
347 continue;
350 rbp_i_g = rbp_i_p;
351 rbp_i_p = rbp_i_c;
352 rbp_i_cmp = Trait::Compare(aNode.Get(), rbp_i_c.Get());
353 if (rbp_i_cmp == Order::eLess) {
354 rbp_i_c = rbp_i_c.Left();
355 } else {
356 MOZ_ASSERT(rbp_i_cmp == Order::eGreater);
357 rbp_i_c = rbp_i_c.Right();
360 // rbp_i_p now refers to the node under which to insert.
361 aNode.SetLeft(nullptr);
362 aNode.SetRight(nullptr);
363 aNode.SetColor(NodeColor::Red);
364 if (rbp_i_cmp == Order::eGreater) {
365 rbp_i_p.SetRight(aNode);
366 rbp_i_t = LeanLeft(rbp_i_p);
367 if (rbp_i_g.Left() == rbp_i_p) {
368 rbp_i_g.SetLeft(rbp_i_t);
369 } else if (rbp_i_g.Right() == rbp_i_p) {
370 rbp_i_g.SetRight(rbp_i_t);
372 } else {
373 rbp_i_p.SetLeft(aNode);
375 // Update the root and make sure that it is black.
376 TreeNode root = TreeNode(rbp_i_s.addr()).Left();
377 root.SetColor(NodeColor::Black);
378 mRoot = root.Get();
381 void Remove(TreeNode aNode) {
382 // rbp_r_s is only used as a placeholder for its RedBlackTreeNode. Use
383 // AlignedStorage2 to avoid running the TreeNode base class constructor.
384 mozilla::AlignedStorage2<T> rbp_r_s;
385 TreeNode rbp_r_p, rbp_r_c, rbp_r_xp, rbp_r_t, rbp_r_u;
386 Order rbp_r_cmp;
387 rbp_r_p = TreeNode(rbp_r_s.addr());
388 rbp_r_p.SetLeft(mRoot);
389 rbp_r_p.SetRight(nullptr);
390 rbp_r_p.SetColor(NodeColor::Black);
391 rbp_r_c = mRoot;
392 rbp_r_xp = nullptr;
393 // Iterate down the tree, but always transform 2-nodes to 3- or
394 // 4-nodes in order to maintain the invariant that the current
395 // node is not a 2-node. This allows simple deletion once a leaf
396 // is reached. Handle the root specially though, since there may
397 // be no way to convert it from a 2-node to a 3-node.
398 rbp_r_cmp = Trait::Compare(aNode.Get(), rbp_r_c.Get());
399 if (rbp_r_cmp == Order::eLess) {
400 rbp_r_t = rbp_r_c.Left();
401 rbp_r_u = rbp_r_t.Left();
402 if (rbp_r_t.IsBlack() && rbp_r_u.IsBlack()) {
403 // Apply standard transform to prepare for left move.
404 rbp_r_t = MoveRedLeft(rbp_r_c);
405 rbp_r_t.SetColor(NodeColor::Black);
406 rbp_r_p.SetLeft(rbp_r_t);
407 rbp_r_c = rbp_r_t;
408 } else {
409 // Move left.
410 rbp_r_p = rbp_r_c;
411 rbp_r_c = rbp_r_c.Left();
413 } else {
414 if (rbp_r_cmp == Order::eEqual) {
415 MOZ_ASSERT(aNode == rbp_r_c);
416 if (!rbp_r_c.Right()) {
417 // Delete root node (which is also a leaf node).
418 if (rbp_r_c.Left()) {
419 rbp_r_t = LeanRight(rbp_r_c);
420 rbp_r_t.SetRight(nullptr);
421 } else {
422 rbp_r_t = nullptr;
424 rbp_r_p.SetLeft(rbp_r_t);
425 } else {
426 // This is the node we want to delete, but we will
427 // instead swap it with its successor and delete the
428 // successor. Record enough information to do the
429 // swap later. rbp_r_xp is the aNode's parent.
430 rbp_r_xp = rbp_r_p;
431 rbp_r_cmp = Order::eGreater; // Note that deletion is incomplete.
434 if (rbp_r_cmp == Order::eGreater) {
435 if (rbp_r_c.Right().Left().IsBlack()) {
436 rbp_r_t = rbp_r_c.Left();
437 if (rbp_r_t.IsRed()) {
438 // Standard transform.
439 rbp_r_t = MoveRedRight(rbp_r_c);
440 } else {
441 // Root-specific transform.
442 rbp_r_c.SetColor(NodeColor::Red);
443 rbp_r_u = rbp_r_t.Left();
444 if (rbp_r_u.IsRed()) {
445 rbp_r_u.SetColor(NodeColor::Black);
446 rbp_r_t = RotateRight(rbp_r_c);
447 rbp_r_u = RotateLeft(rbp_r_c);
448 rbp_r_t.SetRight(rbp_r_u);
449 } else {
450 rbp_r_t.SetColor(NodeColor::Red);
451 rbp_r_t = RotateLeft(rbp_r_c);
454 rbp_r_p.SetLeft(rbp_r_t);
455 rbp_r_c = rbp_r_t;
456 } else {
457 // Move right.
458 rbp_r_p = rbp_r_c;
459 rbp_r_c = rbp_r_c.Right();
463 if (rbp_r_cmp != Order::eEqual) {
464 while (true) {
465 MOZ_ASSERT(rbp_r_p);
466 rbp_r_cmp = Trait::Compare(aNode.Get(), rbp_r_c.Get());
467 if (rbp_r_cmp == Order::eLess) {
468 rbp_r_t = rbp_r_c.Left();
469 if (!rbp_r_t) {
470 // rbp_r_c now refers to the successor node to
471 // relocate, and rbp_r_xp/aNode refer to the
472 // context for the relocation.
473 if (rbp_r_xp.Left() == aNode) {
474 rbp_r_xp.SetLeft(rbp_r_c);
475 } else {
476 MOZ_ASSERT(rbp_r_xp.Right() == (aNode));
477 rbp_r_xp.SetRight(rbp_r_c);
479 rbp_r_c.SetLeft(aNode.Left());
480 rbp_r_c.SetRight(aNode.Right());
481 rbp_r_c.SetColor(aNode.Color());
482 if (rbp_r_p.Left() == rbp_r_c) {
483 rbp_r_p.SetLeft(nullptr);
484 } else {
485 MOZ_ASSERT(rbp_r_p.Right() == rbp_r_c);
486 rbp_r_p.SetRight(nullptr);
488 break;
490 rbp_r_u = rbp_r_t.Left();
491 if (rbp_r_t.IsBlack() && rbp_r_u.IsBlack()) {
492 rbp_r_t = MoveRedLeft(rbp_r_c);
493 if (rbp_r_p.Left() == rbp_r_c) {
494 rbp_r_p.SetLeft(rbp_r_t);
495 } else {
496 rbp_r_p.SetRight(rbp_r_t);
498 rbp_r_c = rbp_r_t;
499 } else {
500 rbp_r_p = rbp_r_c;
501 rbp_r_c = rbp_r_c.Left();
503 } else {
504 // Check whether to delete this node (it has to be
505 // the correct node and a leaf node).
506 if (rbp_r_cmp == Order::eEqual) {
507 MOZ_ASSERT(aNode == rbp_r_c);
508 if (!rbp_r_c.Right()) {
509 // Delete leaf node.
510 if (rbp_r_c.Left()) {
511 rbp_r_t = LeanRight(rbp_r_c);
512 rbp_r_t.SetRight(nullptr);
513 } else {
514 rbp_r_t = nullptr;
516 if (rbp_r_p.Left() == rbp_r_c) {
517 rbp_r_p.SetLeft(rbp_r_t);
518 } else {
519 rbp_r_p.SetRight(rbp_r_t);
521 break;
523 // This is the node we want to delete, but we
524 // will instead swap it with its successor
525 // and delete the successor. Record enough
526 // information to do the swap later.
527 // rbp_r_xp is aNode's parent.
528 rbp_r_xp = rbp_r_p;
530 rbp_r_t = rbp_r_c.Right();
531 rbp_r_u = rbp_r_t.Left();
532 if (rbp_r_u.IsBlack()) {
533 rbp_r_t = MoveRedRight(rbp_r_c);
534 if (rbp_r_p.Left() == rbp_r_c) {
535 rbp_r_p.SetLeft(rbp_r_t);
536 } else {
537 rbp_r_p.SetRight(rbp_r_t);
539 rbp_r_c = rbp_r_t;
540 } else {
541 rbp_r_p = rbp_r_c;
542 rbp_r_c = rbp_r_c.Right();
547 // Update root.
548 mRoot = TreeNode(rbp_r_s.addr()).Left().Get();
549 aNode.SetLeft(nullptr);
550 aNode.SetRight(nullptr);
551 aNode.SetColor(NodeColor::Black);
554 TreeNode RotateLeft(TreeNode aNode) {
555 TreeNode node = aNode.Right();
556 aNode.SetRight(node.Left());
557 node.SetLeft(aNode);
558 return node;
561 TreeNode RotateRight(TreeNode aNode) {
562 TreeNode node = aNode.Left();
563 aNode.SetLeft(node.Right());
564 node.SetRight(aNode);
565 return node;
568 TreeNode LeanLeft(TreeNode aNode) {
569 TreeNode node = RotateLeft(aNode);
570 NodeColor color = aNode.Color();
571 node.SetColor(color);
572 aNode.SetColor(NodeColor::Red);
573 return node;
576 TreeNode LeanRight(TreeNode aNode) {
577 TreeNode node = RotateRight(aNode);
578 NodeColor color = aNode.Color();
579 node.SetColor(color);
580 aNode.SetColor(NodeColor::Red);
581 return node;
584 TreeNode MoveRedLeft(TreeNode aNode) {
585 TreeNode node;
586 TreeNode rbp_mrl_t, rbp_mrl_u;
587 rbp_mrl_t = aNode.Left();
588 rbp_mrl_t.SetColor(NodeColor::Red);
589 rbp_mrl_t = aNode.Right();
590 rbp_mrl_u = rbp_mrl_t.Left();
591 if (rbp_mrl_u.IsRed()) {
592 rbp_mrl_u = RotateRight(rbp_mrl_t);
593 aNode.SetRight(rbp_mrl_u);
594 node = RotateLeft(aNode);
595 rbp_mrl_t = aNode.Right();
596 if (rbp_mrl_t.IsRed()) {
597 rbp_mrl_t.SetColor(NodeColor::Black);
598 aNode.SetColor(NodeColor::Red);
599 rbp_mrl_t = RotateLeft(aNode);
600 node.SetLeft(rbp_mrl_t);
601 } else {
602 aNode.SetColor(NodeColor::Black);
604 } else {
605 aNode.SetColor(NodeColor::Red);
606 node = RotateLeft(aNode);
608 return node;
611 TreeNode MoveRedRight(TreeNode aNode) {
612 TreeNode node;
613 TreeNode rbp_mrr_t;
614 rbp_mrr_t = aNode.Left();
615 if (rbp_mrr_t.IsRed()) {
616 TreeNode rbp_mrr_u, rbp_mrr_v;
617 rbp_mrr_u = rbp_mrr_t.Right();
618 rbp_mrr_v = rbp_mrr_u.Left();
619 if (rbp_mrr_v.IsRed()) {
620 rbp_mrr_u.SetColor(aNode.Color());
621 rbp_mrr_v.SetColor(NodeColor::Black);
622 rbp_mrr_u = RotateLeft(rbp_mrr_t);
623 aNode.SetLeft(rbp_mrr_u);
624 node = RotateRight(aNode);
625 rbp_mrr_t = RotateLeft(aNode);
626 node.SetRight(rbp_mrr_t);
627 } else {
628 rbp_mrr_t.SetColor(aNode.Color());
629 rbp_mrr_u.SetColor(NodeColor::Red);
630 node = RotateRight(aNode);
631 rbp_mrr_t = RotateLeft(aNode);
632 node.SetRight(rbp_mrr_t);
634 aNode.SetColor(NodeColor::Red);
635 } else {
636 rbp_mrr_t.SetColor(NodeColor::Red);
637 rbp_mrr_t = rbp_mrr_t.Left();
638 if (rbp_mrr_t.IsRed()) {
639 rbp_mrr_t.SetColor(NodeColor::Black);
640 node = RotateRight(aNode);
641 rbp_mrr_t = RotateLeft(aNode);
642 node.SetRight(rbp_mrr_t);
643 } else {
644 node = RotateLeft(aNode);
647 return node;
650 // The iterator simulates recursion via an array of pointers that store the
651 // current path. This is critical to performance, since a series of calls to
652 // rb_{next,prev}() would require time proportional to (n lg n), whereas this
653 // implementation only requires time proportional to (n).
655 // Since the iterator caches a path down the tree, any tree modification may
656 // cause the cached path to become invalid. Don't modify the tree during an
657 // iteration.
659 // Size the path arrays such that they are always large enough, even if a
660 // tree consumes all of memory. Since each node must contain a minimum of
661 // two pointers, there can never be more nodes than:
663 // 1 << ((sizeof(void*)<<3) - (log2(sizeof(void*))+1))
665 // Since the depth of a tree is limited to 3*lg(#nodes), the maximum depth
666 // is:
668 // (3 * ((sizeof(void*)<<3) - (log2(sizeof(void*))+1)))
670 // This works out to a maximum depth of 87 and 180 for 32- and 64-bit
671 // systems, respectively (approximately 348 and 1440 bytes, respectively).
672 public:
673 class Iterator {
674 TreeNode mPath[3 * ((sizeof(void*) << 3) - (LOG2(sizeof(void*)) + 1))];
675 unsigned mDepth;
677 public:
678 explicit Iterator(RedBlackTree<T, Trait>* aTree) : mDepth(0) {
679 // Initialize the path to contain the left spine.
680 if (aTree->mRoot) {
681 TreeNode node;
682 mPath[mDepth++] = aTree->mRoot;
683 while ((node = mPath[mDepth - 1].Left())) {
684 mPath[mDepth++] = node;
689 template <typename Iterator>
690 class Item {
691 Iterator* mIterator;
692 T* mItem;
694 public:
695 Item(Iterator* aIterator, T* aItem)
696 : mIterator(aIterator), mItem(aItem) {}
698 bool operator!=(const Item& aOther) const {
699 return (mIterator != aOther.mIterator) || (mItem != aOther.mItem);
702 T* operator*() const { return mItem; }
704 const Item& operator++() {
705 mItem = mIterator->Next();
706 return *this;
710 Item<Iterator> begin() {
711 return Item<Iterator>(this,
712 mDepth > 0 ? mPath[mDepth - 1].Get() : nullptr);
715 Item<Iterator> end() { return Item<Iterator>(this, nullptr); }
717 T* Next() {
718 TreeNode node;
719 if ((node = mPath[mDepth - 1].Right())) {
720 // The successor is the left-most node in the right subtree.
721 mPath[mDepth++] = node;
722 while ((node = mPath[mDepth - 1].Left())) {
723 mPath[mDepth++] = node;
725 } else {
726 // The successor is above the current node. Unwind until a
727 // left-leaning edge is removed from the path, of the path is empty.
728 for (mDepth--; mDepth > 0; mDepth--) {
729 if (mPath[mDepth - 1].Left() == mPath[mDepth]) {
730 break;
734 return mDepth > 0 ? mPath[mDepth - 1].Get() : nullptr;
738 Iterator iter() { return Iterator(this); }
741 #endif // RB_H_