1 module collections.treemap;
2 
3 import std.functional : binaryFun;
4 public import collections.commons;
5 /**
6  * Implements an AVL tree backed treemap.
7  * Intended to used as an alternative to D's own associative array.
8  * If E set to void, then it works more like a regular tree datastructure (as a tree set), and can be indexed with any
9  * type K has an opCmp override.
10  * `nogcIndexing` changes the behavior of `opIndex` if no match is found. If set to true, indexing returns the default
11  * value if no match found, which will need some design consideration. If set to false, indexing throws an exception
12  * if no match found.
13  * Nodes should have the lesser elements on the left side, but this behavior can somewhat changed with alias less.
14  */
15 public struct TreeMap(K, E, bool nogcIndexing = true, alias less = "a < b") {
16 	private struct Node {
17 		K				key;		///Identifier key, also used for automatic sorting
18 		static if (typeid(E) !is typeid(void))//(E.stringof != "void")
19 			E			elem;		///The element stored in this field if exists
20 		Node*			left;		///The node that holds a key with a lesser value
21 		Node*			right;		///The node that holds a key with a greater value
22 		string toString() const {
23 			import std.conv : to;
24 			string result = "{K: " ~ to!string(key) ~ " ; ";
25 			static if (typeid(E) !is typeid(void))
26 				result ~= "E: " ~ to!string(elem) ~ " ; ";
27 			if (left) result ~= "L: " ~ left.toString() ~ " ; ";
28 			if (right) result ~= "R: " ~ right.toString() ~ " ; ";
29 			return result ~ "}";
30 		}
31 		///Returns the balance of the node.
32 		@property sizediff_t balance() @nogc @safe pure nothrow const {
33 			sizediff_t result;
34 			if(left) result -= left.height;
35 			if(right) result += right.height;
36 			return result;
37 		}
38 		///Returns the height of the node.
39 		@property size_t height() @nogc @safe pure nothrow const {
40 			const size_t lhs = left ? left.height + 1 : 0;
41 			const size_t rhs = right ? right.height + 1 : 0;
42 			return lhs >= rhs ? lhs : rhs;
43 		}
44 		static if (typeid(E) !is typeid(void)){
45 			/**
46 			 * Implements a simple left-to-right tree traversal.
47 			 */
48 			int opApply(scope int delegate(ref E) dg) {
49 				if(left !is null)
50 					if(left.opApply(dg))
51 						return 1;
52 				if(dg(elem))
53 					return 1;
54 				if(right !is null)
55 					if(right.opApply(dg))
56 						return 1;
57 				return 0;
58 			}
59 			/**
60 			 * Implements a simple left-to-right tree traversal.
61 			 */
62 			int opApply(scope int delegate(K, ref E) dg) {
63 				if(left !is null)
64 					if(left.opApply(dg))
65 						return 1;
66 				if(dg(key, elem))
67 					return 1;
68 				if(right !is null)
69 					if(right.opApply(dg))
70 						return 1;
71 				return 0;
72 			}
73 			/**
74 			 * Implements a simple right-to-left tree traversal.
75 			 */
76 			int opApplyReverse(scope int delegate(ref E) dg) {
77 				if(right !is null)
78 					if(right.opApply(dg))
79 						return 1;
80 				if(dg(elem))
81 					return 1;
82 				if(left !is null)
83 					if(left.opApply(dg))
84 						return 1;
85 				return 0;
86 			}
87 			/**
88 			 * Implements a simple right-to-left tree traversal.
89 			 */
90 			int opApplyReverse(scope int delegate(K, ref E) dg) {
91 				if(right !is null)
92 					if(right.opApply(dg))
93 						return 1;
94 				if(dg(key, elem))
95 					return 1;
96 				if(left !is null)
97 					if(left.opApply(dg))
98 						return 1;
99 				return 0;
100 			}
101 			///Generates an `opApply` and `opApplyReverse` pair for a TreeMap from potential  attributes 
102 			package static string makeFuncTMNode() {
103 				string makeFunc(string attr) {
104 					return "
105 						int opApply(scope int delegate(ref E) " ~ attr ~ " dg) " ~ attr ~ " {
106 							if(left !is null)
107 								if(left.opApply(dg))
108 									return 1;
109 							if(dg(elem))
110 								return 1;
111 							if(right !is null)
112 								if(right.opApply(dg))
113 									return 1;
114 							return 0;
115 						}
116 						int opApply(scope int delegate(K, ref E) " ~ attr ~ " dg) " ~ attr ~ " {
117 							if(left !is null)
118 								if(left.opApply(dg))
119 									return 1;
120 							if(dg(key, elem))
121 								return 1;
122 							if(right !is null)
123 								if(right.opApply(dg))
124 									return 1;
125 							return 0;
126 						}
127 						int opApplyReverse(scope int delegate(ref E) " ~ attr ~ " dg) " ~ attr ~ " {
128 							if(right !is null)
129 								if(right.opApply(dg))
130 									return 1;
131 							if(dg(elem))
132 								return 1;
133 							if(left !is null)
134 								if(left.opApply(dg))
135 									return 1;
136 							return 0;
137 						}
138 						int opApplyReverse(scope int delegate(K, ref E) " ~ attr ~ " dg) " ~ attr ~ " {
139 							if(right !is null)
140 								if(right.opApply(dg))
141 									return 1;
142 							if(dg(key, elem))
143 								return 1;
144 							if(left !is null)
145 								if(left.opApply(dg))
146 									return 1;
147 							return 0;
148 						}";
149 				}
150 				string result;
151 				foreach (attr; attrList) {
152 					result ~= makeFunc(attr);
153 				}
154 				return result;
155 			}
156 			mixin(makeFuncTMNode);
157 		} else {
158 			/**
159 			 * Implements a simple left-to-right tree traversal.
160 			 */
161 			int opApply(scope int delegate(K) dg) {
162 				if(left !is null)
163 					if(left.opApply(dg))
164 						return 1;
165 				if(dg(key))
166 					return 1;
167 				if(right !is null)
168 					if(right.opApply(dg))
169 						return 1;
170 				return 0;
171 			}
172 			/**
173 			 * Implements a simple right-to-left tree traversal.
174 			 */
175 			int opApplyReverse(scope int delegate(K) dg) {
176 				if(right !is null)
177 					if(right.opApply(dg))
178 						return 1;
179 				if(dg(key))
180 					return 1;
181 				if(left !is null)
182 					if(left.opApply(dg))
183 						return 1;
184 				return 0;
185 			}
186 			///Generates an `opApply` and `opApplyReverse` pair for a TreeSet with the supplied attributes
187 			package static string makeFuncTSNode() {
188 				string makeFunc(string attr){
189 					return "int opApply(scope int delegate(K) " ~ attr ~ " dg) " ~ attr ~ " {
190 						if(left !is null)
191 							if(left.opApply(dg))
192 								return 1;
193 						if(dg(key))
194 							return 1;
195 						if(right !is null)
196 							if(right.opApply(dg))
197 								return 1;
198 						return 0;
199 					}
200 					int opApplyReverse(scope int delegate(K) " ~ attr ~ " dg) " ~ attr ~ " {
201 						if(right !is null)
202 							if(right.opApply(dg))
203 								return 1;
204 						if(dg(key))
205 							return 1;
206 						if(left !is null)
207 							if(left.opApply(dg))
208 								return 1;
209 						return 0;
210 					}";
211 				}
212 				string result;
213 				foreach (attr; attrList) {
214 					result ~= makeFunc(attr);
215 				}
216 				return result;
217 			}
218 			mixin(makeFuncTSNode);
219 		}
220 	}
221 	private size_t		nOfElements;///Current number of elements in this collection
222 	private Node*		root;		///The root element of the tree
223 	
224 	static if (E.stringof != "void") {
225 		static if (nogcIndexing) {
226 			/**
227 			 * @nogc capable indexing.
228 			 * Returns the found element if match found.
229 			 * Returns E.init if match not found.
230 			 */
231 			E opIndex(const K key) @nogc @safe pure nothrow {
232 				Node* crnt = root;
233 				while(crnt) {
234 					if(binaryFun!less(key, crnt.key)) {		//key is smaller than current element's, look at lesser elements
235 						crnt = crnt.left;
236 					} else if(binaryFun!less(crnt.key, key)) {			//key is greater than current element's, look at greater elements
237 						crnt = crnt.right;
238 					} else {	//match found, return element
239 						return crnt.elem;
240 						
241 					}
242 				}
243 				return E.init;
244 			}
245 			/**
246 			 * Returns the pointer of the element, or null if key not found.
247 			 */
248 			E* ptrOf(const K key) @nogc @safe pure nothrow {
249 				Node* crnt = root;
250 				while(crnt) {
251 					if(binaryFun!less(key, crnt.key)) {		//key is smaller than current element's, look at lesser elements
252 						crnt = crnt.left;
253 					} else if(binaryFun!less(crnt.key, key)) {			//key is greater than current element's, look at greater elements
254 						crnt = crnt.right;
255 					} else {	//match found, return element
256 						return &crnt.elem;
257 					}
258 				}
259 				return null;
260 			}
261 			/**
262 			 * Returns true if the treemap has the key.
263 			 */
264 			bool has(const K key) @nogc @safe pure nothrow {
265 				return ptrOf(key) !is null;
266 			}
267 			auto opBinaryRight(string op, K)(const K key) @nogc @safe pure nothrow {
268 				static if (op == "in") {
269 					return has(key);
270 				} else static assert(0, "Operator not supported!");
271 			}
272 		} else {
273 			/**
274 			 * Indexing function that relies on the GC, and throws if no match found
275 			 * Can be indexed with any type of value as long as K.opCmp supports it.
276 			 * Returns the found element if match found.
277 			 */
278 			ref E opIndex(K key) @safe pure {
279 				Node* crnt = root;
280 				while(crnt) {
281 					if(binaryFun!less(key, crnt.key)) {		//key is smaller than current element's, look at lesser elements
282 						crnt = crnt.left;
283 					} else if(binaryFun!less(crnt.key, key)) {			//key is greater than current element's, look at greater elements
284 						crnt = crnt.right;
285 					} else {	//match found, return element
286 						return crnt.elem;
287 					}
288 				}
289 				throw new ElementNotFoundException("No match found");
290 			}
291 			/**
292 			 * Returns true if the treemap has the key.
293 			 */
294 			bool has(const K key) @nogc @safe pure nothrow {
295 				Node* crnt = root;
296 				while(crnt) {
297 					if(binaryFun!less(key, crnt.key)) {		//key is smaller than current element's, look at lesser elements
298 						crnt = crnt.left;
299 					} else if(binaryFun!less(crnt.key, key)) {			//key is greater than current element's, look at greater elements
300 						crnt = crnt.right;
301 					} else {	//match found, return element
302 						return true;
303 					}
304 				}
305 				return false;
306 			}
307 			auto opBinaryRight(string op, K)(const K key) @nogc @safe pure nothrow {
308 				static if (op == "in") {
309 					return has(key);
310 				} else static assert(0, "Operator not supported!");
311 			}
312 		}
313 	} else {
314 		/**
315 		 * Creates a treeset from a preexisting range.
316 		 */
317 		public this(R)(R src) @safe pure nothrow {
318 			foreach (key; src) put(key);
319 		}
320 		/**
321 		 * Returns true if the element exists within the set, false otherwise.
322 		 */
323 		public bool has(T)(const T key) @nogc @safe pure nothrow {
324 			Node* crnt = root;
325 			while(crnt) {
326 				if(binaryFun!less(key, crnt.key)) {		//key is smaller than current element's, look at lesser elements
327 					crnt = crnt.left;
328 				} else if(binaryFun!less(crnt.key, key)) {			//key is greater than current element's, look at greater elements
329 					crnt = crnt.right;
330 				} else {	//match found, return true
331 					return true;
332 				}
333 			}
334 			return false;
335 		}
336 		auto opBinaryRight(string op, T)(const T key) {
337 				static if (op == "in") {
338 					return has(key);
339 				} else static assert(0, "Operator not supported!");
340 			}
341 		/**
342 		 * Returns the amount of elements found in the set.
343 		 */
344 		public size_t hasRange(R)(R range) @nogc @safe pure nothrow {
345 			size_t result;
346 			foreach (key; range) {
347 				if(has(key)) result++;
348 			}
349 			return result;
350 		}
351 		/**
352 		 * Set operators.
353 		 * Enables math operations on sets, like unions and intersections.
354 		 * Could work on ranges in general as long as they implement some basic functions, like iteration.
355 		 */
356 		TreeMap!(K, E, nogcIndexing, less) opBinary(string op, R)(R rhs) {
357 			static if(op == "|" || op == "~") {//Union
358 				TreeMap!(K, E, nogcIndexing, less) result;
359 				foreach(e ; this)
360 					result.put(e);
361 				foreach(e ; rhs) 
362 					result.put(e);
363 				return result;
364 			} else static if(op == "&" || op == "*") {//Intersection
365 				TreeMap!(K, E, nogcIndexing, less) result;
366 				foreach(e ; rhs){
367 					if(this.has(e)) result.put(e);
368 				}
369 				return result;
370 			} else static if(op == "-" || op == "/") {//Complement
371 				TreeMap!(K, E, nogcIndexing, less) result;
372 				foreach(e ; this)
373 					result.put(e);
374 				foreach(e ; rhs){
375 					result.removeByElem(e);
376 				}
377 				return result;
378 			} else static if(op == "^"){//Difference
379 				TreeMap!(K, E, nogcIndexing, less) result = this | rhs;
380 				TreeMap!(K, E, nogcIndexing, less) common = this & rhs;
381 				foreach(e ; common){
382 					result.removeByElem(e);
383 				}
384 				return result;
385 			} else static assert(0, "Operator " ~ op ~ "not supported");
386 		}
387 		/**
388 		 * Set operators.
389 		 */
390 		TreeMap!(K, E, nogcIndexing, less) opOpAssign(string op)(K value) {
391 			static if(op == "~=") {//Append
392 				put(value);
393 			} else static if(op == "-=" || op == "/=") {
394 				removeByElem(value);
395 			} else static assert(0, "Operator " ~ op ~ "not supported");
396 			return this;
397 		}
398 		/**
399 		 * Set operators.
400 		 */
401 		TreeMap!(K, E, nogcIndexing, less) opOpAssign(string op, R)(R range) {
402 			static if(op == "~=" || op == "|=") {//Append
403 				foreach(val; range)
404 					put(val);
405 			} else static if(op == "-=" || op == "/=") {
406 				foreach(val; range)
407 					removeByElem(val);
408 			} else static assert(0, "Operator " ~ op ~ "not supported");
409 			return this;
410 		}
411 		static if (nogcIndexing) {
412 			/**
413 			 * @nogc capable indexing.
414 			 * Can be indexed with any type of value as long as K.opCmp supports it and `alias less` hasn't been changed.
415 			 * Returns the found element if match found.
416 			 * Returns E.init if match not found.
417 			 */
418 			K opIndex(T)(T key) @nogc @safe pure nothrow {
419 				Node* crnt = root;
420 				while(crnt) {
421 					if(binaryFun!less(key, crnt.key)) {		//key is smaller than current element's, look at lesser elements
422 						crnt = crnt.left;
423 					} else if(binaryFun!less(crnt.key, key)) {			//key is greater than current element's, look at greater elements
424 						crnt = crnt.right;
425 					} else {	//match found, return element
426 						return crnt.key;
427 					}
428 				}
429 				return K.init;
430 			}
431 			
432 		} else {
433 			/**
434 			 * Indexing function that relies on the GC, and throws if no match found
435 			 * Can be indexed with any type of value as long as K.opCmp supports it and `alias less` hasn't been changed.
436 			 * Returns the found element if match found.
437 			 */
438 			K opIndex(T)(T key) @safe pure {
439 				Node* crnt = root;
440 				while(crnt) {
441 					if(binaryFun!less(key, crnt.key)) {		//key is smaller than current element's, look at lesser elements
442 						crnt = crnt.left;
443 					} else if(binaryFun!less(crnt.key, key)) {			//key is greater than current element's, look at greater elements
444 						crnt = crnt.right;
445 					} else {	//match found, return element
446 						return crnt.key;
447 					}
448 				}
449 				throw new ElementNotFoundException("No match found");
450 			}
451 		}
452 	}
453 	static if (E.stringof != "void"){
454 		/**
455 		 * Assigns a value to the given key.
456 		 * If key found, the value will be overwritten without node insertion.
457 		 * If key isn't found, a new node will be inserted.
458 		 */
459 		auto opIndexAssign(E elem, K key) @safe pure nothrow {
460 			if(!root){	//Best case scenario: root is empty
461 				nOfElements++;
462 				root = new Node(key, elem, null, null);
463 				return elem;
464 			}
465 			Node* crnt = root;
466 			while(crnt) {
467 				if(binaryFun!less(key, crnt.key)) {	//Key is smaller, look at left hand side
468 					if(crnt.left is null) {
469 						crnt.left = new Node(key, elem, null, null);
470 						crnt = null;
471 						nOfElements++;
472 					}
473 					else crnt = crnt.left;
474 				} else if(binaryFun!less(crnt.key, key)) {		//Key is greater, look ay right hand side
475 					if(crnt.right is null) {
476 						crnt.right = new Node(key, elem, null, null);
477 						crnt = null;
478 						nOfElements++;
479 					}
480 					else crnt = crnt.right;
481 				} else {	//Another best case scenario: a keymatch is found
482 					crnt.elem = elem;
483 					crnt = null;
484 				} 
485 			}
486 			rebalance();
487 			return elem;
488 		}
489 		/**
490 		 * Removes an item by key.
491 		 * Returns the removed item if found, or E.init if not.
492 		 */
493 		public E remove(K key) @safe pure nothrow {
494 			import core.memory : GC;
495 			Node* crnt = root, prev;
496 			while(crnt !is null) {
497 				if(binaryFun!less(key, crnt.key)) {		//Key has a lesser value, search on the left.
498 					prev = crnt;
499 					crnt = crnt.left;
500 				} else if(binaryFun!less(crnt.key, key)) {		//Key has a greater value, search on the right
501 					prev = crnt;
502 					crnt = crnt.right;
503 				} else {				//Keymatch must have been found
504 					E result = crnt.elem;
505 					//dispose of the node properly if needed
506 					if(prev !is null) {
507 						if(crnt.left && crnt.right) {	//Worst case scenario: find the smallest node on the right hand side
508 							Node* temp = findMin(crnt.right);
509 							remove(temp.key);
510 							crnt.key = temp.key;
511 							crnt.elem = temp.elem;
512 							return result;
513 						} else if(!crnt.left && crnt.right) {
514 							if(binaryFun!less(key, prev.key)) {	//The node was on the left side of the previous one
515 								prev.left = crnt.right;
516 							} else {
517 								prev.right = crnt.right;
518 							}
519 						} else if(crnt.left && !crnt.right) {
520 							if(binaryFun!less(key, prev.key)) {	//The node was on the left side of the previous one
521 								prev.left = crnt.left;
522 							} else {
523 								prev.right = crnt.left;
524 							}
525 						} else { //Best case scenario: there are no child nodes, just dereference from prev
526 							if(binaryFun!less(key, prev.key)) {	//The node was on the left side of the previous one
527 								prev.left = null;
528 							} else {
529 								prev.right = null;
530 							}
531 						}
532 					} else {//must be root element
533 						if(crnt.left && crnt.right) {	//Worst case scenario: find the smallest node on the right hand side
534 							Node* temp = findMin(crnt.right);
535 							remove(temp.key);
536 							crnt.key = temp.key;
537 							crnt.elem = temp.elem;
538 							return result;
539 						} else if(!crnt.left && crnt.right) {
540 							root = crnt.right;
541 						} else if(crnt.left && !crnt.right) {
542 							root = crnt.left;
543 						} else { //Best case scenario: there are no child nodes, just dereference from root
544 							root = null;
545 						}
546 					}
547 					nOfElements--;
548 					rebalance();
549 					return result;
550 				}
551 			}
552 			return E.init;
553 		}
554 	} else {
555 		/**
556 		 * Puts an element into the treeset
557 		 */
558 		public K put(K key) @safe pure nothrow {
559 			if(!root){	//Best case scenario: root is empty
560 				nOfElements++;
561 				root = new Node(key, null, null);
562 				return key;
563 			}
564 			Node* crnt = root;
565 			while(crnt) {
566 				if(binaryFun!less(key, crnt.key)) {	//Key is smaller, look at left hand side
567 					if(crnt.left is null) {
568 						crnt.left = new Node(key, null, null);
569 						crnt = null;
570 						nOfElements++;
571 					}
572 					else crnt = crnt.left;
573 				} else if(binaryFun!less(crnt.key, key)) {		//Key is greater, look ay right hand side
574 					if(crnt.right is null) {
575 						crnt.right = new Node(key, null, null);
576 						crnt = null;
577 						nOfElements++;
578 					}
579 					else crnt = crnt.right;
580 				} else {	//Kaymatch found
581 					crnt.key = key;
582 					crnt = null;
583 				}
584 			}
585 			rebalance();
586 			return key;
587 		}
588 		/**
589 		 * Removes an item by key.
590 		 * Returns the removed item if found, or K.init if not.
591 		 */
592 		public K removeByElem(K key) @safe pure nothrow {
593 			import core.memory : GC;
594 			Node* crnt = root, prev;
595 			while(crnt !is null) {
596 				if(binaryFun!less(key,crnt.key)) {		//Key has a lesser value, search on the left.
597 					prev = crnt;
598 					crnt = crnt.left;
599 				} else if(binaryFun!less(crnt.key, key)) {		//Key has a greater value, search on the right
600 					prev = crnt;
601 					crnt = crnt.right;
602 				} else {				//Key must have been found
603 					K result = crnt.key;
604 					//dispose of the node properly if needed
605 					if(prev !is null) {
606 						if(crnt.left && crnt.right) {	//Worst case scenario: find the smallest node on the right hand side
607 							Node* temp = findMin(crnt.right);
608 							remove(temp.key);
609 							crnt.key = temp.key;
610 							return result;
611 						} else if(!crnt.left && crnt.right) {
612 							if(binaryFun!less(key, prev.key)) {	//The node was on the left side of the previous one
613 								prev.left = crnt.right;
614 							} else {
615 								prev.right = crnt.right;
616 							}
617 						} else if(crnt.left && !crnt.right) {
618 							if(binaryFun!less(key, prev.key)) {	//The node was on the left side of the previous one
619 								prev.left = crnt.left;
620 							} else {
621 								prev.right = crnt.left;
622 							}
623 						} else { //Best case scenario: there are no child nodes, just dereference from prev
624 							if(binaryFun!less(key, prev.key)) {	//The node was on the left side of the previous one
625 								prev.left = null;
626 							} else {
627 								prev.right = null;
628 							}
629 						}
630 					} else {//must be root element
631 						if(crnt.left && crnt.right) {	//Worst case scenario: find the smallest node on the right hand side
632 							Node* temp = findMin(crnt.right);
633 							remove(temp.key);
634 							crnt.key = temp.key;
635 							return result;
636 						} else if(!crnt.left && crnt.right) {
637 							root = crnt.right;
638 						} else if(crnt.left && !crnt.right) {
639 							root = crnt.left;
640 						} else { //Best case scenario: there are no child nodes, just dereference from root
641 							root = null;
642 						}
643 					}
644 					nOfElements--;
645 					rebalance();
646 					return result;
647 				}
648 			}
649 			return K.init;
650 		}
651 		alias remove = removeByElem;
652 	}
653 	/**
654 	 * Returns the smallest node
655 	 */
656 	private Node* findMin(Node* currentNode) @nogc @safe pure nothrow {
657 		while(currentNode.left !is null){
658 			currentNode = currentNode.left;
659 		}
660 		return currentNode;
661 	}
662 	/**
663 	 * Rebalances the tree.
664 	 */
665 	public void rebalance() @nogc @safe pure nothrow {
666 		void rebalanceLocal(ref Node* node) @nogc @safe pure nothrow {
667 			if(node.balance >= 2) {		//Right hand imbalance
668 				if(node.right.balance > 0) {
669 					rotateLeft(node);
670 				} else if(node.right.balance < 0) {
671 					rotateLeftRight(node);
672 				}
673 			} else if(node.balance <= -2) {		//Left hand imbalance
674 				if(node.left.balance < 0) {
675 					rotateRight(node);
676 				} else if(node.left.balance > 0) {
677 					rotateRightLeft(node);
678 				}
679 			}
680 			if(node.left) rebalanceLocal(node.left);
681 			if(node.right) rebalanceLocal(node.right);
682 		}
683 		if(root !is null)
684 			rebalanceLocal(root);
685 	}
686 	static if (E.stringof != "void"){
687 		/**
688 		 * Implements a simple left-to-right tree traversal.
689 		 */
690 		int opApply(scope int delegate(ref E) dg) {
691 			if(root !is null) return root.opApply(dg);
692 			else return 0;
693 		}
694 		/**
695 		 * Implements a simple left-to-right tree traversal.
696 		 */
697 		int opApply(scope int delegate(K, ref E) dg) {
698 			if(root !is null) return root.opApply(dg);
699 			else return 0;
700 		}
701 		/**
702 		 * Implements a simple right-to-left tree traversal.
703 		 */
704 		int opApplyReverse(scope int delegate(ref E) dg) {
705 			if(root !is null) return root.opApplyReverse(dg);
706 			else return 0;
707 		}
708 		/**
709 		 * Implements a simple right-to-left tree traversal.
710 		 */
711 		int opApplyReverse(scope int delegate(K, ref E) dg) {
712 			if(root !is null) return root.opApplyReverse(dg);
713 			else return 0;
714 		}
715 		///Generates an `opApply` and `opApplyReverse` pair for a TreeMap with the supplied attributes
716 		package static string makeFuncTM() {
717 			string makeFunc(string attr) {
718 				return "int opApply(scope int delegate(ref E) " ~ attr ~ " dg) " ~ attr ~ " {
719 					if(root !is null) return root.opApply(dg);
720 					else return 0;
721 				}
722 				int opApply(scope int delegate(K, ref E) " ~ attr ~ " dg) " ~ attr ~ " {
723 					if(root !is null) return root.opApply(dg);
724 					else return 0;
725 				}
726 				int opApplyReverse(scope int delegate(ref E) " ~ attr ~ " dg) " ~ attr ~ " {
727 					if(root !is null) return root.opApplyReverse(dg);
728 					else return 0;
729 				}
730 				int opApplyReverse(scope int delegate(K, ref E) " ~ attr ~ " dg) " ~ attr ~ " {
731 					if(root !is null) return root.opApplyReverse(dg);
732 					else return 0;
733 				}";
734 			}
735 			string result;
736 			foreach (attr; attrList) {
737 				result ~= makeFunc(attr);
738 			}
739 			return result;
740 		}
741 		mixin(makeFuncTM);
742 	} else {
743 		/**
744 		 * Implements a simple left-to-right tree traversal by depth.
745 		 */
746 		int opApply(scope int delegate(K) dg) {
747 			if(root !is null) return root.opApply(dg);
748 			else return 0;
749 		}
750 		/**
751 		 * Implements a simple right-to-left tree traversal.
752 		 */
753 		int opApplyReverse(scope int delegate(K) dg) {
754 			if(root !is null) return root.opApplyReverse(dg);
755 			else return 0;
756 		}
757 		/**
758 		 * Returns an array representation of the set.
759 		 */
760 		@property K[] arrayOf() {
761 			K[] result;
762 			result.reserve(nOfElements);
763 			int putToResult(K elem) @safe pure nothrow {
764 				result ~= elem;
765 				return 0;
766 			}
767 			root.opApply(&putToResult);
768 			return result;
769 		}
770 		///Generates an `opApply` and `opApplyReverse` pair for a TreeMap with the supplied attributes
771 		package static string makeFuncTS() {
772 			string makeFunc(string attr) {
773 				return "int opApply(scope int delegate(K) " ~ attr ~ " dg) " ~ attr ~ " {
774 					if(root !is null) return root.opApply(dg);
775 					else return 0;
776 				}
777 				int opApplyReverse(scope int delegate(K) " ~ attr ~ " dg) " ~ attr ~ " {
778 					if(root !is null) return root.opApplyReverse(dg);
779 					else return 0;
780 				}";
781 			}
782 			string result;
783 			foreach (attr; attrList) {
784 				result ~= makeFunc(attr);
785 			}
786 			return result;
787 		}
788 		mixin(makeFuncTS);
789 	}
790 	/**
791 	 * Tree rotation for rebalancing.
792 	 * Rotates the node to the left.
793 	 */
794 	private void rotateLeft(ref Node* node) @nogc @safe pure nothrow {
795 		Node* temp = node.right;
796 		node.right = temp.left;
797 		temp.left = node;
798 		node = temp;
799 	}
800 	/**
801 	 * Tree rotation for rebalancing.
802 	 * Rotates the node to the left.
803 	 */
804 	private void rotateRight(ref Node* node) @nogc @safe pure nothrow {
805 		Node* temp = node.left;
806 		node.left = temp.right;
807 		temp.right = node;
808 		node = temp;
809 	}
810 	/**
811 	 * Tree rotation for rebalancing.
812 	 * Rotates the node's right to the left, then the node to the right.
813 	 */
814 	private void rotateRightLeft(ref Node* node) @nogc @safe pure nothrow {
815 		rotateLeft(node.left);
816 		rotateRight(node);
817 	}
818 	/**
819 	 * Tree rotation for rebalancing.
820 	 * Rotates the node's left to the right, then the node to the left.
821 	 */
822 	private void rotateLeftRight(ref Node* node) @nogc @safe pure nothrow {
823 		rotateRight(node.right);
824 		rotateLeft(node);
825 	}
826 	/**
827 	 * Returns the number of currently held elements within the tree.
828 	 */
829 	public @property size_t length() @nogc @safe pure nothrow const {
830 		return nOfElements;
831 	}
832 	/**
833 	 * Returns the key of the n-th element.
834 	 * NOT WORKING!
835 	 */
836 	/+public K keyOf(size_t n) {
837 		static if(E.stringof != "void"){
838 			foreach (key, elem; root) {
839 				if (n == 0) {
840 					return key;
841 				} else n--;
842 			}
843 		} else {
844 			foreach (key; root) {
845 				if (n == 0) {
846 					return key;
847 				} else n--;
848 			}
849 		}
850 		return K.init;
851 	}+/
852 	/**
853 	 * Returns the string representation of the tree.
854 	 */
855 	public string toString() const {
856 		if(root !is null)
857 			return root.toString;
858 		else
859 			return "Empty";
860 	}
861 }
862 
863 unittest {
864 	import std.stdio : writeln, write;
865 	import std.random : uniform;
866 	import std.exception : assertThrown;
867 	{
868 		alias IntMap = TreeMap!(int, int, true);
869 		IntMap test0, test1, test2, test3;
870 		for(int i ; i < 1024 ; i++)//Stress test to see if large number of elements would cause any issues
871 			test0[uniform(0, 65_536)] = i;
872 		foreach(k, e; test0){
873 
874 		}
875 		foreach_reverse(k, e; test0){
876 
877 		}
878 		for(int i ; i < 16 ; i++)
879 			test1[uniform(0, 65_536)] = i;
880 		//writeln(test1.toString);
881 		for(int i ; i < 32 ; i++)
882 			test2[uniform(0, 65_536)] = i;
883 		//writeln(test2.toString);
884 		for(int i ; i < 64 ; i++)
885 			test3[i] = i;
886 		for(int i ; i < 64 ; i++)
887 			write(test3[i],";");
888 		writeln();
889 		assert(5 in test3);
890 		for(int i ; i < 16 ; i++)
891 			test3.remove(uniform(0,64));
892 		foreach(i ; test3)
893 			write(i,";");
894 		writeln();
895 	}
896 	{
897 		alias IntMap = TreeMap!(int, int, false);
898 		IntMap test0, test1;
899 		for(int i ; i < 64 ; i++)
900 			test0[i] = i;
901 		assert(test0.length == 64, "TreeMap length mismatch");
902 		assertThrown!ElementNotFoundException(test0[420]);
903 		assertThrown!ElementNotFoundException(test0[666]);
904 		for(int i ; i < 64 ; i++)
905 			test0.remove(i);
906 		assert(test0.length == 0, "Treemap item removal failure");
907 		for(int i ; i < 16 ; i++) {
908 			test1[i] = i;
909 			writeln(test1.toString);
910 		}
911 		assert(5 in test1);
912 	}
913 	{
914 		alias IntMap = TreeMap!(int, void, true);
915 		IntMap test0;
916 		for(int i ; i < 64 ; i++) {
917 			test0.put(i);
918 			//writeln(test0.toString());
919 		}
920 		assert(5 in test0);
921 		assert(test0.length == 64, "TreeMap length mismatch");
922 		for(int i ; i < 64 ; i++) {
923 			test0.remove(i);
924 			//writeln(test0.toString());
925 		}
926 		assert(test0.length == 0, "Treemap item removal failure");
927 	}
928 	{
929 		alias IntMap = TreeMap!(int, void, false);
930 		IntMap test0;
931 		for(int i ; i < 64 ; i++) {
932 			test0.put(i);
933 			//writeln(test0.toString());
934 		}
935 		assert(5 in test0);
936 		assert(test0.length == 64, "TreeMap length mismatch");
937 		assertThrown!ElementNotFoundException(test0[420]);
938 		assertThrown!ElementNotFoundException(test0[666]);
939 		for(int i ; i < 64 ; i++) {
940 			test0.remove(i);
941 			writeln(test0.toString());
942 		}
943 		assert(test0.length == 0, "Treemap item removal failure");
944 	}
945 	{	//test set operators
946 		alias IntSet = TreeMap!(int, void, true);
947 		IntSet a = IntSet([1, 3, 5, 7, 9]), b = IntSet([1, 5, 9]), c = IntSet([3, 7]);
948 		IntSet union_ab = a | b, union_ac = a | c, union_bc = b | c;
949 		IntSet intrsctn_ab = a & b, intrsctn_ac = a & c;
950 		IntSet cmplmnt_ab = a - b, cmplmnt_ac = a - c;
951 		IntSet diff_ab = a ^ b, diff_ac = a ^ c, diff_bc = b ^ c;
952 		assert(union_ab.hasRange([1, 3, 5, 7, 9]) == 5);
953 		assert(union_ac.hasRange([1, 3, 5, 7, 9]) == 5);
954 		assert(union_bc.hasRange([1, 3, 5, 7, 9]) == 5);
955 		assert(intrsctn_ab.hasRange([1, 5, 9]) == 3);
956 		assert(intrsctn_ac.hasRange([3, 7]) == 2);
957 		assert(cmplmnt_ab.hasRange([3, 7]) == 2);
958 		assert(cmplmnt_ac.hasRange([1, 5, 9]) == 3);
959 		assert(diff_ab.hasRange([3, 7]) == 2);
960 		assert(diff_ac.hasRange([1, 5, 9]) == 3);
961 		assert(diff_bc.hasRange([1, 3, 5, 7, 9]) == 5);
962 	}
963 }
964 @safe pure unittest {
965 	alias IntMap = TreeMap!(int, int, false);
966 	IntMap test;
967 	test[5] = 5;
968 	test[7] = 7;
969 	test[3] = 3;
970 	foreach(elem, key; test) {
971 		assert(elem == key);
972 	}
973 }