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