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 (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 (E.stringof != "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 (E.stringof != "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(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(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 				}
260 				return null;
261 			}
262 		} else {
263 			/**
264 			 * Indexing function that relies on the GC, and throws if no match found
265 			 * Can be indexed with any type of value as long as K.opCmp supports it.
266 			 * Returns the found element if match found.
267 			 */
268 			ref E opIndex(K key) @safe pure {
269 				Node* crnt = root;
270 				while(crnt) {
271 					if(binaryFun!less(key, crnt.key)) {		//key is smaller than current element's, look at lesser elements
272 						crnt = crnt.left;
273 					} else if(binaryFun!less(crnt.key, key)) {			//key is greater than current element's, look at greater elements
274 						crnt = crnt.right;
275 					} else {	//match found, return element
276 						return crnt.elem;
277 					}
278 				}
279 				throw new ElementNotFoundException("No match found");
280 			}
281 		}
282 	} else {
283 		/**
284 		 * Creates a treeset from a preexisting range.
285 		 */
286 		public this(R)(R src) @safe pure nothrow {
287 			foreach (key; src) put(key);
288 		}
289 		/**
290 		 * Returns true if the element exists within the set, false otherwise.
291 		 */
292 		public bool has(T)(T key) @nogc @safe pure nothrow {
293 			Node* crnt = root;
294 			while(crnt) {
295 				if(binaryFun!less(key, crnt.key)) {		//key is smaller than current element's, look at lesser elements
296 					crnt = crnt.left;
297 				} else if(binaryFun!less(crnt.key, key)) {			//key is greater than current element's, look at greater elements
298 					crnt = crnt.right;
299 				} else {	//match found, return true
300 					return true;
301 				}
302 			}
303 			return false;
304 		}
305 		/**
306 		 * Returns the amount of elements found in the set.
307 		 */
308 		public size_t hasRange(R)(R range) @nogc @safe pure nothrow {
309 			size_t result;
310 			foreach (key; range) {
311 				if(has(key)) result++;
312 			}
313 			return result;
314 		}
315 		/**
316 		 * Set operators.
317 		 * Enables math operations on sets, like unions and intersections.
318 		 * Could work on ranges in general as long as they implement some basic functions, like iteration.
319 		 */
320 		TreeMap!(K, E, nogcIndexing, less) opBinary(string op, R)(R rhs) {
321 			static if(op == "|" || op == "~") {//Union
322 				TreeMap!(K, E, nogcIndexing, less) result;
323 				foreach(e ; this)
324 					result.put(e);
325 				foreach(e ; rhs) 
326 					result.put(e);
327 				return result;
328 			} else static if(op == "&" || op == "*") {//Intersection
329 				TreeMap!(K, E, nogcIndexing, less) result;
330 				foreach(e ; rhs){
331 					if(this.has(e)) result.put(e);
332 				}
333 				return result;
334 			} else static if(op == "-" || op == "/") {//Complement
335 				TreeMap!(K, E, nogcIndexing, less) result;
336 				foreach(e ; this)
337 					result.put(e);
338 				foreach(e ; rhs){
339 					result.removeByElem(e);
340 				}
341 				return result;
342 			} else static if(op == "^"){//Difference
343 				TreeMap!(K, E, nogcIndexing, less) result = this | rhs;
344 				TreeMap!(K, E, nogcIndexing, less) common = this & rhs;
345 				foreach(e ; common){
346 					result.removeByElem(e);
347 				}
348 				return result;
349 			} else static assert(0, "Operator " ~ op ~ "not supported");
350 		}
351 		/**
352 		 * Set operators.
353 		 */
354 		TreeMap!(K, E, nogcIndexing, less) opOpAssign(string op)(K value) {
355 			static if(op == "~=") {//Append
356 				put(value);
357 			} else static if(op == "-=" || op == "/=") {
358 				removeByElem(value);
359 			} else static assert(0, "Operator " ~ op ~ "not supported");
360 			return this;
361 		}
362 		/**
363 		 * Set operators.
364 		 */
365 		TreeMap!(K, E, nogcIndexing, less) opOpAssign(string op, R)(R range) {
366 			static if(op == "~=" || op == "|=") {//Append
367 				foreach(val; range)
368 					put(val);
369 			} else static if(op == "-=" || op == "/=") {
370 				foreach(val; range)
371 					removeByElem(val);
372 			} else static assert(0, "Operator " ~ op ~ "not supported");
373 			return this;
374 		}
375 		static if (nogcIndexing) {
376 			/**
377 			 * @nogc capable indexing.
378 			 * Can be indexed with any type of value as long as K.opCmp supports it and `alias less` hasn't been changed.
379 			 * Returns the found element if match found.
380 			 * Returns E.init if match not found.
381 			 */
382 			K opIndex(T)(T key) @nogc @safe pure nothrow {
383 				Node* crnt = root;
384 				while(crnt) {
385 					if(binaryFun!less(key, crnt.key)) {		//key is smaller than current element's, look at lesser elements
386 						crnt = crnt.left;
387 					} else if(binaryFun!less(crnt.key, key)) {			//key is greater than current element's, look at greater elements
388 						crnt = crnt.right;
389 					} else {	//match found, return element
390 						return crnt.key;
391 					}
392 				}
393 				return K.init;
394 			}
395 			
396 		} else {
397 			/**
398 			 * Indexing function that relies on the GC, and throws if no match found
399 			 * Can be indexed with any type of value as long as K.opCmp supports it and `alias less` hasn't been changed.
400 			 * Returns the found element if match found.
401 			 */
402 			K opIndex(T)(T key) @safe pure {
403 				Node* crnt = root;
404 				while(crnt) {
405 					if(binaryFun!less(key, crnt.key)) {		//key is smaller than current element's, look at lesser elements
406 						crnt = crnt.left;
407 					} else if(binaryFun!less(crnt.key, key)) {			//key is greater than current element's, look at greater elements
408 						crnt = crnt.right;
409 					} else {	//match found, return element
410 						return crnt.key;
411 					}
412 				}
413 				throw new ElementNotFoundException("No match found");
414 			}
415 		}
416 	}
417 	static if (E.stringof != "void"){
418 		/**
419 		 * Assigns a value to the given key.
420 		 * If key found, the value will be overwritten without node insertion.
421 		 * If key isn't found, a new node will be inserted.
422 		 */
423 		auto opIndexAssign(E elem, K key) @safe pure nothrow {
424 			if(!root){	//Best case scenario: root is empty
425 				nOfElements++;
426 				root = new Node(key, elem, null, null);
427 				return elem;
428 			}
429 			Node* crnt = root;
430 			while(crnt) {
431 				if(binaryFun!less(key, crnt.key)) {	//Key is smaller, look at left hand side
432 					if(crnt.left is null) {
433 						crnt.left = new Node(key, elem, null, null);
434 						crnt = null;
435 						nOfElements++;
436 					}
437 					else crnt = crnt.left;
438 				} else if(binaryFun!less(crnt.key, key)) {		//Key is greater, look ay right hand side
439 					if(crnt.right is null) {
440 						crnt.right = new Node(key, elem, null, null);
441 						crnt = null;
442 						nOfElements++;
443 					}
444 					else crnt = crnt.right;
445 				} else {	//Another best case scenario: a keymatch is found
446 					crnt.elem = elem;
447 					crnt = null;
448 				} 
449 			}
450 			rebalance();
451 			return elem;
452 		}
453 		/**
454 		 * Removes an item by key.
455 		 * Returns the removed item if found, or E.init if not.
456 		 */
457 		public E remove(K key) @safe pure nothrow {
458 			import core.memory : GC;
459 			Node* crnt = root, prev;
460 			while(crnt !is null) {
461 				if(binaryFun!less(key, crnt.key)) {		//Key has a lesser value, search on the left.
462 					prev = crnt;
463 					crnt = crnt.left;
464 				} else if(binaryFun!less(crnt.key, key)) {		//Key has a greater value, search on the right
465 					prev = crnt;
466 					crnt = crnt.right;
467 				} else {				//Keymatch must have been found
468 					E result = crnt.elem;
469 					//dispose of the node properly if needed
470 					if(prev !is null) {
471 						if(crnt.left && crnt.right) {	//Worst case scenario: find the smallest node on the right hand side
472 							Node* temp = findMin(crnt.right);
473 							remove(temp.key);
474 							crnt.key = temp.key;
475 							crnt.elem = temp.elem;
476 							return result;
477 						} else if(!crnt.left && crnt.right) {
478 							if(binaryFun!less(key, prev.key)) {	//The node was on the left side of the previous one
479 								prev.left = crnt.right;
480 							} else {
481 								prev.right = crnt.right;
482 							}
483 						} else if(crnt.left && !crnt.right) {
484 							if(binaryFun!less(key, prev.key)) {	//The node was on the left side of the previous one
485 								prev.left = crnt.left;
486 							} else {
487 								prev.right = crnt.left;
488 							}
489 						} else { //Best case scenario: there are no child nodes, just dereference from prev
490 							if(binaryFun!less(key, prev.key)) {	//The node was on the left side of the previous one
491 								prev.left = null;
492 							} else {
493 								prev.right = null;
494 							}
495 						}
496 					} else {//must be root element
497 						if(crnt.left && crnt.right) {	//Worst case scenario: find the smallest node on the right hand side
498 							Node* temp = findMin(crnt.right);
499 							remove(temp.key);
500 							crnt.key = temp.key;
501 							crnt.elem = temp.elem;
502 							return result;
503 						} else if(!crnt.left && crnt.right) {
504 							root = crnt.right;
505 						} else if(crnt.left && !crnt.right) {
506 							root = crnt.left;
507 						} else { //Best case scenario: there are no child nodes, just dereference from root
508 							root = null;
509 						}
510 					}
511 					nOfElements--;
512 					rebalance();
513 					return result;
514 				}
515 			}
516 			return E.init;
517 		}
518 	} else {
519 		/**
520 		 * Puts an element into the treeset
521 		 */
522 		public K put(K key) @safe pure nothrow {
523 			if(!root){	//Best case scenario: root is empty
524 				nOfElements++;
525 				root = new Node(key, null, null);
526 				return key;
527 			}
528 			Node* crnt = root;
529 			while(crnt) {
530 				if(binaryFun!less(key, crnt.key)) {	//Key is smaller, look at left hand side
531 					if(crnt.left is null) {
532 						crnt.left = new Node(key, null, null);
533 						crnt = null;
534 						nOfElements++;
535 					}
536 					else crnt = crnt.left;
537 				} else if(binaryFun!less(crnt.key, key)) {		//Key is greater, look ay right hand side
538 					if(crnt.right is null) {
539 						crnt.right = new Node(key, null, null);
540 						crnt = null;
541 						nOfElements++;
542 					}
543 					else crnt = crnt.right;
544 				} else {	//Kaymatch found
545 					crnt.key = key;
546 					crnt = null;
547 				}
548 			}
549 			rebalance();
550 			return key;
551 		}
552 		/**
553 		 * Removes an item by key.
554 		 * Returns the removed item if found, or K.init if not.
555 		 */
556 		public K removeByElem(K key) @safe pure nothrow {
557 			import core.memory : GC;
558 			Node* crnt = root, prev;
559 			while(crnt !is null) {
560 				if(binaryFun!less(key,crnt.key)) {		//Key has a lesser value, search on the left.
561 					prev = crnt;
562 					crnt = crnt.left;
563 				} else if(binaryFun!less(crnt.key, key)) {		//Key has a greater value, search on the right
564 					prev = crnt;
565 					crnt = crnt.right;
566 				} else {				//Key must have been found
567 					K result = crnt.key;
568 					//dispose of the node properly if needed
569 					if(prev !is null) {
570 						if(crnt.left && crnt.right) {	//Worst case scenario: find the smallest node on the right hand side
571 							Node* temp = findMin(crnt.right);
572 							remove(temp.key);
573 							crnt.key = temp.key;
574 							return result;
575 						} else if(!crnt.left && crnt.right) {
576 							if(binaryFun!less(key, prev.key)) {	//The node was on the left side of the previous one
577 								prev.left = crnt.right;
578 							} else {
579 								prev.right = crnt.right;
580 							}
581 						} else if(crnt.left && !crnt.right) {
582 							if(binaryFun!less(key, prev.key)) {	//The node was on the left side of the previous one
583 								prev.left = crnt.left;
584 							} else {
585 								prev.right = crnt.left;
586 							}
587 						} else { //Best case scenario: there are no child nodes, just dereference from prev
588 							if(binaryFun!less(key, prev.key)) {	//The node was on the left side of the previous one
589 								prev.left = null;
590 							} else {
591 								prev.right = null;
592 							}
593 						}
594 					} else {//must be root element
595 						if(crnt.left && crnt.right) {	//Worst case scenario: find the smallest node on the right hand side
596 							Node* temp = findMin(crnt.right);
597 							remove(temp.key);
598 							crnt.key = temp.key;
599 							return result;
600 						} else if(!crnt.left && crnt.right) {
601 							root = crnt.right;
602 						} else if(crnt.left && !crnt.right) {
603 							root = crnt.left;
604 						} else { //Best case scenario: there are no child nodes, just dereference from root
605 							root = null;
606 						}
607 					}
608 					nOfElements--;
609 					rebalance();
610 					return result;
611 				}
612 			}
613 			return K.init;
614 		}
615 		alias remove = removeByElem;
616 	}
617 	/**
618 	 * Returns the smallest node
619 	 */
620 	private Node* findMin(Node* currentNode) @nogc @safe pure nothrow {
621 		while(currentNode.left !is null){
622 			currentNode = currentNode.left;
623 		}
624 		return currentNode;
625 	}
626 	/**
627 	 * Rebalances the tree.
628 	 */
629 	public void rebalance() @nogc @safe pure nothrow {
630 		void rebalanceLocal(ref Node* node) @nogc @safe pure nothrow {
631 			if(node.balance >= 2) {		//Right hand imbalance
632 				if(node.right.balance > 0) {
633 					rotateLeft(node);
634 				} else if(node.right.balance < 0) {
635 					rotateLeftRight(node);
636 				}
637 			} else if(node.balance <= -2) {		//Left hand imbalance
638 				if(node.left.balance < 0) {
639 					rotateRight(node);
640 				} else if(node.left.balance > 0) {
641 					rotateRightLeft(node);
642 				}
643 			}
644 			if(node.left) rebalanceLocal(node.left);
645 			if(node.right) rebalanceLocal(node.right);
646 		}
647 		if(root !is null)
648 			rebalanceLocal(root);
649 	}
650 	static if (E.stringof != "void"){
651 		/**
652 		 * Implements a simple left-to-right tree traversal.
653 		 */
654 		int opApply(scope int delegate(ref E) dg) {
655 			if(root !is null) return root.opApply(dg);
656 			else return 0;
657 		}
658 		/**
659 		 * Implements a simple left-to-right tree traversal.
660 		 */
661 		int opApply(scope int delegate(K, ref E) dg) {
662 			if(root !is null) return root.opApply(dg);
663 			else return 0;
664 		}
665 		/**
666 		 * Implements a simple right-to-left tree traversal.
667 		 */
668 		int opApplyReverse(scope int delegate(ref E) dg) {
669 			if(root !is null) return root.opApplyReverse(dg);
670 			else return 0;
671 		}
672 		/**
673 		 * Implements a simple right-to-left tree traversal.
674 		 */
675 		int opApplyReverse(scope int delegate(K, ref E) dg) {
676 			if(root !is null) return root.opApplyReverse(dg);
677 			else return 0;
678 		}
679 		///Generates an `opApply` and `opApplyReverse` pair for a TreeMap with the supplied attributes
680 		package static string makeFuncTM() {
681 			string makeFunc(string attr) {
682 				return "int opApply(scope int delegate(ref E) " ~ attr ~ " dg) " ~ attr ~ " {
683 					if(root !is null) return root.opApply(dg);
684 					else return 0;
685 				}
686 				int opApply(scope int delegate(K, ref E) " ~ attr ~ " dg) " ~ attr ~ " {
687 					if(root !is null) return root.opApply(dg);
688 					else return 0;
689 				}
690 				int opApplyReverse(scope int delegate(ref E) " ~ attr ~ " dg) " ~ attr ~ " {
691 					if(root !is null) return root.opApplyReverse(dg);
692 					else return 0;
693 				}
694 				int opApplyReverse(scope int delegate(K, ref E) " ~ attr ~ " dg) " ~ attr ~ " {
695 					if(root !is null) return root.opApplyReverse(dg);
696 					else return 0;
697 				}";
698 			}
699 			string result;
700 			foreach (attr; attrList) {
701 				result ~= makeFunc(attr);
702 			}
703 			return result;
704 		}
705 		mixin(makeFuncTM);
706 	} else {
707 		/**
708 		 * Implements a simple left-to-right tree traversal by depth.
709 		 */
710 		int opApply(scope int delegate(K) dg) {
711 			if(root !is null) return root.opApply(dg);
712 			else return 0;
713 		}
714 		/**
715 		 * Implements a simple right-to-left tree traversal.
716 		 */
717 		int opApplyReverse(scope int delegate(K) dg) {
718 			if(root !is null) return root.opApplyReverse(dg);
719 			else return 0;
720 		}
721 		/**
722 		 * Returns an array representation of the set.
723 		 */
724 		@property K[] arrayOf() {
725 			K[] result;
726 			result.reserve(nOfElements);
727 			int putToResult(K elem) @safe pure nothrow {
728 				result ~= elem;
729 				return 0;
730 			}
731 			root.opApply(&putToResult);
732 			return result;
733 		}
734 		///Generates an `opApply` and `opApplyReverse` pair for a TreeMap with the supplied attributes
735 		package static string makeFuncTS() {
736 			string makeFunc(string attr) {
737 				return "int opApply(scope int delegate(K) " ~ attr ~ " dg) " ~ attr ~ " {
738 					if(root !is null) return root.opApply(dg);
739 					else return 0;
740 				}
741 				int opApplyReverse(scope int delegate(K) " ~ attr ~ " dg) " ~ attr ~ " {
742 					if(root !is null) return root.opApplyReverse(dg);
743 					else return 0;
744 				}";
745 			}
746 			string result;
747 			foreach (attr; attrList) {
748 				result ~= makeFunc(attr);
749 			}
750 			return result;
751 		}
752 		mixin(makeFuncTS);
753 	}
754 	/**
755 	 * Tree rotation for rebalancing.
756 	 * Rotates the node to the left.
757 	 */
758 	private void rotateLeft(ref Node* node) @nogc @safe pure nothrow {
759 		Node* temp = node.right;
760 		node.right = temp.left;
761 		temp.left = node;
762 		node = temp;
763 	}
764 	/**
765 	 * Tree rotation for rebalancing.
766 	 * Rotates the node to the left.
767 	 */
768 	private void rotateRight(ref Node* node) @nogc @safe pure nothrow {
769 		Node* temp = node.left;
770 		node.left = temp.right;
771 		temp.right = node;
772 		node = temp;
773 	}
774 	/**
775 	 * Tree rotation for rebalancing.
776 	 * Rotates the node's right to the left, then the node to the right.
777 	 */
778 	private void rotateRightLeft(ref Node* node) @nogc @safe pure nothrow {
779 		rotateLeft(node.left);
780 		rotateRight(node);
781 	}
782 	/**
783 	 * Tree rotation for rebalancing.
784 	 * Rotates the node's left to the right, then the node to the left.
785 	 */
786 	private void rotateLeftRight(ref Node* node) @nogc @safe pure nothrow {
787 		rotateRight(node.right);
788 		rotateLeft(node);
789 	}
790 	/**
791 	 * Returns the number of currently held elements within the tree.
792 	 */
793 	public @property size_t length() @nogc @safe pure nothrow const {
794 		return nOfElements;
795 	}
796 	/**
797 	 * Returns the key of the n-th element.
798 	 * NOT WORKING!
799 	 */
800 	/+public K keyOf(size_t n) {
801 		static if(E.stringof != "void"){
802 			foreach (key, elem; root) {
803 				if (n == 0) {
804 					return key;
805 				} else n--;
806 			}
807 		} else {
808 			foreach (key; root) {
809 				if (n == 0) {
810 					return key;
811 				} else n--;
812 			}
813 		}
814 		return K.init;
815 	}+/
816 	/**
817 	 * Returns the string representation of the tree.
818 	 */
819 	public string toString() const {
820 		if(root !is null)
821 			return root.toString;
822 		else
823 			return "Empty";
824 	}
825 }
826 
827 unittest {
828 	import std.stdio : writeln, write;
829 	import std.random : uniform;
830 	import std.exception : assertThrown;
831 	{
832 		alias IntMap = TreeMap!(int, int, true);
833 		IntMap test0, test1, test2, test3;
834 		for(int i ; i < 1024 ; i++)//Stress test to see if large number of elements would cause any issues
835 			test0[uniform(0, 65536)] = i;
836 		foreach(k, e; test0){
837 
838 		}
839 		foreach_reverse(k, e; test0){
840 
841 		}
842 		for(int i ; i < 16 ; i++)
843 			test1[uniform(0, 65536)] = i;
844 		//writeln(test1.toString);
845 		for(int i ; i < 32 ; i++)
846 			test2[uniform(0, 65536)] = i;
847 		//writeln(test2.toString);
848 		for(int i ; i < 64 ; i++)
849 			test3[i] = i;
850 		for(int i ; i < 64 ; i++)
851 			write(test3[i],";");
852 		writeln();
853 		for(int i ; i < 16 ; i++)
854 			test3.remove(uniform(0,64));
855 		foreach(i ; test3)
856 			write(i,";");
857 		writeln();
858 	}
859 	{
860 		alias IntMap = TreeMap!(int, int, false);
861 		IntMap test0, test1;
862 		for(int i ; i < 64 ; i++)
863 			test0[i] = i;
864 		assert(test0.length == 64, "TreeMap length mismatch");
865 		assertThrown!ElementNotFoundException(test0[420]);
866 		assertThrown!ElementNotFoundException(test0[666]);
867 		for(int i ; i < 64 ; i++)
868 			test0.remove(i);
869 		assert(test0.length == 0, "Treemap item removal failure");
870 		for(int i ; i < 16 ; i++) {
871 			test1[i] = i;
872 			writeln(test1.toString);
873 		}
874 	}
875 	{
876 		alias IntMap = TreeMap!(int, void, true);
877 		IntMap test0;
878 		for(int i ; i < 64 ; i++) {
879 			test0.put(i);
880 			writeln(test0.toString());
881 		}
882 		assert(test0.length == 64, "TreeMap length mismatch");
883 		for(int i ; i < 64 ; i++) {
884 			test0.remove(i);
885 			writeln(test0.toString());
886 		}
887 		assert(test0.length == 0, "Treemap item removal failure");
888 	}
889 	{
890 		alias IntMap = TreeMap!(int, void, false);
891 		IntMap test0;
892 		for(int i ; i < 64 ; i++) {
893 			test0.put(i);
894 			writeln(test0.toString());
895 		}
896 		assert(test0.length == 64, "TreeMap length mismatch");
897 		assertThrown!ElementNotFoundException(test0[420]);
898 		assertThrown!ElementNotFoundException(test0[666]);
899 		for(int i ; i < 64 ; i++) {
900 			test0.remove(i);
901 			writeln(test0.toString());
902 		}
903 		assert(test0.length == 0, "Treemap item removal failure");
904 	}
905 	{	//test set operators
906 		alias IntSet = TreeMap!(int, void, true);
907 		IntSet a = IntSet([1, 3, 5, 7, 9]), b = IntSet([1, 5, 9]), c = IntSet([3, 7]);
908 		IntSet union_ab = a | b, union_ac = a | c, union_bc = b | c;
909 		IntSet intrsctn_ab = a & b, intrsctn_ac = a & c;
910 		IntSet cmplmnt_ab = a - b, cmplmnt_ac = a - c;
911 		IntSet diff_ab = a ^ b, diff_ac = a ^ c, diff_bc = b ^ c;
912 		assert(union_ab.hasRange([1, 3, 5, 7, 9]) == 5);
913 		assert(union_ac.hasRange([1, 3, 5, 7, 9]) == 5);
914 		assert(union_bc.hasRange([1, 3, 5, 7, 9]) == 5);
915 		assert(intrsctn_ab.hasRange([1, 5, 9]) == 3);
916 		assert(intrsctn_ac.hasRange([3, 7]) == 2);
917 		assert(cmplmnt_ab.hasRange([3, 7]) == 2);
918 		assert(cmplmnt_ac.hasRange([1, 5, 9]) == 3);
919 		assert(diff_ab.hasRange([3, 7]) == 2);
920 		assert(diff_ac.hasRange([1, 5, 9]) == 3);
921 		assert(diff_bc.hasRange([1, 3, 5, 7, 9]) == 5);
922 	}
923 }
924 @safe pure unittest {
925 	alias IntMap = TreeMap!(int, int, false);
926 	IntMap test;
927 	test[5] = 5;
928 	test[7] = 7;
929 	test[3] = 3;
930 	foreach(elem, key; test) {
931 		assert(elem == key);
932 	}
933 }