1 /// "Each with each other" random range 2 module eerange.base; 3 4 @safe: 5 6 /// 7 @nogc struct EachWithEachOtherRangeBase(R) 8 { 9 private R srcRange; 10 11 /// 12 this(R r) 13 { 14 srcRange = r; 15 } 16 17 /// 18 size_t length() const pure 19 { 20 const len = srcRange.length; 21 22 return (len * len - len) / 2; 23 } 24 25 private static struct Coords 26 { 27 size_t x; 28 size_t y; 29 } 30 31 private Coords coordsInSquare(size_t idx) const pure 32 { 33 return Coords( 34 idx % srcRange.length, 35 idx / srcRange.length 36 ); 37 } 38 39 import std.range.primitives: ElementType; 40 41 private alias T = ElementType!R; 42 43 private T[2] getElemBySquareCoords(Coords c) const pure 44 { 45 return [srcRange[c.x], srcRange[c.y]]; 46 } 47 48 /// 49 T[2] opIndex(size_t idx) const pure 50 { 51 assert(idx < length); 52 53 Coords coords = coordsInSquare(idx); 54 55 if(coords.x <= coords.y) // under diagonal line? 56 { 57 const latestIdx = srcRange.length - 1; 58 59 // Mirroring coords 60 coords.x = latestIdx - coords.x; 61 coords.y = latestIdx - coords.y - 1; // shifted above diagonal 62 } 63 64 return getElemBySquareCoords(coords); 65 } 66 } 67 68 unittest 69 { 70 import std.parallelism; 71 72 int[] arr = [100, 200, 300, 400]; 73 74 auto r = EachWithEachOtherRangeBase!(int[])(arr); 75 76 size_t cnt; 77 78 foreach(i; 0 .. r.length) 79 { 80 auto pair = r[i]; 81 82 cnt++; 83 } 84 85 assert(cnt == 6); 86 }