The OpenD Programming Language

1 /**
2  * T-Tree.
3  * Copyright: © 2015 Economic Modeling Specialists, Intl.
4  * Authors: Brian Schott
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
6  */
7 
8 module containers.ttree;
9 
10 private import containers.internal.node : shouldAddGCRange;
11 private import containers.internal.mixins : AllocatorState;
12 private import std.experimental.allocator.mallocator : Mallocator;
13 
14 /**
15  * Implements a binary search tree with multiple items per tree node.
16  *
17  * T-tree Nodes are (by default) sized to fit within a 64-byte
18  * cache line. The number of items stored per node can be read from the
19  * `nodeCapacity` enum. Each node has 0, 1, or 2 children. Each node has between
20  * 1 and `nodeCapacity` items, or it has `nodeCapacity` items and 0 or
21  * more children.
22  *
23  * Inserting or removing items while iterating a range returned from `opSlice`,
24  * `upperBound`, `equalRange`, or other similar functions will result in
25  * unpredicable and likely invalid iteration orders.
26  *
27  * Params:
28  *     T = the element type
29  *     Allocator = the allocator to use. Defaults to `Mallocator`.
30  *     allowDuplicates = if true, duplicate values will be allowed in the tree
31  *     less = the comparitor function to use
32  *     supportGC = true if the container should support holding references to
33  *         GC-allocated memory.
34  *     cacheLineSize = Nodes will be sized to fit within this number of bytes.
35  * See_also: $(LINK http://en.wikipedia.org/wiki/T-tree)
36  */
37 struct TTree(T, Allocator = Mallocator, bool allowDuplicates = false,
38 	alias less = "a < b", bool supportGC = shouldAddGCRange!T, size_t cacheLineSize = 64)
39 {
40 	/**
41 	 * T-Trees are not copyable due to the way they manage memory and interact
42 	 * with allocators.
43 	 */
44 	this(this) @disable;
45 
46 	static if (stateSize!Allocator != 0)
47 	{
48 		/// No default construction if an allocator must be provided.
49 		this() @disable;
50 
51 		/**
52 		 * Use `allocator` to allocate and free nodes in the tree.
53 		 */
54 		this(Allocator allocator)
55 		in
56 		{
57 			static if (is(typeof(allocator is null)))
58 				assert(allocator !is null, "Allocator must not be null");
59 		}
60 		do
61 		{
62 			this.allocator = allocator;
63 		}
64 
65 		private alias AllocatorType = Allocator;
66 	}
67 	else
68 		private alias AllocatorType = void*;
69 
70 	~this() @trusted
71 	{
72 		scope(failure) assert(false, "TTree destructor threw an exception");
73 		clear();
74 	}
75 
76 	/**
77 	 * Removes all elements from the tree.
78 	 */
79 	void clear()
80 	{
81 		_length = 0;
82 		if (root is null)
83 			return;
84 		static if (stateSize!Allocator > 0)
85 			deallocateNode(root, allocator);
86 		else
87 			deallocateNode(root, null);
88 	}
89 
90 	debug(EMSI_CONTAINERS) invariant()
91 	{
92 		assert (root is null || _length != 0, "Empty tree with non-null root");
93 	}
94 
95 	/**
96 	 * $(B tree ~= item) operator overload.
97 	 */
98 	void opOpAssign(string op)(T value) if (op == "~")
99 	{
100 		insert(value);
101 	}
102 
103 	/**
104 	 * Inserts the given value(s) into the tree.
105 	 *
106 	 * This is not a stable insert. You will get strange results if you insert
107 	 * into a tree while iterating over it.
108 	 *
109 	 * Params:
110 	 *     value = the value to insert
111 	 *     overwrite = if `true` the given `value` will replace the first item
112 	 *         in the tree that is equivalent (That is greater-than and less-than
113 	 *         are both false) to `value`. This is useful in cases where opCmp
114 	 *         and opEquals for `T` type have different meanings. For example,
115 	 *         if the element type is a circle that has a position and a color,
116 	 *         the circle could implement `opCmp` to sort by color, and calling
117 	 *         `insert` with `overwrite` set to `true` would allow you to update
118 	 *         the position of the circle with a certain color in the tree.
119 	 * Returns: the number of values added.
120 	 */
121 	size_t insert(T value, bool overwrite = false) @safe
122 	{
123 		if (root is null)
124 		{
125 			static if (stateSize!Allocator > 0)
126 				root = allocateNode(cast(Value) value, null, allocator);
127 			else
128 				root = allocateNode(cast(Value) value, null, null);
129 			++_length;
130 			return true;
131 		}
132 		static if (stateSize!Allocator > 0)
133 			immutable bool r = root.insert(cast(Value) value, root, allocator, overwrite);
134 		else
135 			immutable bool r = root.insert(cast(Value) value, root, null, overwrite);
136 		if (r)
137 			++_length;
138 		return r ? 1 : 0;
139 	}
140 
141 	/// ditto
142 	size_t insert(R)(R r, bool overwrite = false) if (isInputRange!R && is(ElementType!R == T))
143 	{
144 		size_t retVal;
145 		while (!r.empty)
146 		{
147 			retVal += insert(r.front(), overwrite);
148 			r.popFront();
149 		}
150 		return retVal;
151 	}
152 
153 	/// ditto
154 	size_t insert(T[] values, bool overwrite = false)
155 	{
156 		size_t retVal;
157 		foreach (ref v; values)
158 			retVal += insert(v, overwrite);
159 		return retVal;
160 	}
161 
162 	/// ditto
163 	alias insertAnywhere = insert;
164 
165 	/// ditto
166 	alias put = insert;
167 
168 	/**
169 	 * Removes a single value from the tree, or does nothing.
170 	 *
171 	 * If `allowDuplicates` is true only a single element that is equivalent to
172 	 * the given `value` will be removed. Which of these elements is removed is
173 	 * not defined.
174 	 *
175 	 * Params:
176 	 *     value = a value equal to the one to be removed
177 	 *     cleanup = a function that should be run on the removed item
178 	 * Retuns: true if any value was removed
179 	 */
180 	bool remove(T value, void delegate(T) cleanup = null)
181 	{
182 		static if (stateSize!Allocator > 0)
183 			immutable bool removed = root !is null && root.remove(cast(Value) value, root, allocator, cleanup);
184 		else
185 			immutable bool removed = root !is null && root.remove(cast(Value) value, root, null, cleanup);
186 		if (removed)
187 		{
188 			--_length;
189 			if (_length == 0)
190 			{
191 				static if (stateSize!Allocator > 0)
192 					deallocateNode(root, allocator);
193 				else
194 					deallocateNode(root, null);
195 			}
196 		}
197 		return removed;
198 	}
199 
200 	/**
201 	 * Returns: true if the tree _conains the given value
202 	 */
203 	bool contains(T value) const @nogc @safe
204 	{
205 		return root !is null && root.contains(value);
206 	}
207 
208 	/**
209 	 * Returns: the number of elements in the tree.
210 	 */
211 	size_t length() const pure nothrow @nogc @safe @property
212 	{
213 		return _length;
214 	}
215 
216 	/**
217 	 * Returns: true if the tree is empty.
218 	 */
219 	bool empty() const pure nothrow @nogc @safe @property
220 	{
221 		return _length == 0;
222 	}
223 
224 	/**
225 	 * Returns: a range over the tree. Do not insert into the tree while
226 	 *     iterating because you may iterate over the same value multiple times
227 	 *     or skip some values entirely.
228 	 */
229 	auto opSlice(this This)() inout @trusted @nogc
230 	{
231 		return Range!(This)(cast(const(Node)*) root, RangeType.all, T.init);
232 	}
233 
234 	/**
235 	 * Returns: a range of elements which are less than value.
236 	 */
237 	auto lowerBound(this This)(inout T value) inout @trusted
238 	{
239 		return Range!(This)(cast(const(Node)*) root, RangeType.lower, value);
240 	}
241 
242 	/**
243 	 * Returns: a range of elements which are equivalent (though not necessarily
244 	 *     equal) to value.
245 	 */
246 	auto equalRange(this This)(inout T value) inout @trusted
247 	{
248 		return Range!(This)(cast(const(Node)*) root, RangeType.equal, value);
249 	}
250 
251 	/**
252 	 * Returns: a range of elements which are greater than value.
253 	 */
254 	auto upperBound(this This)(inout T value) inout @trusted
255 	{
256 		return Range!(This)(cast(const(Node)*) root, RangeType.upper, value);
257 	}
258 
259 	/**
260 	 * Returns: the first element in the tree.
261 	 */
262 	auto front(this This)() inout pure @trusted @property
263 	{
264 		import std.exception : enforce;
265 
266 		alias CET = ContainerElementType!(This, T);
267 		enforce(!empty(), "Attepted to get the front of an empty tree.");
268 		Node* current = cast(Node*) root;
269 		while (current.left !is null)
270 			current = current.left;
271 		return cast(CET) current.values[0];
272 	}
273 
274 	/**
275 	 * Returns: the last element in the tree.
276 	 */
277 	auto back(this This)() inout pure @trusted @property
278 	{
279 		import std.exception : enforce;
280 
281 		alias CET = ContainerElementType!(This, T);
282 		enforce(!empty(), "Attepted to get the back of an empty tree.");
283 		Node* current = cast(Node*) root;
284 		while (current.right !is null)
285 			current = current.right;
286 		return cast(CET) current.values[current.nextAvailableIndex - 1];
287 	}
288 
289 	/**
290 	 * Tree range
291 	 */
292 	static struct Range(ThisT)
293 	{
294 		@disable this();
295 
296 		/**
297 		 * Standard range operations
298 		 */
299 		ET front() const @property @nogc
300 		{
301 			return cast(typeof(return)) current.values[index];
302 		}
303 
304 		/// ditto
305 		bool empty() const pure nothrow @nogc @safe @property
306 		{
307 			return current is null;
308 		}
309 
310 		/// ditto
311 		void popFront()
312 		{
313 			_popFront();
314 			if (current is null)
315 				return;
316 			with (RangeType) final switch (type)
317 			{
318 			case upper:
319 			case all: break;
320 			case equal:
321 				if (_less(val, front()))
322 					current = null;
323 				break;
324 			case lower:
325 				if (!_less(front(), val))
326 					current = null;
327 				break;
328 			}
329 		}
330 
331 	package(containers):
332 
333 		// The TreeMap container needs to be able to modify part of the tree
334 		// in-place. The reason that this works is that the value part of the
335 		// key-value struct contained in a TTree used by a TreeMap is not used
336 		// when comparing nodes. Normal users of the containers library cannot
337 		// get a reference to the elements because modifying them will violate
338 		// the ordering invariant of the tree.
339 		T* _containersFront() const @property @nogc @trusted
340 		{
341 			return cast(T*) &current.values[index];
342 		}
343 
344 	private:
345 
346 		alias ET = ContainerElementType!(ThisT, T);
347 
348 		void currentToLeftmost() @nogc
349 		{
350 			if (current is null)
351 				return;
352 			while (current.left !is null)
353 				current = current.left;
354 		}
355 
356 		void currentToLeastContaining(inout T val)
357 		{
358 			if (current is null)
359 				return;
360 			while (current !is null)
361 			{
362 				assert(current.registry != 0, "Empty node");
363 				auto first = current.values[0];
364 				auto last = current.values[current.nextAvailableIndex - 1];
365 				immutable bool valLessFirst = _less(val, first);
366 				immutable bool valLessLast = _less(val, last);
367 				immutable bool firstLessVal = _less(first, val);
368 				immutable bool lastLessVal = _less(last, val);
369 				if (firstLessVal && valLessLast)
370 					return;
371 				else if (valLessFirst)
372 					current = current.left;
373 				else if (lastLessVal)
374 					current = current.right;
375 				else
376 				{
377 					static if (allowDuplicates)
378 					{
379 						if (!valLessFirst && !firstLessVal)
380 						{
381 							auto c = current;
382 							current = current.left;
383 							currentToLeastContaining(val);
384 							if (current is null)
385 								current = c;
386 							return;
387 						}
388 						else
389 							return;
390 					}
391 					else
392 						return;
393 				}
394 
395 			}
396 		}
397 
398 		this(inout(Node)* n, RangeType type, inout T val) @nogc
399 		{
400 			current = n;
401 			this.type = type;
402 			this.val = val;
403 			with (RangeType) final switch(type)
404 			{
405 			case all:
406 				currentToLeftmost();
407 				break;
408 			case lower:
409 				currentToLeftmost();
410 				if (_less(val, front()))
411 					current = null;
412 				break;
413 			case equal:
414 				currentToLeastContaining(val);
415 				while (current !is null && _less(front(), val))
416 					_popFront();
417 				if (current is null || _less(front(), val) || _less(val, front()))
418 					current = null;
419 				break;
420 			case upper:
421 				currentToLeastContaining(val);
422 				while (current !is null && !_less(val, front()))
423 					_popFront();
424 				break;
425 			}
426 		}
427 
428 		void _popFront() @nogc
429 		in
430 		{
431 			assert (!empty, "Calling .popFront with empty TTree");
432 		}
433 		do
434 		{
435 			index++;
436 			if (index >= nodeCapacity || current.isFree(index))
437 			{
438 				index = 0;
439 				if (current.right !is null)
440 				{
441 					current = current.right;
442 					while (current.left !is null)
443 						current = current.left;
444 				}
445 				else if (current.parent is null)
446 					current = null;
447 				else if (current.parent.left is current)
448 					current = current.parent;
449 				else
450 				{
451 					while (current.parent.right is current)
452 					{
453 						current = current.parent;
454 						if (current.parent is null)
455 						{
456 							current = null;
457 							return;
458 						}
459 					}
460 					current = current.parent;
461 				}
462 			}
463 		}
464 
465 		size_t index;
466 		const(Node)* current;
467 		const RangeType type;
468 		const T val;
469 	}
470 
471 	mixin AllocatorState!Allocator;
472 
473 	/// The number of values that can be stored in a single T-Tree node.
474 	enum size_t nodeCapacity = N[0];
475 
476 private:
477 
478 	import containers.internal.element_type : ContainerElementType;
479 	import containers.internal.node : FatNodeInfo, fullBits, shouldAddGCRange, shouldNullSlot;
480 	import containers.internal.storage_type : ContainerStorageType;
481 	import std.algorithm : sort;
482 	import std.functional: binaryFun;
483 	import std.range : ElementType, isInputRange;
484 	import std.traits: isPointer, PointerTarget;
485 	import std.experimental.allocator.common : stateSize;
486 
487 	alias N = FatNodeInfo!(T.sizeof, 3, cacheLineSize, ulong.sizeof);
488 	alias Value = ContainerStorageType!T;
489 	alias BookkeepingType = N[1];
490 	enum HEIGHT_BIT_OFFSET = 48UL;
491 	enum fullBitPattern = fullBits!(ulong, nodeCapacity);
492 	enum RangeType : ubyte { all, lower, equal, upper }
493 	enum bool useGC = supportGC && shouldAddGCRange!T;
494 
495 	static assert (nodeCapacity <= HEIGHT_BIT_OFFSET, "cannot fit height info and registry in ulong");
496 	static assert (nodeCapacity <= (typeof(Node.registry).sizeof * 8));
497 	static assert (Node.sizeof <= cacheLineSize);
498 
499 	// If we're storing a struct that defines opCmp, don't compare pointers as
500 	// that is almost certainly not what the user intended.
501 	static if (is(typeof(less) == string ))
502 	{
503 		// Everything inside of this `static if` is dumb. `binaryFun` does not
504 		// correctly infer nothrow and @nogc attributes, among other things, so
505 		// we need to declare a function here that has its attributes properly
506 		// inferred. It's not currently possible, however, to use this function
507 		// with std.algorithm.sort because of symbol visibility issues. Because
508 		// of this problem, keep a duplicate of the sorting predicate in string
509 		// form in the `_lessStr` alias.
510 		static if (less == "a < b" && isPointer!T
511 				&& __traits(hasMember, PointerTarget!T, "opCmp"))
512 		{
513 			enum _lessStr = "a.opCmp(*b) < 0";
514 			static bool _less(TT)(const TT a, const TT b)
515 			{
516 				return a.opCmp(*b) < 0;
517 			}
518 		}
519 		else
520 		{
521 			enum _lessStr = less;
522 			alias _less = binaryFun!less;
523 		}
524 	}
525 	else
526 		alias _less = binaryFun!less;
527 
528 	static Node* allocateNode(Value value, Node* parent, AllocatorType allocator) @trusted
529 	out (result)
530 	{
531 		assert (result.left is null);
532 		assert (result.right is null);
533 	}
534 	do
535 	{
536 		import core.memory : GC;
537 		import std.experimental.allocator : make;
538 
539 		static if (stateSize!Allocator == 0)
540 			Node* n = make!Node(Allocator.instance);
541 		else
542 			Node* n = make!Node(allocator);
543 		n.parent = parent;
544 		n.markUsed(0);
545 		n.values[0] = cast(Value) value;
546 		static if (useGC)
547 			GC.addRange(n, Node.sizeof);
548 		return n;
549 	}
550 
551 	static void deallocateNode(ref Node* n, AllocatorType allocator)
552 	in
553 	{
554 		assert (n !is null);
555 	}
556 	do
557 	{
558 		import std.experimental.allocator : dispose;
559 		import core.memory : GC;
560 
561 		if (n.left !is null)
562 			deallocateNode(n.left, allocator);
563 		if (n.right !is null)
564 			deallocateNode(n.right, allocator);
565 
566 		static if (useGC)
567 			GC.removeRange(n);
568 		static if (stateSize!Allocator == 0)
569 			dispose(Allocator.instance, n);
570 		else
571 			dispose(allocator, n);
572 		n = null;
573 	}
574 
575 	static struct Node
576 	{
577 		private size_t nextAvailableIndex() const pure nothrow @nogc @safe
578 		{
579 			import containers.internal.backwards : bsf;
580 
581 			return bsf(~(registry & fullBitPattern));
582 		}
583 
584 		private void markUsed(size_t index) pure nothrow @nogc @safe
585 		{
586 			registry |= (1UL << index);
587 		}
588 
589 		private void markUnused(size_t index) pure nothrow @nogc @safe
590 		{
591 			registry &= ~(1UL << index);
592 			static if (shouldNullSlot!T)
593 				values[index] = null;
594 		}
595 
596 		private bool isFree(size_t index) const pure nothrow @nogc @safe
597 		{
598 			return (registry & (1UL << index)) == 0;
599 		}
600 
601 		private bool isFull() const pure nothrow @nogc @safe
602 		{
603 			return (registry & fullBitPattern) == fullBitPattern;
604 		}
605 
606 		private bool isEmpty() const pure nothrow @nogc @safe
607 		{
608 			return (registry & fullBitPattern) == 0;
609 		}
610 
611 		bool contains(Value value) const @trusted
612 		{
613 			import std.range : assumeSorted;
614 			size_t i = nextAvailableIndex();
615 			if (_less(value, cast(Value) values[0]))
616 				return left !is null && left.contains(value);
617 			if (_less(values[i - 1], value))
618 				return right !is null && right.contains(value);
619 			static if (is(typeof(_lessStr)))
620 				return !assumeSorted!_lessStr(values[0 .. i]).equalRange(value).empty;
621 			else
622 				return !assumeSorted!_less(values[0 .. i]).equalRange(value).empty;
623 		}
624 
625 		ulong calcHeight() pure nothrow @nogc @safe
626 		{
627 			immutable ulong l = left !is null ? left.height() : 0;
628 			immutable ulong r = right !is null ? right.height() : 0;
629 			immutable ulong h = 1 + (l > r ? l : r);
630 			assert (h < ushort.max, "Height overflow");
631 			registry &= fullBitPattern;
632 			registry |= (h << HEIGHT_BIT_OFFSET);
633 			return h;
634 		}
635 
636 		ulong height() const pure nothrow @nogc @safe
637 		{
638 			return registry >>> HEIGHT_BIT_OFFSET;
639 		}
640 
641 		int imbalanced() const pure nothrow @nogc @safe
642 		{
643 			if (right !is null
644 					&& ((left is null && right.height() > 1)
645 					|| (left !is null && right.height() > left.height() + 1)))
646 				return 1;
647 			if (left !is null
648 					&& ((right is null && left.height() > 1)
649 					|| (right !is null && left.height() > right.height() + 1)))
650 				return -1;
651 			return 0;
652 		}
653 
654 		bool insert(T value, ref Node* root, AllocatorType allocator, bool overwrite) @trusted
655 		in
656 		{
657 			static if (isPointer!T || is (T == class) || is (T == interface))
658 				assert (value !is null, "Inserting null values is not allowed");
659 		}
660 		do
661 		{
662 			import std.algorithm : sort;
663 			import std.range : assumeSorted;
664 			if (!isFull())
665 			{
666 				immutable size_t index = nextAvailableIndex();
667 				static if (!allowDuplicates)
668 				{
669 					static if (is(typeof(_lessStr)))
670 						auto r = assumeSorted!_lessStr(values[0 .. index]).trisect(
671 							cast(Value) value);
672 					else
673 						auto r = assumeSorted!_less(values[0 .. index]).trisect(
674 							cast(Value) value);
675 					if (!r[1].empty)
676 					{
677 						if (overwrite)
678 						{
679 							values[r[0].length] = cast(Value) value;
680 							return true;
681 						}
682 						return false;
683 					}
684 				}
685 				values[index] = cast(Value) value;
686 				markUsed(index);
687 				static if (is(typeof(_lessStr)))
688 					sort!_lessStr(values[0 .. index + 1]);
689 				else
690 					sort!_less(values[0 .. index + 1]);
691 				return true;
692 			}
693 			if (_less(value, values[0]))
694 			{
695 				if (left is null)
696 				{
697 					left = allocateNode(cast(Value) value, &this, allocator);
698 					calcHeight();
699 					return true;
700 				}
701 				immutable bool b = left.insert(value, root, allocator, overwrite);
702 				if (imbalanced() == -1)
703 					rotateRight(root, allocator);
704 				calcHeight();
705 				return b;
706 			}
707 			if (_less(values[$ - 1], cast(Value) value))
708 			{
709 				if (right is null)
710 				{
711 					right = allocateNode(value, &this, allocator);
712 					calcHeight();
713 					return true;
714 				}
715 				immutable bool b = right.insert(value, root, allocator, overwrite);
716 				if (imbalanced() == 1)
717 					rotateLeft(root, allocator);
718 				calcHeight();
719 				return b;
720 			}
721 			static if (!allowDuplicates)
722 			{
723 				static if (is(typeof(_lessStr)))
724 				{
725 					if (!assumeSorted!_lessStr(values[]).equalRange(cast(Value) value).empty)
726 						return false;
727 				}
728 				else
729 				{
730 					if (!assumeSorted!_less(values[]).equalRange(cast(Value) value).empty)
731 						return false;
732 				}
733 			}
734 
735 			Value[nodeCapacity + 1] temp = void;
736 			temp[0 .. $ - 1] = values[];
737 			temp[$ - 1] = cast(Value) value;
738 			static if (is(typeof(_lessStr)))
739 				sort!_lessStr(temp[]);
740 			else
741 				sort!_less(temp[]);
742 			if (right is null)
743 			{
744 				values[] = temp[0 .. $ - 1];
745 				right = allocateNode(temp[$ - 1], &this, allocator);
746 				return true;
747 			}
748 			if (left is null)
749 			{
750 				values[] = temp[1 .. $];
751 				left = allocateNode(temp[0], &this, allocator);
752 				return true;
753 			}
754 			if (right.height < left.height)
755 			{
756 				values[] = temp[0 .. $ - 1];
757 				immutable bool b = right.insert(temp[$ - 1], root, allocator, overwrite);
758 				if (imbalanced() == 1)
759 					rotateLeft(root, allocator);
760 				calcHeight();
761 				return b;
762 			}
763 			values[] = temp[1 .. $];
764 			immutable bool b = left.insert(temp[0], root, allocator, overwrite);
765 			if (imbalanced() == -1)
766 				rotateRight(root, allocator);
767 			calcHeight();
768 			return b;
769 		}
770 
771 		bool remove(Value value, ref Node* n, AllocatorType allocator,
772 			void delegate(T) cleanup = null)
773 		{
774 			import std.range : assumeSorted;
775 			assert (!isEmpty(), "Calling .remove on an empty TTree.Node");
776 			if (isFull() && _less(value, values[0]))
777 			{
778 				immutable bool r = left !is null && left.remove(value, left, allocator, cleanup);
779 				if (left.isEmpty())
780 					deallocateNode(left, allocator);
781 				return r;
782 			}
783 			if (isFull() && _less(values[$ - 1], value))
784 			{
785 				immutable bool r = right !is null && right.remove(value, right, allocator, cleanup);
786 				if (right.isEmpty())
787 					deallocateNode(right, allocator);
788 				return r;
789 			}
790 			size_t i = nextAvailableIndex();
791 			static if (is(typeof(_lessStr)))
792 				auto sv = assumeSorted!_lessStr(values[0 .. i]);
793 			else
794 				auto sv = assumeSorted!_less(values[0 .. i]);
795 			auto tri = sv.trisect(value);
796 			if (tri[1].length == 0)
797 				return false;
798 			// Clean up removed item
799 			if (cleanup !is null)
800 				cleanup(tri[1][0]);
801 			immutable size_t l = tri[0].length;
802 			if (right is null && left is null)
803 			{
804 				Value[nodeCapacity - 1] temp;
805 				temp[0 .. l] = values[0 .. l];
806 				temp[l .. $] = values[l + 1 .. $];
807 				values[0 .. $ - 1] = temp[];
808 				markUnused(nextAvailableIndex() - 1);
809 			}
810 			else if (right !is null)
811 			{
812 				Value[nodeCapacity - 1] temp;
813 				temp[0 .. l] = values[0 .. l];
814 				temp[l .. $] = values[l + 1 .. $];
815 				values[0 .. $ - 1] = temp[];
816 				values[$ - 1] = right.removeSmallest(allocator);
817 				if (right.isEmpty())
818 					deallocateNode(right, allocator);
819 			}
820 			else if (left !is null)
821 			{
822 				Value[nodeCapacity - 1] temp;
823 				temp[0 .. l] = values[0 .. l];
824 				temp[l .. $] = values[l + 1 .. $];
825 				values[1 .. $] = temp[];
826 				values[0] = left.removeLargest(allocator);
827 				if (left.isEmpty())
828 					deallocateNode(left, allocator);
829 			}
830 			return true;
831 		}
832 
833 		Value removeSmallest(AllocatorType allocator)
834 		in
835 		{
836 			assert (!isEmpty(), "Calling .removeSmallest on an empty TTree.Node");
837 		}
838 		do
839 		{
840 			if (left is null && right is null)
841 			{
842 				Value r = values[0];
843 				Value[nodeCapacity - 1] temp = void;
844 				temp[] = values[1 .. $];
845 				values[0 .. $ - 1] = temp[];
846 				markUnused(nextAvailableIndex() - 1);
847 				return r;
848 			}
849 			if (left !is null)
850 			{
851 				auto r = left.removeSmallest(allocator);
852 				if (left.isEmpty())
853 					deallocateNode(left, allocator);
854 				return r;
855 			}
856 			Value r = values[0];
857 			Value[nodeCapacity - 1] temp = void;
858 			temp[] = values[1 .. $];
859 			values[0 .. $ - 1] = temp[];
860 			values[$ - 1] = right.removeSmallest(allocator);
861 			if (right.isEmpty())
862 				deallocateNode(right, allocator);
863 			return r;
864 		}
865 
866 		Value removeLargest(AllocatorType allocator)
867 		in
868 		{
869 			assert (!isEmpty(), "Calling .removeLargest on an empty TTree.Node");
870 		}
871 		out (result)
872 		{
873 			static if (isPointer!T || is (T == class) || is(T == interface))
874 				assert (result !is null, "Removed a null value");
875 		}
876 		do
877 		{
878 			if (left is null && right is null)
879 			{
880 				immutable size_t i = nextAvailableIndex() - 1;
881 				Value r = values[i];
882 				markUnused(i);
883 				return r;
884 			}
885 			if (right !is null)
886 			{
887 				auto r = right.removeLargest(allocator);
888 				if (right.isEmpty())
889 					deallocateNode(right, allocator);
890 				return r;
891 			}
892 			Value r = values[$ - 1];
893 			Value[nodeCapacity - 1] temp = void;
894 			temp[] = values[0 .. $ - 1];
895 			values[1 .. $] = temp[];
896 			values[0] = left.removeLargest(allocator);
897 			if (left.isEmpty())
898 				deallocateNode(left, allocator);
899 			return r;
900 		}
901 
902 		void rotateLeft(ref Node* root, AllocatorType allocator) @safe
903 		{
904 			Node* newRoot;
905 			if (right.left !is null && right.right is null)
906 			{
907 				newRoot = right.left;
908 				newRoot.parent = this.parent;
909 				newRoot.left = &this;
910 				newRoot.left.parent = newRoot;
911 				newRoot.right = right;
912 				newRoot.right.parent = newRoot;
913 				newRoot.right.left = null;
914 				right = null;
915 				left = null;
916 			}
917 			else
918 			{
919 				newRoot = right;
920 				newRoot.parent = this.parent;
921 				right = newRoot.left;
922 				if (right !is null)
923 					right.parent = &this;
924 				newRoot.left = &this;
925 				this.parent = newRoot;
926 			}
927 			cleanup(newRoot, root, allocator);
928 		}
929 
930 		void rotateRight(ref Node* root, AllocatorType allocator) @safe
931 		{
932 			Node* newRoot;
933 			if (left.right !is null && left.left is null)
934 			{
935 				newRoot = left.right;
936 				newRoot.parent = this.parent;
937 				newRoot.right = &this;
938 				newRoot.right.parent = newRoot;
939 				newRoot.left = left;
940 				newRoot.left.parent = newRoot;
941 				newRoot.left.right = null;
942 				left = null;
943 				right = null;
944 			}
945 			else
946 			{
947 				newRoot = left;
948 				newRoot.parent = this.parent;
949 				left = newRoot.right;
950 				if (left !is null)
951 					left.parent = &this;
952 				newRoot.right = &this;
953 				this.parent = newRoot;
954 			}
955 			cleanup(newRoot, root, allocator);
956 		}
957 
958 		void cleanup(Node* newRoot, ref Node* root, AllocatorType allocator) @safe
959 		{
960 			if (newRoot.parent !is null)
961 			{
962 				if (newRoot.parent.right is &this)
963 					newRoot.parent.right = newRoot;
964 				else
965 					newRoot.parent.left = newRoot;
966 			}
967 			else
968 				root = newRoot;
969 			newRoot.fillFromChildren(root, allocator);
970 			if (newRoot.left !is null)
971 			{
972 				newRoot.left.fillFromChildren(root, allocator);
973 			}
974 			if (newRoot.right !is null)
975 			{
976 				newRoot.right.fillFromChildren(root, allocator);
977 			}
978 			if (newRoot.left !is null)
979 				newRoot.left.calcHeight();
980 			if (newRoot.right !is null)
981 				newRoot.right.calcHeight();
982 			newRoot.calcHeight();
983 		}
984 
985 		void fillFromChildren(ref Node* root, AllocatorType allocator) @trusted
986 		{
987 			while (!isFull())
988 			{
989 				if (left !is null)
990 				{
991 					insert(left.removeLargest(allocator), root, allocator, false);
992 					if (left.isEmpty())
993 						deallocateNode(left, allocator);
994 				}
995 				else if (right !is null)
996 				{
997 					insert(right.removeSmallest(allocator), root, allocator, false);
998 					if (right.isEmpty())
999 						deallocateNode(right, allocator);
1000 				}
1001 				else
1002 					return;
1003 			}
1004 		}
1005 
1006 		debug(EMSI_CONTAINERS) invariant()
1007 		{
1008 			import std.string : format;
1009 			assert (&this !is null, "Null this");
1010 			assert (left !is &this, "%x, %x".format(left, &this));
1011 			assert (right !is &this, "%x, %x".format(right, &this));
1012 			if (left !is null)
1013 			{
1014 				assert (left.left !is &this, "%s".format(values));
1015 				assert (left.right !is &this, "%x, %x".format(left.right, &this));
1016 				assert (left.parent is &this, "%x, %x, %x".format(left, left.parent, &this));
1017 			}
1018 			if (right !is null)
1019 			{
1020 				assert (right.left !is &this, "%s".format(values));
1021 				assert (right.right !is &this, "%s".format(values));
1022 				assert (right.parent is &this, "%x, %x, %x".format(right, right.parent, &this));
1023 			}
1024 		}
1025 
1026 		Value[nodeCapacity] values;
1027 		Node* left;
1028 		Node* right;
1029 		Node* parent;
1030 		ulong registry = 1UL << HEIGHT_BIT_OFFSET;
1031 	}
1032 
1033 	size_t _length;
1034 	Node* root;
1035 }
1036 
1037 version(emsi_containers_unittest) unittest
1038 {
1039 	import core.memory : GC;
1040 	import std.algorithm : equal, sort, map, filter, each;
1041 	import std.array : array;
1042 	import std.range : iota, walkLength, isInputRange;
1043 	import std.string : format;
1044 	import std.uuid : randomUUID;
1045 
1046 	{
1047 		TTree!int kt;
1048 		assert (kt.empty);
1049 		foreach (i; 0 .. 200)
1050 			assert (kt.insert(i));
1051 		assert(kt.front == 0);
1052 		assert(kt.back == 199);
1053 		assert(!kt.empty);
1054 		assert(kt.length == 200);
1055 		assert(kt.contains(30));
1056 	}
1057 
1058 	{
1059 		TTree!int kt;
1060 		assert (!kt.contains(5));
1061 		kt.insert(2_000);
1062 		assert (kt.contains(2_000));
1063 		foreach_reverse (i; 0 .. 1_000)
1064 		{
1065 			assert (kt.insert(i));
1066 		}
1067 		assert (!kt.contains(100_000));
1068 	}
1069 
1070 	{
1071 		import std.random : uniform;
1072 		TTree!int kt;
1073 		foreach (i; 0 .. 1_000)
1074 			kt.insert(uniform(0, 100_000));
1075 	}
1076 
1077 	{
1078 		TTree!int kt;
1079 		kt.insert(10);
1080 		assert (kt.length == 1);
1081 		assert (!kt.insert(10));
1082 		assert (kt.length == 1);
1083 	}
1084 
1085 	{
1086 		TTree!(int, Mallocator, true) kt;
1087 		assert (kt.insert(1));
1088 		assert (kt.length == 1);
1089 		assert (kt.insert(1));
1090 		assert (kt.length == 2);
1091 		assert (kt.contains(1));
1092 	}
1093 
1094 	{
1095 		TTree!(int) kt;
1096 		foreach (i; 0 .. 200)
1097 			assert (kt.insert(i));
1098 		assert (kt.length == 200);
1099 		assert (kt.remove(79));
1100 		assert (!kt.remove(79));
1101 		assert (kt.length == 199);
1102 	}
1103 
1104 	{
1105 		string[] strs = [
1106 			"2c381d2a-bacd-40db-b6d8-055b144c5ee6",
1107 			"62104b50-e235-4c95-bcb9-a545e88e2d09",
1108 			"828c8fc0-a392-4738-a49c-62e991fce090",
1109 			"62e30465-79eb-446e-b34f-af5d7c491486",
1110 			"93ec245b-60d2-4422-91ff-66a6d7e299fc",
1111 			"c1d2f3d7-82cc-4d90-a2c5-9fba335f36cd",
1112 			"c9d8d980-94eb-4941-b873-00d68021522f",
1113 			"82dbc4df-cb3c-447a-9d73-cd6291a0ba02",
1114 			"8d259231-6ab6-49e4-9bb6-fe097c4153ed",
1115 			"f9f2d719-61e1-4f62-ae2c-bf2a24a13d5b"
1116 		];
1117 		TTree!string strings;
1118 		foreach (i, s; strs)
1119 			assert (strings.insert(s));
1120 		sort(strs[]);
1121 		assert (equal(strs, strings[]));
1122 	}
1123 
1124 	foreach (x; 0 .. 1000)
1125 	{
1126 		TTree!string strings;
1127 		string[] strs = iota(10).map!(a => randomUUID().toString()).array();
1128 		foreach (i, s; strs)
1129 			assert (strings.insert(s));
1130 		assert (strings.length == strs.length);
1131 		sort(strs);
1132 		assert (equal(strs, strings[]));
1133 	}
1134 
1135 	{
1136 		TTree!string strings;
1137 		strings.insert(["e", "f", "a", "b", "c", "d"]);
1138 		assert (equal(strings[], ["a", "b", "c", "d", "e", "f"]));
1139 	}
1140 
1141 	{
1142 		TTree!(string, Mallocator, true) strings;
1143 		assert (strings.insert("b"));
1144 		assert (strings.insert("c"));
1145 		assert (strings.insert("a"));
1146 		assert (strings.insert("d"));
1147 		assert (strings.insert("d"));
1148 		assert (strings.length == 5);
1149 		assert (equal(strings.equalRange("d"), ["d", "d"]), format("%s", strings.equalRange("d")));
1150 		assert (equal(strings.equalRange("a"), ["a"]), format("%s", strings.equalRange("a")));
1151 		assert (equal(strings.lowerBound("d"), ["a", "b", "c"]), format("%s", strings.lowerBound("d")));
1152 		assert (equal(strings.upperBound("c"), ["d", "d"]), format("%s", strings.upperBound("c")));
1153 	}
1154 
1155 	{
1156 		static struct S
1157 		{
1158 			string x;
1159 			int opCmp (ref const S other) const @nogc
1160 			{
1161 				if (x < other.x)
1162 					return -1;
1163 				if (x > other.x)
1164 					return 1;
1165 				return 0;
1166 			}
1167 		}
1168 
1169 		TTree!(S*, Mallocator, true) stringTree;
1170 		auto one = S("offset");
1171 		stringTree.insert(&one);
1172 		auto two = S("object");
1173 		assert (stringTree.equalRange(&two).empty);
1174 		assert (!stringTree.equalRange(&one).empty);
1175 		assert (stringTree[].front.x == "offset");
1176 	}
1177 
1178 	{
1179 		static struct TestStruct
1180 		{
1181 			int opCmp(ref const TestStruct other) const @nogc
1182 			{
1183 				return x < other.x ? -1 : (x > other.x ? 1 : 0);
1184 			}
1185 			int x;
1186 			int y;
1187 		}
1188 		TTree!(TestStruct*) tsTree;
1189 		static assert (isInputRange!(typeof(tsTree[])));
1190 		foreach (i; 0 .. 100)
1191 			assert(tsTree.insert(new TestStruct(i, i * 2)));
1192 		assert (tsTree.length == 100);
1193 		auto r = tsTree[];
1194 		TestStruct* prev = r.front();
1195 		r.popFront();
1196 		while (!r.empty)
1197 		{
1198 			assert (r.front.x > prev.x, format("%s %s", prev.x, r.front.x));
1199 			prev = r.front;
1200 			r.popFront();
1201 		}
1202 		TestStruct a = TestStruct(30, 100);
1203 		auto eqArray = array(tsTree.equalRange(&a));
1204 		assert (eqArray.length == 1, format("%d", eqArray.length));
1205 	}
1206 
1207 	{
1208 		import std.algorithm : canFind;
1209 		TTree!int ints;
1210 		foreach (i; 0 .. 50)
1211 			ints ~= i;
1212 		assert (canFind(ints[], 20));
1213 		assert (walkLength(ints[]) == 50);
1214 		assert (walkLength(filter!(a => (a & 1) == 0)(ints[])) == 25);
1215 	}
1216 
1217 	{
1218 		TTree!int ints;
1219 		foreach (i; 0 .. 50)
1220 			ints ~=  i;
1221 		ints.remove(0);
1222 		assert (ints.length == 49);
1223 		foreach (i; 1 .. 12)
1224 			ints.remove(i);
1225 		assert (ints.length == 49 - 11);
1226 	}
1227 
1228 	{
1229 		const(TTree!(const(int))) getInts()
1230 		{
1231 			TTree!(const(int)) t;
1232 			t.insert(1);
1233 			t.insert(2);
1234 			t.insert(3);
1235 			return t;
1236 		}
1237 		auto t = getInts();
1238 		static assert (is (typeof(t[].front) == const(int)));
1239 		assert (equal(t[].filter!(a => a & 1), [1, 3]));
1240 	}
1241 
1242 
1243 	{
1244 		static struct ABC
1245 		{
1246 			ulong a;
1247 			ulong b;
1248 
1249 			int opCmp(ref const ABC other) const @nogc
1250 			{
1251 				if (this.a < other.a)
1252 					return -1;
1253 				if (this.a > other.a)
1254 					return 1;
1255 				return 0;
1256 			}
1257 		}
1258 
1259 		TTree!(ABC, Mallocator, true) tree;
1260 		foreach (i; 0 .. 10)
1261 			tree.insert(ABC(i));
1262 		tree.insert(ABC(15));
1263 		tree.insert(ABC(15));
1264 		tree.insert(ABC(15));
1265 		tree.insert(ABC(15));
1266 		foreach (i; 20 .. 30)
1267 			tree.insert(ABC(i));
1268 		assert(tree.equalRange(ABC(15)).walkLength() == 4,
1269 			format("Actual length = %d", tree.equalRange(ABC(15)).walkLength()));
1270 	}
1271 
1272 	{
1273 		TTree!int ints2;
1274 		iota(0, 1_000_000).each!(a => ints2.insert(a));
1275 		assert(equal(iota(0, 1_000_000), ints2[]));
1276 		assert(ints2.length == 1_000_000);
1277 		foreach (i; 0 .. 1_000_000)
1278 			assert(!ints2.equalRange(i).empty, format("Could not find %d", i));
1279 	}
1280 
1281 	{
1282 		TTree!int ints3;
1283 		foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 0))
1284 			ints3.insert(i);
1285 		assert(ints3.length == 500_000);
1286 		foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 0))
1287 			assert(!ints3.equalRange(i).empty);
1288 		foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 1))
1289 			assert(ints3.equalRange(i).empty);
1290 	}
1291 
1292 	{
1293 		TTree!(ubyte, Mallocator, true) ubytes;
1294 		foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 0).map!(a => cast(ubyte)(a % ubyte.max)))
1295 			ubytes.insert(i);
1296 		assert(ubytes[].walkLength == 500_000, "%d".format(ubytes[].walkLength));
1297 		assert(ubytes.length == 500_000, "%d".format(ubytes.length));
1298 		foreach (i; iota(0, 1_000_000).filter!(a => a % 2 == 0).map!(a => cast(ubyte)(a % ubyte.max)))
1299 			assert(!ubytes.equalRange(i).empty);
1300 	}
1301 
1302 	{
1303 		import std.experimental.allocator.building_blocks.free_list : FreeList;
1304 		import std.experimental.allocator.building_blocks.allocator_list : AllocatorList;
1305 		import std.experimental.allocator.building_blocks.region : Region;
1306 		import std.experimental.allocator.building_blocks.stats_collector : StatsCollector;
1307 		import std.stdio : stdout;
1308 
1309 		StatsCollector!(FreeList!(AllocatorList!(a => Region!(Mallocator)(1024 * 1024)),
1310 			64)) allocator;
1311 		{
1312 			auto ints4 = TTree!(int, typeof(&allocator))(&allocator);
1313 			foreach (i; 0 .. 10_000)
1314 				ints4.insert(i);
1315 			assert(walkLength(ints4[]) == 10_000);
1316 		}
1317 		assert(allocator.numAllocate == allocator.numDeallocate);
1318 		assert(allocator.bytesUsed == 0);
1319 	}
1320 }
1321 
1322 version(emsi_containers_unittest) unittest
1323 {
1324 	static class Foo
1325 	{
1326 		string name;
1327 
1328 		this(string s)
1329 		{
1330 			this.name = s;
1331 		}
1332 	}
1333 
1334 	TTree!(Foo, Mallocator, false, "a.name < b.name") tt;
1335 	auto f = new Foo("foo");
1336 	tt.insert(f);
1337 	f = new Foo("bar");
1338 	tt.insert(f);
1339 	auto r = tt[];
1340 }
1341 
1342 version(emsi_containers_unittest) unittest
1343 {
1344 	import std.range : walkLength;
1345 	import std.stdio;
1346 
1347 	TTree!(int, Mallocator, true) tt;
1348 	tt.insert(10);
1349 	tt.insert(11);
1350 	tt.insert(12);
1351 	assert(tt.length == 3);
1352 	tt.insert(11);
1353 	assert(tt.length == 4);
1354 	tt.remove(11);
1355 	assert(tt.length == 3);
1356 	assert(tt[].walkLength == tt.length);
1357 }