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