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