1 module nxt.permutations; 2 3 import std.range.primitives: isInputRange; 4 5 /** Cartesian power. 6 See_Also: http://forum.dlang.org/thread/mailman.1434.1339436657.24740.digitalmars-d-learn@puremagic.com#post-uftixibnvfffugjwsdbl:40forum.dlang.org 7 */ 8 struct CartesianPower(bool doCopy = true, T) 9 { 10 T[] items; 11 ulong repeat; 12 T[] row; 13 ulong i, maxN; 14 15 this(T[] items_, in uint repeat_, T[] buffer) 16 { 17 this.items = items_; 18 this.repeat = repeat_; 19 row = buffer[0 .. repeat]; 20 row[] = items[0]; 21 maxN = items.length ^^ repeat; 22 } 23 24 static if (doCopy) 25 { 26 @property T[] front() 27 { 28 return row.dup; 29 } 30 } 31 else 32 { 33 @property T[] front() 34 { 35 return row; 36 } 37 } 38 39 @property bool empty() const @safe pure nothrow @nogc 40 { 41 return i >= maxN; 42 } 43 44 void popFront() 45 { 46 i++; 47 if (empty) { return; } 48 ulong n = i; 49 size_t count = repeat - 1; 50 while (n) 51 { 52 row[count] = items[n % items.length]; 53 count--; 54 n /= items.length; 55 } 56 } 57 } 58 59 version(unittest) 60 { 61 import nxt.array_help : s; 62 static assert(isInputRange!(typeof([1, 2].s[].cartesianPower!false(4)))); 63 } 64 65 auto cartesianPower(bool doCopy = true, T)(T[] items, in uint repeat) 66 pure nothrow @safe 67 { 68 return CartesianPower!(doCopy, T)(items, repeat, new T[repeat]); 69 } 70 71 auto cartesianPower(bool doCopy = true, T)(T[] items, in uint repeat, T[] buffer) 72 pure nothrow @safe @nogc 73 { 74 if (buffer.length >= repeat) 75 { 76 return CartesianPower!(doCopy, T)(items, repeat, buffer); 77 } 78 else 79 { 80 // Is this correct in presence of chaining? 81 static immutable err = new Error("buffer.length < repeat"); 82 throw err; 83 } 84 } 85 86 @safe pure nothrow @nogc unittest 87 { 88 int[2] items = [1, 2]; 89 const n = 4; 90 int[n] buf; 91 import std.algorithm.comparison : equal; 92 assert(items.cartesianPower!false(n, buf) 93 .equal([[1, 1, 1, 1].s[], 94 [1, 1, 1, 2].s[], 95 [1, 1, 2, 1].s[], 96 [1, 1, 2, 2].s[], 97 [1, 2, 1, 1].s[], 98 [1, 2, 1, 2].s[], 99 [1, 2, 2, 1].s[], 100 [1, 2, 2, 2].s[], 101 [2, 1, 1, 1].s[], 102 [2, 1, 1, 2].s[], 103 [2, 1, 2, 1].s[], 104 [2, 1, 2, 2].s[], 105 [2, 2, 1, 1].s[], 106 [2, 2, 1, 2].s[], 107 [2, 2, 2, 1].s[], 108 [2, 2, 2, 2].s[]].s[])); 109 }