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 @property Elem front() 683 { 684 return _begin.value; 685 } 686 687 /** 688 * Returns the last element in the range 689 */ 690 @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 * If `allowDuplicates` is set to `true`, then inserting the same element more than 741 * once continues to add more elements. If it is `false`, duplicate elements are 742 * ignored on insertion. If duplicates are allowed, then new elements are 743 * inserted after all existing duplicate elements. 744 */ 745 final class RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false) 746 if (is(typeof(binaryFun!less(T.init, T.init)))) 747 { 748 import std.meta : allSatisfy; 749 import std.range : Take; 750 import std.range.primitives : isInputRange, walkLength; 751 import std.traits : isIntegral, isDynamicArray, isImplicitlyConvertible; 752 753 alias _less = binaryFun!less; 754 755 version (StdUnittest) 756 { 757 static if (is(typeof(less) == string)) 758 { 759 private enum doUnittest = is(byte : T) && isIntegral!T && (less == "a < b" || less == "a > b"); 760 } 761 else 762 enum doUnittest = false; 763 764 // note, this must be final so it does not affect the vtable layout 765 bool arrayEqual(T[] arr) 766 { 767 if (walkLength(this[]) == arr.length) 768 { 769 foreach (v; arr) 770 { 771 if (!(v in this)) 772 return false; 773 } 774 return true; 775 } 776 return false; 777 } 778 } 779 else 780 { 781 private enum doUnittest = false; 782 } 783 784 /** 785 * Element type for the tree 786 */ 787 alias Elem = T; 788 789 // used for convenience 790 private alias RBNode = .RBNode!Elem; 791 private alias Node = RBNode.Node; 792 793 private Node _end; 794 private Node _begin; 795 private size_t _length; 796 797 private void _setup() 798 { 799 //Make sure that _setup isn't run more than once. 800 assert(!_end, "Setup must only be run once"); 801 _begin = _end = allocate(); 802 } 803 804 static private Node allocate() 805 { 806 return new RBNode; 807 } 808 809 static private Node allocate(Elem v) 810 { 811 return new RBNode(null, null, null, v); 812 } 813 814 /** 815 * The range types for `RedBlackTree` 816 */ 817 alias Range = RBRange!(RBNode*); 818 alias ConstRange = RBRange!(const(RBNode)*); /// Ditto 819 alias ImmutableRange = RBRange!(immutable(RBNode)*); /// Ditto 820 821 static if (doUnittest) @safe pure unittest 822 { 823 import std.algorithm.comparison : equal; 824 import std.range.primitives; 825 auto ts = new RedBlackTree(1, 2, 3, 4, 5); 826 assert(ts.length == 5); 827 auto r = ts[]; 828 829 static if (less == "a < b") 830 auto vals = [1, 2, 3, 4, 5]; 831 else 832 auto vals = [5, 4, 3, 2, 1]; 833 assert(equal(r, vals)); 834 835 assert(r.front == vals.front); 836 assert(r.back != r.front); 837 auto oldfront = r.front; 838 auto oldback = r.back; 839 r.popFront(); 840 r.popBack(); 841 assert(r.front != r.back); 842 assert(r.front != oldfront); 843 assert(r.back != oldback); 844 assert(ts.length == 5); 845 } 846 847 // find a node based on an element value 848 private inout(RBNode)* _find(Elem e) inout 849 { 850 static if (allowDuplicates) 851 { 852 inout(RBNode)* cur = _end.left; 853 inout(RBNode)* result = null; 854 while (cur) 855 { 856 if (_less(cur.value, e)) 857 cur = cur.right; 858 else if (_less(e, cur.value)) 859 cur = cur.left; 860 else 861 { 862 // want to find the left-most element 863 result = cur; 864 cur = cur.left; 865 } 866 } 867 return result; 868 } 869 else 870 { 871 inout(RBNode)* cur = _end.left; 872 while (cur) 873 { 874 if (_less(cur.value, e)) 875 cur = cur.right; 876 else if (_less(e, cur.value)) 877 cur = cur.left; 878 else 879 return cur; 880 } 881 return null; 882 } 883 } 884 885 /* add an element to the tree, returns the node added, or the existing node 886 * if it has already been added and allowDuplicates is false 887 * Returns: 888 * true if node was added 889 */ 890 private bool _add(return scope Elem n) 891 { 892 Node result; 893 static if (!allowDuplicates) 894 bool added = true; 895 896 if (!_end.left) 897 { 898 result = allocate(n); 899 (() @trusted { _end.left = _begin = result; }) (); 900 } 901 else 902 { 903 Node newParent = _end.left; 904 Node nxt; 905 while (true) 906 { 907 if (_less(n, newParent.value)) 908 { 909 nxt = newParent.left; 910 if (nxt is null) 911 { 912 // 913 // add to right of new parent 914 // 915 result = allocate(n); 916 (() @trusted { newParent.left = result; }) (); 917 break; 918 } 919 } 920 else 921 { 922 static if (!allowDuplicates) 923 { 924 if (!_less(newParent.value, n)) 925 { 926 result = newParent; 927 added = false; 928 break; 929 } 930 } 931 nxt = newParent.right; 932 if (nxt is null) 933 { 934 // 935 // add to right of new parent 936 // 937 result = allocate(n); 938 (() @trusted { newParent.right = result; }) (); 939 break; 940 } 941 } 942 newParent = nxt; 943 } 944 if (_begin.left) 945 _begin = _begin.left; 946 } 947 static if (allowDuplicates) 948 { 949 result.setColor(_end); 950 debug(RBDoChecks) 951 check(); 952 ++_length; 953 return true; 954 } 955 else 956 { 957 if (added) 958 { 959 ++_length; 960 result.setColor(_end); 961 } 962 debug(RBDoChecks) 963 check(); 964 return added; 965 } 966 } 967 968 969 /** 970 * Check if any elements exist in the container. Returns `false` if at least 971 * one element exists. 972 */ 973 @property bool empty() const // pure, nothrow, @safe, @nogc: are inferred 974 { 975 return _end.left is null; 976 } 977 978 /++ 979 Returns the number of elements in the container. 980 981 Complexity: $(BIGOH 1). 982 +/ 983 @property size_t length() const 984 { 985 return _length; 986 } 987 988 /** 989 * Duplicate this container. The resulting container contains a shallow 990 * copy of the elements. 991 * 992 * Complexity: $(BIGOH n) 993 */ 994 @property RedBlackTree dup() 995 { 996 return new RedBlackTree(_end.dup(), _length); 997 } 998 999 static if (doUnittest) @safe pure unittest 1000 { 1001 import std.algorithm.comparison : equal; 1002 auto ts = new RedBlackTree(1, 2, 3, 4, 5); 1003 assert(ts.length == 5); 1004 auto ts2 = ts.dup; 1005 assert(ts2.length == 5); 1006 assert(equal(ts[], ts2[])); 1007 ts2.insert(cast(Elem) 6); 1008 assert(!equal(ts[], ts2[])); 1009 assert(ts.length == 5 && ts2.length == 6); 1010 } 1011 1012 /** 1013 * Fetch a range that spans all the elements in the container. 1014 * 1015 * Complexity: $(BIGOH 1) 1016 */ 1017 Range opSlice() 1018 { 1019 return Range(_begin, _end); 1020 } 1021 1022 /// Ditto 1023 ConstRange opSlice() const 1024 { 1025 return ConstRange(_begin, _end); 1026 } 1027 1028 /// Ditto 1029 ImmutableRange opSlice() immutable 1030 { 1031 return ImmutableRange(_begin, _end); 1032 } 1033 1034 /** 1035 * The front element in the container 1036 * 1037 * Complexity: $(BIGOH 1) 1038 */ 1039 inout(Elem) front() inout 1040 { 1041 return _begin.value; 1042 } 1043 1044 /** 1045 * The last element in the container 1046 * 1047 * Complexity: $(BIGOH log(n)) 1048 */ 1049 inout(Elem) back() inout 1050 { 1051 return _end.prev.value; 1052 } 1053 1054 /++ 1055 `in` operator. Check to see if the given element exists in the 1056 container. 1057 1058 Complexity: $(BIGOH log(n)) 1059 +/ 1060 bool opBinaryRight(string op)(Elem e) const 1061 if (op == "in") 1062 { 1063 return _find(e) !is null; 1064 } 1065 1066 static if (doUnittest) @safe pure unittest 1067 { 1068 auto ts = new RedBlackTree(1, 2, 3, 4, 5); 1069 assert(cast(Elem) 3 in ts); 1070 assert(cast(Elem) 6 !in ts); 1071 } 1072 1073 /** 1074 * Compares two trees for equality. 1075 * 1076 * Complexity: $(BIGOH n) 1077 */ 1078 override bool opEquals(Object rhs) 1079 { 1080 import std.algorithm.comparison : equal; 1081 1082 RedBlackTree that = cast(RedBlackTree) rhs; 1083 if (that is null) return false; 1084 1085 // If there aren't the same number of nodes, we can't be equal. 1086 if (this._length != that._length) return false; 1087 1088 auto thisRange = this[]; 1089 auto thatRange = that[]; 1090 return equal!((Elem a, Elem b) => !_less(a,b) && !_less(b,a)) 1091 (thisRange, thatRange); 1092 } 1093 1094 static if (doUnittest) @system unittest 1095 { 1096 auto t1 = new RedBlackTree(1,2,3,4); 1097 auto t2 = new RedBlackTree(1,2,3,4); 1098 auto t3 = new RedBlackTree(1,2,3,5); 1099 auto t4 = new RedBlackTree(1,2,3,4,5); 1100 auto o = new Object(); 1101 1102 assert(t1 == t1); 1103 assert(t1 == t2); 1104 assert(t1 != t3); 1105 assert(t1 != t4); 1106 assert(t1 != o); // pathological case, must not crash 1107 } 1108 1109 /** 1110 * Generates a hash for the tree. Note that with a custom comparison function 1111 * it may not hold that if two rbtrees are equal, the hashes of the trees 1112 * will be equal. 1113 */ 1114 override size_t toHash() nothrow @safe 1115 { 1116 size_t hash = cast(size_t) 0x6b63_616c_4264_6552UL; 1117 foreach (ref e; this[]) 1118 // As in boost::hash_combine 1119 // https://www.boost.org/doc/libs/1_55_0/doc/html/hash/reference.html#boost.hash_combine 1120 hash += .hashOf(e) + 0x9e3779b9 + (hash << 6) + (hash >>> 2); 1121 return hash; 1122 } 1123 1124 static if (doUnittest) @system unittest 1125 { 1126 auto t1 = new RedBlackTree(1,2,3,4); 1127 auto t2 = new RedBlackTree(1,2,3,4); 1128 auto t3 = new RedBlackTree(1,2,3,5); 1129 auto t4 = new RedBlackTree(1,2,3,4,5); 1130 1131 assert(t1.toHash() == t2.toHash); 1132 1133 assert(t1.toHash() != t3.toHash); 1134 assert(t2.toHash() != t3.toHash); 1135 1136 assert(t3.toHash() != t4.toHash); 1137 assert(t1.toHash() != t4.toHash); 1138 1139 // empty tree 1140 auto t5 = new RedBlackTree(); 1141 auto t6 = new RedBlackTree(); 1142 1143 assert(t5.toHash() == t6.toHash()); 1144 1145 auto t7 = new RedBlackTree!string("red", "black"); 1146 auto t8 = new RedBlackTree!string("white", "black"); 1147 auto t9 = new RedBlackTree!string("red", "black"); 1148 1149 assert(t7.toHash() == t9.toHash()); 1150 assert(t7.toHash() != t8.toHash()); 1151 1152 static struct MyInt 1153 { 1154 int x; 1155 1156 @safe: 1157 1158 this(int init_x) 1159 { 1160 x = init_x; 1161 } 1162 1163 size_t toHash() const nothrow 1164 { 1165 return typeid(x).getHash(&x) ^ 0xF0F0_F0F0; 1166 } 1167 1168 int opCmp(const MyInt that) const 1169 { 1170 return (x > that.x) - (x < that.x); 1171 } 1172 1173 bool opEquals(const MyInt that) const 1174 { 1175 return (this.x == that.x); 1176 } 1177 } 1178 1179 auto rbt1 = new RedBlackTree!MyInt(MyInt(1), MyInt(2), MyInt(3), MyInt(4)); 1180 auto rbt2 = new RedBlackTree!MyInt(MyInt(1), MyInt(2), MyInt(3), MyInt(4)); 1181 1182 assert(rbt1.toHash() == rbt2.toHash()); 1183 assert(rbt1.toHash() != t1.toHash()); 1184 1185 auto rbt3 = new RedBlackTree!MyInt(MyInt(4), MyInt(2), MyInt(3), MyInt(4)); 1186 1187 assert(rbt1.toHash() != rbt3.toHash()); 1188 1189 class MyInt2 1190 { 1191 int x; 1192 1193 this(int init_x) 1194 { 1195 x = init_x; 1196 } 1197 1198 override size_t toHash() const @safe nothrow 1199 { 1200 return typeid(x).getHash(&x) ^ 0xF0F0_F0F0; 1201 } 1202 1203 int opCmp(const MyInt2 that) const 1204 { 1205 return (x > that.x) - (x < that.x); 1206 } 1207 1208 bool opEquals(const MyInt2 that) const 1209 { 1210 return (this.x == that.x); 1211 } 1212 } 1213 1214 static bool nullSafeLess(scope const MyInt2 a, scope const MyInt2 b) 1215 { 1216 return a is null ? b !is null : (b !is null && a < b); 1217 } 1218 1219 auto rbt4 = new RedBlackTree!MyInt2(new MyInt2(1), new MyInt2(9), new MyInt2(3), new MyInt2(42)); 1220 auto rbt5 = new RedBlackTree!MyInt2(new MyInt2(1), new MyInt2(9), new MyInt2(3), new MyInt2(42)); 1221 auto rbt6 = new RedBlackTree!(MyInt2, nullSafeLess)(new MyInt2(9), new MyInt2(3), new MyInt2(42)); 1222 auto rbt7 = new RedBlackTree!(MyInt2, nullSafeLess)(null); 1223 1224 assert(rbt6.toHash() != rbt5.toHash()); 1225 assert(rbt6.toHash() != rbt4.toHash()); 1226 assert(rbt6.toHash() != rbt7.toHash()); 1227 assert(rbt4.toHash() == rbt5.toHash()); 1228 1229 auto rbt8 = new RedBlackTree!(MyInt2, nullSafeLess)(null, new MyInt2(9), null, new MyInt2(42)); 1230 auto rbt9 = new RedBlackTree!(MyInt2, nullSafeLess)(null, new MyInt2(9), null, new MyInt2(42)); 1231 auto rbt10 = new RedBlackTree!(MyInt2, nullSafeLess)(new MyInt2(94), null, new MyInt2(147)); 1232 1233 assert(rbt8.toHash() == rbt9.toHash()); 1234 assert(rbt8.toHash() != rbt10.toHash()); 1235 } 1236 1237 /** 1238 * Removes all elements from the container. 1239 * 1240 * Complexity: $(BIGOH 1) 1241 */ 1242 void clear() 1243 { 1244 _end.left = null; 1245 _begin = _end; 1246 _length = 0; 1247 } 1248 1249 static if (doUnittest) @safe pure unittest 1250 { 1251 auto ts = new RedBlackTree(1,2,3,4,5); 1252 assert(ts.length == 5); 1253 ts.clear(); 1254 assert(ts.empty && ts.length == 0); 1255 } 1256 1257 /** 1258 * Insert a single element in the container. Note that this does not 1259 * invalidate any ranges currently iterating the container. 1260 * 1261 * Returns: The number of elements inserted. 1262 * 1263 * Complexity: $(BIGOH log(n)) 1264 */ 1265 size_t stableInsert(Stuff)(Stuff stuff) 1266 if (isImplicitlyConvertible!(Stuff, Elem)) 1267 { 1268 static if (allowDuplicates) 1269 { 1270 _add(stuff); 1271 return 1; 1272 } 1273 else 1274 { 1275 return _add(stuff); 1276 } 1277 } 1278 1279 /** 1280 * Insert a range of elements in the container. Note that this does not 1281 * invalidate any ranges currently iterating the container. 1282 * 1283 * Returns: The number of elements inserted. 1284 * 1285 * Complexity: $(BIGOH m * log(n)) 1286 */ 1287 size_t stableInsert(Stuff)(scope Stuff stuff) 1288 if (isInputRange!Stuff && 1289 isImplicitlyConvertible!(ElementType!Stuff, Elem)) 1290 { 1291 size_t result = 0; 1292 static if (allowDuplicates) 1293 { 1294 foreach (e; stuff) 1295 { 1296 ++result; 1297 _add(e); 1298 } 1299 } 1300 else 1301 { 1302 foreach (e; stuff) 1303 { 1304 result += _add(e); 1305 } 1306 } 1307 return result; 1308 } 1309 1310 /// ditto 1311 alias insert = stableInsert; 1312 1313 static if (doUnittest) @safe pure unittest 1314 { 1315 auto ts = new RedBlackTree(2,1,3,4,5,2,5); 1316 static if (allowDuplicates) 1317 { 1318 assert(ts.length == 7); 1319 assert(ts.stableInsert(cast(Elem[])[7, 8, 6, 9, 10, 8]) == 6); 1320 assert(ts.length == 13); 1321 assert(ts.stableInsert(cast(Elem) 11) == 1 && ts.length == 14); 1322 assert(ts.stableInsert(cast(Elem) 7) == 1 && ts.length == 15); 1323 1324 static if (less == "a < b") 1325 assert(ts.arrayEqual([1,2,2,3,4,5,5,6,7,7,8,8,9,10,11])); 1326 else 1327 assert(ts.arrayEqual([11,10,9,8,8,7,7,6,5,5,4,3,2,2,1])); 1328 } 1329 else 1330 { 1331 assert(ts.length == 5); 1332 Elem[] elems = [7, 8, 6, 9, 10, 8]; 1333 assert(ts.stableInsert(elems) == 5); 1334 assert(ts.length == 10); 1335 assert(ts.stableInsert(cast(Elem) 11) == 1 && ts.length == 11); 1336 assert(ts.stableInsert(cast(Elem) 7) == 0 && ts.length == 11); 1337 1338 static if (less == "a < b") 1339 assert(ts.arrayEqual([1,2,3,4,5,6,7,8,9,10,11])); 1340 else 1341 assert(ts.arrayEqual([11,10,9,8,7,6,5,4,3,2,1])); 1342 } 1343 } 1344 1345 /** 1346 * Remove an element from the container and return its value. 1347 * 1348 * Complexity: $(BIGOH log(n)) 1349 */ 1350 Elem removeAny() 1351 { 1352 scope(success) 1353 --_length; 1354 auto n = _begin; 1355 auto result = n.value; 1356 _begin = n.remove(_end); 1357 debug(RBDoChecks) 1358 check(); 1359 return result; 1360 } 1361 1362 static if (doUnittest) @safe pure unittest 1363 { 1364 auto ts = new RedBlackTree(1,2,3,4,5); 1365 assert(ts.length == 5); 1366 auto x = ts.removeAny(); 1367 assert(ts.length == 4); 1368 Elem[] arr; 1369 foreach (Elem i; 1 .. 6) 1370 if (i != x) arr ~= i; 1371 assert(ts.arrayEqual(arr)); 1372 } 1373 1374 /** 1375 * Remove the front element from the container. 1376 * 1377 * Complexity: $(BIGOH log(n)) 1378 */ 1379 void removeFront() 1380 { 1381 scope(success) 1382 --_length; 1383 _begin = _begin.remove(_end); 1384 debug(RBDoChecks) 1385 check(); 1386 } 1387 1388 /** 1389 * Remove the back element from the container. 1390 * 1391 * Complexity: $(BIGOH log(n)) 1392 */ 1393 void removeBack() 1394 { 1395 scope(success) 1396 --_length; 1397 auto lastnode = _end.prev; 1398 if (lastnode is _begin) 1399 _begin = _begin.remove(_end); 1400 else 1401 lastnode.remove(_end); 1402 debug(RBDoChecks) 1403 check(); 1404 } 1405 1406 static if (doUnittest) @safe pure unittest 1407 { 1408 auto ts = new RedBlackTree(1,2,3,4,5); 1409 assert(ts.length == 5); 1410 ts.removeBack(); 1411 assert(ts.length == 4); 1412 1413 static if (less == "a < b") 1414 assert(ts.arrayEqual([1,2,3,4])); 1415 else 1416 assert(ts.arrayEqual([2,3,4,5])); 1417 1418 ts.removeFront(); 1419 assert(ts.arrayEqual([2,3,4]) && ts.length == 3); 1420 } 1421 1422 /++ 1423 Removes the given range from the container. 1424 1425 Returns: A range containing all of the elements that were after the 1426 given range. 1427 1428 Complexity: $(BIGOH m * log(n)) (where m is the number of elements in 1429 the range) 1430 +/ 1431 Range remove(Range r) 1432 { 1433 auto b = r._begin; 1434 auto e = r._end; 1435 if (_begin is b) 1436 _begin = e; 1437 while (b !is e) 1438 { 1439 b = b.remove(_end); 1440 --_length; 1441 } 1442 debug(RBDoChecks) 1443 check(); 1444 return Range(e, _end); 1445 } 1446 1447 static if (doUnittest) @safe pure unittest 1448 { 1449 import std.algorithm.comparison : equal; 1450 auto ts = new RedBlackTree(1,2,3,4,5); 1451 assert(ts.length == 5); 1452 auto r = ts[]; 1453 r.popFront(); 1454 r.popBack(); 1455 assert(ts.length == 5); 1456 auto r2 = ts.remove(r); 1457 assert(ts.length == 2); 1458 assert(ts.arrayEqual([1,5])); 1459 1460 static if (less == "a < b") 1461 assert(equal(r2, [5])); 1462 else 1463 assert(equal(r2, [1])); 1464 } 1465 1466 /++ 1467 Removes the given `Take!Range` from the container 1468 1469 Returns: A range containing all of the elements that were after the 1470 given range. 1471 1472 Complexity: $(BIGOH m * log(n)) (where m is the number of elements in 1473 the range) 1474 +/ 1475 Range remove(Take!Range r) 1476 { 1477 immutable isBegin = (r.source._begin is _begin); 1478 auto b = r.source._begin; 1479 1480 while (!r.empty) 1481 { 1482 r.popFront(); 1483 b = b.remove(_end); 1484 --_length; 1485 } 1486 1487 if (isBegin) 1488 _begin = b; 1489 1490 return Range(b, _end); 1491 } 1492 1493 static if (doUnittest) @safe pure unittest 1494 { 1495 import std.algorithm.comparison : equal; 1496 import std.range : take; 1497 auto ts = new RedBlackTree(1,2,3,4,5); 1498 auto r = ts[]; 1499 r.popFront(); 1500 assert(ts.length == 5); 1501 auto r2 = ts.remove(take(r, 0)); 1502 1503 static if (less == "a < b") 1504 { 1505 assert(equal(r2, [2,3,4,5])); 1506 auto r3 = ts.remove(take(r, 2)); 1507 assert(ts.arrayEqual([1,4,5]) && ts.length == 3); 1508 assert(equal(r3, [4,5])); 1509 } 1510 else 1511 { 1512 assert(equal(r2, [4,3,2,1])); 1513 auto r3 = ts.remove(take(r, 2)); 1514 assert(ts.arrayEqual([5,2,1]) && ts.length == 3); 1515 assert(equal(r3, [2,1])); 1516 } 1517 } 1518 1519 /++ 1520 Removes elements from the container that are equal to the given values 1521 according to the less comparator. One element is removed for each value 1522 given which is in the container. If `allowDuplicates` is true, 1523 duplicates are removed only if duplicate values are given. 1524 1525 Returns: The number of elements removed. 1526 1527 Complexity: $(BIGOH m log(n)) (where m is the number of elements to remove) 1528 1529 Example: 1530 -------------------- 1531 auto rbt = redBlackTree!true(0, 1, 1, 1, 4, 5, 7); 1532 rbt.removeKey(1, 4, 7); 1533 assert(equal(rbt[], [0, 1, 1, 5])); 1534 rbt.removeKey(1, 1, 0); 1535 assert(equal(rbt[], [5])); 1536 -------------------- 1537 +/ 1538 size_t removeKey(U...)(U elems) 1539 if (allSatisfy!(isImplicitlyConvertibleToElem, U)) 1540 { 1541 Elem[U.length] toRemove = [elems]; 1542 return removeKey(toRemove[]); 1543 } 1544 1545 /++ Ditto +/ 1546 size_t removeKey(U)(scope U[] elems) 1547 if (isImplicitlyConvertible!(U, Elem)) 1548 { 1549 immutable lenBefore = length; 1550 1551 foreach (e; elems) 1552 { 1553 auto beg = _firstGreaterEqual(e); 1554 if (beg is _end || _less(e, beg.value)) 1555 // no values are equal 1556 continue; 1557 immutable isBegin = (beg is _begin); 1558 beg = beg.remove(_end); 1559 if (isBegin) 1560 _begin = beg; 1561 --_length; 1562 } 1563 1564 return lenBefore - length; 1565 } 1566 1567 /++ Ditto +/ 1568 size_t removeKey(Stuff)(Stuff stuff) 1569 if (isInputRange!Stuff && 1570 isImplicitlyConvertible!(ElementType!Stuff, Elem) && 1571 !isDynamicArray!Stuff) 1572 { 1573 import std.array : array; 1574 //We use array in case stuff is a Range from this RedBlackTree - either 1575 //directly or indirectly. 1576 return removeKey(array(stuff)); 1577 } 1578 1579 //Helper for removeKey. 1580 private template isImplicitlyConvertibleToElem(U) 1581 { 1582 enum isImplicitlyConvertibleToElem = isImplicitlyConvertible!(U, Elem); 1583 } 1584 1585 static if (doUnittest) @safe pure unittest 1586 { 1587 import std.algorithm.comparison : equal; 1588 import std.range : take; 1589 auto rbt = new RedBlackTree(5, 4, 3, 7, 2, 1, 7, 6, 2, 19, 45); 1590 1591 //The cast(Elem) is because these tests are instantiated with a variety 1592 //of numeric types, and the literals are all int, which is not always 1593 //implicitly convertible to Elem (e.g. short). 1594 static if (allowDuplicates) 1595 { 1596 assert(rbt.length == 11); 1597 assert(rbt.removeKey(cast(Elem) 4) == 1 && rbt.length == 10); 1598 assert(rbt.arrayEqual([1,2,2,3,5,6,7,7,19,45]) && rbt.length == 10); 1599 1600 assert(rbt.removeKey(cast(Elem) 6, cast(Elem) 2, cast(Elem) 1) == 3); 1601 assert(rbt.arrayEqual([2,3,5,7,7,19,45]) && rbt.length == 7); 1602 1603 assert(rbt.removeKey(cast(Elem)(42)) == 0 && rbt.length == 7); 1604 assert(rbt.removeKey(take(rbt[], 3)) == 3 && rbt.length == 4); 1605 1606 static if (less == "a < b") 1607 assert(equal(rbt[], [7,7,19,45])); 1608 else 1609 assert(equal(rbt[], [7,5,3,2])); 1610 } 1611 else 1612 { 1613 assert(rbt.length == 9); 1614 assert(rbt.removeKey(cast(Elem) 4) == 1 && rbt.length == 8); 1615 assert(rbt.arrayEqual([1,2,3,5,6,7,19,45])); 1616 1617 assert(rbt.removeKey(cast(Elem) 6, cast(Elem) 2, cast(Elem) 1) == 3); 1618 assert(rbt.arrayEqual([3,5,7,19,45]) && rbt.length == 5); 1619 1620 assert(rbt.removeKey(cast(Elem)(42)) == 0 && rbt.length == 5); 1621 assert(rbt.removeKey(take(rbt[], 3)) == 3 && rbt.length == 2); 1622 1623 static if (less == "a < b") 1624 assert(equal(rbt[], [19,45])); 1625 else 1626 assert(equal(rbt[], [5,3])); 1627 } 1628 } 1629 1630 // find the first node where the value is > e 1631 private inout(RBNode)* _firstGreater(Elem e) inout 1632 { 1633 // can't use _find, because we cannot return null 1634 auto cur = _end.left; 1635 inout(RBNode)* result = _end; 1636 while (cur) 1637 { 1638 if (_less(e, cur.value)) 1639 { 1640 result = cur; 1641 cur = cur.left; 1642 } 1643 else 1644 cur = cur.right; 1645 } 1646 return result; 1647 } 1648 1649 // find the first node where the value is >= e 1650 private inout(RBNode)* _firstGreaterEqual(Elem e) inout 1651 { 1652 // can't use _find, because we cannot return null. 1653 auto cur = _end.left; 1654 inout(RBNode)* result = _end; 1655 while (cur) 1656 { 1657 if (_less(cur.value, e)) 1658 cur = cur.right; 1659 else 1660 { 1661 result = cur; 1662 cur = cur.left; 1663 } 1664 1665 } 1666 return result; 1667 } 1668 1669 /** 1670 * Get a range from the container with all elements that are > e according 1671 * to the less comparator 1672 * 1673 * Complexity: $(BIGOH log(n)) 1674 */ 1675 Range upperBound(Elem e) 1676 { 1677 return Range(_firstGreater(e), _end); 1678 } 1679 1680 /// Ditto 1681 ConstRange upperBound(Elem e) const 1682 { 1683 return ConstRange(_firstGreater(e), _end); 1684 } 1685 1686 /// Ditto 1687 ImmutableRange upperBound(Elem e) immutable 1688 { 1689 return ImmutableRange(_firstGreater(e), _end); 1690 } 1691 1692 /** 1693 * Get a range from the container with all elements that are < e according 1694 * to the less comparator 1695 * 1696 * Complexity: $(BIGOH log(n)) 1697 */ 1698 Range lowerBound(Elem e) 1699 { 1700 return Range(_begin, _firstGreaterEqual(e)); 1701 } 1702 1703 /// Ditto 1704 ConstRange lowerBound(Elem e) const 1705 { 1706 return ConstRange(_begin, _firstGreaterEqual(e)); 1707 } 1708 1709 /// Ditto 1710 ImmutableRange lowerBound(Elem e) immutable 1711 { 1712 return ImmutableRange(_begin, _firstGreaterEqual(e)); 1713 } 1714 1715 /** 1716 * Get a range from the container with all elements that are == e according 1717 * to the less comparator 1718 * 1719 * Complexity: $(BIGOH log(n)) 1720 */ 1721 auto equalRange(this This)(Elem e) 1722 { 1723 auto beg = _firstGreaterEqual(e); 1724 alias RangeType = RBRange!(typeof(beg)); 1725 if (beg is _end || _less(e, beg.value)) 1726 // no values are equal 1727 return RangeType(beg, beg); 1728 static if (allowDuplicates) 1729 { 1730 return RangeType(beg, _firstGreater(e)); 1731 } 1732 else 1733 { 1734 // no sense in doing a full search, no duplicates are allowed, 1735 // so we just get the next node. 1736 return RangeType(beg, beg.next); 1737 } 1738 } 1739 1740 static if (doUnittest) @safe pure unittest 1741 { 1742 import std.algorithm.comparison : equal; 1743 auto ts = new RedBlackTree(1, 2, 3, 4, 5); 1744 auto rl = ts.lowerBound(3); 1745 auto ru = ts.upperBound(3); 1746 auto re = ts.equalRange(3); 1747 1748 static if (less == "a < b") 1749 { 1750 assert(equal(rl, [1,2])); 1751 assert(equal(ru, [4,5])); 1752 } 1753 else 1754 { 1755 assert(equal(rl, [5,4])); 1756 assert(equal(ru, [2,1])); 1757 } 1758 1759 assert(equal(re, [3])); 1760 } 1761 1762 debug(RBDoChecks) 1763 { 1764 /* 1765 * Print the tree. This prints a sideways view of the tree in ASCII form, 1766 * with the number of indentations representing the level of the nodes. 1767 * It does not print values, only the tree structure and color of nodes. 1768 */ 1769 void printTree(Node n, int indent = 0) 1770 { 1771 import std.stdio : write, writeln; 1772 if (n !is null) 1773 { 1774 printTree(n.right, indent + 2); 1775 for (int i = 0; i < indent; i++) 1776 write("."); 1777 writeln(n.color == n.color.Black ? "B" : "R"); 1778 printTree(n.left, indent + 2); 1779 } 1780 else 1781 { 1782 for (int i = 0; i < indent; i++) 1783 write("."); 1784 writeln("N"); 1785 } 1786 if (indent is 0) 1787 writeln(); 1788 } 1789 1790 /* 1791 * Check the tree for validity. This is called after every add or remove. 1792 * This should only be enabled to debug the implementation of the RB Tree. 1793 */ 1794 void check() @trusted 1795 { 1796 // 1797 // check implementation of the tree 1798 // 1799 int recurse(Node n, string path) 1800 { 1801 import std.stdio : writeln; 1802 if (n is null) 1803 return 1; 1804 if (n.parent.left !is n && n.parent.right !is n) 1805 throw new Exception("Node at path " ~ path ~ " has inconsistent pointers"); 1806 Node next = n.next; 1807 static if (allowDuplicates) 1808 { 1809 if (next !is _end && _less(next.value, n.value)) 1810 throw new Exception("ordering invalid at path " ~ path); 1811 } 1812 else 1813 { 1814 if (next !is _end && !_less(n.value, next.value)) 1815 throw new Exception("ordering invalid at path " ~ path); 1816 } 1817 if (n.color == n.color.Red) 1818 { 1819 if ((n.left !is null && n.left.color == n.color.Red) || 1820 (n.right !is null && n.right.color == n.color.Red)) 1821 throw new Exception("Node at path " ~ path ~ " is red with a red child"); 1822 } 1823 1824 int l = recurse(n.left, path ~ "L"); 1825 int r = recurse(n.right, path ~ "R"); 1826 if (l != r) 1827 { 1828 writeln("bad tree at:"); 1829 debug printTree(n); 1830 throw new Exception( 1831 "Node at path " ~ path ~ " has different number of black nodes on left and right paths" 1832 ); 1833 } 1834 return l + (n.color == n.color.Black ? 1 : 0); 1835 } 1836 1837 try 1838 { 1839 recurse(_end.left, ""); 1840 } 1841 catch (Exception e) 1842 { 1843 debug printTree(_end.left, 0); 1844 throw e; 1845 } 1846 } 1847 } 1848 1849 /** 1850 Formats the RedBlackTree into a sink function. For more info see $(D 1851 std.format.formatValue). Note that this only is available when the 1852 element type can be formatted. Otherwise, the default toString from 1853 Object is used. 1854 */ 1855 static if (is(typeof((){FormatSpec!(char) fmt; formatValue((const(char)[]) {}, ConstRange.init, fmt);}))) 1856 { 1857 void toString(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) const 1858 { 1859 sink("RedBlackTree("); 1860 sink.formatValue(this[], fmt); 1861 sink(")"); 1862 } 1863 } 1864 1865 /** 1866 * Constructor. Pass in an array of elements, or individual elements to 1867 * initialize the tree with. 1868 */ 1869 this(Elem[] elems...) 1870 { 1871 _setup(); 1872 stableInsert(elems); 1873 } 1874 1875 /** 1876 * Constructor. Pass in a range of elements to initialize the tree with. 1877 */ 1878 this(Stuff)(Stuff stuff) 1879 if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, Elem)) 1880 { 1881 _setup(); 1882 stableInsert(stuff); 1883 } 1884 1885 /// 1886 this() 1887 { 1888 _setup(); 1889 } 1890 1891 private this(Node end, size_t length) 1892 { 1893 _end = end; 1894 _begin = end.leftmost; 1895 _length = length; 1896 } 1897 } 1898 1899 //Verify Example for removeKey. 1900 @safe pure unittest 1901 { 1902 import std.algorithm.comparison : equal; 1903 auto rbt = redBlackTree!true(0, 1, 1, 1, 4, 5, 7); 1904 rbt.removeKey(1, 4, 7); 1905 assert(equal(rbt[], [0, 1, 1, 5])); 1906 rbt.removeKey(1, 1, 0); 1907 assert(equal(rbt[], [5])); 1908 } 1909 1910 //Tests for removeKey 1911 @safe pure unittest 1912 { 1913 import std.algorithm.comparison : equal; 1914 { 1915 auto rbt = redBlackTree(["hello", "world", "foo", "bar"]); 1916 assert(equal(rbt[], ["bar", "foo", "hello", "world"])); 1917 assert(rbt.removeKey("hello") == 1); 1918 assert(equal(rbt[], ["bar", "foo", "world"])); 1919 assert(rbt.removeKey("hello") == 0); 1920 assert(equal(rbt[], ["bar", "foo", "world"])); 1921 assert(rbt.removeKey("hello", "foo", "bar") == 2); 1922 assert(equal(rbt[], ["world"])); 1923 assert(rbt.removeKey(["", "world", "hello"]) == 1); 1924 assert(rbt.empty); 1925 } 1926 1927 { 1928 auto rbt = redBlackTree([1, 2, 12, 27, 4, 500]); 1929 assert(equal(rbt[], [1, 2, 4, 12, 27, 500])); 1930 assert(rbt.removeKey(1u) == 1); 1931 assert(equal(rbt[], [2, 4, 12, 27, 500])); 1932 assert(rbt.removeKey(cast(byte) 1) == 0); 1933 assert(equal(rbt[], [2, 4, 12, 27, 500])); 1934 assert(rbt.removeKey(1, 12u, cast(byte) 27) == 2); 1935 assert(equal(rbt[], [2, 4, 500])); 1936 assert(rbt.removeKey([cast(short) 0, cast(short) 500, cast(short) 1]) == 1); 1937 assert(equal(rbt[], [2, 4])); 1938 } 1939 } 1940 1941 @safe pure unittest 1942 { 1943 void test(T)() 1944 { 1945 auto rt1 = new RedBlackTree!(T, "a < b", false)(); 1946 auto rt2 = new RedBlackTree!(T, "a < b", true)(); 1947 auto rt3 = new RedBlackTree!(T, "a > b", false)(); 1948 auto rt4 = new RedBlackTree!(T, "a > b", true)(); 1949 } 1950 1951 test!long(); 1952 test!ulong(); 1953 test!int(); 1954 test!uint(); 1955 test!short(); 1956 test!ushort(); 1957 test!byte(); 1958 test!byte(); 1959 } 1960 1961 // https://issues.dlang.org/show_bug.cgi?id=19626 1962 @safe pure unittest 1963 { 1964 enum T { a, b } 1965 alias t = RedBlackTree!T; 1966 } 1967 1968 import std.range.primitives : isInputRange, ElementType; 1969 import std.traits : isArray, isSomeString; 1970 1971 /++ 1972 Convenience function for creating a `RedBlackTree!E` from a list of 1973 values. 1974 1975 Params: 1976 allowDuplicates = Whether duplicates should be allowed (optional, default: false) 1977 less = predicate to sort by (optional) 1978 elems = elements to insert into the rbtree (variadic arguments) 1979 range = range elements to insert into the rbtree (alternative to elems) 1980 +/ 1981 auto redBlackTree(E)(E[] elems...) 1982 { 1983 return new RedBlackTree!E(elems); 1984 } 1985 1986 /++ Ditto +/ 1987 auto redBlackTree(bool allowDuplicates, E)(E[] elems...) 1988 { 1989 return new RedBlackTree!(E, "a < b", allowDuplicates)(elems); 1990 } 1991 1992 /++ Ditto +/ 1993 auto redBlackTree(alias less, E)(E[] elems...) 1994 if (is(typeof(binaryFun!less(E.init, E.init)))) 1995 { 1996 return new RedBlackTree!(E, less)(elems); 1997 } 1998 1999 /++ Ditto +/ 2000 auto redBlackTree(alias less, bool allowDuplicates, E)(E[] elems...) 2001 if (is(typeof(binaryFun!less(E.init, E.init)))) 2002 { 2003 //We shouldn't need to instantiate less here, but for some reason, 2004 //dmd can't handle it if we don't (even though the template which 2005 //takes less but not allowDuplicates works just fine). 2006 return new RedBlackTree!(E, binaryFun!less, allowDuplicates)(elems); 2007 } 2008 2009 /++ Ditto +/ 2010 auto redBlackTree(Stuff)(Stuff range) 2011 if (isInputRange!Stuff && !isArray!(Stuff)) 2012 { 2013 return new RedBlackTree!(ElementType!Stuff)(range); 2014 } 2015 2016 /++ Ditto +/ 2017 auto redBlackTree(bool allowDuplicates, Stuff)(Stuff range) 2018 if (isInputRange!Stuff && !isArray!(Stuff)) 2019 { 2020 return new RedBlackTree!(ElementType!Stuff, "a < b", allowDuplicates)(range); 2021 } 2022 2023 /++ Ditto +/ 2024 auto redBlackTree(alias less, Stuff)(Stuff range) 2025 if ( is(typeof(binaryFun!less((ElementType!Stuff).init, (ElementType!Stuff).init))) 2026 && isInputRange!Stuff && !isArray!(Stuff)) 2027 { 2028 return new RedBlackTree!(ElementType!Stuff, less)(range); 2029 } 2030 2031 /++ Ditto +/ 2032 auto redBlackTree(alias less, bool allowDuplicates, Stuff)(Stuff range) 2033 if ( is(typeof(binaryFun!less((ElementType!Stuff).init, (ElementType!Stuff).init))) 2034 && isInputRange!Stuff && !isArray!(Stuff)) 2035 { 2036 //We shouldn't need to instantiate less here, but for some reason, 2037 //dmd can't handle it if we don't (even though the template which 2038 //takes less but not allowDuplicates works just fine). 2039 return new RedBlackTree!(ElementType!Stuff, binaryFun!less, allowDuplicates)(range); 2040 } 2041 2042 /// 2043 @safe pure unittest 2044 { 2045 import std.range : iota; 2046 2047 auto rbt1 = redBlackTree(0, 1, 5, 7); 2048 auto rbt2 = redBlackTree!string("hello", "world"); 2049 auto rbt3 = redBlackTree!true(0, 1, 5, 7, 5); 2050 auto rbt4 = redBlackTree!"a > b"(0, 1, 5, 7); 2051 auto rbt5 = redBlackTree!("a > b", true)(0.1, 1.3, 5.9, 7.2, 5.9); 2052 2053 // also works with ranges 2054 auto rbt6 = redBlackTree(iota(3)); 2055 auto rbt7 = redBlackTree!true(iota(3)); 2056 auto rbt8 = redBlackTree!"a > b"(iota(3)); 2057 auto rbt9 = redBlackTree!("a > b", true)(iota(3)); 2058 } 2059 2060 //Combinations not in examples. 2061 @system pure unittest 2062 { 2063 auto rbt1 = redBlackTree!(true, string)("hello", "hello"); 2064 auto rbt2 = redBlackTree!((a, b){return a < b;}, double)(5.1, 2.3); 2065 auto rbt3 = redBlackTree!("a > b", true, string)("hello", "world"); 2066 } 2067 2068 //Range construction. 2069 @safe pure unittest 2070 { 2071 import std.algorithm.comparison : equal; 2072 import std.range : iota; 2073 auto rbt = new RedBlackTree!(int, "a > b")(iota(5)); 2074 assert(equal(rbt[], [4, 3, 2, 1, 0])); 2075 } 2076 2077 2078 // construction with arrays 2079 @safe pure unittest 2080 { 2081 import std.algorithm.comparison : equal; 2082 2083 auto rbt = redBlackTree!"a > b"([0, 1, 2, 3, 4]); 2084 assert(equal(rbt[], [4, 3, 2, 1, 0])); 2085 2086 auto rbt2 = redBlackTree!"a > b"(["a", "b"]); 2087 assert(equal(rbt2[], ["b", "a"])); 2088 2089 auto rbt3 = redBlackTree!"a > b"([1, 2]); 2090 assert(equal(rbt3[], [2, 1])); 2091 2092 auto rbt4 = redBlackTree([0, 1, 7, 5]); 2093 assert(equal(rbt4[], [0, 1, 5, 7])); 2094 2095 auto rbt5 = redBlackTree(["hello", "world"]); 2096 assert(equal(rbt5[], ["hello", "world"])); 2097 2098 auto rbt6 = redBlackTree!true([0, 1, 5, 7, 5]); 2099 assert(equal(rbt6[], [0, 1, 5, 5, 7])); 2100 2101 auto rbt7 = redBlackTree!"a > b"([0, 1, 5, 7]); 2102 assert(equal(rbt7[], [7, 5, 1, 0])); 2103 2104 auto rbt8 = redBlackTree!("a > b", true)([0.1, 1.3, 5.9, 7.2, 5.9]); 2105 assert(equal(rbt8[], [7.2, 5.9, 5.9, 1.3, 0.1])); 2106 } 2107 2108 // convenience wrapper range construction 2109 @safe pure unittest 2110 { 2111 import std.algorithm.comparison : equal; 2112 import std.range : chain, iota; 2113 2114 auto rbt = redBlackTree(iota(3)); 2115 assert(equal(rbt[], [0, 1, 2])); 2116 2117 auto rbt2 = redBlackTree!"a > b"(iota(2)); 2118 assert(equal(rbt2[], [1, 0])); 2119 2120 auto rbt3 = redBlackTree(chain([0, 1], [7, 5])); 2121 assert(equal(rbt3[], [0, 1, 5, 7])); 2122 2123 auto rbt4 = redBlackTree(chain(["hello"], ["world"])); 2124 assert(equal(rbt4[], ["hello", "world"])); 2125 2126 auto rbt5 = redBlackTree!true(chain([0, 1], [5, 7, 5])); 2127 assert(equal(rbt5[], [0, 1, 5, 5, 7])); 2128 2129 auto rbt6 = redBlackTree!("a > b", true)(chain([0.1, 1.3], [5.9, 7.2, 5.9])); 2130 assert(equal(rbt6[], [7.2, 5.9, 5.9, 1.3, 0.1])); 2131 } 2132 2133 @safe pure unittest 2134 { 2135 import std.array : array; 2136 2137 auto rt1 = redBlackTree(5, 4, 3, 2, 1); 2138 assert(rt1.length == 5); 2139 assert(array(rt1[]) == [1, 2, 3, 4, 5]); 2140 2141 auto rt2 = redBlackTree!"a > b"(1.1, 2.1); 2142 assert(rt2.length == 2); 2143 assert(array(rt2[]) == [2.1, 1.1]); 2144 2145 auto rt3 = redBlackTree!true(5, 5, 4); 2146 assert(rt3.length == 3); 2147 assert(array(rt3[]) == [4, 5, 5]); 2148 2149 auto rt4 = redBlackTree!string("hello", "hello"); 2150 assert(rt4.length == 1); 2151 assert(array(rt4[]) == ["hello"]); 2152 } 2153 2154 @system unittest 2155 { 2156 import std.conv : to; 2157 2158 auto rt1 = redBlackTree!string(); 2159 assert(rt1.to!string == "RedBlackTree([])"); 2160 2161 auto rt2 = redBlackTree!string("hello"); 2162 assert(rt2.to!string == "RedBlackTree([\"hello\"])"); 2163 2164 auto rt3 = redBlackTree!string("hello", "world", "!"); 2165 assert(rt3.to!string == "RedBlackTree([\"!\", \"hello\", \"world\"])"); 2166 2167 // type deduction can be done automatically 2168 auto rt4 = redBlackTree(["hello"]); 2169 assert(rt4.to!string == "RedBlackTree([\"hello\"])"); 2170 } 2171 2172 //constness checks 2173 @safe pure unittest 2174 { 2175 const rt1 = redBlackTree(5,4,3,2,1); 2176 void allQualifiers() pure nothrow @safe @nogc { 2177 assert(!rt1.empty); 2178 assert(rt1.length == 5); 2179 assert(5 in rt1); 2180 } 2181 allQualifiers(); 2182 2183 static assert(is(typeof(rt1.upperBound(3).front) == const(int))); 2184 import std.algorithm.comparison : equal; 2185 assert(rt1.upperBound(3).equal([4, 5])); 2186 assert(rt1.lowerBound(3).equal([1, 2])); 2187 assert(rt1.equalRange(3).equal([3])); 2188 assert(rt1[].equal([1, 2, 3, 4, 5])); 2189 } 2190 2191 //immutable checks 2192 @safe pure unittest 2193 { 2194 immutable rt1 = redBlackTree(5,4,3,2,1); 2195 static assert(is(typeof(rt1.empty))); 2196 static assert(is(typeof(rt1.length))); 2197 static assert(is(typeof(5 in rt1))); 2198 2199 static assert(is(typeof(rt1.upperBound(3).front) == immutable(int))); 2200 import std.algorithm.comparison : equal; 2201 assert(rt1.upperBound(2).equal([3, 4, 5])); 2202 } 2203 2204 // https://issues.dlang.org/show_bug.cgi?id=15941 2205 @safe pure unittest 2206 { 2207 class C {} 2208 RedBlackTree!(C, "cast(void*)a < cast(void*) b") tree; 2209 } 2210 2211 // const/immutable elements (https://issues.dlang.org/show_bug.cgi?id=17519) 2212 @safe pure unittest 2213 { 2214 RedBlackTree!(immutable int) t1; 2215 RedBlackTree!(const int) t2; 2216 2217 import std.algorithm.iteration : map; 2218 static struct S { int* p; } 2219 auto t3 = new RedBlackTree!(immutable S, (a, b) => *a.p < *b.p); 2220 t3.insert([1, 2, 3].map!(x => immutable S(new int(x)))); 2221 static assert(!__traits(compiles, *t3.front.p = 4)); 2222 assert(*t3.front.p == 1); 2223 } 2224 2225 // make sure the comparator can be a delegate 2226 @safe pure unittest 2227 { 2228 import std.algorithm.comparison : equal; 2229 2230 auto t = new RedBlackTree!(int, delegate(a, b) => a > b); 2231 t.insert([1, 3, 5, 4, 2]); 2232 assert(t[].equal([5, 4, 3, 2, 1])); 2233 }