1 /// 2 module eerange.base; 3 4 @safe: 5 6 /// 7 struct EachWithEachOtherRangeBase 8 { 9 @nogc: 10 11 package size_t srcLength; 12 13 /// 14 this(size_t srcLen) pure nothrow 15 { 16 srcLength = srcLen; 17 } 18 19 /// 20 size_t length() pure const nothrow 21 { 22 const len = srcLength; 23 24 return (len * len - len) / 2; 25 } 26 27 private static struct Coords 28 { 29 size_t x; 30 size_t y; 31 } 32 33 private Coords coordsInSquare(size_t idx) pure 34 { 35 return Coords( 36 idx % srcLength, 37 idx / srcLength 38 ); 39 } 40 41 /// 42 size_t[2] opIndex(size_t idx) pure 43 { 44 version(D_NoBoundsChecks){} 45 else 46 { 47 import core.exception: RangeError; 48 49 if(idx >= length) 50 throw new RangeError; 51 } 52 53 Coords coords = coordsInSquare(idx); 54 55 import std.traits; 56 static assert(isMutable!(typeof(coords))); 57 58 if(coords.x <= coords.y) // under diagonal line? 59 { 60 const latestIdx = srcLength - 1; 61 62 // Mirroring coords 63 coords.x = latestIdx - coords.x; 64 coords.y = latestIdx - coords.y - 1; // shifted above diagonal 65 } 66 67 return [coords.x, coords.y]; 68 } 69 } 70 71 unittest 72 { 73 import std.parallelism; 74 75 enum srcLen = 4; 76 77 auto r = EachWithEachOtherRangeBase(srcLen); 78 79 size_t cnt; 80 81 foreach(i; 0 .. r.length) 82 { 83 auto pair = r[i]; 84 85 cnt++; 86 } 87 88 assert(cnt == 6); 89 }