1 /** 2 This module implements a red-black tree container. 3 4 This module is a submodule of $(MREF std, container). 5 6 Source: $(PHOBOSSRC std/container/rbtree.d) 7 8 Copyright: Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code 9 copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders. 10 11 License: Distributed under the Boost Software License, Version 1.0. 12 (See accompanying file LICENSE_1_0.txt or copy at $(HTTP 13 boost.org/LICENSE_1_0.txt)). 14 15 Authors: Steven Schveighoffer, $(HTTP erdani.com, Andrei Alexandrescu) 16 */ 17 module std.container.rbtree; 18 19 /// 20 @safe pure unittest 21 { 22 import std.algorithm.comparison : equal; 23 import std.container.rbtree; 24 25 auto rbt = redBlackTree(3, 1, 4, 2, 5); 26 assert(rbt.front == 1); 27 assert(equal(rbt[], [1, 2, 3, 4, 5])); 28 29 rbt.removeKey(1, 4); 30 assert(equal(rbt[], [2, 3, 5])); 31 32 rbt.removeFront(); 33 assert(equal(rbt[], [3, 5])); 34 35 rbt.insert([1, 2, 4]); 36 assert(equal(rbt[], [1, 2, 3, 4, 5])); 37 38 // Query bounds in O(log(n)) 39 assert(rbt.lowerBound(3).equal([1, 2])); 40 assert(rbt.equalRange(3).equal([3])); 41 assert(rbt.upperBound(3).equal([4, 5])); 42 43 // A Red Black tree with the highest element at front: 44 import std.range : iota; 45 auto maxTree = redBlackTree!"a > b"(iota(5)); 46 assert(equal(maxTree[], [4, 3, 2, 1, 0])); 47 48 // adding duplicates will not add them, but return 0 49 auto rbt2 = redBlackTree(1, 3); 50 assert(rbt2.insert(1) == 0); 51 assert(equal(rbt2[], [1, 3])); 52 assert(rbt2.insert(2) == 1); 53 54 // however you can allow duplicates 55 auto ubt = redBlackTree!true([0, 1, 0, 1]); 56 assert(equal(ubt[], [0, 0, 1, 1])); 57 } 58 59 import std.format; 60 import std.functional : binaryFun; 61 62 public import std.container.util; 63 64 version (StdUnittest) debug = RBDoChecks; 65 66 //debug = RBDoChecks; 67 68 /* 69 * Implementation for a Red Black node for use in a Red Black Tree (see below) 70 * 71 * this implementation assumes we have a marker Node that is the parent of the 72 * root Node. This marker Node is not a valid Node, but marks the end of the 73 * collection. The root is the left child of the marker Node, so it is always 74 * last in the collection. The marker Node is passed in to the setColor 75 * function, and the Node which has this Node as its parent is assumed to be 76 * the root Node. 77 * 78 * A Red Black tree should have O(lg(n)) insertion, removal, and search time. 79 */ 80 struct RBNode(V) 81 { 82 /* 83 * Convenience alias 84 */ 85 alias Node = RBNode*; 86 87 private Node _left; 88 private Node _right; 89 private Node _parent; 90 91 /** 92 * The value held by this node 93 */ 94 V value; 95 96 /** 97 * Enumeration determining what color the node is. Null nodes are assumed 98 * to be black. 99 */ 100 enum Color : byte 101 { 102 Red, 103 Black 104 } 105 106 /** 107 * The color of the node. 108 */ 109 Color color; 110 111 /** 112 * Get the left child 113 */ 114 @property inout(RBNode)* left() inout return scope 115 { 116 return _left; 117 } 118 119 /** 120 * Get the right child 121 */ 122 @property inout(RBNode)* right() inout return scope 123 { 124 return _right; 125 } 126 127 /** 128 * Get the parent 129 */ 130 @property inout(RBNode)* parent() inout return scope 131 { 132 return _parent; 133 } 134 135 /** 136 * Set the left child. Also updates the new child's parent node. This 137 * does not update the previous child. 138 * 139 * $(RED Warning: If the node this is called on is a local variable, a stack pointer can be 140 * escaped through `newNode.parent`. It's marked `@trusted` only for backwards compatibility.) 141 * 142 * Returns newNode 143 */ 144 @property Node left(return scope Node newNode) @trusted 145 { 146 _left = newNode; 147 if (newNode !is null) 148 newNode._parent = &this; 149 return newNode; 150 } 151 152 /** 153 * Set the right child. Also updates the new child's parent node. This 154 * does not update the previous child. 155 * 156 * $(RED Warning: If the node this is called on is a local variable, a stack pointer can be 157 * escaped through `newNode.parent`. It's marked `@trusted` only for backwards compatibility.) 158 * 159 * Returns newNode 160 */ 161 @property Node right(return scope Node newNode) @trusted 162 { 163 _right = newNode; 164 if (newNode !is null) 165 newNode._parent = &this; 166 return newNode; 167 } 168 169 // assume _left is not null 170 // 171 // performs rotate-right operation, where this is T, _right is R, _left is 172 // L, _parent is P: 173 // 174 // P P 175 // | -> | 176 // T L 177 // / \ / \ 178 // L R a T 179 // / \ / \ 180 // a b b R 181 // 182 /** 183 * Rotate right. This performs the following operations: 184 * - The left child becomes the parent of this node. 185 * - This node becomes the new parent's right child. 186 * - The old right child of the new parent becomes the left child of this 187 * node. 188 */ 189 Node rotateR() 190 in 191 { 192 assert(_left !is null, "left node must not be null"); 193 } 194 do 195 { 196 // sets _left._parent also 197 if (isLeftNode) 198 parent.left = _left; 199 else 200 parent.right = _left; 201 Node tmp = _left._right; 202 203 // sets _parent also 204 _left.right = &this; 205 206 // sets tmp._parent also 207 left = tmp; 208 209 return &this; 210 } 211 212 // assumes _right is non null 213 // 214 // performs rotate-left operation, where this is T, _right is R, _left is 215 // L, _parent is P: 216 // 217 // P P 218 // | -> | 219 // T R 220 // / \ / \ 221 // L R T b 222 // / \ / \ 223 // a b L a 224 // 225 /** 226 * Rotate left. This performs the following operations: 227 * - The right child becomes the parent of this node. 228 * - This node becomes the new parent's left child. 229 * - The old left child of the new parent becomes the right child of this 230 * node. 231 */ 232 Node rotateL() 233 in 234 { 235 assert(_right !is null, "right node must not be null"); 236 } 237 do 238 { 239 // sets _right._parent also 240 if (isLeftNode) 241 parent.left = _right; 242 else 243 parent.right = _right; 244 Node tmp = _right._left; 245 246 // sets _parent also 247 _right.left = &this; 248 249 // sets tmp._parent also 250 right = tmp; 251 return &this; 252 } 253 254 255 /** 256 * Returns true if this node is a left child. 257 * 258 * Note that this should always return a value because the root has a 259 * parent which is the marker node. 260 */ 261 @property bool isLeftNode() const 262 in 263 { 264 assert(_parent !is null, "parent must not be null"); 265 } 266 do 267 { 268 return _parent._left is &this; 269 } 270 271 /** 272 * Set the color of the node after it is inserted. This performs an 273 * update to the whole tree, possibly rotating nodes to keep the Red-Black 274 * properties correct. This is an O(lg(n)) operation, where n is the 275 * number of nodes in the tree. 276 * 277 * end is the marker node, which is the parent of the topmost valid node. 278 */ 279 void setColor(Node end) 280 { 281 // test against the marker node 282 if (_parent !is end) 283 { 284 if (_parent.color == Color.Red) 285 { 286 Node cur = &this; 287 while (true) 288 { 289 // because root is always black, _parent._parent always exists 290 if (cur._parent.isLeftNode) 291 { 292 // parent is left node, y is 'uncle', could be null 293 Node y = cur._parent._parent._right; 294 if (y !is null && y.color == Color.Red) 295 { 296 cur._parent.color = Color.Black; 297 y.color = Color.Black; 298 cur = cur._parent._parent; 299 if (cur._parent is end) 300 { 301 // root node 302 cur.color = Color.Black; 303 break; 304 } 305 else 306 { 307 // not root node 308 cur.color = Color.Red; 309 if (cur._parent.color == Color.Black) 310 // satisfied, exit the loop 311 break; 312 } 313 } 314 else 315 { 316 if (!cur.isLeftNode) 317 cur = cur._parent.rotateL(); 318 cur._parent.color = Color.Black; 319 cur = cur._parent._parent.rotateR(); 320 cur.color = Color.Red; 321 // tree should be satisfied now 322 break; 323 } 324 } 325 else 326 { 327 // parent is right node, y is 'uncle' 328 Node y = cur._parent._parent._left; 329 if (y !is null && y.color == Color.Red) 330 { 331 cur._parent.color = Color.Black; 332 y.color = Color.Black; 333 cur = cur._parent._parent; 334 if (cur._parent is end) 335 { 336 // root node 337 cur.color = Color.Black; 338 break; 339 } 340 else 341 { 342 // not root node 343 cur.color = Color.Red; 344 if (cur._parent.color == Color.Black) 345 // satisfied, exit the loop 346 break; 347 } 348 } 349 else 350 { 351 if (cur.isLeftNode) 352 cur = cur._parent.rotateR(); 353 cur._parent.color = Color.Black; 354 cur = cur._parent._parent.rotateL(); 355 cur.color = Color.Red; 356 // tree should be satisfied now 357 break; 358 } 359 } 360 } 361 362 } 363 } 364 else 365 { 366 // 367 // this is the root node, color it black 368 // 369 color = Color.Black; 370 } 371 } 372 373 /** 374 * Remove this node from the tree. The 'end' node is used as the marker 375 * which is root's parent. Note that this cannot be null! 376 * 377 * Returns the next highest valued node in the tree after this one, or end 378 * if this was the highest-valued node. 379 */ 380 Node remove(Node end) return 381 { 382 // 383 // remove this node from the tree, fixing the color if necessary. 384 // 385 Node x; 386 Node ret = next; 387 388 // if this node has 2 children 389 if (_left !is null && _right !is null) 390 { 391 // 392 // normally, we can just swap this node's and y's value, but 393 // because an iterator could be pointing to y and we don't want to 394 // disturb it, we swap this node and y's structure instead. This 395 // can also be a benefit if the value of the tree is a large 396 // struct, which takes a long time to copy. 397 // 398 Node yp, yl, yr; 399 Node y = ret; // y = next 400 yp = y._parent; 401 yl = y._left; 402 yr = y._right; 403 auto yc = y.color; 404 auto isyleft = y.isLeftNode; 405 406 // 407 // replace y's structure with structure of this node. 408 // 409 if (isLeftNode) 410 _parent.left = y; 411 else 412 _parent.right = y; 413 // 414 // need special case so y doesn't point back to itself 415 // 416 y.left = _left; 417 if (_right is y) 418 y.right = &this; 419 else 420 y.right = _right; 421 y.color = color; 422 423 // 424 // replace this node's structure with structure of y. 425 // 426 left = yl; 427 right = yr; 428 if (_parent !is y) 429 { 430 if (isyleft) 431 yp.left = &this; 432 else 433 yp.right = &this; 434 } 435 color = yc; 436 } 437 438 // if this has less than 2 children, remove it 439 if (_left !is null) 440 x = _left; 441 else 442 x = _right; 443 444 bool deferedUnlink = false; 445 if (x is null) 446 { 447 // pretend this is a null node, defer unlinking the node 448 x = &this; 449 deferedUnlink = true; 450 } 451 else if (isLeftNode) 452 _parent.left = x; 453 else 454 _parent.right = x; 455 456 // if the color of this is black, then it needs to be fixed 457 if (color == color.Black) 458 { 459 // need to recolor the tree. 460 while (x._parent !is end && x.color == Node.Color.Black) 461 { 462 if (x.isLeftNode) 463 { 464 // left node 465 Node w = x._parent._right; 466 if (w.color == Node.Color.Red) 467 { 468 w.color = Node.Color.Black; 469 x._parent.color = Node.Color.Red; 470 x._parent.rotateL(); 471 w = x._parent._right; 472 } 473 Node wl = w.left; 474 Node wr = w.right; 475 if ((wl is null || wl.color == Node.Color.Black) && 476 (wr is null || wr.color == Node.Color.Black)) 477 { 478 w.color = Node.Color.Red; 479 x = x._parent; 480 } 481 else 482 { 483 if (wr is null || wr.color == Node.Color.Black) 484 { 485 // wl cannot be null here 486 wl.color = Node.Color.Black; 487 w.color = Node.Color.Red; 488 w.rotateR(); 489 w = x._parent._right; 490 } 491 492 w.color = x._parent.color; 493 x._parent.color = Node.Color.Black; 494 w._right.color = Node.Color.Black; 495 x._parent.rotateL(); 496 x = end.left; // x = root 497 } 498 } 499 else 500 { 501 // right node 502 Node w = x._parent._left; 503 if (w.color == Node.Color.Red) 504 { 505 w.color = Node.Color.Black; 506 x._parent.color = Node.Color.Red; 507 x._parent.rotateR(); 508 w = x._parent._left; 509 } 510 Node wl = w.left; 511 Node wr = w.right; 512 if ((wl is null || wl.color == Node.Color.Black) && 513 (wr is null || wr.color == Node.Color.Black)) 514 { 515 w.color = Node.Color.Red; 516 x = x._parent; 517 } 518 else 519 { 520 if (wl is null || wl.color == Node.Color.Black) 521 { 522 // wr cannot be null here 523 wr.color = Node.Color.Black; 524 w.color = Node.Color.Red; 525 w.rotateL(); 526 w = x._parent._left; 527 } 528 529 w.color = x._parent.color; 530 x._parent.color = Node.Color.Black; 531 w._left.color = Node.Color.Black; 532 x._parent.rotateR(); 533 x = end.left; // x = root 534 } 535 } 536 } 537 x.color = Node.Color.Black; 538 } 539 540 if (deferedUnlink) 541 { 542 // 543 // unlink this node from the tree 544 // 545 if (isLeftNode) 546 _parent.left = null; 547 else 548 _parent.right = null; 549 } 550 551 // clean references to help GC 552 // https://issues.dlang.org/show_bug.cgi?id=12915 553 _left = _right = _parent = null; 554 555 return ret; 556 } 557 558 /** 559 * Return the leftmost descendant of this node. 560 */ 561 @property inout(RBNode)* leftmost() inout return 562 { 563 inout(RBNode)* result = &this; 564 while (result._left !is null) 565 result = result._left; 566 return result; 567 } 568 569 /** 570 * Return the rightmost descendant of this node 571 */ 572 @property inout(RBNode)* rightmost() inout return 573 { 574 inout(RBNode)* result = &this; 575 while (result._right !is null) 576 result = result._right; 577 return result; 578 } 579 580 /** 581 * Returns the next valued node in the tree. 582 * 583 * You should never call this on the marker node, as it is assumed that 584 * there is a valid next node. 585 */ 586 @property inout(RBNode)* next() inout return 587 { 588 inout(RBNode)* n = &this; 589 if (n.right is null) 590 { 591 while (!n.isLeftNode) 592 n = n._parent; 593 return n._parent; 594 } 595 else 596 return n.right.leftmost; 597 } 598 599 /** 600 * Returns the previous valued node in the tree. 601 * 602 * You should never call this on the leftmost node of the tree as it is 603 * assumed that there is a valid previous node. 604 */ 605 @property inout(RBNode)* prev() inout return 606 { 607 inout(RBNode)* n = &this; 608 if (n.left is null) 609 { 610 while (n.isLeftNode) 611 n = n._parent; 612 return n._parent; 613 } 614 else 615 return n.left.rightmost; 616 } 617 618 Node dup(scope Node delegate(V v) alloc) 619 { 620 // 621 // duplicate this and all child nodes 622 // 623 // The recursion should be lg(n), so we shouldn't have to worry about 624 // stack size. 625 // 626 Node copy = alloc(value); 627 copy.color = color; 628 if (_left !is null) 629 copy.left = _left.dup(alloc); 630 if (_right !is null) 631 copy.right = _right.dup(alloc); 632 return copy; 633 } 634 635 Node dup() 636 { 637 Node copy = new RBNode!V(null, null, null, value); 638 copy.color = color; 639 if (_left !is null) 640 copy.left = _left.dup(); 641 if (_right !is null) 642 copy.right = _right.dup(); 643 return copy; 644 } 645 } 646 647 //constness checks 648 @safe pure unittest 649 { 650 const RBNode!int n; 651 static assert(is(typeof(n.leftmost))); 652 static assert(is(typeof(n.rightmost))); 653 static assert(is(typeof(n.next))); 654 static assert(is(typeof(n.prev))); 655 } 656 657 private struct RBRange(N) 658 { 659 alias Node = N; 660 alias Elem = typeof(Node.value); 661 662 private Node _begin; 663 private Node _end; 664 665 private this(Node b, Node e) 666 { 667 _begin = b; 668 _end = e; 669 } 670 671 /** 672 * Returns `true` if the range is _empty 673 */ 674 @property bool empty() const 675 { 676 return _begin is _end; 677 } 678 679 /** 680 * Returns the first element in the range 681 */ 682 ref @property Elem front() 683 { 684 return _begin.value; 685 } 686 687 /** 688 * Returns the last element in the range 689 */ 690 ref @property Elem back() 691 { 692 return _end.prev.value; 693 } 694 695 /** 696 * pop the front element from the range 697 * 698 * Complexity: amortized $(BIGOH 1) 699 */ 700 void popFront() 701 { 702 _begin = _begin.next; 703 } 704 705 /** 706 * pop the back element from the range 707 * 708 * Complexity: amortized $(BIGOH 1) 709 */ 710 void popBack() 711 { 712 _end = _end.prev; 713 } 714 715 /** 716 * Trivial _save implementation, needed for `isForwardRange`. 717 */ 718 @property RBRange save() 719 { 720 return this; 721 } 722 } 723 724 /** 725 * Implementation of a $(LINK2 https://en.wikipedia.org/wiki/Red%E2%80%93black_tree, 726 * red-black tree) container. 727 * 728 * All inserts, removes, searches, and any function in general has complexity 729 * of $(BIGOH lg(n)). 730 * 731 * To use a different comparison than $(D "a < b"), pass a different operator string 732 * that can be used by $(REF binaryFun, std,functional), or pass in a 733 * function, delegate, functor, or any type where $(D less(a, b)) results in a `bool` 734 * value. 735 * 736 * Note that less should produce a strict ordering. That is, for two unequal 737 * elements `a` and `b`, $(D less(a, b) == !less(b, a)). $(D less(a, a)) should 738 * always equal `false`. 739 * 740 * Care should also be taken to not modify elements in the tree (e.g. via `front` / 741 * `back`, which return by `ref`) in a way which would affect the order defined by 742 * the `less` predicate. 743 * 744 * If `allowDuplicates` is set to `true`, then inserting the same element more than 745 * once continues to add more elements. If it is `false`, duplicate elements are 746 * ignored on insertion. If duplicates are allowed, then new elements are 747 * inserted after all existing duplicate elements. 748 */ 749 final class RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false) 750 if (is(typeof(binaryFun!less(T.init, T.init)))) 751 { 752 import std.meta : allSatisfy; 753 import std.range : Take; 754 import std.range.primitives : isInputRange, walkLength; 755 import std.traits : isIntegral, isDynamicArray, isImplicitlyConvertible; 756 757 alias _less = binaryFun!less; 758 759 version (StdUnittest) 760 { 761 static if (is(typeof(less) == string)) 762 { 763 private enum doUnittest = is(byte : T) && isIntegral!T && (less == "a < b" || less == "a > b"); 764 } 765 else 766 enum doUnittest = false; 767 768 // note, this must be final so it does not affect the vtable layout 769 bool arrayEqual(T[] arr) 770 { 771 if (walkLength(this[]) == arr.length) 772 { 773 foreach (v; arr) 774 { 775 if (!(v in this)) 776 return false; 777 } 778 return true; 779 } 780 return false; 781 } 782 } 783 else 784 { 785 private enum doUnittest = false; 786 } 787 788 /** 789 * Element type for the tree 790 */ 791 alias Elem = T; 792 793 // used for convenience 794 private alias RBNode = .RBNode!Elem; 795 private alias Node = RBNode.Node; 796 797 private Node _end; 798 private Node _begin; 799 private size_t _length; 800 801 private void _setup() 802 { 803 //Make sure that _setup isn't run more than once. 804 assert(!_end, "Setup must only be run once"); 805 _begin = _end = allocate(); 806 } 807 808 static private Node allocate() 809 { 810 return new RBNode; 811 } 812 813 static private Node allocate(Elem v) 814 { 815 return new RBNode(null, null, null, v); 816 } 817 818 /** 819 * The range types for `RedBlackTree` 820 */ 821 alias Range = RBRange!(RBNode*); 822 alias ConstRange = RBRange!(const(RBNode)*); /// Ditto 823 alias ImmutableRange = RBRange!(immutable(RBNode)*); /// Ditto 824 825 static if (doUnittest) @safe pure unittest 826 { 827 import std.algorithm.comparison : equal; 828 import std.range.primitives; 829 auto ts = new RedBlackTree(1, 2, 3, 4, 5); 830 assert(ts.length == 5); 831 auto r = ts[]; 832 833 static if (less == "a < b") 834 auto vals = [1, 2, 3, 4, 5]; 835 else 836 auto vals = [5, 4, 3, 2, 1]; 837 assert(equal(r, vals)); 838 839 assert(r.front == vals.front); 840 assert(r.back != r.front); 841 auto oldfront = r.front; 842 auto oldback = r.back; 843 r.popFront(); 844 r.popBack(); 845 assert(r.front != r.back); 846 assert(r.front != oldfront); 847 assert(r.back != oldback); 848 assert(ts.length == 5); 849 } 850 851 // find a node based on an element value 852 private inout(RBNode)* _find(Elem e) inout 853 { 854 static if (allowDuplicates) 855 { 856 inout(RBNode)* cur = _end.left; 857 inout(RBNode)* result = null; 858 while (cur) 859 { 860 if (_less(cur.value, e)) 861 cur = cur.right; 862 else if (_less(e, cur.value)) 863 cur = cur.left; 864 else 865 { 866 // want to find the left-most element 867 result = cur; 868 cur = cur.left; 869 } 870 } 871 return result; 872 } 873 else 874 { 875 inout(RBNode)* cur = _end.left; 876 while (cur) 877 { 878 if (_less(cur.value, e)) 879 cur = cur.right; 880 else if (_less(e, cur.value)) 881 cur = cur.left; 882 else 883 return cur; 884 } 885 return null; 886 } 887 } 888 889 /* add an element to the tree, returns the node added, or the existing node 890 * if it has already been added and allowDuplicates is false 891 * Returns: 892 * true if node was added 893 */ 894 private bool _add(return scope Elem n) 895 { 896 Node result; 897 static if (!allowDuplicates) 898 bool added = true; 899 900 if (!_end.left) 901 { 902 result = allocate(n); 903 (() @trusted { _end.left = _begin = result; }) (); 904 } 905 else 906 { 907 Node newParent = _end.left; 908 Node nxt; 909 while (true) 910 { 911 if (_less(n, newParent.value)) 912 { 913 nxt = newParent.left; 914 if (nxt is null) 915 { 916 // 917 // add to right of new parent 918 // 919 result = allocate(n); 920 (() @trusted { newParent.left = result; }) (); 921 break; 922 } 923 } 924 else 925 { 926 static if (!allowDuplicates) 927 { 928 if (!_less(newParent.value, n)) 929 { 930 result = newParent; 931 added = false; 932 break; 933 } 934 } 935 nxt = newParent.right; 936 if (nxt is null) 937 { 938 // 939 // add to right of new parent 940 // 941 result = allocate(n); 942 (() @trusted { newParent.right = result; }) (); 943 break; 944 } 945 } 946 newParent = nxt; 947 } 948 if (_begin.left) 949 _begin = _begin.left; 950 } 951 static if (allowDuplicates) 952 { 953 result.setColor(_end); 954 debug(RBDoChecks) 955 check(); 956 ++_length; 957 return true; 958 } 959 else 960 { 961 if (added) 962 { 963 ++_length; 964 result.setColor(_end); 965 } 966 debug(RBDoChecks) 967 check(); 968 return added; 969 } 970 } 971 972 973 /** 974 * Check if any elements exist in the container. Returns `false` if at least 975 * one element exists. 976 */ 977 @property bool empty() const // pure, nothrow, @safe, @nogc: are inferred 978 { 979 return _end.left is null; 980 } 981 982 /++ 983 Returns the number of elements in the container. 984 985 Complexity: $(BIGOH 1). 986 +/ 987 @property size_t length() const 988 { 989 return _length; 990 } 991 992 /** 993 * Duplicate this container. The resulting container contains a shallow 994 * copy of the elements. 995 * 996 * Complexity: $(BIGOH n) 997 */ 998 @property RedBlackTree dup() 999 { 1000 return new RedBlackTree(_end.dup(), _length); 1001 } 1002 1003 static if (doUnittest) @safe pure unittest 1004 { 1005 import std.algorithm.comparison : equal; 1006 auto ts = new RedBlackTree(1, 2, 3, 4, 5); 1007 assert(ts.length == 5); 1008 auto ts2 = ts.dup; 1009 assert(ts2.length == 5); 1010 assert(equal(ts[], ts2[])); 1011 ts2.insert(cast(Elem) 6); 1012 assert(!equal(ts[], ts2[])); 1013 assert(ts.length == 5 && ts2.length == 6); 1014 } 1015 1016 /** 1017 * Fetch a range that spans all the elements in the container. 1018 * 1019 * Complexity: $(BIGOH 1) 1020 */ 1021 Range opSlice() 1022 { 1023 return Range(_begin, _end); 1024 } 1025 1026 /// Ditto 1027 ConstRange opSlice() const 1028 { 1029 return ConstRange(_begin, _end); 1030 } 1031 1032 /// Ditto 1033 ImmutableRange opSlice() immutable 1034 { 1035 return ImmutableRange(_begin, _end); 1036 } 1037 1038 /** 1039 * The front element in the container 1040 * 1041 * Complexity: $(BIGOH 1) 1042 */ 1043 ref inout(Elem) front() inout 1044 { 1045 return _begin.value; 1046 } 1047 1048 /** 1049 * The last element in the container 1050 * 1051 * Complexity: $(BIGOH log(n)) 1052 */ 1053 ref inout(Elem) back() inout 1054 { 1055 return _end.prev.value; 1056 } 1057 1058 /++ 1059 `in` operator. Check to see if the given element exists in the 1060 container. 1061 1062 Complexity: $(BIGOH log(n)) 1063 +/ 1064 bool opBinaryRight(string op)(Elem e) const 1065 if (op == "in") 1066 { 1067 return _find(e) !is null; 1068 } 1069 1070 static if (doUnittest) @safe pure unittest 1071 { 1072 auto ts = new RedBlackTree(1, 2, 3, 4, 5); 1073 assert(cast(Elem) 3 in ts); 1074 assert(cast(Elem) 6 !in ts); 1075 } 1076 1077 /** 1078 * Compares two trees for equality. 1079 * 1080 * Complexity: $(BIGOH n) 1081 */ 1082 override bool opEquals(Object rhs) 1083 { 1084 import std.algorithm.comparison : equal; 1085 1086 RedBlackTree that = cast(RedBlackTree) rhs; 1087 if (that is null) return false; 1088 1089 // If there aren't the same number of nodes, we can't be equal. 1090 if (this._length != that._length) return false; 1091 1092 auto thisRange = this[]; 1093 auto thatRange = that[]; 1094 return equal!((Elem a, Elem b) => !_less(a,b) && !_less(b,a)) 1095 (thisRange, thatRange); 1096 } 1097 1098 static if (doUnittest) @system unittest 1099 { 1100 auto t1 = new RedBlackTree(1,2,3,4); 1101 auto t2 = new RedBlackTree(1,2,3,4); 1102 auto t3 = new RedBlackTree(1,2,3,5); 1103 auto t4 = new RedBlackTree(1,2,3,4,5); 1104 auto o = new Object(); 1105 1106 assert(t1 == t1); 1107 assert(t1 == t2); 1108 assert(t1 != t3); 1109 assert(t1 != t4); 1110 assert(t1 != o); // pathological case, must not crash 1111 } 1112 1113 /** 1114 * Generates a hash for the tree. Note that with a custom comparison function 1115 * it may not hold that if two rbtrees are equal, the hashes of the trees 1116 * will be equal. 1117 */ 1118 override size_t toHash() nothrow @safe 1119 { 1120 size_t hash = cast(size_t) 0x6b63_616c_4264_6552UL; 1121 foreach (ref e; this[]) 1122 // As in boost::hash_combine 1123 // https://www.boost.org/doc/libs/1_55_0/doc/html/hash/reference.html#boost.hash_combine 1124 hash += .hashOf(e) + 0x9e3779b9 + (hash << 6) + (hash >>> 2); 1125 return hash; 1126 } 1127 1128 static if (doUnittest) @system unittest 1129 { 1130 auto t1 = new RedBlackTree(1,2,3,4); 1131 auto t2 = new RedBlackTree(1,2,3,4); 1132 auto t3 = new RedBlackTree(1,2,3,5); 1133 auto t4 = new RedBlackTree(1,2,3,4,5); 1134 1135 assert(t1.toHash() == t2.toHash); 1136 1137 assert(t1.toHash() != t3.toHash); 1138 assert(t2.toHash() != t3.toHash); 1139 1140 assert(t3.toHash() != t4.toHash); 1141 assert(t1.toHash() != t4.toHash); 1142 1143 // empty tree 1144 auto t5 = new RedBlackTree(); 1145 auto t6 = new RedBlackTree(); 1146 1147 assert(t5.toHash() == t6.toHash()); 1148 1149 auto t7 = new RedBlackTree!string("red", "black"); 1150 auto t8 = new RedBlackTree!string("white", "black"); 1151 auto t9 = new RedBlackTree!string("red", "black"); 1152 1153 assert(t7.toHash() == t9.toHash()); 1154 assert(t7.toHash() != t8.toHash()); 1155 1156 static struct MyInt 1157 { 1158 int x; 1159 1160 @safe: 1161 1162 this(int init_x) 1163 { 1164 x = init_x; 1165 } 1166 1167 size_t toHash() const nothrow 1168 { 1169 return typeid(x).getHash(&x) ^ 0xF0F0_F0F0; 1170 } 1171 1172 int opCmp(const MyInt that) const 1173 { 1174 return (x > that.x) - (x < that.x); 1175 } 1176 1177 bool opEquals(const MyInt that) const 1178 { 1179 return (this.x == that.x); 1180 } 1181 } 1182 1183 auto rbt1 = new RedBlackTree!MyInt(MyInt(1), MyInt(2), MyInt(3), MyInt(4)); 1184 auto rbt2 = new RedBlackTree!MyInt(MyInt(1), MyInt(2), MyInt(3), MyInt(4)); 1185 1186 assert(rbt1.toHash() == rbt2.toHash()); 1187 assert(rbt1.toHash() != t1.toHash()); 1188 1189 auto rbt3 = new RedBlackTree!MyInt(MyInt(4), MyInt(2), MyInt(3), MyInt(4)); 1190 1191 assert(rbt1.toHash() != rbt3.toHash()); 1192 1193 class MyInt2 1194 { 1195 int x; 1196 1197 this(int init_x) 1198 { 1199 x = init_x; 1200 } 1201 1202 override size_t toHash() const @safe nothrow 1203 { 1204 return typeid(x).getHash(&x) ^ 0xF0F0_F0F0; 1205 } 1206 1207 int opCmp(const MyInt2 that) const 1208 { 1209 return (x > that.x) - (x < that.x); 1210 } 1211 1212 bool opEquals(const MyInt2 that) const 1213 { 1214 return (this.x == that.x); 1215 } 1216 } 1217 1218 static bool nullSafeLess(scope const MyInt2 a, scope const MyInt2 b) 1219 { 1220 return a is null ? b !is null : (b !is null && a < b); 1221 } 1222 1223 auto rbt4 = new RedBlackTree!MyInt2(new MyInt2(1), new MyInt2(9), new MyInt2(3), new MyInt2(42)); 1224 auto rbt5 = new RedBlackTree!MyInt2(new MyInt2(1), new MyInt2(9), new MyInt2(3), new MyInt2(42)); 1225 auto rbt6 = new RedBlackTree!(MyInt2, nullSafeLess)(new MyInt2(9), new MyInt2(3), new MyInt2(42)); 1226 auto rbt7 = new RedBlackTree!(MyInt2, nullSafeLess)(null); 1227 1228 assert(rbt6.toHash() != rbt5.toHash()); 1229 assert(rbt6.toHash() != rbt4.toHash()); 1230 assert(rbt6.toHash() != rbt7.toHash()); 1231 assert(rbt4.toHash() == rbt5.toHash()); 1232 1233 auto rbt8 = new RedBlackTree!(MyInt2, nullSafeLess)(null, new MyInt2(9), null, new MyInt2(42)); 1234 auto rbt9 = new RedBlackTree!(MyInt2, nullSafeLess)(null, new MyInt2(9), null, new MyInt2(42)); 1235 auto rbt10 = new RedBlackTree!(MyInt2, nullSafeLess)(new MyInt2(94), null, new MyInt2(147)); 1236 1237 assert(rbt8.toHash() == rbt9.toHash()); 1238 assert(rbt8.toHash() != rbt10.toHash()); 1239 } 1240 1241 /** 1242 * Removes all elements from the container. 1243 * 1244 * Complexity: $(BIGOH 1) 1245 */ 1246 void clear() 1247 { 1248 _end.left = null; 1249 _begin = _end; 1250 _length = 0; 1251 } 1252 1253 static if (doUnittest) @safe pure unittest 1254 { 1255 auto ts = new RedBlackTree(1,2,3,4,5); 1256 assert(ts.length == 5); 1257 ts.clear(); 1258 assert(ts.empty && ts.length == 0); 1259 } 1260 1261 /** 1262 * Insert a single element in the container. Note that this does not 1263 * invalidate any ranges currently iterating the container. 1264 * 1265 * Returns: The number of elements inserted. 1266 * 1267 * Complexity: $(BIGOH log(n)) 1268 */ 1269 size_t stableInsert(Stuff)(Stuff stuff) 1270 if (isImplicitlyConvertible!(Stuff, Elem)) 1271 { 1272 static if (allowDuplicates) 1273 { 1274 _add(stuff); 1275 return 1; 1276 } 1277 else 1278 { 1279 return _add(stuff); 1280 } 1281 } 1282 1283 /** 1284 * Insert a range of elements in the container. Note that this does not 1285 * invalidate any ranges currently iterating the container. 1286 * 1287 * Returns: The number of elements inserted. 1288 * 1289 * Complexity: $(BIGOH m * log(n)) 1290 */ 1291 size_t stableInsert(Stuff)(scope Stuff stuff) 1292 if (isInputRange!Stuff && 1293 isImplicitlyConvertible!(ElementType!Stuff, Elem)) 1294 { 1295 size_t result = 0; 1296 static if (allowDuplicates) 1297 { 1298 foreach (e; stuff) 1299 { 1300 ++result; 1301 _add(e); 1302 } 1303 } 1304 else 1305 { 1306 foreach (e; stuff) 1307 { 1308 result += _add(e); 1309 } 1310 } 1311 return result; 1312 } 1313 1314 /// ditto 1315 alias insert = stableInsert; 1316 1317 static if (doUnittest) @safe pure unittest 1318 { 1319 auto ts = new RedBlackTree(2,1,3,4,5,2,5); 1320 static if (allowDuplicates) 1321 { 1322 assert(ts.length == 7); 1323 assert(ts.stableInsert(cast(Elem[])[7, 8, 6, 9, 10, 8]) == 6); 1324 assert(ts.length == 13); 1325 assert(ts.stableInsert(cast(Elem) 11) == 1 && ts.length == 14); 1326 assert(ts.stableInsert(cast(Elem) 7) == 1 && ts.length == 15); 1327 1328 static if (less == "a < b") 1329 assert(ts.arrayEqual([1,2,2,3,4,5,5,6,7,7,8,8,9,10,11])); 1330 else 1331 assert(ts.arrayEqual([11,10,9,8,8,7,7,6,5,5,4,3,2,2,1])); 1332 } 1333 else 1334 { 1335 assert(ts.length == 5); 1336 Elem[] elems = [7, 8, 6, 9, 10, 8]; 1337 assert(ts.stableInsert(elems) == 5); 1338 assert(ts.length == 10); 1339 assert(ts.stableInsert(cast(Elem) 11) == 1 && ts.length == 11); 1340 assert(ts.stableInsert(cast(Elem) 7) == 0 && ts.length == 11); 1341 1342 static if (less == "a < b") 1343 assert(ts.arrayEqual([1,2,3,4,5,6,7,8,9,10,11])); 1344 else 1345 assert(ts.arrayEqual([11,10,9,8,7,6,5,4,3,2,1])); 1346 } 1347 } 1348 1349 /** 1350 * Remove an element from the container and return its value. 1351 * 1352 * Complexity: $(BIGOH log(n)) 1353 */ 1354 Elem removeAny() 1355 { 1356 scope(success) 1357 --_length; 1358 auto n = _begin; 1359 auto result = n.value; 1360 _begin = n.remove(_end); 1361 debug(RBDoChecks) 1362 check(); 1363 return result; 1364 } 1365 1366 static if (doUnittest) @safe pure unittest 1367 { 1368 auto ts = new RedBlackTree(1,2,3,4,5); 1369 assert(ts.length == 5); 1370 auto x = ts.removeAny(); 1371 assert(ts.length == 4); 1372 Elem[] arr; 1373 foreach (Elem i; 1 .. 6) 1374 if (i != x) arr ~= i; 1375 assert(ts.arrayEqual(arr)); 1376 } 1377 1378 /** 1379 * Remove the front element from the container. 1380 * 1381 * Complexity: $(BIGOH log(n)) 1382 */ 1383 void removeFront() 1384 { 1385 scope(success) 1386 --_length; 1387 _begin = _begin.remove(_end); 1388 debug(RBDoChecks) 1389 check(); 1390 } 1391 1392 /** 1393 * Remove the back element from the container. 1394 * 1395 * Complexity: $(BIGOH log(n)) 1396 */ 1397 void removeBack() 1398 { 1399 scope(success) 1400 --_length; 1401 auto lastnode = _end.prev; 1402 if (lastnode is _begin) 1403 _begin = _begin.remove(_end); 1404 else 1405 lastnode.remove(_end); 1406 debug(RBDoChecks) 1407 check(); 1408 } 1409 1410 static if (doUnittest) @safe pure unittest 1411 { 1412 auto ts = new RedBlackTree(1,2,3,4,5); 1413 assert(ts.length == 5); 1414 ts.removeBack(); 1415 assert(ts.length == 4); 1416 1417 static if (less == "a < b") 1418 assert(ts.arrayEqual([1,2,3,4])); 1419 else 1420 assert(ts.arrayEqual([2,3,4,5])); 1421 1422 ts.removeFront(); 1423 assert(ts.arrayEqual([2,3,4]) && ts.length == 3); 1424 } 1425 1426 /++ 1427 Removes the given range from the container. 1428 1429 Returns: A range containing all of the elements that were after the 1430 given range. 1431 1432 Complexity: $(BIGOH m * log(n)) (where m is the number of elements in 1433 the range) 1434 +/ 1435 Range remove(Range r) 1436 { 1437 auto b = r._begin; 1438 auto e = r._end; 1439 if (_begin is b) 1440 _begin = e; 1441 while (b !is e) 1442 { 1443 b = b.remove(_end); 1444 --_length; 1445 } 1446 debug(RBDoChecks) 1447 check(); 1448 return Range(e, _end); 1449 } 1450 1451 static if (doUnittest) @safe pure unittest 1452 { 1453 import std.algorithm.comparison : equal; 1454 auto ts = new RedBlackTree(1,2,3,4,5); 1455 assert(ts.length == 5); 1456 auto r = ts[]; 1457 r.popFront(); 1458 r.popBack(); 1459 assert(ts.length == 5); 1460 auto r2 = ts.remove(r); 1461 assert(ts.length == 2); 1462 assert(ts.arrayEqual([1,5])); 1463 1464 static if (less == "a < b") 1465 assert(equal(r2, [5])); 1466 else 1467 assert(equal(r2, [1])); 1468 } 1469 1470 /++ 1471 Removes the given `Take!Range` from the container 1472 1473 Returns: A range containing all of the elements that were after the 1474 given range. 1475 1476 Complexity: $(BIGOH m * log(n)) (where m is the number of elements in 1477 the range) 1478 +/ 1479 Range remove(Take!Range r) 1480 { 1481 immutable isBegin = (r.source._begin is _begin); 1482 auto b = r.source._begin; 1483 1484 while (!r.empty) 1485 { 1486 r.popFront(); 1487 b = b.remove(_end); 1488 --_length; 1489 } 1490 1491 if (isBegin) 1492 _begin = b; 1493 1494 return Range(b, _end); 1495 } 1496 1497 static if (doUnittest) @safe pure unittest 1498 { 1499 import std.algorithm.comparison : equal; 1500 import std.range : take; 1501 auto ts = new RedBlackTree(1,2,3,4,5); 1502 auto r = ts[]; 1503 r.popFront(); 1504 assert(ts.length == 5); 1505 auto r2 = ts.remove(take(r, 0)); 1506 1507 static if (less == "a < b") 1508 { 1509 assert(equal(r2, [2,3,4,5])); 1510 auto r3 = ts.remove(take(r, 2)); 1511 assert(ts.arrayEqual([1,4,5]) && ts.length == 3); 1512 assert(equal(r3, [4,5])); 1513 } 1514 else 1515 { 1516 assert(equal(r2, [4,3,2,1])); 1517 auto r3 = ts.remove(take(r, 2)); 1518 assert(ts.arrayEqual([5,2,1]) && ts.length == 3); 1519 assert(equal(r3, [2,1])); 1520 } 1521 } 1522 1523 /++ 1524 Removes elements from the container that are equal to the given values 1525 according to the less comparator. One element is removed for each value 1526 given which is in the container. If `allowDuplicates` is true, 1527 duplicates are removed only if duplicate values are given. 1528 1529 Returns: The number of elements removed. 1530 1531 Complexity: $(BIGOH m log(n)) (where m is the number of elements to remove) 1532 1533 Example: 1534 -------------------- 1535 auto rbt = redBlackTree!true(0, 1, 1, 1, 4, 5, 7); 1536 rbt.removeKey(1, 4, 7); 1537 assert(equal(rbt[], [0, 1, 1, 5])); 1538 rbt.removeKey(1, 1, 0); 1539 assert(equal(rbt[], [5])); 1540 -------------------- 1541 +/ 1542 size_t removeKey(U...)(U elems) 1543 if (allSatisfy!(isImplicitlyConvertibleToElem, U)) 1544 { 1545 Elem[U.length] toRemove = [elems]; 1546 return removeKey(toRemove[]); 1547 } 1548 1549 /++ Ditto +/ 1550 size_t removeKey(U)(scope U[] elems) 1551 if (isImplicitlyConvertible!(U, Elem)) 1552 { 1553 immutable lenBefore = length; 1554 1555 foreach (e; elems) 1556 { 1557 auto beg = _firstGreaterEqual(e); 1558 if (beg is _end || _less(e, beg.value)) 1559 // no values are equal 1560 continue; 1561 immutable isBegin = (beg is _begin); 1562 beg = beg.remove(_end); 1563 if (isBegin) 1564 _begin = beg; 1565 --_length; 1566 } 1567 1568 return lenBefore - length; 1569 } 1570 1571 /++ Ditto +/ 1572 size_t removeKey(Stuff)(Stuff stuff) 1573 if (isInputRange!Stuff && 1574 isImplicitlyConvertible!(ElementType!Stuff, Elem) && 1575 !isDynamicArray!Stuff) 1576 { 1577 import std.array : array; 1578 //We use array in case stuff is a Range from this RedBlackTree - either 1579 //directly or indirectly. 1580 return removeKey(array(stuff)); 1581 } 1582 1583 //Helper for removeKey. 1584 private template isImplicitlyConvertibleToElem(U) 1585 { 1586 enum isImplicitlyConvertibleToElem = isImplicitlyConvertible!(U, Elem); 1587 } 1588 1589 static if (doUnittest) @safe pure unittest 1590 { 1591 import std.algorithm.comparison : equal; 1592 import std.range : take; 1593 auto rbt = new RedBlackTree(5, 4, 3, 7, 2, 1, 7, 6, 2, 19, 45); 1594 1595 //The cast(Elem) is because these tests are instantiated with a variety 1596 //of numeric types, and the literals are all int, which is not always 1597 //implicitly convertible to Elem (e.g. short). 1598 static if (allowDuplicates) 1599 { 1600 assert(rbt.length == 11); 1601 assert(rbt.removeKey(cast(Elem) 4) == 1 && rbt.length == 10); 1602 assert(rbt.arrayEqual([1,2,2,3,5,6,7,7,19,45]) && rbt.length == 10); 1603 1604 assert(rbt.removeKey(cast(Elem) 6, cast(Elem) 2, cast(Elem) 1) == 3); 1605 assert(rbt.arrayEqual([2,3,5,7,7,19,45]) && rbt.length == 7); 1606 1607 assert(rbt.removeKey(cast(Elem)(42)) == 0 && rbt.length == 7); 1608 assert(rbt.removeKey(take(rbt[], 3)) == 3 && rbt.length == 4); 1609 1610 static if (less == "a < b") 1611 assert(equal(rbt[], [7,7,19,45])); 1612 else 1613 assert(equal(rbt[], [7,5,3,2])); 1614 } 1615 else 1616 { 1617 assert(rbt.length == 9); 1618 assert(rbt.removeKey(cast(Elem) 4) == 1 && rbt.length == 8); 1619 assert(rbt.arrayEqual([1,2,3,5,6,7,19,45])); 1620 1621 assert(rbt.removeKey(cast(Elem) 6, cast(Elem) 2, cast(Elem) 1) == 3); 1622 assert(rbt.arrayEqual([3,5,7,19,45]) && rbt.length == 5); 1623 1624 assert(rbt.removeKey(cast(Elem)(42)) == 0 && rbt.length == 5); 1625 assert(rbt.removeKey(take(rbt[], 3)) == 3 && rbt.length == 2); 1626 1627 static if (less == "a < b") 1628 assert(equal(rbt[], [19,45])); 1629 else 1630 assert(equal(rbt[], [5,3])); 1631 } 1632 } 1633 1634 // find the first node where the value is > e 1635 private inout(RBNode)* _firstGreater(Elem e) inout 1636 { 1637 // can't use _find, because we cannot return null 1638 auto cur = _end.left; 1639 inout(RBNode)* result = _end; 1640 while (cur) 1641 { 1642 if (_less(e, cur.value)) 1643 { 1644 result = cur; 1645 cur = cur.left; 1646 } 1647 else 1648 cur = cur.right; 1649 } 1650 return result; 1651 } 1652 1653 // find the first node where the value is >= e 1654 private inout(RBNode)* _firstGreaterEqual(Elem e) inout 1655 { 1656 // can't use _find, because we cannot return null. 1657 auto cur = _end.left; 1658 inout(RBNode)* result = _end; 1659 while (cur) 1660 { 1661 if (_less(cur.value, e)) 1662 cur = cur.right; 1663 else 1664 { 1665 result = cur; 1666 cur = cur.left; 1667 } 1668 1669 } 1670 return result; 1671 } 1672 1673 /** 1674 * Get a range from the container with all elements that are > e according 1675 * to the less comparator 1676 * 1677 * Complexity: $(BIGOH log(n)) 1678 */ 1679 Range upperBound(Elem e) 1680 { 1681 return Range(_firstGreater(e), _end); 1682 } 1683 1684 /// Ditto 1685 ConstRange upperBound(Elem e) const 1686 { 1687 return ConstRange(_firstGreater(e), _end); 1688 } 1689 1690 /// Ditto 1691 ImmutableRange upperBound(Elem e) immutable 1692 { 1693 return ImmutableRange(_firstGreater(e), _end); 1694 } 1695 1696 /** 1697 * Get a range from the container with all elements that are < e according 1698 * to the less comparator 1699 * 1700 * Complexity: $(BIGOH log(n)) 1701 */ 1702 Range lowerBound(Elem e) 1703 { 1704 return Range(_begin, _firstGreaterEqual(e)); 1705 } 1706 1707 /// Ditto 1708 ConstRange lowerBound(Elem e) const 1709 { 1710 return ConstRange(_begin, _firstGreaterEqual(e)); 1711 } 1712 1713 /// Ditto 1714 ImmutableRange lowerBound(Elem e) immutable 1715 { 1716 return ImmutableRange(_begin, _firstGreaterEqual(e)); 1717 } 1718 1719 /** 1720 * Get a range from the container with all elements that are == e according 1721 * to the less comparator 1722 * 1723 * Complexity: $(BIGOH log(n)) 1724 */ 1725 auto equalRange(this This)(Elem e) 1726 { 1727 auto beg = _firstGreaterEqual(e); 1728 alias RangeType = RBRange!(typeof(beg)); 1729 if (beg is _end || _less(e, beg.value)) 1730 // no values are equal 1731 return RangeType(beg, beg); 1732 static if (allowDuplicates) 1733 { 1734 return RangeType(beg, _firstGreater(e)); 1735 } 1736 else 1737 { 1738 // no sense in doing a full search, no duplicates are allowed, 1739 // so we just get the next node. 1740 return RangeType(beg, beg.next); 1741 } 1742 } 1743 1744 /** 1745 * Returns a static array of 3 ranges `r` such that `r[0]` is the 1746 * same as the result of `lowerBound(value)`, `r[1]` is the same 1747 * as the result of $(D equalRange(value)), and `r[2]` is the same 1748 * as the result of $(D upperBound(value)). 1749 * 1750 * Complexity: $(BIGOH log(n)) 1751 */ 1752 auto trisect(this This)(Elem e) 1753 { 1754 auto equalRange = this.equalRange(e); 1755 alias RangeType = typeof(equalRange); 1756 RangeType[3] result = [ 1757 RangeType(_begin, equalRange._begin), 1758 equalRange, 1759 RangeType(equalRange._end, _end) 1760 ]; 1761 return result; 1762 } 1763 1764 static if (doUnittest) @safe pure unittest 1765 { 1766 import std.algorithm.comparison : equal; 1767 auto ts = new RedBlackTree(1, 2, 3, 4, 5); 1768 auto rl = ts.lowerBound(3); 1769 auto ru = ts.upperBound(3); 1770 auto re = ts.equalRange(3); 1771 1772 static if (less == "a < b") 1773 { 1774 assert(equal(rl, [1,2])); 1775 assert(equal(ru, [4,5])); 1776 } 1777 else 1778 { 1779 assert(equal(rl, [5,4])); 1780 assert(equal(ru, [2,1])); 1781 } 1782 1783 assert(equal(re, [3])); 1784 } 1785 1786 debug(RBDoChecks) 1787 { 1788 /* 1789 * Print the tree. This prints a sideways view of the tree in ASCII form, 1790 * with the number of indentations representing the level of the nodes. 1791 * It does not print values, only the tree structure and color of nodes. 1792 */ 1793 void printTree(Node n, int indent = 0) 1794 { 1795 import std.stdio : write, writeln; 1796 if (n !is null) 1797 { 1798 printTree(n.right, indent + 2); 1799 for (int i = 0; i < indent; i++) 1800 write("."); 1801 writeln(n.color == n.color.Black ? "B" : "R"); 1802 printTree(n.left, indent + 2); 1803 } 1804 else 1805 { 1806 for (int i = 0; i < indent; i++) 1807 write("."); 1808 writeln("N"); 1809 } 1810 if (indent is 0) 1811 writeln(); 1812 } 1813 1814 /* 1815 * Check the tree for validity. This is called after every add or remove. 1816 * This should only be enabled to debug the implementation of the RB Tree. 1817 */ 1818 void check() @trusted 1819 { 1820 // 1821 // check implementation of the tree 1822 // 1823 int recurse(Node n, string path) 1824 { 1825 import std.stdio : writeln; 1826 if (n is null) 1827 return 1; 1828 if (n.parent.left !is n && n.parent.right !is n) 1829 throw new Exception("Node at path " ~ path ~ " has inconsistent pointers"); 1830 Node next = n.next; 1831 static if (allowDuplicates) 1832 { 1833 if (next !is _end && _less(next.value, n.value)) 1834 throw new Exception("ordering invalid at path " ~ path); 1835 } 1836 else 1837 { 1838 if (next !is _end && !_less(n.value, next.value)) 1839 throw new Exception("ordering invalid at path " ~ path); 1840 } 1841 if (n.color == n.color.Red) 1842 { 1843 if ((n.left !is null && n.left.color == n.color.Red) || 1844 (n.right !is null && n.right.color == n.color.Red)) 1845 throw new Exception("Node at path " ~ path ~ " is red with a red child"); 1846 } 1847 1848 int l = recurse(n.left, path ~ "L"); 1849 int r = recurse(n.right, path ~ "R"); 1850 if (l != r) 1851 { 1852 writeln("bad tree at:"); 1853 debug printTree(n); 1854 throw new Exception( 1855 "Node at path " ~ path ~ " has different number of black nodes on left and right paths" 1856 ); 1857 } 1858 return l + (n.color == n.color.Black ? 1 : 0); 1859 } 1860 1861 try 1862 { 1863 recurse(_end.left, ""); 1864 } 1865 catch (Exception e) 1866 { 1867 debug printTree(_end.left, 0); 1868 throw e; 1869 } 1870 } 1871 } 1872 1873 /** 1874 Formats the RedBlackTree into a sink function. For more info see $(D 1875 std.format.formatValue). Note that this only is available when the 1876 element type can be formatted. Otherwise, the default toString from 1877 Object is used. 1878 */ 1879 static if (is(typeof((){FormatSpec!(char) fmt; formatValue((const(char)[]) {}, ConstRange.init, fmt);}))) 1880 { 1881 void toString(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) const 1882 { 1883 sink("RedBlackTree("); 1884 sink.formatValue(this[], fmt); 1885 sink(")"); 1886 } 1887 } 1888 1889 /** 1890 * Constructor. Pass in an array of elements, or individual elements to 1891 * initialize the tree with. 1892 */ 1893 this(Elem[] elems...) 1894 { 1895 _setup(); 1896 stableInsert(elems); 1897 } 1898 1899 /** 1900 * Constructor. Pass in a range of elements to initialize the tree with. 1901 */ 1902 this(Stuff)(Stuff stuff) 1903 if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, Elem)) 1904 { 1905 _setup(); 1906 stableInsert(stuff); 1907 } 1908 1909 /// 1910 this() 1911 { 1912 _setup(); 1913 } 1914 1915 private this(Node end, size_t length) 1916 { 1917 _end = end; 1918 _begin = end.leftmost; 1919 _length = length; 1920 } 1921 } 1922 1923 //Verify Example for removeKey. 1924 @safe pure unittest 1925 { 1926 import std.algorithm.comparison : equal; 1927 auto rbt = redBlackTree!true(0, 1, 1, 1, 4, 5, 7); 1928 rbt.removeKey(1, 4, 7); 1929 assert(equal(rbt[], [0, 1, 1, 5])); 1930 rbt.removeKey(1, 1, 0); 1931 assert(equal(rbt[], [5])); 1932 } 1933 1934 //Tests for removeKey 1935 @safe pure unittest 1936 { 1937 import std.algorithm.comparison : equal; 1938 { 1939 auto rbt = redBlackTree(["hello", "world", "foo", "bar"]); 1940 assert(equal(rbt[], ["bar", "foo", "hello", "world"])); 1941 assert(rbt.removeKey("hello") == 1); 1942 assert(equal(rbt[], ["bar", "foo", "world"])); 1943 assert(rbt.removeKey("hello") == 0); 1944 assert(equal(rbt[], ["bar", "foo", "world"])); 1945 assert(rbt.removeKey("hello", "foo", "bar") == 2); 1946 assert(equal(rbt[], ["world"])); 1947 assert(rbt.removeKey(["", "world", "hello"]) == 1); 1948 assert(rbt.empty); 1949 } 1950 1951 { 1952 auto rbt = redBlackTree([1, 2, 12, 27, 4, 500]); 1953 assert(equal(rbt[], [1, 2, 4, 12, 27, 500])); 1954 assert(rbt.removeKey(1u) == 1); 1955 assert(equal(rbt[], [2, 4, 12, 27, 500])); 1956 assert(rbt.removeKey(cast(byte) 1) == 0); 1957 assert(equal(rbt[], [2, 4, 12, 27, 500])); 1958 assert(rbt.removeKey(1, 12u, cast(byte) 27) == 2); 1959 assert(equal(rbt[], [2, 4, 500])); 1960 assert(rbt.removeKey([cast(short) 0, cast(short) 500, cast(short) 1]) == 1); 1961 assert(equal(rbt[], [2, 4])); 1962 } 1963 } 1964 1965 @safe pure unittest 1966 { 1967 void test(T)() 1968 { 1969 auto rt1 = new RedBlackTree!(T, "a < b", false)(); 1970 auto rt2 = new RedBlackTree!(T, "a < b", true)(); 1971 auto rt3 = new RedBlackTree!(T, "a > b", false)(); 1972 auto rt4 = new RedBlackTree!(T, "a > b", true)(); 1973 } 1974 1975 test!long(); 1976 test!ulong(); 1977 test!int(); 1978 test!uint(); 1979 test!short(); 1980 test!ushort(); 1981 test!byte(); 1982 test!byte(); 1983 } 1984 1985 // https://issues.dlang.org/show_bug.cgi?id=19626 1986 @safe pure unittest 1987 { 1988 enum T { a, b } 1989 alias t = RedBlackTree!T; 1990 } 1991 1992 import std.range.primitives : isInputRange, ElementType; 1993 import std.traits : isArray, isSomeString; 1994 1995 /++ 1996 Convenience function for creating a `RedBlackTree!E` from a list of 1997 values. 1998 1999 Params: 2000 allowDuplicates = Whether duplicates should be allowed (optional, default: false) 2001 less = predicate to sort by (optional) 2002 elems = elements to insert into the rbtree (variadic arguments) 2003 range = range elements to insert into the rbtree (alternative to elems) 2004 +/ 2005 auto redBlackTree(E)(E[] elems...) 2006 { 2007 return new RedBlackTree!E(elems); 2008 } 2009 2010 /++ Ditto +/ 2011 auto redBlackTree(bool allowDuplicates, E)(E[] elems...) 2012 { 2013 return new RedBlackTree!(E, "a < b", allowDuplicates)(elems); 2014 } 2015 2016 /++ Ditto +/ 2017 auto redBlackTree(alias less, E)(E[] elems...) 2018 if (is(typeof(binaryFun!less(E.init, E.init)))) 2019 { 2020 return new RedBlackTree!(E, less)(elems); 2021 } 2022 2023 /++ Ditto +/ 2024 auto redBlackTree(alias less, bool allowDuplicates, E)(E[] elems...) 2025 if (is(typeof(binaryFun!less(E.init, E.init)))) 2026 { 2027 //We shouldn't need to instantiate less here, but for some reason, 2028 //dmd can't handle it if we don't (even though the template which 2029 //takes less but not allowDuplicates works just fine). 2030 return new RedBlackTree!(E, binaryFun!less, allowDuplicates)(elems); 2031 } 2032 2033 /++ Ditto +/ 2034 auto redBlackTree(Stuff)(Stuff range) 2035 if (isInputRange!Stuff && !isArray!(Stuff)) 2036 { 2037 return new RedBlackTree!(ElementType!Stuff)(range); 2038 } 2039 2040 /++ Ditto +/ 2041 auto redBlackTree(bool allowDuplicates, Stuff)(Stuff range) 2042 if (isInputRange!Stuff && !isArray!(Stuff)) 2043 { 2044 return new RedBlackTree!(ElementType!Stuff, "a < b", allowDuplicates)(range); 2045 } 2046 2047 /++ Ditto +/ 2048 auto redBlackTree(alias less, Stuff)(Stuff range) 2049 if ( is(typeof(binaryFun!less((ElementType!Stuff).init, (ElementType!Stuff).init))) 2050 && isInputRange!Stuff && !isArray!(Stuff)) 2051 { 2052 return new RedBlackTree!(ElementType!Stuff, less)(range); 2053 } 2054 2055 /++ Ditto +/ 2056 auto redBlackTree(alias less, bool allowDuplicates, Stuff)(Stuff range) 2057 if ( is(typeof(binaryFun!less((ElementType!Stuff).init, (ElementType!Stuff).init))) 2058 && isInputRange!Stuff && !isArray!(Stuff)) 2059 { 2060 //We shouldn't need to instantiate less here, but for some reason, 2061 //dmd can't handle it if we don't (even though the template which 2062 //takes less but not allowDuplicates works just fine). 2063 return new RedBlackTree!(ElementType!Stuff, binaryFun!less, allowDuplicates)(range); 2064 } 2065 2066 /// 2067 @safe pure unittest 2068 { 2069 import std.range : iota; 2070 2071 auto rbt1 = redBlackTree(0, 1, 5, 7); 2072 auto rbt2 = redBlackTree!string("hello", "world"); 2073 auto rbt3 = redBlackTree!true(0, 1, 5, 7, 5); 2074 auto rbt4 = redBlackTree!"a > b"(0, 1, 5, 7); 2075 auto rbt5 = redBlackTree!("a > b", true)(0.1, 1.3, 5.9, 7.2, 5.9); 2076 2077 // also works with ranges 2078 auto rbt6 = redBlackTree(iota(3)); 2079 auto rbt7 = redBlackTree!true(iota(3)); 2080 auto rbt8 = redBlackTree!"a > b"(iota(3)); 2081 auto rbt9 = redBlackTree!("a > b", true)(iota(3)); 2082 } 2083 2084 //Combinations not in examples. 2085 @system pure unittest 2086 { 2087 auto rbt1 = redBlackTree!(true, string)("hello", "hello"); 2088 auto rbt2 = redBlackTree!((a, b){return a < b;}, double)(5.1, 2.3); 2089 auto rbt3 = redBlackTree!("a > b", true, string)("hello", "world"); 2090 } 2091 2092 //Range construction. 2093 @safe pure unittest 2094 { 2095 import std.algorithm.comparison : equal; 2096 import std.range : iota; 2097 auto rbt = new RedBlackTree!(int, "a > b")(iota(5)); 2098 assert(equal(rbt[], [4, 3, 2, 1, 0])); 2099 } 2100 2101 2102 // construction with arrays 2103 @safe pure unittest 2104 { 2105 import std.algorithm.comparison : equal; 2106 2107 auto rbt = redBlackTree!"a > b"([0, 1, 2, 3, 4]); 2108 assert(equal(rbt[], [4, 3, 2, 1, 0])); 2109 2110 auto rbt2 = redBlackTree!"a > b"(["a", "b"]); 2111 assert(equal(rbt2[], ["b", "a"])); 2112 2113 auto rbt3 = redBlackTree!"a > b"([1, 2]); 2114 assert(equal(rbt3[], [2, 1])); 2115 2116 auto rbt4 = redBlackTree([0, 1, 7, 5]); 2117 assert(equal(rbt4[], [0, 1, 5, 7])); 2118 2119 auto rbt5 = redBlackTree(["hello", "world"]); 2120 assert(equal(rbt5[], ["hello", "world"])); 2121 2122 auto rbt6 = redBlackTree!true([0, 1, 5, 7, 5]); 2123 assert(equal(rbt6[], [0, 1, 5, 5, 7])); 2124 2125 auto rbt7 = redBlackTree!"a > b"([0, 1, 5, 7]); 2126 assert(equal(rbt7[], [7, 5, 1, 0])); 2127 2128 auto rbt8 = redBlackTree!("a > b", true)([0.1, 1.3, 5.9, 7.2, 5.9]); 2129 assert(equal(rbt8[], [7.2, 5.9, 5.9, 1.3, 0.1])); 2130 } 2131 2132 // convenience wrapper range construction 2133 @safe pure unittest 2134 { 2135 import std.algorithm.comparison : equal; 2136 import std.range : chain, iota; 2137 2138 auto rbt = redBlackTree(iota(3)); 2139 assert(equal(rbt[], [0, 1, 2])); 2140 2141 auto rbt2 = redBlackTree!"a > b"(iota(2)); 2142 assert(equal(rbt2[], [1, 0])); 2143 2144 auto rbt3 = redBlackTree(chain([0, 1], [7, 5])); 2145 assert(equal(rbt3[], [0, 1, 5, 7])); 2146 2147 auto rbt4 = redBlackTree(chain(["hello"], ["world"])); 2148 assert(equal(rbt4[], ["hello", "world"])); 2149 2150 auto rbt5 = redBlackTree!true(chain([0, 1], [5, 7, 5])); 2151 assert(equal(rbt5[], [0, 1, 5, 5, 7])); 2152 2153 auto rbt6 = redBlackTree!("a > b", true)(chain([0.1, 1.3], [5.9, 7.2, 5.9])); 2154 assert(equal(rbt6[], [7.2, 5.9, 5.9, 1.3, 0.1])); 2155 } 2156 2157 @safe pure unittest 2158 { 2159 import std.array : array; 2160 2161 auto rt1 = redBlackTree(5, 4, 3, 2, 1); 2162 assert(rt1.length == 5); 2163 assert(array(rt1[]) == [1, 2, 3, 4, 5]); 2164 2165 auto rt2 = redBlackTree!"a > b"(1.1, 2.1); 2166 assert(rt2.length == 2); 2167 assert(array(rt2[]) == [2.1, 1.1]); 2168 2169 auto rt3 = redBlackTree!true(5, 5, 4); 2170 assert(rt3.length == 3); 2171 assert(array(rt3[]) == [4, 5, 5]); 2172 2173 auto rt4 = redBlackTree!string("hello", "hello"); 2174 assert(rt4.length == 1); 2175 assert(array(rt4[]) == ["hello"]); 2176 } 2177 2178 @system unittest 2179 { 2180 import std.conv : to; 2181 2182 auto rt1 = redBlackTree!string(); 2183 assert(rt1.to!string == "RedBlackTree([])"); 2184 2185 auto rt2 = redBlackTree!string("hello"); 2186 assert(rt2.to!string == "RedBlackTree([\"hello\"])"); 2187 2188 auto rt3 = redBlackTree!string("hello", "world", "!"); 2189 assert(rt3.to!string == "RedBlackTree([\"!\", \"hello\", \"world\"])"); 2190 2191 // type deduction can be done automatically 2192 auto rt4 = redBlackTree(["hello"]); 2193 assert(rt4.to!string == "RedBlackTree([\"hello\"])"); 2194 } 2195 2196 //constness checks 2197 @safe pure unittest 2198 { 2199 const rt1 = redBlackTree(5,4,3,2,1); 2200 void allQualifiers() pure nothrow @safe @nogc { 2201 assert(!rt1.empty); 2202 assert(rt1.length == 5); 2203 assert(5 in rt1); 2204 } 2205 allQualifiers(); 2206 2207 static assert(is(typeof(rt1.upperBound(3).front) == const(int))); 2208 import std.algorithm.comparison : equal; 2209 assert(rt1.upperBound(3).equal([4, 5])); 2210 assert(rt1.lowerBound(3).equal([1, 2])); 2211 assert(rt1.equalRange(3).equal([3])); 2212 assert(rt1[].equal([1, 2, 3, 4, 5])); 2213 2214 auto t = rt1.trisect(3); 2215 assert(t[0].equal(rt1.lowerBound(3))); 2216 assert(t[1].equal(rt1.equalRange(3))); 2217 assert(t[2].equal(rt1.upperBound(3))); 2218 } 2219 2220 //immutable checks 2221 @safe pure unittest 2222 { 2223 immutable rt1 = redBlackTree(5,4,3,2,1); 2224 static assert(is(typeof(rt1.empty))); 2225 static assert(is(typeof(rt1.length))); 2226 static assert(is(typeof(5 in rt1))); 2227 2228 static assert(is(typeof(rt1.upperBound(3).front) == immutable(int))); 2229 import std.algorithm.comparison : equal; 2230 assert(rt1.upperBound(2).equal([3, 4, 5])); 2231 } 2232 2233 // https://issues.dlang.org/show_bug.cgi?id=15941 2234 @safe pure unittest 2235 { 2236 class C {} 2237 RedBlackTree!(C, "cast(void*)a < cast(void*) b") tree; 2238 } 2239 2240 // const/immutable elements (https://issues.dlang.org/show_bug.cgi?id=17519) 2241 @safe pure unittest 2242 { 2243 RedBlackTree!(immutable int) t1; 2244 RedBlackTree!(const int) t2; 2245 2246 import std.algorithm.iteration : map; 2247 static struct S { int* p; } 2248 auto t3 = new RedBlackTree!(immutable S, (a, b) => *a.p < *b.p); 2249 t3.insert([1, 2, 3].map!(x => immutable S(new int(x)))); 2250 static assert(!__traits(compiles, *t3.front.p = 4)); 2251 assert(*t3.front.p == 1); 2252 } 2253 2254 // make sure the comparator can be a delegate 2255 @safe pure unittest 2256 { 2257 import std.algorithm.comparison : equal; 2258 2259 auto t = new RedBlackTree!(int, delegate(a, b) => a > b); 2260 t.insert([1, 3, 5, 4, 2]); 2261 assert(t[].equal([5, 4, 3, 2, 1])); 2262 }