PageRenderTime 84ms CodeModel.GetById 23ms app.highlight 55ms RepoModel.GetById 1ms app.codeStats 1ms

/data/iterable.d

http://github.com/wilkie/djehuty
D | 828 lines | 653 code | 108 blank | 67 comment | 95 complexity | 38dadcbcfaaf0ad79c19d42c382617fe MD5 | raw file
  1module data.iterable;
  2
  3import djehuty;
  4import io.console;
  5
  6// Description: This template resolves to true when the type T is
  7//   either an array or a class that inherits from Iterable.
  8template IsIterableImpl(int idx = 0, Base, T...) {
  9	static if (idx == T.length) {
 10		// Go to the base class and start over...
 11		const bool IsIterableImpl = IsIterable!(Super!(Base));
 12	}
 13	else static if (IsInterface!(T[idx])) {
 14		// Check each interface for whether it is Iterable
 15		static if (T[idx].stringof == "Iterable") {
 16			const bool IsIterableImpl = true;
 17		}
 18		else {
 19			const bool IsIterableImpl = IsIterableImpl!(idx+1, Base, T);
 20		}
 21	}
 22	else {
 23		// Well... this doesn't make sense... give up!
 24		const bool IsIterableImpl = false;
 25	}
 26}
 27
 28template IsIterable(T) {
 29	static if (IsArray!(T)) {
 30		// T is an array, so it is iterable
 31		const bool IsIterable = true;
 32	}
 33	else static if (is(T == Object)) {
 34		// Cannot be iterable if T is Object
 35		const bool IsIterable = false;
 36	}
 37	else static if (IsInterface!(T)) {
 38		static if (T.stringof == "Iterable") {
 39			const bool IsIterable = true;
 40		}
 41		else {
 42			const bool IsIterable = false;
 43		}
 44	}
 45	else static if (IsClass!(T)) {
 46		// It is some class... we should read its interfaces
 47		const bool IsIterable = IsIterableImpl!(0, T, Interfaces!(T));
 48	}
 49	else {
 50		// It is some other type...
 51		const bool IsIterable = false;
 52	}
 53}
 54
 55// Description: Returns Iterable!(T) for any class that inherits Iterable.
 56template BaseIterable(T) {
 57	static if (IsClass!(T)) {
 58		static if (is(T == Object)) {
 59			alias T BaseIterable;
 60		}
 61		else {
 62			alias BaseIterable!(Super!(T)) BaseIterable;
 63		}
 64	}
 65	static if (IsInterface!(T)) {
 66		alias T BaseIterable;
 67	}
 68	else {
 69		alias T BaseIterable;
 70	}
 71}
 72
 73// Description: This template resolves to the base type for any class that
 74//   inherits Iterable or any array. That is int[][] will return int.
 75//   And List!(List!(int)) will return int.
 76template BaseIterableType(T) {
 77	static if (IsIterable!(IterableType!(T))) {
 78		alias BaseIterableType!(IterableType!(T)) BaseIterableType;
 79	}
 80	else {
 81		alias IterableType!(T) BaseIterableType;
 82	}
 83}
 84
 85// Description: This template resolves to the iterated type for any class that
 86//   inherits Iterable or any array. That is int[][] will return int[].
 87//   And List!(List!(int)) will return List!(int). int[] will return int.
 88template IterableType(T) {
 89	static if (IsIterable!(T)) {
 90		static if (IsArray!(T)) {
 91			alias ArrayType!(T) IterableType;
 92		}
 93		else {
 94			alias T.BaseType IterableType;
 95		}
 96	}
 97	else {
 98		alias T IterableType;
 99	}
100}
101
102interface Iterable(T) {
103	private alias T BaseType;
104
105	template add(R) {
106		void add(R item);
107	}
108
109	template addAt(R) {
110		void addAt(R item, size_t idx);
111	}
112
113	T remove();
114	T removeAt(size_t idx);
115
116	T peek();
117	T peekAt(size_t idx);
118
119	template set(R) {
120		void set(R value);
121	}
122
123	template setAt(R) {
124		void setAt(size_t idx, R value);
125	}
126
127	template apply(R, S) {
128		void apply(R delegate(S) func);
129	}
130
131	template contains(R) {
132		bool contains(R value);
133	}
134
135	bool empty();
136	void clear();
137	T[] array();
138	Iterable!(T) dup();
139	Iterable!(T) slice(size_t start, size_t end);
140	Iterable!(T) reverse();
141	size_t length();
142
143	T opIndex(size_t i1);
144
145	template opIndexAssign(R) {
146		size_t opIndexAssign(R value, size_t i1);
147	}
148
149	int opApply(int delegate(ref T) loopFunc);
150	int opApply(int delegate(ref size_t, ref T) loopFunc);
151
152	int opApplyReverse(int delegate(ref T) loopFunc);
153	int opApplyReverse(int delegate(ref size_t, ref T) loopFunc);
154
155	Iterable!(T) opCat(T[] list);
156	Iterable!(T) opCat(Iterable!(T) list);
157	Iterable!(T) opCat(T item);
158
159	void opCatAssign(T[] list);
160	void opCatAssign(Iterable!(T) list);
161	void opCatAssign(T item);
162
163}
164
165int[] range(int start, int end) {
166	int[] ret = new int[end-start];
167	for (int i = start, o; i < end; i++, o++) {
168		ret[o] = i;
169	}
170	return ret;
171}
172
173template filter(T, S) {
174	static assert(IsIterable!(T), "filter: " ~ T.stringof ~ " is not iterable.");
175	T filter(bool delegate(S) pred, T list) {
176		T ret;
177		static if (!IsArray!(T)) {
178			ret = new T;
179		}
180		foreach(item; list) {
181			if (pred(item)) {
182				ret ~= item;
183			}
184		}
185		return ret;
186	}
187}
188
189template filter(T, S) {
190	static assert(IsIterable!(T), "filter: " ~ T.stringof ~ " is not iterable.");
191    T filter(bool function(S) pred, T list) {
192        T ret;
193		static if (!IsArray!(T)) {
194			ret = new T;
195		}
196        foreach(item; list) {
197            if (pred(item)) {
198                ret ~= item;
199            }
200        }
201        return ret;
202    }
203}
204
205template count(T, S) {
206	static assert(IsIterable!(T), "count: " ~ T.stringof ~ " is not iterable.");
207	size_t count(bool delegate(S) pred, T list) {
208		size_t acc = 0;
209        foreach(item; list) {
210            if (pred(item)) {
211            	acc++;
212            }
213        }
214        return acc;
215	}
216}
217
218template count(T, S) {
219	static assert(IsIterable!(T), "count: " ~ T.stringof ~ " is not iterable.");
220	size_t count(bool function(S) pred, T list) {
221		size_t acc = 0;
222        foreach(item; list) {
223            if (pred(item)) {
224            	acc++;
225            }
226        }
227        return acc;
228	}
229}
230
231template filterNot(T, S) {
232	static assert(IsIterable!(T), "filterNot: " ~ T.stringof ~ " is not iterable.");
233	T filterNot(bool delegate(S) pred, T list) {
234		T ret;
235		static if (!IsArray!(T)) {
236			ret = new T;
237		}
238		foreach(item; list) {
239			if (!pred(item)) {
240				ret ~= item;
241			}
242		}
243		return ret;
244	}
245}
246
247template filterNot(T, S) {
248	static assert(IsIterable!(T), "filterNot: " ~ T.stringof ~ " is not iterable.");
249    T filterNot(bool function(S) pred, T list) {
250        T ret;
251		static if (!IsArray!(T)) {
252			ret = new T;
253		}
254        foreach(item; list) {
255            if (!pred(item)) {
256                ret ~= item;
257            }
258        }
259        return ret;
260    }
261}
262
263template map(T, R, S) {
264	static assert(IsIterable!(T), "map: " ~ T.stringof ~ " is not iterable.");
265    S[] map(S delegate(R) func, T list) {
266		S[] ret;
267		ret = new S[list.length];
268
269        foreach(size_t i, R item; list) {
270			ret[i] = func(item);
271        }
272
273        return ret;
274    }
275}
276
277template map(T, R, S) {
278	static assert(IsIterable!(T), "map: " ~ T.stringof ~ " is not iterable.");
279    S[] map(S function(R) func, T list) {
280		S[] ret;
281		ret = new S[list.length];
282
283        foreach(uint i, item; list) {
284			ret[i] = func(item);
285        }
286
287        return ret;
288    }
289}
290
291template foldl(T, R, S) {
292	static assert(IsIterable!(T), "foldl: " ~ T.stringof ~ " is not iterable.");
293	S foldl(S delegate(R, R) func, T list) {
294		if (list.length == 1) {
295			return cast(S)list[0];
296		}
297		S acc = func(list[0], list[1]);
298		foreach(item; list[2..list.length]) {
299			acc = func(acc, item);
300		}
301		return acc;
302	}
303}
304
305template foldl(T, R, S) {
306	static assert(IsIterable!(T), "foldl: " ~ T.stringof ~ " is not iterable.");
307	S foldl(S function(R, R) func, T list) {
308		if (list.length == 1) {
309			return cast(S)list[0];
310		}
311		S acc = func(list[0], list[1]);
312		foreach(item; list[2..list.length]) {
313			acc = func(acc, item);
314		}
315		return acc;
316	}
317}
318
319template foldr(T, R, S) {
320	static assert(IsIterable!(T), "foldr: " ~ T.stringof ~ " is not iterable.");
321	S foldr(S delegate(R, R) func, T list) {
322		if (list.length == 1) {
323			return cast(S)list[0];
324		}
325		S acc = func(list[list.length-2], list[list.length-1]);
326		foreach_reverse(item; list[0..list.length-2]) {
327			acc = func(item, acc);
328		}
329		return acc;
330	}
331}
332
333template foldr(T, R, S) {
334	static assert(IsIterable!(T), "foldr: " ~ T.stringof ~ " is not iterable.");
335	S foldr(S function(R, R) func, T list) {
336		if (list.length == 1) {
337			return cast(S)list[0];
338		}
339		S acc = func(list[list.length-2], list[list.length-1]);
340		foreach_reverse(item; list[0..list.length-2]) {
341			acc = func(item, acc);
342		}
343		return acc;
344	}
345}
346
347template member(T, S) {
348	static assert(IsIterable!(T), "member: " ~ T.stringof ~ " is not iterable.");
349	T member(S value, T list) {
350		foreach(size_t i, S item; list) {
351			if (value == item) {
352				return cast(T)(list[i..list.length]);
353			}
354		}
355		return null;
356	}
357}
358
359template remove(T, S) {
360	static assert(IsIterable!(T), "remove: " ~ T.stringof ~ " is not iterable.");
361	T remove(S value, T list) {
362		foreach(uint i, item; list) {
363			if (value == item) {
364				return cast(T)(list[0..i] ~ list[i+1..list.length]);
365			}
366		}
367		return list;
368	}
369}
370
371template remove(T, S, R, Q) {
372	static assert(IsIterable!(T), "remove: " ~ T.stringof ~ " is not iterable.");
373	T remove(S value, T list, bool delegate(R, Q) equalFunc) {
374		foreach(uint i, item; list) {
375			if (equalFunc(value, item)) {
376				return cast(T)(list[0..i] ~ list[i+1..list.length]);
377			}
378		}
379		return list;
380	}
381}
382
383template car(T) {
384	static assert(IsIterable!(T), "car: " ~ T.stringof ~ " is not iterable.");
385	IterableType!(T) car(T list) {
386		return list[0];
387	}
388}
389
390template cdr(T) {
391	static assert(IsIterable!(T), "cdr: " ~ T.stringof ~ " is not iterable.");
392	T cdr(T list) {
393		return list[1..list.length];
394	}
395}
396
397template cadr(T) {
398	static assert(IsIterable!(T), "cadr: " ~ T.stringof ~ " is not iterable.");
399	IterableType!(T) cadr(T list) {
400		return car(cdr(list));
401	}
402}
403
404template caar(T) {
405	static assert(IsIterable!(T), "caar: " ~ T.stringof ~ " is not iterable.");
406	static assert(IsIterable!(IterableType!(T)), "caar: " ~ T.stringof ~ "'s inner type (" ~ IterableType!(T).stringof ~ ") is not iterable.");
407	IterableType!(IterableType!(T)) caar(T list) {
408		return car(car(list));
409	}
410}
411
412template first(T) {
413	static assert(IsIterable!(T), "first: " ~ T.stringof ~ " is not iterable.");
414	IterableType!(T) first(T list) {
415		return list[0];
416	}
417}
418
419template second(T) {
420	static assert(IsIterable!(T), "second: " ~ T.stringof ~ " is not iterable.");
421	IterableType!(T) second(T list) {
422		return list[1];
423	}
424}
425
426template third(T) {
427	static assert(IsIterable!(T), "third: " ~ T.stringof ~ " is not iterable.");
428	IterableType!(T) third(T[] list) {
429		return list[2];
430	}
431}
432
433template fourth(T) {
434	static assert(IsIterable!(T), "fourth: " ~ T.stringof ~ " is not iterable.");
435	IterableType!(T) fourth(T list) {
436		return list[3];
437	}
438}
439
440template fifth(T) {
441	static assert(IsIterable!(T), "fifth: " ~ T.stringof ~ " is not iterable.");
442	IterableType!(T) fifth(T list) {
443		return list[4];
444	}
445}
446
447template sixth(T) {
448	static assert(IsIterable!(T), "sixth: " ~ T.stringof ~ " is not iterable.");
449	IterableType!(T) sixth(T list) {
450		return list[5];
451	}
452}
453
454template seventh(T) {
455	static assert(IsIterable!(T), "seventh: " ~ T.stringof ~ " is not iterable.");
456	IterableType!(T) seventh(T list) {
457		return list[6];
458	}
459}
460
461template eighth(T) {
462	static assert(IsIterable!(T), "eighth: " ~ T.stringof ~ " is not iterable.");
463	IterableType!(T) eighth(T list) {
464		return list[7];
465	}
466}
467
468template ninth(T) {
469	static assert(IsIterable!(T), "ninth: " ~ T.stringof ~ " is not iterable.");
470	IterableType!(T) ninth(T list) {
471		return list[8];
472	}
473}
474
475template tenth(T) {
476	static assert(IsIterable!(T), "tenth: " ~ T.stringof ~ " is not iterable.");
477	IterableType!(T) tenth(T list) {
478		return list[9];
479	}
480}
481
482template last(T) {
483	static assert(IsIterable!(T), "last: " ~ T.stringof ~ " is not iterable.");
484	IterableType!(T) last(T list) {
485		return list[list.length-1];
486	}
487}
488
489template rest(T) {
490	static assert(IsIterable!(T), "rest: " ~ T.stringof ~ " is not iterable.");
491	T rest(T list) {
492		return list[1..list.length];
493	}
494}
495
496template drop(T) {
497	static assert(IsIterable!(T), "drop: " ~ T.stringof ~ " is not iterable.");
498	T drop(T list, uint num) {
499		return list[num..list.length];
500	}
501}
502
503template dropRight(T) {
504	static assert(IsIterable!(T), "dropRight: " ~ T.stringof ~ " is not iterable.");
505	T dropRight(T list, uint num) {
506		return list[0..list.length-num];
507	}
508}
509
510template take(T) {
511	static assert(IsIterable!(T), "take: " ~ T.stringof ~ " is not iterable.");
512	T take(T list, uint num) {
513		return list[0..num];
514	}
515}
516
517template takeRight(T) {
518	static assert(IsIterable!(T), "takeRight: " ~ T.stringof ~ " is not iterable.");
519	T takeRight(T list, uint num) {
520		return list[list.length-num..list.length];
521	}
522}
523
524template flatten(T) {
525	static assert(IsIterable!(T), "flatten: " ~ T.stringof ~ " is not iterable.");
526	BaseIterableType!(T)[] flatten(T list) {
527		static if (IsIterable!(IterableType!(T))) {
528			// recursive
529			BaseIterableType!(T)[] ret;
530			foreach(sublist; list) {
531				ret ~= flatten(sublist);
532			}
533			return ret;
534		}
535		else {
536			// base case
537			BaseIterableType!(T)[] ret;
538			foreach(item; list) {
539				ret ~= item;
540			}
541			return ret;
542		}
543	}
544}
545
546template argmin(T, R, S) {
547	static assert(IsIterable!(T), "argmin: " ~ T.stringof ~ " is not iterable.");
548	IterableType!(T) argmin(S delegate(R) func, T list) {
549		IterableType!(T) min;
550		uint idx = uint.max;
551		foreach(uint i, item; list) {
552			S cur = func(item);
553			if (idx == uint.max || cur < min) {
554				idx = i;
555				min = item;
556			}
557		}
558		return min;
559	}
560}
561
562template argmin(T, R, S) {
563	static assert(IsIterable!(T), "argmin: " ~ T.stringof ~ " is not iterable.");
564	IterableType!(T) argmin(S function(R) func, T list) {
565		IterableType!(T) min;
566		uint idx = uint.max;
567		foreach(uint i, item; list) {
568			S cur = func(item);
569			if (idx == uint.max || cur < min) {
570				idx = i;
571				min = item;
572			}
573		}
574		return min;
575	}
576}
577
578template argmax(T, R, S) {
579	static assert(IsIterable!(T), "argmax: " ~ T.stringof ~ " is not iterable.");
580	IterableType!(T) argmax(S delegate(R) func, T list) {
581		IterableType!(T) max;
582		uint idx = uint.max;
583		foreach(uint i, item; list) {
584			S cur = func(item);
585			if (idx == uint.max || cur > max) {
586				idx = i;
587				max = item;
588			}
589		}
590		return max;
591	}
592}
593
594template argmax(T, R, S) {
595	static assert(IsIterable!(T), "argmax: " ~ T.stringof ~ " is not iterable.");
596	IterableType!(T) argmax(S function(R) func, T list) {
597		IterableType!(T) max;
598		uint idx = uint.max;
599		foreach(uint i, item; list) {
600			S cur = func(item);
601			if (idx == uint.max || cur > max) {
602				idx = i;
603				max = item;
604			}
605		}
606		return max;
607	}
608}
609
610template makeList(T) {
611	T[] makeList(uint amt, T item) {
612		T[] ret = new T[amt];
613		ret[] = item;
614		return ret;
615	}
616}
617
618template addBetween(T, S) {
619	T addBetween(T list, S val) {
620		T ret;
621		static if (!IsArray!(T)) {
622			ret = new T;
623		}
624		for (uint i; i < list.length - 1; i++) {
625			ret ~= [list[i], val];
626		}
627		ret ~= [list[list.length-1]];
628
629		return ret;
630	}
631}
632
633// Description: This function will rotate an array by shifting the contents in place.
634// list: An Iterable type.
635// amount: The amount to rotate to the left. To rotate to the right, specify a negative value.
636// Returns: Simply returns the reference to the input.
637template rotate(T) {
638	static assert(IsIterable!(T), "rotate: " ~ T.stringof ~ " is not iterable.");
639	IterableType!(T)[] rotate(T list, int amount) {
640		if (list.length == 0) {
641			return list;
642		}
643
644		amount %= list.length;
645		if (amount == 0) {
646			return list;
647		}
648
649		IterableType!(T) tmp;
650
651		size_t iterations = 1;
652		if ((list.length % amount) == 0) {
653			// Will require multiple passes
654			iterations = amount;
655		}
656
657		// Figure out the number of swaps per iteration
658		size_t maxSwaps = list.length / iterations;
659		maxSwaps--;		// account for final swap outside of loop
660
661		while(iterations > 0) {
662			size_t swapWith;
663			size_t swapIndex = iterations-1;
664			tmp = list[swapIndex];
665			for (size_t i = 0; i < maxSwaps; i++) {
666				swapWith = (swapIndex + amount) % list.length;
667				list[swapIndex] = list[swapWith];
668				swapIndex = swapWith;
669			}
670			list[swapIndex] = tmp;
671
672			iterations--;
673		}
674
675		return list;
676	}
677}
678
679// Description: This function will reverse the contents of the array in place. It will respect unicode
680//   encoding in terms of grouping combining marks for utf encoded strings.
681// list: An Iterable type.
682// Returns: Simply returns the reference to the input.
683template reverse(T) {
684	static assert(IsIterable!(T), "reverse: " ~ T.stringof ~ " is not iterable.");
685	IterableType!(T)[] reverse(T list) {
686		static if (IsCharType!(IterableType!(T))) {
687			// We are reversing a unicode string
688			return unicode_reverse(list);
689		}
690		else {
691			// Normal reverse
692			size_t front, end;
693
694			// Go from front to end, and swap each index
695
696			// Note: Since the array passed has a length measured in a factor
697			//   of elementSize, we need to account for that when we treat
698			//   it is a byte array.
699
700			if (list.length == 0) {
701				return list;
702			}
703
704			front = 0;
705			end = list.length-1;
706
707			while(front < end) {
708				IterableType!(T) tmp = list[front];
709				list[front] = list[end];
710				list[end] = tmp;
711
712				front++;
713				end--;
714			}
715
716			return list;
717		}
718	}
719}
720
721// This internal function will reverse a unicode string of any flavor.
722private template unicode_reverse(T) {
723	T[] unicode_reverse(T[] a) {
724		// for all elements in 'a'
725		// A: Identify two substrings to swap
726		// B: Swap
727
728		size_t frontIndex = 0;
729		size_t frontLength = 0;
730
731		size_t endIndex = a.length;
732		size_t endLength = 0;
733
734		size_t swapLength = 0;
735		int swapRotate = 0;
736
737		// Two sections will swap: 
738		// - a[frontIndex..frontIndex+frontLength]
739		// - a[endIndex..endIndex+endLength]
740
741		// If the two sections do not completely match up, it passes
742		// responsibility to the next iteration to move the remaining elements.
743
744		// Like so:
745		// [0][1][ ][ ][ ][ ][2][3][4]
746		//  \- frontIndex
747		// |----| frontLength
748		//                    \- endIndex
749		//                   |-------| endLength
750
751		// Will become:
752		// [2][3][ ][ ][ ][ ][4][0][1]
753		//       |-------------| next iteration
754		//                    \- endIndex
755		//                   |-| - endLength
756
757		// The next iteration will move the remaining elements to the front during
758		// the swap phase. This is done to avoid phase shifting an array and to
759		// promote a O(1) space complexity.
760
761		while(frontIndex <= endIndex) {
762			// Find length of next substring to swap
763			if (frontLength == 0) {
764				frontLength = 1;
765				while(!Unicode.isStartChar(a[frontIndex+frontLength]) 
766						|| Unicode.isDeadChar(a[frontIndex+frontLength..$])) {
767					if (frontIndex + frontLength == endIndex) {
768						// Do not count it if it is within the endIndex,
769						// This would mean the combining marks have been swapped onto another character
770						break;
771					}
772					frontLength++;
773				}
774			}
775
776			// Find length of next substring from end to swap with
777			if (endLength == 0) {
778				endIndex--;
779				while(!Unicode.isStartChar(a[endIndex]) 
780						|| Unicode.isDeadChar(a[endIndex..$])) {
781					endIndex--;
782					endLength++;
783				}
784				endLength++;
785			}
786
787			if (frontIndex + frontLength > endIndex) {
788				// We do not have to move the middle substring
789				break;
790			}
791
792			// Figure out the number to swap (lowest length)
793			if (frontLength < endLength) {
794				swapLength = frontLength;
795				swapRotate = cast(int)(swapLength);
796
797				// Shift end
798				a[endIndex..endIndex+endLength].rotate(swapRotate);
799			}
800			else {
801				swapLength = endLength;
802				swapRotate = cast(int)(cast(long)frontLength - cast(long)swapLength);
803
804				// Shift front
805				a[frontIndex..frontIndex+frontLength].rotate(swapRotate);
806			}
807
808			// xor swap front and end
809			for(size_t swapCount = 0; swapCount < swapLength; swapCount++) {
810				size_t index1 = frontIndex + swapCount;
811				size_t index2 = endIndex + endLength - swapLength + swapCount;
812				a[index1] ^= a[index2];
813				a[index2] ^= a[index1];
814				a[index1] ^= a[index2];
815			}
816
817			// Move to next position in string
818			frontIndex += swapLength;
819
820			frontLength -= swapLength;
821			endLength -= swapLength;
822		}
823
824		return a;
825	}
826}
827
828