1 /++
2 	Some data structures
3 +/
4 module utils.ds;
5 
6 import std.file;
7 import std.stdio;
8 import std.conv : to;
9 import utils.misc;
10 
11 /// Used to read some data type as `ubyte[x]`
12 union ByteUnion(T){
13 	T data; /// data
14 	ubyte[T.sizeof] array; /// array of bytes
15 	/// constructor
16 	this(T data){
17 		this.data = data;
18 	}
19 	/// ditto
20 	this(ubyte[T.sizeof] array){
21 		this.array = array;
22 	}
23 }
24 
25 /// Use to manage dynamic arrays that frequently change lengths
26 /// 
27 /// Provides more functionality for arrays, like searching in arrays, removing elements...
28 class List(T){
29 private:
30 	T[] list; /// the actual list
31 	uinteger taken=0; /// how many elements are actually stored in the list
32 	uinteger extraAlloc; /// how many extra elements to make space for when list length runs out
33 	uinteger _seek = 0; /// where to read/write next if index isn't specified
34 public:
35 	/// constructor
36 	/// 
37 	/// extraCount is the number of extra space to make for new elements when making "room" for new elements
38 	this(uinteger extraCount = 4){
39 		extraAlloc = extraCount;
40 	}
41 	/// appends an element to the list
42 	void append(T dat){
43 		if (taken==list.length){
44 			list.length+=extraAlloc;
45 		}
46 		list[taken] = dat;
47 		taken++;
48 	}
49 	/// appends an array to the list
50 	void append(T[] dat){
51 		list = list[0 .. taken]~dat.dup;
52 		taken = list.length;
53 	}
54 	/// Changes the value of element at an index.
55 	/// 
56 	/// Arguments:
57 	/// `dat` is the new data
58 	/// 
59 	/// Returns: false if index is out of bounds, true if successful
60 	bool set(uinteger index, T dat){
61 		if (index >= taken){
62 			return false;
63 		}
64 		list[index]=dat;
65 		return true;
66 	}
67 	/// Changes the value of element at seek. Seek is increased by one
68 	/// 
69 	/// Arguments:
70 	/// `value` is the new value
71 	/// 
72 	/// Returns: true if successful, false if seek if out of bounds
73 	bool write (T value){
74 		if (_seek >= taken){
75 			return false;
76 		}
77 		list[_seek] = value;
78 		_seek ++;
79 		return true;
80 	}
81 	/// Changes the value of elements starting at index=seek. Seek is increased by number of elements affected
82 	/// 
83 	/// Arguments:
84 	/// `elements` is the array of new values of the elements
85 	/// 
86 	/// Returns: true if successful, false if not enough elements in list or seek out of bounds
87 	bool write (T[] elements){
88 		if (_seek + elements.length >= taken){
89 			return false;
90 		}
91 		list[_seek .. _seek + elements.length] = elements.dup;
92 		_seek += elements.length;
93 		return true;
94 	}
95 	/// Reads an element at index=seek. Seek is increased by one
96 	/// 
97 	/// Returns: the read element
98 	/// 
99 	/// Throws: Exception if seek is out of bounds
100 	T read(){
101 		if (_seek >= taken){
102 			throw new Exception ("seek out of bounds");
103 		}
104 		T r = list[_seek];
105 		_seek ++;
106 		return r;
107 	}
108 	/// Reads a number of elements starting at index=seek. Seek is increased by number of elements
109 	/// 
110 	/// Arguments:
111 	/// `buffer` is the array into which the elements will be read. set `buffer.length` to number of elements to read
112 	/// 
113 	/// Returns: number of elements read into the buffer
114 	uinteger read(ref T[] buffer){
115 		if (_seek >= taken || buffer.length == 0){
116 			return 0;
117 		}
118 		uinteger count = _seek + buffer.length < taken ? buffer.length : taken - _seek;
119 		buffer = list[_seek .. _seek + count].dup;
120 		_seek += count;
121 		return count;
122 	}
123 	/// The seek position
124 	@property uinteger seek(){
125 		return _seek;
126 	}
127 	/// ditto
128 	@property uinteger seek(uinteger newSeek){
129 		return _seek = newSeek;
130 	}
131 	/// Removes last elements(s) starting from an index
132 	/// 
133 	/// Arguments:
134 	/// `count ` is number of elements to remove
135 	/// 
136 	/// Returns: false if range is out of bounds, true if successful
137 	bool remove(uinteger index, uinteger count=1){
138 		if (index + count >= taken){
139 			return false;
140 		}
141 		integer i;
142 		integer till=taken-count;
143 		for (i=index;i<till;i++){
144 			list[i] = list[i+count];
145 		}
146 		list.length-=count;
147 		taken-=count;
148 		return true;
149 	}
150 	/// Removes number of elements from end of list
151 	/// 
152 	/// Returns: true if successful, false if not enough elements to remove
153 	bool removeLast(uinteger count = 1){
154 		if (count > taken){
155 			return false;
156 		}
157 		taken -= count;
158 		return true;
159 	}
160 	/// shrinks the size of the list, removing last elements.
161 	/// 
162 	/// Returns: true if shrunk, false if not for example if `newSize` was greater than actual size
163 	bool shrink(uinteger newSize){
164 		if (newSize < taken){
165 			list.length=newSize;
166 			taken = list.length;
167 			return true;
168 		}
169 		return false;
170 	}
171 	/// Returns: how many elements can be appended before list length needs to increase
172 	@property uinteger freeSpace(){
173 		return list.length - taken;
174 	}
175 	/// make more free space for new elements, or reduce it. To reduce, use n as negative. To decrease by 2, `n=-2`
176 	/// 
177 	/// Returns: true if done, false if not done, for example if there wasn't enough free space in list to be removed
178 	bool setFreeSpace(integer n){
179 		if (n < 0 && -n > list.length - taken){
180 			return false;
181 		}
182 		try{
183 			list.length = list.length + n;
184 		}catch (Exception e){
185 			.destroy (e);
186 			return false;
187 		}
188 		return true;
189 	}
190 	/// removes the free space, if any, for adding new elements. Call this when done with adding to list.
191 	void clearFreeSpace(){
192 		list.length = taken;
193 	}
194 	/// Inserts an array into this list
195 	/// 
196 	/// Returns: true if done, false if index out of bounds, or not done
197 	bool insert(uinteger index, T[] dat){
198 		if (index >= taken){
199 			return false;
200 		}
201 		list = list[0 .. index] ~ dat.dup ~ list[index .. taken];
202 		taken = list.length;
203 		return true;
204 	}
205 	/// Inserts an element into this list
206 	/// 
207 	/// Returns: true if done, false if index out of bounds, or not done
208 	bool insert(uinteger index, T dat){
209 		if (index >= taken){
210 			return false;
211 		}
212 		list = list[0 .. index] ~ dat ~ list[index .. taken];
213 		taken = list.length;
214 		return true;
215 	}
216 	/// Writes the list to a file.
217 	/// 
218 	/// Arguemnts:
219 	/// `s` is the filename  
220 	/// `sp` is the separator, it will be added to the end of each list-element  
221 	/// 
222 	/// Returns: true if done, false if not due to some Exception
223 	bool saveFile(string s, T sp){
224 		try{
225 			File f = File(s,"w");
226 			uinteger i;
227 			for (i=0;i<taken;i++){
228 				f.write(list[i],sp);
229 			}
230 			f.close;
231 		}catch (Exception e){
232 			.destroy(e);
233 			return false;
234 		}
235 		return true;
236 	}
237 	/// Reads an element at an index
238 	/// 
239 	/// Returns: the element read
240 	/// 
241 	/// Throws: Exception if index out of bounds
242 	T read(uinteger index){
243 		if (index >= taken){
244 			throw new Exception("index out of bounds");
245 		}
246 		return list[index];
247 	}
248 	/// Read a slice from the list.
249 	/// 
250 	/// Returns: the elements read
251 	/// 
252 	/// Throws: Exception if index out of bounds
253 	T[] read(uinteger index,uinteger i2){
254 		if (index >= taken){
255 			throw new Exception("index out of bounds");
256 		}
257 		return list[index .. i2].dup;
258 	}
259 	/// Returns: pointer to element at an index
260 	/// 
261 	/// Be careful that the pointer might not be valid after the list has been resized, so try only to use it after all appending is done
262 	/// 
263 	/// Throws: Exception if index out of bounds
264 	T* readPtr(uinteger index){
265 		if (index >= taken){
266 			throw new Exception ("index out of bounds");
267 		}
268 		return &(list[index]);
269 	}
270 	/// Reads the last element in list.
271 	/// 
272 	/// Returns: the last element in list
273 	/// 
274 	/// Throws: Exception if list length is zero
275 	T readLast(){
276 		if (taken == 0){
277 			throw new Exception ("List has no elements, can not readLast");
278 		}
279 		return list[taken-1];
280 	}
281 	/// Reads number of elements from end of list
282 	/// 
283 	/// Returns: the elements read
284 	/// 
285 	/// Throws: Exception if not enough elements i.e range out of bounds
286 	T[] readLast(uinteger count){
287 		if (count > taken){
288 			throw new Exception ("range out of bounds");
289 		}
290 		return list[taken-count..taken].dup;
291 	}
292 	/// Returns: length of the list
293 	@property integer length(){
294 		return taken;
295 	}
296 	/// Exports this list into a array
297 	/// 
298 	/// Returns: the array containing the elements in this list
299 	T[] toArray(){
300 		return list[0 .. taken].dup;
301 	}
302 	/// Loads list from an array
303 	void loadArray(T[] newList){
304 		uinteger i;
305 		list = newList.dup;
306 		taken = newList.length;
307 		_seek = 0;
308 	}
309 	/// empties the list
310 	void clear(){
311 		list = [];
312 		taken = 0;
313 		_seek = 0;
314 	}
315 	/// Returns: index of the first matching element. -1 if not found
316 	/// 
317 	/// Arguments:
318 	/// `dat` is the element to search for  
319 	/// `i` is the index from where to start, default is 0  
320 	/// `forward` if true, searches in a forward direction, from lower index to higher  
321 	integer indexOf(bool forward=true)(T dat, integer i=0){
322 		static if (forward){
323 			for (;i<taken;i++){
324 				if (list[i]==dat){break;}
325 				if (i==taken-1){i=-1;break;}
326 			}
327 		}else{
328 			for (;i>=0;i--){
329 				if (list[i]==dat){break;}
330 				if (i==0){i=-1;break;}
331 			}
332 		}
333 		if (taken==0){
334 			i=-1;
335 		}
336 		return i;
337 	}
338 }
339 ///
340 unittest{
341 	List!ubyte list = new List!ubyte(4);
342 	//`List.insert` and `List.add` and `List.toArray`
343 	list.append(0);
344 	list.append(1);
345 	list.insert(1, 2);
346 	assert(list.toArray() == [0, 2, 1]);
347 	//`List.indexOf`
348 	assert(list.indexOf(1) == 2);
349 	//`List.clear`
350 	list.clear;
351 	assert(list.length == 0);
352 	//`List.loadArray`
353 	list.loadArray([0, 1, 2, 3]);
354 	assert(list.length == 4);
355 	assert(list.indexOf(3) == 3);
356 	//`List.addArray`
357 	list.append([4, 5, 6, 7, 8]);
358 	assert(list.length == 9);
359 	//`List.set` and `List.read`
360 	list.set(0, 1);
361 	assert(list.read(0) == 1);
362 	//`List.readLast`
363 	assert(list.readLast() == 8);
364 	assert(list.readLast(2) == [7, 8]);
365 	//`List.readRange`
366 	assert(list.read(0, 2) == [1, 1]);
367 	//`List.remove`
368 	list.remove(0, 2);
369 	assert(list.read(0) == 2);
370 	//`List.removeLast`
371 	list.removeLast(2);
372 	assert(list.readLast() == 6);
373 	//`List.freeSpace`
374 	list.clear;
375 	foreach (i; cast(ubyte[])[0,1,2])
376 		list.append(i);
377 	assert(list.freeSpace == 1, to!string(list.freeSpace));
378 	list.append(3);
379 	assert(list.freeSpace == 0);
380 	list.setFreeSpace(6);
381 	assert(list.freeSpace == 6 && list.length == 4);
382 	list.setFreeSpace(-3);
383 	assert(list.freeSpace == 3);
384 	assert(list.setFreeSpace(-10) == false);
385 	//reading/writing with seek
386 	list.clear;
387 	assert(list.seek == 0);
388 	list.append([0,1,2,3,4,5,6,7,8]);
389 	assert(list.seek == 0);
390 	ubyte[] buffer;
391 	buffer.length = 4;
392 	assert(list.read(buffer) == 4);
393 	assert(buffer == [0,1,2,3]);
394 	assert(list.seek == 4);
395 	assert(list.read == 4);
396 	assert(list.write(5) == true);
397 	assert(list.read(buffer) == 3);
398 	assert(buffer[0 .. 3] == [6,7,8]);
399 	assert(list.seek == 9);
400 	//`List.readPtr`
401 	list.clear;
402 	list.append ([0,1,2,3,4,5]);
403 	ubyte* ptr = list.readPtr(5);
404 	*ptr = 4;
405 	assert (list.toArray == [0,1,2,3,4,4]);
406 
407 	destroy(list);
408 }
409 
410 /// A basic stack with push, and pop
411 class Stack(T){
412 private:
413 	struct stackItem(T){
414 		T data; /// the data this item holds
415 		stackItem* prev; /// pointer to previous stackItem
416 	}
417 	stackItem!(T)* lastItemPtr;
418 	uinteger itemCount;
419 public:
420 	this(){
421 		lastItemPtr = null;
422 		itemCount = 0;
423 	}
424 	~this(){
425 		clear;
426 	}
427 	/// Appends an item to the stack
428 	void push(T item){
429 		stackItem!(T)* newItem = new stackItem!T;
430 		(*newItem).data = item;
431 		(*newItem).prev = lastItemPtr;
432 		lastItemPtr = newItem;
433 		//increase count
434 		itemCount ++;
435 	}
436 	/// Appends an array of items to the stack
437 	void push(T[] items){
438 		// put them all in stackItem[]
439 		stackItem!(T)*[] newItems;
440 		newItems.length = items.length;
441 		for (uinteger i = 0; i < items.length; i ++){
442 			newItems[i] = new stackItem!T;
443 			(*newItems[i]).data = items[i];
444 		}
445 		// make them all point to their previous item, except for the first one, which should point to `lastItemPtr`
446 		for (uinteger i = newItems.length - 1; i > 0; i --){
447 			(*newItems[i]).prev = newItems[i-1];
448 		}
449 		(*newItems[0]).prev = lastItemPtr;
450 		lastItemPtr = newItems[newItems.length - 1];
451 		//increase count
452 		itemCount += newItems.length;
453 	}
454 	/// pops an item from stack
455 	/// 
456 	/// Returns: the item poped
457 	/// 
458 	/// Throws: Exception if stack is empty
459 	T pop(){
460 		// make sure its not null
461 		if (lastItemPtr !is null){
462 			T r = (*lastItemPtr).data;
463 			// delete it from stack
464 			stackItem!(T)* prevItem = (*lastItemPtr).prev;
465 			destroy(*lastItemPtr);
466 			lastItemPtr = prevItem;
467 			//decrease count
468 			itemCount --;
469 			return r;
470 		}else{
471 			throw new Exception("Cannot pop from empty stack");
472 		}
473 	}
474 	/// Reads and removes an array of items from the stack,
475 	/// 
476 	/// Throws: Exception if there are not enough items in stack
477 	/// 
478 	/// Returns: the items read
479 	/// 
480 	/// Arguments:
481 	/// `count` is the number of elements to return  
482 	/// `reverse`, if true, elements are read in reverse, last-pushed is last in array  
483 	T[] pop(bool reverse=false)(uinteger count){
484 		//make sure there are enough items
485 		if (itemCount >= count){
486 			T[] r;
487 			r.length = count;
488 			stackItem!(T)* ptr = lastItemPtr;
489 			static if (reverse){
490 				for (integer i = count-1; i >= 0; i --){
491 					r[i] = (*ptr).data;
492 					ptr = (*ptr).prev;
493 					// delete this item
494 					.destroy(*lastItemPtr);
495 					lastItemPtr = ptr;
496 				}
497 			}else{
498 				for (uinteger i = 0; i < count; i ++){
499 					r[i] = (*ptr).data;
500 					ptr = (*ptr).prev;
501 					//delete it
502 					.destroy(*lastItemPtr);
503 					lastItemPtr = ptr;
504 				}
505 			}
506 			//decrease count
507 			itemCount -= r.length;
508 			return r;
509 		}else{
510 			throw new Exception("Not enough items in stack");
511 		}
512 	}
513 	/// Empties the stack, pops all items
514 	void clear(){
515 		// go through all items and delete em
516 		stackItem!(T)* ptr;
517 		ptr = lastItemPtr;
518 		while (ptr !is null){
519 			stackItem!(T)* prevPtr = (*ptr).prev;
520 			destroy(*ptr);
521 			ptr = prevPtr;
522 		}
523 		lastItemPtr = null;
524 		itemCount = 0;
525 	}
526 	/// Number of items in stack
527 	@property uinteger count(){
528 		return itemCount;
529 	}
530 }
531 ///
532 unittest{
533 	Stack!ubyte stack = new Stack!ubyte;
534 	//`Stack.push` and `Stack.pop`
535 	stack.push(0);
536 	stack.push([1, 2]);
537 	assert(stack.pop == 2);
538 	assert(stack.pop(2) == [1, 0]);
539 	stack.push([1, 0]);
540 	assert(stack.pop!(true)(2) == [1, 0]);
541 	//`Stack.clear` && `Stack.count`
542 	stack.push(0);
543 	assert(stack.count == 1);
544 	stack.clear;
545 	assert(stack.count == 0);
546 	stack.destroy;
547 }
548 
549 /// A FIFO (First In is First Out, first element pushed will be removed first) stack
550 class FIFOStack(T){
551 private:
552 	/// to store data in a linked manner
553 	struct StackElement(T){
554 		T data; /// the data stored
555 		StackElement!(T)* next = null; /// pointer to data which was pushed after it
556 	}
557 	/// pointer to first item (first pushed, the one to pop next)
558 	StackElement!(T)* firstItemPtr;
559 	/// pointer to last item (last pushed)
560 	StackElement!(T)* lastItemPtr;
561 	/// stores number of elements pushed
562 	uinteger _count;
563 public:
564 	/// constructor
565 	this (){
566 		firstItemPtr = null;
567 		lastItemPtr = null;
568 		_count = 0;
569 	}
570 	/// destructor
571 	~this (){
572 		// clear the whole stack
573 		clear;
574 	}
575 	/// clears the whole stack, pops all items
576 	void clear(){
577 		for (StackElement!(T)* i = firstItemPtr, next = null; i !is null; i = next){
578 			next = (*i).next;
579 			.destroy(*i);
580 		}
581 		_count = 0;
582 	}
583 	/// Returns: number of items in stack
584 	@property uinteger count(){
585 		return _count;
586 	}
587 	/// pushes an element to stack
588 	void push(T element){
589 		StackElement!(T)* toPush = new StackElement!(T);
590 		(*toPush).data = element;
591 		(*toPush).next = null;
592 		// check if stack is empty
593 		if (lastItemPtr is null){
594 			firstItemPtr = toPush;
595 		}else{
596 			(*lastItemPtr).next = toPush;
597 		}
598 		lastItemPtr = toPush;
599 		_count ++;
600 	}
601 	/// pushes an array of elements to stack
602 	void push(T[] elements){
603 		StackElement!(T)*[] toPush;
604 		toPush.length = elements.length;
605 		if (toPush.length > 0){
606 			// make a linked stack for just these elements first
607 			foreach (i, element; elements){
608 				toPush[i] = new StackElement!(T);
609 				(*toPush[i]).data = element;
610 				if (i > 0){
611 					(*toPush[i-1]).next = toPush[i];
612 				}
613 			}
614 			(*toPush[toPush.length-1]).next = null;
615 			// now "insert" it
616 			if (lastItemPtr is null){
617 				firstItemPtr = toPush[0];
618 			}else{
619 				(*lastItemPtr).next = toPush[0];
620 			}
621 			lastItemPtr = toPush[toPush.length-1];
622 			_count += elements.length;
623 		}
624 	}
625 	/// pops an item from the stack (from bottom of stack, since it's a FIFO stack)
626 	/// 
627 	/// Returns: the element pop-ed
628 	/// 
629 	/// Throws: Exception if the stack is empty
630 	T pop(){
631 		if (firstItemPtr is null){
632 			throw new Exception("Cannot pop from empty stack");
633 		}
634 		T r = (*firstItemPtr).data;
635 		StackElement!(T)* toDestroy = firstItemPtr;
636 		firstItemPtr = (*firstItemPtr).next;
637 		.destroy(toDestroy);
638 		_count --;
639 		// check if list is now empty
640 		if (firstItemPtr is null){
641 			lastItemPtr = null;
642 		}
643 		return r;
644 	}
645 	/// pops a number of items from the stack (from bottom since it's a FIFO Stack)
646 	/// 
647 	/// If there aren't enoguh items in stack, all the items are poped, and the returned array's length is less than `popCount`
648 	/// 
649 	/// Returns: the elements poped
650 	/// 
651 	/// Throws: Exception if stack is empty
652 	T[] pop(uinteger popCount){
653 		if (count == 0){
654 			throw new Exception("Cannot pop from empty stack");
655 		}
656 		if (_count < popCount){
657 			popCount = _count;
658 		}
659 		uinteger i = 0;
660 		StackElement!(T)* item = firstItemPtr;
661 		T[] r;
662 		r.length = popCount;
663 		while (i < popCount && item !is null){
664 			StackElement!(T)* toDestroy = item;
665 			r[i] = (*item).data;
666 			item = (*item).next;
667 			.destroy(toDestroy);
668 			i ++;
669 		}
670 		firstItemPtr = item;
671 		_count -= popCount;
672 		// check if list is empty now
673 		if (firstItemPtr is null){
674 			lastItemPtr = null;
675 		}
676 		return r;
677 	}
678 }
679 ///
680 unittest{
681 	FIFOStack!int stack = new FIFOStack!int;
682 	stack.push(0);
683 	stack.push([1,2,3,4]);
684 	assert(stack.count == 5);
685 	assert(stack.pop == 0);
686 	assert(stack.count == 4);
687 	assert(stack.pop(2) == [1,2]);
688 	assert(stack.count == 2);
689 	assert(stack.pop(2) == [3,4]);
690 	assert(stack.count == 0);
691 	stack.push([0,1,2]);
692 	assert(stack.count == 3);
693 	assert(stack.pop(3) == [0,1,2]);
694 }
695 
696 /// To manage allocating extra for cases like lists where you need to create new objects often. Also manages initializing the objects  
697 /// through a init function.
698 /// Creates a number of extra objects at one time, so it has to allocate memory less often.
699 class ExtraAlloc(T){
700 private:
701 	/// stores the free objects.
702 	FIFOStack!T _store;
703 	/// number of elements to allocate at one time
704 	uinteger _allocCount;
705 	/// max number of free elements present at one time, if more are present, extra are freed
706 	uinteger _maxCount;
707 	/// the delegate that will be called to get a new object
708 	T delegate() _initFunction;
709 public:
710 	/// constructor
711 	this (uinteger extraAllocCount, uinteger maxAllocCount, T delegate() initFunction){
712 		_store = new FIFOStack!T;
713 		_allocCount = extraAllocCount;
714 		_maxCount = maxAllocCount;
715 		_initFunction = initFunction;
716 	}
717 	/// destructor. Destroys all objects created by this
718 	~this (){
719 		while (_store.count > 0){
720 			.destroy(_store.pop);
721 		}
722 		.destroy(_store);
723 	}
724 	/// allocates and initializes objects to fill extraAllocCount
725 	/// 
726 	/// Returns: true if more objects were allocated, false if the queue is already full, or if the queue had more than maxAlloc, and they were freed
727 	bool allocate(){
728 		if (_store.count < _allocCount){
729 			T[] allocated;
730 			allocated.length = _allocCount - _store.count;
731 			for (uinteger i = 0; i < allocated.length; i ++){
732 				allocated[i] = _initFunction();
733 			}
734 			_store.push(allocated);
735 			return true;
736 		}
737 		while (_store.count > _maxCount){
738 			.destroy(_store.pop);
739 		}
740 		return false;
741 	}
742 	/// Returns: an object
743 	T get(){
744 		if (_store.count == 0){
745 			allocate();
746 		}
747 		return _store.pop;
748 	}
749 	/// Marks an object as free. Frees is if there are already enough free objects
750 	void free(T obj){
751 		_store.push(obj);
752 		if (_store.count > _maxCount){
753 			allocate();
754 		}
755 	}
756 }
757 
758 /// A linked list, used where only reading in the forward direction is required
759 class LinkedList(T){
760 private:
761 	///represents an item in a linked list. contains the item, and pointer to the next item's container
762 	struct LinkedItem(T){
763 		T data;
764 		LinkedItem!(T)* next = null;//mark it null to show the list has ended
765 	}
766 	LinkedItem!(T)* firstItemPtr;
767 	LinkedItem!(T)* lastItemPtr;//the pointer of the last item, used for appending new items
768 	LinkedItem!(T)* nextReadPtr;//the pointer of the next item to be read
769 	LinkedItem!(T)* lastReadPtr;//the pointer to the last item that was read
770 
771 	uinteger itemCount;//stores the total number of items
772 
773 	LinkedItem!(T)*[uinteger] bookmarks;
774 public:
775 	this(){
776 		firstItemPtr = null;
777 		lastItemPtr = null;
778 		nextReadPtr = null;
779 		lastReadPtr = null;
780 		itemCount = 0;
781 	}
782 	~this(){
783 		//free all the memory occupied
784 		clear();
785 	}
786 	/// clears/resets the list, by deleting all elements
787 	void clear(){
788 		//make sure that the list is populated
789 		if (firstItemPtr !is null){
790 			LinkedItem!(T)* nextPtr;
791 			for (nextReadPtr = firstItemPtr; nextReadPtr !is null; nextReadPtr = nextPtr){
792 				nextPtr = (*nextReadPtr).next;
793 				destroy(*nextReadPtr);
794 			}
795 			//reset all variables
796 			firstItemPtr = null;
797 			lastItemPtr = null;
798 			nextReadPtr = null;
799 			lastReadPtr = null;
800 			itemCount = 0;
801 		}
802 	}
803 	/// adds a new node/element to the end of the list
804 	void append(T item){
805 		LinkedItem!(T)* ptr = new LinkedItem!(T);
806 		(*ptr).data = item;
807 		(*ptr).next = null;
808 		//add it to the list
809 		if (firstItemPtr is null){
810 			firstItemPtr = ptr;
811 			nextReadPtr = firstItemPtr;
812 		}else{
813 			(*lastItemPtr).next = ptr;
814 		}
815 		//mark this item as last
816 		lastItemPtr = ptr;
817 		//increase item count
818 		itemCount ++;
819 	}
820 	/// adds new nodes/items at end of list
821 	void append(T[] items){
822 		if (items.length > 0){
823 			LinkedItem!(T)*[] newNodes;
824 			newNodes.length = items.length;
825 			// put nodes inside the LinkedItem list
826 			for (uinteger i = 0; i < items.length; i++){
827 				newNodes[i] = new LinkedItem!T;
828 				(*newNodes[i]).data = items[i];
829 			}
830 			// make them point to their next node
831 			for (uinteger i = 0, end = newNodes.length-1; i < end; i ++){
832 				(*newNodes[i]).next = newNodes[i+1];
833 			}
834 			// make last item from newNodes point to null
835 			(*newNodes[newNodes.length-1]).next = null;
836 			// make the last item point to first item in newNodes
837 			if (firstItemPtr is null){
838 				firstItemPtr = newNodes[0];
839 				nextReadPtr = newNodes[0];
840 			}else{
841 				(*lastItemPtr).next = newNodes[0];
842 			}
843 			// mark the last item in newNodes as last in list
844 			lastItemPtr = newNodes[newNodes.length-1];
845 			//increase count
846 			itemCount += newNodes.length;
847 		}
848 	}
849 	/// removes the first node in list
850 	/// 
851 	/// If the list is empty, this function does nothing
852 	void removeFirst(){
853 		//make sure list is populated
854 		if (firstItemPtr !is null){
855 			LinkedItem!(T)* first;
856 			first = firstItemPtr;
857 			//mark the second item as first, if there isn't a second item, it'll automatically be marked null
858 			firstItemPtr = (*firstItemPtr).next;
859 			//if nextReadPtr is firstItemPtr, move it to next as well
860 			if (nextReadPtr is first){
861 				nextReadPtr = firstItemPtr;
862 			}
863 			// if the last-read is pointing to first item, null it
864 			if (lastReadPtr is first){
865 				lastReadPtr = null;
866 			}
867 			//free memory occupied by first
868 			destroy(*first);
869 			//decrease count
870 			itemCount --;
871 		}
872 	}
873 	/// removes the node that was last read using `LinkedList.read`. The last node cannot be removed using this.
874 	///
875 	/// It works by moving contents of next item into the last-read one, and removing the next node
876 	/// 
877 	/// Returns: true in case the node/item was removed, false if not
878 	bool removeLastRead(){
879 		bool r = false;
880 		if (lastReadPtr !is null){
881 			LinkedItem!(T)* thisItem = lastReadPtr;// the item to delete
882 			LinkedItem!(T)* nextItem = (*thisItem).next;// the item after last read
883 			// make sure that the item to be deleted isn't last
884 			if (nextItem !is null){
885 				// move contents of next to this item
886 				thisItem.data = nextItem.data;
887 				// set the pointer to the item after next
888 				thisItem.next = nextItem.next;
889 				// if nextItem is last item, move last item pointer to thisItem
890 				if (nextItem is lastItemPtr){
891 					lastItemPtr = thisItem;
892 				}
893 				// delete nextItem
894 				destroy(*nextItem);
895 
896 				r = true;
897 			}else{
898 				// if there is only one item, or the pointer to second-last item is available, then it can be deleted
899 				if (itemCount == 1){
900 					// just clearing the list will do the job
901 					this.clear();
902 					// but we must increase the item count because at the end, it will be deceased by one
903 					itemCount ++;// a workaround...
904 					r = true;
905 				}else{
906 					//we'll have to read till second-last item to get be able to remove the last item
907 					LinkedItem!(T)* item = firstItemPtr;
908 					for (uinteger i = 0, end = itemCount-2; i < end; i ++){
909 						item = item.next;
910 					}
911 					// now `item` is pointing to second last item, make sure this is true
912 					if (item.next == lastItemPtr){
913 						//make the list end here
914 						item.next = null;
915 						// destroy last one
916 						destroy(*lastItemPtr);
917 						lastItemPtr = item;
918 
919 						r = true;
920 					}/*else{
921 						something that shouldn't have gone wrong went wrong with `LinkedList.itemCount`
922 					}*/
923 
924 				}
925 			}
926 			//decrease count
927 			if (r){
928 				itemCount --;
929 				//since the last-read has been removed, null that pointer, to prevent segFault
930 				lastReadPtr = null;
931 			}
932 		}
933 		return r;
934 	}
935 	/// finds an element, if found, deletes it
936 	/// 
937 	/// any function that works based on last-item-read should not be called while this is running, like in another thread...
938 	/// 
939 	/// Arguments:
940 	/// `toRemove` is the data to search for and delete  
941 	/// `count` is the number of times to search for it and delete it again. if 0, every element which is `==toRemove` is deleted  
942 	/// 
943 	/// Returns: true if was found and deleted, false if not found
944 	/// 
945 	/// Throws: Exception if failed to delete an element
946 	bool remove(T toRemove, uinteger count=0){
947 		LinkedItem!(T)* ptr = firstItemPtr, prev = null;
948 		bool r = false;
949 		uinteger removedCount = 0;
950 		// I'll just use a "hack" and use removeLastRead to remove it
951 		LinkedItem!(T)* actualLastRead = lastReadPtr;
952 		while (ptr && ( (count > 0 && removedCount < count) || count == 0 )){
953 			LinkedItem!(T)* next = (*ptr).next;
954 			if ((*ptr).data == toRemove){
955 				lastReadPtr = ptr;
956 				r = this.removeLastRead();
957 				removedCount ++;
958 				if (!r){
959 					throw new Exception("Failed to delete element in LinkedList->remove->removeLastRead");
960 				}
961 				ptr = prev;
962 				if (!ptr){
963 					ptr = firstItemPtr;
964 				}
965 				continue;
966 			}
967 			prev = ptr;
968 			ptr = ptr.next;
969 		}
970 		lastReadPtr = actualLastRead;
971 		return r;
972 	}
973 	/// searches the whole list, and any element that matches with elements in the array are deleted
974 	/// 
975 	/// any function that works based on last-item-read should not be called while this is running, like in another thread...
976 	/// 
977 	/// Arguments:
978 	/// `toRemove` is the array containing the elements to delete  
979 	/// 
980 	/// Returns: true on success, false if no elements matched
981 	/// 
982 	/// Throws: Exception if failed to delete an element
983 	bool remove(T[] toRemove){
984 		LinkedItem!(T)* ptr = firstItemPtr, prev = null;
985 		bool r = false;
986 		uinteger removedCount = 0;
987 		// I'll just use a "hack" and use removeLastRead to remove it
988 		LinkedItem!(T)* actualLastRead = lastReadPtr;
989 		while (ptr){
990 			LinkedItem!(T)* next = (*ptr).next;
991 			if (toRemove.hasElement((*ptr).data)){
992 				lastReadPtr = ptr;
993 				r = this.removeLastRead();
994 				if (!r){
995 					throw new Exception("Failed to delete element in LinkedList->remove->removeLastRead");
996 				}
997 				ptr = prev;
998 				if (!ptr){
999 					ptr = firstItemPtr;
1000 				}
1001 				continue;
1002 			}
1003 			prev = ptr;
1004 			ptr = ptr.next;
1005 		}
1006 		lastReadPtr = actualLastRead;
1007 		return r;
1008 	}
1009 	/// Returns: number of items that the list is holding
1010 	@property uinteger count(){
1011 		return itemCount;
1012 	}
1013 	///resets the read position, i.e: set reading position to first node, and nulls the last-read-ptr
1014 	void resetRead(){
1015 		nextReadPtr = firstItemPtr;
1016 		lastReadPtr = null;
1017 	}
1018 	/// Returns: pointer of next node to be read, null if there are no more nodes
1019 	/// 
1020 	/// increments the read-position by 1, so next time it's called, the next item is read
1021 	T* read(){
1022 		T* r;
1023 		if (nextReadPtr !is null){
1024 			r = &((*nextReadPtr).data);
1025 			//mark this item as last read
1026 			lastReadPtr = nextReadPtr;
1027 			//move read position
1028 			nextReadPtr = (*nextReadPtr).next;
1029 		}else{
1030 			r = null;
1031 			lastReadPtr = null;
1032 		}
1033 		return r;
1034 	}
1035 	/// Returns: the pointer to the first node in the list
1036 	T* readFirst(){
1037 		if (firstItemPtr !is null){
1038 			lastReadPtr = firstItemPtr;
1039 			return &((*firstItemPtr).data);
1040 		}else{
1041 			return null;
1042 		}
1043 	}
1044 	/// Returns: the pointer to the last node in the list
1045 	T* readLast(){
1046 		if (lastItemPtr !is null){
1047 			lastReadPtr = lastItemPtr;
1048 			return &((*lastItemPtr).data);
1049 		}else{
1050 			return null;
1051 		}
1052 	}
1053 	/// Reads the list into an array
1054 	/// 
1055 	/// Returns: the array formed from this list
1056 	T[] toArray(){
1057 		LinkedItem!(T)* currentNode = firstItemPtr;
1058 		uinteger i = 0;
1059 		T[] r;
1060 		r.length = itemCount;
1061 		while (currentNode !is null){
1062 			r[i] = (*currentNode).data;
1063 			// move to next node
1064 			currentNode = (*currentNode).next;
1065 			i ++;
1066 		}
1067 		return r;
1068 	}
1069 	/// Inserts a node after the position of last-read-node, i.e, to insert at position from where next item is to be read
1070 	/// 
1071 	/// To insert at beginning, call `resetRead` before inserting
1072 	/// For inserting more than one nodes, use `LinkedList.insert([...])`
1073 	void insert(T node){
1074 		LinkedItem!(T)* newNode = new LinkedItem!T;
1075 		(*newNode).data = node;
1076 		// check if has to insert at beginning or at after last-read
1077 		if (lastReadPtr !is null){
1078 			// make new node point to the current next-to-be-read node
1079 			(*newNode).next = lastReadPtr.next;
1080 			// make last read node point to new node
1081 			(*lastReadPtr).next = newNode;
1082 		}else{
1083 			// make this item point to first-item
1084 			(*newNode).next = firstItemPtr;
1085 			// mark this as first item
1086 			firstItemPtr = newNode;
1087 		}
1088 		// make next read point to this node now
1089 		nextReadPtr = newNode;
1090 		//increase count
1091 		itemCount ++;
1092 	}
1093 	/// Inserts nodes after the position of last-read-node, i.e, to insert at position from where next item is to be read
1094 	/// 
1095 	/// If there is no last-read-item, the item is inserted at beginning. To do this, call `resetRead` before inserting
1096 	/// 
1097 	/// Returns: true on success, false on failure
1098 	void insert(T[] nodes){
1099 		if (nodes.length > 0){
1100 			LinkedItem!(T)*[] newNodes;
1101 			newNodes.length = nodes.length;
1102 			// put nodes inside the LinkedItem list
1103 			for (uinteger i = 0; i < nodes.length; i++){
1104 				newNodes[i] = new LinkedItem!T;
1105 				(*newNodes[i]).data = nodes[i];
1106 			}
1107 			// make them point to their next node
1108 			for (uinteger i = 0, end = newNodes.length-1; i < end; i ++){
1109 				(*newNodes[i]).next = newNodes[i+1];
1110 			}
1111 			// check if has to insert at beginning or at after last-read
1112 			if (lastReadPtr !is null && nodes.length > 0){
1113 				// and make the last node in list point to the node after last-read
1114 				(*newNodes[newNodes.length-1]).next = (*lastReadPtr).next;
1115 				// make last read node point to the first new-node
1116 				(*lastReadPtr).next = newNodes[0];
1117 			}else{
1118 				// insert at beginning
1119 				(*newNodes[newNodes.length-1]).next = firstItemPtr;
1120 				// make this the first node
1121 				firstItemPtr = newNodes[0];
1122 			}
1123 			//make next read point to this
1124 			nextReadPtr = newNodes[0];
1125 			//increase count
1126 			itemCount += nodes.length;
1127 		}
1128 	}
1129 	/// Returns: true if list contains a node, i.e searches for a node and returns true if found
1130 	bool hasElement(T node){
1131 		bool r = false;
1132 		LinkedItem!(T)* currentNode = firstItemPtr;
1133 		while (currentNode !is null){
1134 			if ((*currentNode).data == node){
1135 				r = true;
1136 				break;
1137 			}
1138 			// move to next node
1139 			currentNode = (*currentNode).next;
1140 		}
1141 		return r;
1142 	}
1143 	/// matches all elements from an array to elements in list, to see if all elements in array are present in the list
1144 	///  
1145 	/// If the same element is present at more than one index in array, it won't work
1146 	/// 
1147 	/// Returns: true if list contains all elements provided in an array, else, false
1148 	bool hasElements(T[] nodes){
1149 		bool r = false;
1150 		nodes = nodes.dup;
1151 		// go through the list and match as many elements as possible
1152 		LinkedItem!(T)* currentNode = firstItemPtr;
1153 		while (currentNode !is null){
1154 			// check if current node matches any in array
1155 			integer index = nodes.indexOf((*currentNode).data);
1156 			if (index >= 0){
1157 				// this node matched, so remove it from the array
1158 				nodes = nodes.deleteElement(index);
1159 			}
1160 			// check if all elements have been checked against
1161 			if (nodes.length == 0){
1162 				break;
1163 			}
1164 			// move to next node
1165 			currentNode = (*currentNode).next;
1166 		}
1167 		// Now check if the nodes array is empty, if yes, then all nodes were matched
1168 		if (nodes.length == 0){
1169 			r = true;
1170 		}
1171 		return r;
1172 	}
1173 	/// Sets a "bookmark"
1174 	/// 
1175 	/// the returned ID can later be used to go back to the reading position at which the bookmark was placed  
1176 	/// and be careful not to remove an item to which bookmark is pointing, because then if you moveToBookmark, it'll segfault.
1177 	/// 
1178 	/// Returns: the bookmark-ID
1179 	/// 
1180 	/// Throws: Exception if there is no last-read item
1181 	uinteger placeBookmark(){
1182 		if (lastReadPtr is null){
1183 			throw new Exception("no last-read-item to place bookmark on");
1184 		}else{
1185 			// go through bookmarks list to find empty slot, or create a new one
1186 			uinteger id = 0;
1187 			while (true){
1188 				if (id in bookmarks){
1189 					id ++;
1190 				}else{
1191 					break;
1192 				}
1193 			}
1194 			bookmarks[id] = lastReadPtr.next;
1195 			return id;
1196 		}
1197 	}
1198 	/// moves read position back to a bookmark using the bookmark ID
1199 	/// 
1200 	/// Does NOT delete the bookmark. Use `LinkedList.removeBookmark` to delete
1201 	/// 
1202 	/// Returns: true if successful, false if the bookmark no longer exists
1203 	bool moveToBookmark(uinteger id){
1204 		if (id !in bookmarks){
1205 			return false;
1206 		}else{
1207 			nextReadPtr = bookmarks[id];
1208 			return true;
1209 		}
1210 	}
1211 	/// removes a bookmark using the bookmark id
1212 	/// 
1213 	/// Returns: true if bookmark is removed, false if it doesn't exist
1214 	bool removeBookmark(uinteger id){
1215 		if (id !in bookmarks){
1216 			return false;
1217 		}else{
1218 			bookmarks.remove(id);
1219 			return true;
1220 		}
1221 	}
1222 	/// Removes all bookmarks
1223 	void clearBookmarks(){
1224 		foreach(key; bookmarks.keys){
1225 			bookmarks.remove(key);
1226 		}
1227 	}
1228 }
1229 ///
1230 unittest{
1231 	import std.conv : to;
1232 	LinkedList!ubyte list = new LinkedList!ubyte;
1233 	//`LinkedList.append` and `LinkedList.read` and `LinkedList.readFirst` and `LinkedList.readLast` and `LinkedList.resetRead`
1234 	list.append(0);
1235 	list.append(1);
1236 	list.append(2);
1237 	assert(*(list.readFirst()) == 0);
1238 	assert(*(list.readLast()) == 2);
1239 	assert(list.count == 3);
1240 	list.read();// to skip, we wanna read the node at index 1 (2nd node)
1241 	assert(*(list.read()) == 1);
1242 	list.resetRead();
1243 	assert(*(list.read()) == 0);
1244 	// `LinkedList.append(T[])`:
1245 	list.clear();
1246 	list.append(0);
1247 	list.append([1, 2, 3]);
1248 	assert(list.count == 4);
1249 	assert(list.toArray ==[0, 1, 2, 3]);
1250 	list.clear;
1251 	list.append([0, 1, 2]);
1252 	list.append(3);
1253 	assert(list.count == 4);
1254 	assert(list.toArray == [0, 1, 2, 3]);
1255 	//`LinkedList.clear`
1256 	list.clear();
1257 	list.append(3);
1258 	list.append(4);
1259 	assert(*(list.read()) == 3);
1260 	assert(list.count == 2);
1261 	list.clear();
1262 	//`LinkedList.removeLastRead` and `Linkedlist.removeFirst`
1263 	list.append(0);
1264 	list.append(1);
1265 	list.append(2);
1266 	list.read();
1267 	list.read();
1268 	list.removeLastRead();
1269 	list.resetRead();
1270 	assert(*(list.read()) == 0);
1271 	assert(*(list.read()) == 2);
1272 	assert(list.count == 2);
1273 	list.removeFirst();
1274 	list.resetRead();
1275 	assert(*(list.read()) == 2);
1276 	assert(list.count == 1);
1277 	list.removeLastRead();
1278 	assert(list.count == 0);
1279 	//`LinkedList.toArray` and `LinkedList.insertNode` and `LinkedList.insertNodes`
1280 	list.clear();// to reset stuff
1281 	list.append(0);
1282 	list.append(4);
1283 	list.read();
1284 	list.insert(1);
1285 	assert(*(list.read()) == 1);
1286 	list.insert([2, 3]);
1287 	list.resetRead();
1288 	assert(list.count == 5);
1289 	assert(list.toArray == [0, 1, 2, 3, 4]);
1290 	//`Linkedlist.hasElement` and `LinkedList.hasElements`
1291 	assert(list.hasElement(0) == true);
1292 	assert(list.hasElement(4) == true);
1293 	assert(list.hasElement(5) == false);
1294 	assert(list.hasElement(7) == false);
1295 	assert(list.hasElements([3, 1, 2, 0, 4]) == true);
1296 	assert(list.hasElements([0, 1, 2, 6]) == false);
1297 	// `LinkedList.insert` at beginning
1298 	list.clear;
1299 	list.insert([1, 2]);
1300 	list.insert(0);
1301 	assert(list.count == 3);
1302 	assert(list.toArray == [0, 1, 2]);
1303 	//destroying last item
1304 	list.clear();
1305 	list.append(0);
1306 	list.append(1);
1307 	list.append(2);
1308 	list.read();
1309 	list.read();
1310 	list.read();
1311 	assert(list.removeLastRead() == true);
1312 	assert(list.toArray() == [0, 1]);
1313 	//bookmarks
1314 	list.clear;
1315 	list.append([0, 1, 2, 3, 4, 5]);
1316 	assert(*list.read == 0);
1317 	assert(*list.read == 1);
1318 	assert(*list.read == 2);
1319 	{
1320 		uinteger id = list.placeBookmark;
1321 		assert(*list.read == 3);
1322 		assert(list.moveToBookmark(id + 1) == false);
1323 		assert(list.moveToBookmark(id) == true);
1324 		assert(*list.read == 3);
1325 		assert(list.removeBookmark(id) == true);
1326 	}
1327 	// now to test LinkedList.remove
1328 	list.clear;
1329 	list.append([0,0,1,1,2,3,3,4,5,6,0,0]);
1330 	assert(list.remove(0,2) == true);
1331 	assert(list.toArray == [1,1,2,3,3,4,5,6,0,0], to!string(list.toArray));
1332 	assert(list.remove(0) == true);
1333 	assert(list.toArray == [1,1,2,3,3,4,5,6]);
1334 	assert(list.remove([1,3]) == true);
1335 	assert(list.toArray == [2,4,5,6]);
1336 	destroy(list);
1337 }
1338 
1339 /// Used in log display widgets (like in dub package `qui` `qui.widgets.LogWidget`)
1340 /// 
1341 /// Holds up to a certain number of items, after which it starts over-writing older ones
1342 deprecated class LogList(T){
1343 private:
1344 	List!T list;
1345 	uinteger readFrom, maxLen;
1346 public:
1347 	this(uinteger maxLength=100){
1348 		list = new List!T;
1349 		readFrom = 0;
1350 		maxLen = maxLength;
1351 	}
1352 	~this(){
1353 		delete list;
1354 	}
1355 	/// adds an item to the log
1356 	void add(T dat){
1357 		if (list.length>=maxLen){
1358 			list.set(readFrom,dat);
1359 			readFrom++;
1360 		}else{
1361 			list.add(dat);
1362 		}
1363 	}
1364 	/// Returns: array containing items
1365 	T[] read(uinteger count=0){
1366 		T[] r;
1367 		if (count>list.length){
1368 			count = list.length;
1369 		}
1370 		if (count > 0){
1371 			uinteger i;
1372 			if (count>list.length){
1373 				count = list.length;
1374 			}
1375 			r.length = count;
1376 			for (i = readFrom; i < count; i++){
1377 				r[i] = list.read((readFrom+i)%count);
1378 			}
1379 		}else{
1380 			r = null;
1381 		}
1382 		return r;
1383 	}
1384 	/// resets and clears the log
1385 	void reset(){
1386 		list.clear;
1387 		readFrom = 0;
1388 	}
1389 	/// Returns: the max number of items that can be stored
1390 	@property uinteger maxCapacity(){
1391 		return maxLen;
1392 	}
1393 }
1394 
1395 /// TODO: do something about this
1396 /// For reading large files which otherwise, would take too much memory
1397 /// 
1398 /// Aside from reading, it can also write to files. TODO make it ready
1399 /*class FileReader{
1400 private:
1401 	File file; /// the file currently loaded
1402 	bool closeOnDestroy; /// stores if the file will be closed when this object is destroyed
1403 	uinteger _minSeek; /// stores the minimum value of seek, if zero, it has no effect
1404 	uinteger _maxSeek; /// stores the maximum value of seek, if zero, it has no effect
1405 	uinteger _maxSize; /// stores the max size of the file in case _minSeek and _maxSeek are set non-zero
1406 	string _filename; /// the filename of the file opened
1407 public:
1408 	/// prepares a file for reading/writing through this class
1409 	///
1410 	/// if filename does not exists, attempts to create it
1411 	/// 
1412 	/// Throws: Exception (ErrnoException) if some error occurs
1413 	this(string filename){
1414 		file = File (filename, filename.exists ? "r+" : "w+");
1415 		closeOnDestroy = true;
1416 		_filename = filename;
1417 		_minSeek = 0;
1418 		_maxSeek = 0;
1419 	}
1420 	/// prepares this object for reading/writing an already opened file
1421 	/// 
1422 	/// When this constructor is used, file will not be closed when this object is destroyed  
1423 	/// and keep in mind that modifying the seek of `f` will also modify it in this object, so try not to use `f` outside,  
1424 	/// or do so with some precaution.
1425 	this (File f){
1426 		file = f;
1427 		closeOnDestroy = false;
1428 		_minSeek = 0;
1429 		_maxSeek = 0;
1430 	}
1431 	/// prepares this object for reading/writing an already opened file, where the read/write can only take place between a
1432 	/// certain range. 
1433 	/// 
1434 	/// When this constructor is used, file will not be closed when this object is destroyed  
1435 	/// and keep in mind that modifying the seek of `f` will also modify it in this object, so try not to use `f` outside,  
1436 	/// or do so with some precaution.  
1437 	/// The object will treat the File segment as the whole file in the functions:  
1438 	/// * seek will return relative to minSeek. i.e, if actual seek is `minSeek + 1`, it will return `1`  
1439 	/// * size will return `(maxSeek - minSeek) + 1` if the actual size is greater than maxSeek, otherwise, it will be `size - maxSeek`  
1440 	/// * `lock()` (locking whole file) will only lock the segment  
1441 	/// * `unlock()` (unlocking whole file) will only unlock the segment
1442 	/// 
1443 	/// Arguments:
1444 	/// `f` if the File to do reading/writing on  
1445 	/// `minSeek` is the index from where reading/writing can begin from.
1446 	/// `maxSeek` is the index after which no reading writing can be done.
1447 	this (File f, uinteger minSeek, uinteger maxSeek){
1448 		file = f;
1449 		assert (minSeek < maxSeek, "minSeek must be smaller than maxSeek");
1450 		this._minSeek = minSeek;
1451 		this._maxSeek = maxSeek;
1452 		this._maxSize = (maxSeek - minSeek) + 1;
1453 	}
1454 	/// destructor
1455 	~this(){
1456 		if (closeOnDestroy)
1457 			file.close();
1458 	}
1459 	/// locks a file segment (readWrite lock)
1460 	/// 
1461 	/// Throws: Exception if this FileReader is only for a segment and it tries to access outdside that segment
1462 	/// 
1463 	/// Returns: true if lock was successful, false if already locked
1464 	bool lock(uinteger start, uinteger length){
1465 		if (_minSeek + _maxSeek > 0){
1466 			start = start + _minSeek;
1467 		}
1468 		// make sure it's not accessing anything outside the segment, if there is a segment limit
1469 		if (start + length > _maxSeek + 1){
1470 			throw new Exception ("trying to access outside _maxSeek");
1471 		}
1472 		return file.tryLock(LockType.readWrite, start, length);	
1473 	}
1474 	/// locks the whole file (readWrite lock)
1475 	/// 
1476 	/// Returns: true if lock was successful, false if alrady locked
1477 	bool lock(){
1478 		if (_minSeek + _maxSeek == 0){
1479 			return file.tryLock(LockType.readWrite, 0, 0);
1480 		}
1481 		return file.tryLock(LockType.readWrite, _minSeek, _maxSize);
1482 	}
1483 	/// unlocks a file segment
1484 	/// 
1485 	/// Throws: Exception if this FileReader is only for a segment and it tries to access outdside that segment
1486 	void unlock (uinteger start, uinteger length){
1487 		if (_minSeek + _maxSeek > 0){
1488 			start = start + _minSeek;
1489 		}
1490 		// make sure it's not accessing anything outside the segment, if there is a segment limit
1491 		if (start + length > _maxSeek + 1){
1492 			throw new Exception ("trying to access outside _maxSeek");
1493 		}
1494 		file.unlock (start, length);
1495 	}
1496 	/// unlocks the whole file
1497 	void unlock (){
1498 		if (_minSeek + _maxSeek == 0){
1499 			file.unlock (0, file.size);
1500 		}else if (file.size > 0){
1501 			file.unlock(_minSeek, _maxSize);
1502 		}
1503 	}
1504 	/// reads a number of bytes
1505 	/// 
1506 	/// Returns: the bytes read. If there were not enough bytes left to read in the file, an array of smaller size is returned
1507 	///
1508 	/// Throws: Exception (ErrnoException) in case of an error
1509 	ubyte[] read (uinteger n){
1510 		ubyte[] buffer;
1511 		buffer.length = this.size - this.seek > n ? n : this.size - this.seek;
1512 		file.rawRead(buffer);
1513 		return buffer;
1514 	}
1515 	/// reads till a specific byte is reached, or if eof is reached
1516 	///
1517 	/// Returns: the bytes read including the terminating byte
1518 	///
1519 	/// Throws: Exception (ErrnoException) in case of an error
1520 	ubyte[] read (ubyte terminateByte){
1521 		ubyte[] r;
1522 		while (this.seek < this.size){
1523 			ubyte[1] currentByte;
1524 			file.rawRead(currentByte);
1525 			r = r ~ currentByte[0];
1526 			if (currentByte[0] == terminateByte){
1527 				break;
1528 			}
1529 		}
1530 		return r;
1531 	}
1532 	/// writes some bytes
1533 	///
1534 	/// Throws: Exception (ErrnoException) in case of an error
1535 	void write (ubyte[] buffer){
1536 		// make sure it won't overflow the _maxSeek
1537 		if (buffer.length + this.seek > _maxSize){
1538 			buffer = buffer.dup;
1539 			buffer.length = _maxSize - this.seek;
1540 		}
1541 		file.rawWrite(buffer);
1542 	}
1543 	/// Removes a number of bytes from the file, starting at an index.
1544 	///
1545 	/// Arguments:
1546 	/// `index` is index to begin removing from  
1547 	/// `length` is number of bytes to remove  
1548 	/// `chunkSize` is the number of bytes to shift in one iteration
1549 	/// 
1550 	/// Returns: true if done, false if not, or index was out of bounds TODO add tests for this
1551 	bool remove (uinteger index, uinteger length){
1552 		if (this.size <= index || this.size - index < length)
1553 			return false;
1554 		try{
1555 			for (this.seek = index+length; this.seek < this.size;){
1556 				ubyte[] toShift = this.read(length);
1557 				this.seek = this.seek - length;
1558 				this.write (toShift);
1559 			}
1560 			truncate(this.size - length);
1561 		}catch(Exception e){
1562 			.destroy (e);
1563 			return false;
1564 		}
1565 		return true;
1566 	}
1567 	/// inserts some bytes at the seek. i.e, shifts existing data from index=seek+1 onwards and makes space for new data, and writes it
1568 	/// 
1569 	/// Does not work if minSeek or maxSeek is set
1570 	/// 
1571 	/// Returns: true if successful, false if not
1572 	bool insert (ubyte[] data){
1573 		// TODO make this
1574 	}
1575 	/// truncates a file, i.e removes last byte(s) from file.
1576 	/// 
1577 	/// Does not work if minSeek and/or maxSeek were non-zero.
1578 	/// 
1579 	/// TODO: read file `byChunk`, write it to new file, excluding last byte(s), replace old file with newfile; will be faster
1580 	/// 
1581 	/// Arguments:
1582 	/// `newSize` is the new number of bytes in file.  
1583 	/// `onFailTrySlow` if true, when `SetEndOfFile` or `ftruncate` fails, it'll use a slower method that might work
1584 	/// 
1585 	/// Returns: true if file was truncated, false if not, for example if the file size was less than newSize TODO add tests
1586 	bool truncate(uinteger newSize, bool onFailTrySlow=false){
1587 		if (_minSeek + _maxSeek != 0 || newSize < this.size){
1588 			return false;
1589 		}
1590 		try{
1591 			version (Posix){
1592 				import core.sys.posix.unistd: ftruncate;
1593 				ftruncate(file.fileno, newSize);
1594 			}
1595 			version (Windows){
1596 				import core.sys.windows.windows: SetEndOfFile;
1597 				uinteger oldSeek = this.seek;
1598 				this.seek = newSize-1;
1599 				SetEndOfFile (file.HANDLE);
1600 				this.seek = oldSeek;
1601 			}
1602 		}catch (Exception e){
1603 			return false;
1604 		}
1605 		return (file.size == newSize);
1606 	}
1607 	/// from where the next byte will be read/write
1608 	@property ulong seek (){
1609 		if (_maxSeek + _minSeek == 0){
1610 			return file.tell();
1611 		}
1612 		ulong actualSeek = file.tell();
1613 		if (actualSeek < _minSeek){
1614 			this.seek = 0;
1615 		}else if (actualSeek > _maxSeek){
1616 			this.seek = _maxSeek;
1617 		}
1618 		return file.tell() - _minSeek;
1619 	}
1620 	/// from where the next byte will be read/write
1621 	@property ulong seek (ulong newSeek){
1622 		if (_maxSeek + _minSeek == 0){
1623 			file.seek (newSeek, SEEK_SET);
1624 			return file.tell();
1625 		}
1626 		newSeek += _minSeek;
1627 		if (newSeek > _maxSeek){
1628 			newSeek = _maxSeek;
1629 		}
1630 		file.seek (newSeek, SEEK_SET);
1631 		return file.tell() - _minSeek;
1632 	}
1633 	/// number of bytes in file
1634 	@property ulong size (){
1635 		ulong actualSize = file.size();
1636 		if (actualSize > _maxSize){
1637 			actualSize = _maxSize;
1638 		}
1639 		return actualSize;
1640 	}
1641 	/// the filename currently being read/written
1642 	@property string filename (){
1643 		return _filename;
1644 	}
1645 }
1646 ///
1647 unittest{
1648 	import std.path : dirSeparator;
1649 	import std.conv : to;
1650 	// delete the file if it already exists, so it wont mess up the tests
1651 	string fname = tempDir ~ dirSeparator ~ "utilsfilereader";
1652 	if (fname.exists){
1653 		remove (fname);
1654 	}
1655 	FileReader fread = new FileReader(fname);
1656 	assert (fread.seek == 0, "seek is not zero at file open");
1657 	assert (fread.size == 0, "size is not zero for newly created file");
1658 	assert (fread.filename == fname, "filename is not "~fname);
1659 	// first fill it with some data
1660 	fread.write ([1,3,4,5,6,7,8,0,8,7,6,5,4,3,2,1]);
1661 	assert (fread.seek == 16);
1662 	assert (fread.size == 16);
1663 	fread.seek = 1;
1664 	fread.write ([2]);
1665 	assert (fread.seek == 2);
1666 	assert (fread.size == 16);
1667 	// close it, and see if opening existing files works
1668 	.destroy (fread);
1669 	fread = new FileReader(fname);
1670 	assert (fread.size == 16);
1671 	assert (fread.filename == fname);
1672 	assert (fread.seek == 0);
1673 	/// test read-until-terminator
1674 	assert (fread.read(cast(ubyte)0) == [1,2,4,5,6,7,8,0]);
1675 	assert (fread.seek == 8);
1676 	/// test read-number of bytes
1677 	assert (fread.read(cast(uinteger)5) == [8,7,6,5,4]);
1678 	assert (fread.seek == 13);
1679 	assert (fread.read(999) == [3,2,1]);
1680 	/// test move-seek and read
1681 	fread.seek = 2;
1682 	assert (fread.read(cast(ubyte)0) == [4,5,6,7,8,0]);
1683 	/// close it
1684 	.destroy (fread);
1685 	remove (fname);
1686 }*/
1687 
1688 /// For reading/writing sequentially to a ubyte[]
1689 /// 
1690 /// be careful using maxSize and grow, they're not tested
1691 class ByteStream{
1692 private:
1693 	ubyte[] _stream;
1694 	uinteger _seek;
1695 	bool _grow;
1696 	uinteger _maxSize;
1697 public:
1698 	/// constructor
1699 	/// 
1700 	/// `grow` is whether the stream is allowed to grow in size while writing  
1701 	/// `maxSize` is the maximum size stream is allowed to grow to (0 for no limit)
1702 	this(bool grow = true, uinteger maxSize = 0){
1703 		_grow = grow;
1704 		_maxSize = maxSize;
1705 	}
1706 	~this(){
1707 		.destroy(_stream);
1708 	}
1709 	/// Seek position (i.e: next read/write index)
1710 	@property uinteger seek(){
1711 		return _seek;
1712 	}
1713 	/// ditto
1714 	@property uinteger seek(uinteger newVal){
1715 		return _seek = newVal > _stream.length ? _stream.length : newVal;
1716 	}
1717 	/// if the stream is allowed to grow in size while writing
1718 	@property bool grow(){
1719 		return _grow;
1720 	}
1721 	/// ditto
1722 	@property bool grow(bool newVal){
1723 		return _grow = newVal;
1724 	}
1725 	/// maximum size stream is allowed to grow to, 0 for no limit.  
1726 	/// 
1727 	/// This is enforced while writing, or changing `ByteStream.size`
1728 	@property uinteger maxSize(){
1729 		return _maxSize;
1730 	}
1731 	/// ditto
1732 	@property uinteger maxSize(uinteger newVal){
1733 		_maxSize = newVal;
1734 		if (_seek > _maxSize)
1735 			_seek = _maxSize;
1736 		return _maxSize;
1737 	}
1738 	/// The stream
1739 	@property ubyte[] stream(){
1740 		return _stream;
1741 	}
1742 	/// ditto
1743 	@property ubyte[] stream(ubyte[] newVal){
1744 		return _stream = newVal;
1745 	}
1746 	/// Size, in bytes, of stream
1747 	@property uinteger size(){
1748 		return _stream.length;
1749 	}
1750 	/// Size, setter. if new size is >maxSize, size is set to maxSize
1751 	@property uinteger size(uinteger newVal){
1752 		_stream.length = _maxSize < newVal ? _maxSize : newVal;
1753 		if (_seek > _stream.length)
1754 			_seek = _stream.length;
1755 		return _stream.length;
1756 	}
1757 	/// Writes this stream to a file
1758 	/// 
1759 	/// Returns: true if successful, false if not
1760 	bool toFile(string fname){
1761 		try{
1762 			std.file.write(fname, _stream);
1763 		}catch (Exception e){
1764 			.destroy(e);
1765 			return false;
1766 		}
1767 		return true;
1768 	}
1769 	/// Reads a stream from file.  
1770 	/// if successful, seek and maxSize are set to 0;
1771 	/// 
1772 	/// Returns: true if done successfully, false if not
1773 	bool fromFile(string fname){
1774 		try{
1775 			_stream = cast(ubyte[])std.file.read(fname);
1776 		}catch (Exception e){
1777 			.destroy(e);
1778 			return false;
1779 		}
1780 		_seek = 0;
1781 		_maxSize = 0;
1782 		return true;
1783 	}
1784 	/// Reads a slice from the stream into buffer. Will read number of bytes so as to fill `buffer`
1785 	/// 
1786 	/// Returns: number of bytes read
1787 	uinteger readRaw(ubyte[] buffer){
1788 		immutable uinteger len = _seek + buffer.length > _stream.length ? _stream.length - _seek : buffer.length;
1789 		buffer[0 .. len] = _stream[_seek .. _seek + len];
1790 		_seek += len;
1791 		return len;
1792 	}
1793 	/// Reads at a seek without changing seek. **Does not work for dynamic arrays**
1794 	/// 
1795 	/// Will still return an invalid value if reading outside stream  
1796 	/// Sets `incompleteRead` to true if there were less bytes in stream that T.sizeof
1797 	/// 
1798 	/// Returns: the data read at position
1799 	T readAt(T)(uinteger at, ref bool incompleteRead){
1800 		ByteUnion!T r;
1801 		immutable uinteger prevSeek = _seek;
1802 		at = at > _stream.length ? _stream.length : at;
1803 		immutable uinteger len = at + r.array.length > _stream.length ? _stream.length - at : r.array.length;
1804 		incompleteRead = len < r.array.length;
1805 		r.array[0 .. len] = _stream[at .. at + len];
1806 		return r.data;
1807 	}
1808 	/// ditto
1809 	T readAt(T)(uinteger at){
1810 		bool dummyBool;
1811 		return readAt!T(at, dummyBool);
1812 	}
1813 	/// Reads a data type T from current seek. **Do not use this for reading arrays**
1814 	///
1815 	/// Will return invalid data if there are insufficient bytes to read from. 
1816 	/// Sets `incompleteRead` to true if there were less bytes in stream that T.sizeof 
1817 	/// If value of `n` is non-zero, that number of bytes will be read.
1818 	/// 
1819 	/// Returns: the read data
1820 	T read(T)(ref bool incompleteRead, ubyte n=0){
1821 		ByteUnion!T u;
1822 		uinteger readCount;
1823 		if (n == 0 || n > T.sizeof)
1824 			readCount = readRaw(u.array);
1825 		else
1826 			readCount = readRaw(u.array[0 .. n]);
1827 		incompleteRead = readCount < n;
1828 		if (n > T.sizeof)
1829 			_seek += n - T.sizeof;
1830 		return u.data;
1831 	}
1832 	/// ditto
1833 	T read(T)(ubyte n=0){
1834 		bool dummyBool;
1835 		return read!T(dummyBool, n);
1836 	}
1837 	/// Reads an array.
1838 	/// 
1839 	/// in case of insufficient bytes in stream, will return array of correct length but missing bytes at end.  
1840 	/// `readCount` is the number of elements that were actually read (this can be < length if stream doesnt have enough bytes)
1841 	/// `n` is the number of bytes to read for length of array, default(`0`) is `size_t.sizeof`
1842 	/// 
1843 	/// Returns: the read array
1844 	T[] readArray(T)(ref uinteger readCount, ubyte n=0){
1845 		immutable uinteger len = read!uinteger(n);
1846 		T[] r;
1847 		r.length = len / T.sizeof;
1848 		readCount = readRaw((cast(ubyte*)r.ptr)[0 .. r.length * T.sizeof]) / T.sizeof;
1849 		return r;
1850 	}
1851 	/// ditto
1852 	T[] readArray(T)(ubyte n=0){
1853 		uinteger dummyUint;
1854 		return readArray!T(dummyUint, n);
1855 	}
1856 	/// Writes data at seek. **Do not use this for arrays**
1857 	/// 
1858 	/// `n` is number of bytes to actually write, default (0) is `T.sizeof`
1859 	/// 
1860 	/// Returns: true if written, false if not (could be because stream not allowed to grow, or max size reached)
1861 	bool write(T)(T data, ubyte n=0){
1862 		ByteUnion!T u;
1863 		u.data = data;
1864 		immutable uinteger newSize = _seek + (n == 0 ? u.array.length : n); // size after writing
1865 		if (newSize > _stream.length){
1866 			if (!_grow || (_maxSize && newSize > _maxSize))
1867 				return false;
1868 			_stream.length = newSize;
1869 		}
1870 		if (n == 0 || n > u.array.length){
1871 			_stream[_seek .. _seek + u.array.length] = u.array;
1872 			_seek += u.array.length;
1873 			if (n <= u.array.length)
1874 				return true;
1875 			n -= u.array.length;
1876 			if (n){
1877 				_stream[_seek .. _seek + n] = 0;
1878 				_seek += n;
1879 			}
1880 			return true;
1881 		}
1882 		_stream[_seek .. _seek + n] = u.array[0 .. n];
1883 		_seek += n;
1884 		return true;
1885 	}
1886 	/// Writes an array without its size.
1887 	/// 
1888 	/// Returns: number of bytes written, **not the number of elements**
1889 	uinteger writeRaw(T)(T[] data){
1890 		uinteger len = data.length * T.sizeof;
1891 		if (_seek + len > _stream.length){
1892 			if (!_grow)
1893 				len = _stream.length - _seek;
1894 			else if (_maxSize && _seek + len > _maxSize)
1895 				len = _maxSize - _seek;
1896 			_stream.length = _seek + len;
1897 		}
1898 		_stream[_seek .. _seek + len] = (cast(ubyte*)data.ptr)[0 .. len];
1899 		_seek += len;
1900 		return len;
1901 	}
1902 	/// Writes (overwriting existing) data `at` a seek, without changing seek. 
1903 	/// 
1904 	/// `n` is number of bytes to actually write. default (0) is T.sizeof
1905 	/// Will append to end of stream if `at` is outside stream
1906 	/// 
1907 	/// Returns: true if written successfully, false if not
1908 	bool writeAt(T)(uinteger at, T data, ubyte n = 0){
1909 		// writing is bit complicated, so just use `write` and change seek back to original after
1910 		immutable uinteger prevSeek = _seek;
1911 		_seek = at > _stream.length ? _stream.length : at;
1912 		immutable bool r = this.write(data, n);
1913 		_seek = prevSeek;
1914 		return r;
1915 	}
1916 	/// Writes an array at seek.
1917 	/// 
1918 	/// `n` is the number of bytes to use for storing length of array, default (`0`) is `size_t.sizeof`
1919 	/// 
1920 	/// Returns: true if written, false if not (due to maxSize reached or not allowed to grow)
1921 	bool writeArray(T)(T[] data, ubyte n=0){
1922 		immutable uinteger newSize = _seek + (n == 0 ? uinteger.sizeof : n) + (data.length * T.sizeof);
1923 		if (newSize > _stream.length){
1924 			if (!_grow || (_maxSize && newSize > _maxSize))
1925 				return false;
1926 			_stream.length = newSize;
1927 		}
1928 		if (this.write(data.length * T.sizeof, n)){
1929 			return writeRaw(data) == data.length * T.sizeof;
1930 		}
1931 		return false; // something bad went wrong, while writing size
1932 	}
1933 }
1934 /// 
1935 unittest{
1936 	ByteStream stream = new ByteStream();
1937 	ubyte[] buffer;
1938 	uint[] uintArray = [12_345, 123_456, 1_234_567, 12_345_678, 123_456_789];
1939 
1940 	stream.write(1024, 8); // 1024 as ulong
1941 	stream.seek = 0;
1942 	assert(stream.read!uint(8) == 1024);
1943 	assert(stream.seek == 8, stream.seek.to!string);
1944 	stream.writeRaw(uintArray);
1945 	stream.seek = 8;
1946 	buffer.length = 50;
1947 	stream.readRaw(buffer);
1948 	assert((cast(uint*)buffer.ptr)[0 .. 5] == uintArray);
1949 
1950 	stream.seek = 0;
1951 	stream.writeArray(uintArray, 6);
1952 	assert(stream.seek == (uintArray.length * 4) + 6);
1953 	stream.seek = 0;
1954 	uintArray = stream.readArray!(uint)(6);
1955 	assert (uintArray == [12_345, 123_456, 1_234_567, 12_345_678, 123_456_789], uintArray.to!string);
1956 
1957 	stream.seek = 0;
1958 	stream.writeRaw(uintArray);
1959 	stream.writeAt(0, cast(uint)50);
1960 	buffer.length = uintArray.length * uint.sizeof;
1961 	stream.seek = 0;
1962 	assert(stream.readRaw(buffer) == buffer.length);
1963 	uintArray = (cast(uint*)buffer.ptr)[0 .. uintArray.length];
1964 	assert(uintArray[0] == 50 && uintArray[1 .. $] == [123_456, 1_234_567, 12_345_678, 123_456_789]);
1965 	assert(stream.readAt!uint(4) == 123_456);
1966 }
1967 
1968 /// used by Tree class to hold individual nodes in the tree
1969 struct TreeNode(T){
1970 	T data; /// the data stored
1971 	TreeNode!(T)* parentPtr; /// pointer to the parent node, if this is null, this is the root of the tree
1972 	TreeNode!(T)*[] childNodes; /// stores child nodes
1973 	/// constructor
1974 	this(T dataToStore){
1975 		data = dataToStore;
1976 	}
1977 	/// constructor
1978 	this(TreeNode!(T)* parent){
1979 		parentPtr = parent;
1980 	}
1981 	/// constructor
1982 	this(TreeNode!(T)*[] children){
1983 		childNodes = children.dup;
1984 	}
1985 	/// constructor
1986 	this(T dataToStore, TreeNode!(T)*[] children, TreeNode!(T)* parent){
1987 		data = dataToStore;
1988 		childNodes = children.dup;
1989 		parentPtr = parent;
1990 	}
1991 }
1992 /// To make reading a Tree (made up of TreeNode) a bit easier
1993 /// 
1994 /// and while using it, make sure you do not make a loop in TreeNodes by putting a parent or parent's parent in a node's childNodes,
1995 /// doing so will cause an infinite loop, TreeReader cannot currently handle this
1996 struct TreeReader(T){
1997 	/// the root node
1998 	TreeNode!(T)* root;
1999 	/// .destroy()s children of the root, including children of children and so on, the root is also .destroy-ed
2000 	void clear(){
2001 		/// called by iterate to destroy a node
2002 		static bool destroyNode(TreeNode!(T)* node){
2003 			.destroy(*node);
2004 			return true;
2005 		}
2006 		// start killing every node
2007 		this.iterate(&destroyNode);
2008 	}
2009 	/// counts and returns number of nodes in the tree
2010 	/// 
2011 	/// Returns: the number of nodes in the tree, counting all child-nodes and their child-nodes and so on
2012 	uinteger count(){
2013 		// stores the count
2014 		uinteger r = 0;
2015 		/// used to "receive" nodes from iterate
2016 		bool increaseCount(TreeNode!(T)* node){
2017 			r ++;
2018 			return true;
2019 		}
2020 		// start counting
2021 		iterate(&increaseCount);
2022 		return r;
2023 	}
2024 	/// counts and returns number of nodes in the tree
2025 	/// 
2026 	/// if `doCount` is not null, only nodes for which `doCount` function returns true will be counted
2027 	/// 
2028 	/// Returns: number of nodes for which `doCount(node)` returned true
2029 	uinteger count(bool function(TreeNode!(T)*) doCount=null){
2030 		/// stores the count
2031 		uinteger r = 0;
2032 		/// used to "receive" nodes from iterate
2033 		bool increaseCount(TreeNode!(T)* node){
2034 			if (doCount !is null && (*doCount)(node)){
2035 				r ++;
2036 			}
2037 			return true;
2038 		}
2039 		// start counting
2040 		iterate(&increaseCount);
2041 		return r;
2042 	}
2043 	/// calls a function on every node
2044 	///
2045 	/// loop is terminated as soon as false is returned from function
2046 	/// No recursion is used, as it uses a stack to store which nodes it has to call a function on
2047 	void iterate(bool function(TreeNode!(T)*) func){
2048 		if (func is null){
2049 			throw new Exception ("func cannot be null in iterate");
2050 		}
2051 		/// stores all the nodes of whose childNodes's  have to be sent
2052 		Stack!(TreeNode!(T)*) nodes = new Stack!(TreeNode!(T)*);
2053 		/// start from root
2054 		nodes.push(root);
2055 		while (nodes.count > 0){
2056 			/// the node whose childs are being currently being "sent":
2057 			TreeNode!(T)* currentNode = nodes.pop;
2058 			// "send" this node
2059 			func(currentNode);
2060 			// and have to send their childNodes too
2061 			foreach (childPtr; (*currentNode).childNodes){
2062 				nodes.push(childPtr);
2063 			}
2064 		}
2065 		.destroy(nodes);
2066 	}
2067 	/// calls a delegate on every node
2068 	///
2069 	/// loop is terminated as soon as false is returned from function
2070 	/// No recursion is used, as it uses a stack to store which nodes it has to call a delegate on
2071 	void iterate(bool delegate(TreeNode!(T)*) func){
2072 		if (func is null){
2073 			throw new Exception ("func cannot be null in iterate");
2074 		}
2075 		/// stores all the nodes of whose childNodes's  have to be sent
2076 		Stack!(TreeNode!(T)*) nodes = new Stack!(TreeNode!(T)*);
2077 		/// start from root
2078 		nodes.push(root);
2079 		while (nodes.count > 0){
2080 			/// the node whose childs are being currently being "sent":
2081 			TreeNode!(T)* currentNode = nodes.pop;
2082 			// "send" this node
2083 			func(currentNode);
2084 			// and have to send their childNodes too
2085 			foreach (childPtr; (*currentNode).childNodes){
2086 				nodes.push(childPtr);
2087 			}
2088 		}
2089 		.destroy(nodes);
2090 	}
2091 }
2092 ///
2093 unittest{
2094 	TreeReader!int tree;
2095 	// testing iterate
2096 	// make a sample tree
2097 	TreeNode!int rootNode;
2098 	rootNode.data = 0;
2099 	// childNodes of root
2100 	TreeNode!int rootChild0 = TreeNode!int(1), rootChild1=TreeNode!int(2);
2101 	// childNodes of rootChild0
2102 	TreeNode!int child0child0 = TreeNode!int(3), child0child1 = TreeNode!int(4);
2103 	// childNodes of rootChild1
2104 	TreeNode!int child1child0 = TreeNode!int(5), child1child1 = TreeNode!int(6);
2105 	// arrange them in a tree
2106 	rootNode.childNodes = [&rootChild0, &rootChild1];
2107 	rootChild0.childNodes = [&child0child0, &child0child1];
2108 	rootChild1.childNodes = [&child1child0, &child1child1];
2109 	tree.root = &rootNode;
2110 	// check if iterate's working
2111 	int[] iteratedNodes;
2112 	tree.iterate((TreeNode!(int)* node){iteratedNodes ~= (*node).data; return true;});
2113 	// make sure each number was iterated
2114 	assert ([0,1,2,3,4,5,6].matchElements(iteratedNodes), "TreeReader.iterate did not iterate through all nodes");
2115 	/// now test count
2116 	assert (tree.count == 7, "TreeReader.count returned invalid count");
2117 	/// thats all unit tests for now, so destroy all nodes now
2118 	tree.clear;
2119 }