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