1 /// "Each with each other" random range 2 module eerange.randomrange; 3 4 import eerange.base; 5 6 @safe: 7 8 /// 9 @nogc struct EachWithEachOtherRandomAccessRange(R) 10 { 11 EachWithEachOtherRangeBase!R base; 12 alias base this; 13 14 private size_t fwdIdx = 0; 15 private size_t backIdx; 16 17 /// 18 this(R r) 19 { 20 base = EachWithEachOtherRangeBase!R(r); 21 22 backIdx = length - 1; 23 } 24 25 /// 26 bool empty() const 27 { 28 return fwdIdx >= length || backIdx < 0; 29 } 30 31 auto front() { 32 version(D_NoBoundsChecks){} 33 else 34 assert(!empty); 35 36 return opIndex(fwdIdx); 37 } 38 39 auto back() { 40 version(D_NoBoundsChecks){} 41 else 42 assert(!empty); 43 44 return opIndex(backIdx); 45 } 46 47 /// 48 void popFront() { fwdIdx++; } 49 50 /// 51 void popBack() { backIdx--; } 52 53 /// 54 EachWithEachOtherRandomAccessRange!R save() { return this; } 55 } 56 57 /// 58 auto eeRandomRange(T)(T inputRange) pure @nogc 59 { 60 return EachWithEachOtherRandomAccessRange!(T)(inputRange); 61 } 62 63 unittest 64 { 65 import std.range.primitives; 66 import std.traits; 67 68 alias R = EachWithEachOtherRandomAccessRange!(int[]); 69 70 static assert(is(typeof(lvalueOf!R[1]) == ElementType!R)); 71 static assert(isInputRange!R); 72 static assert(is(ReturnType!((R r) => r.save) == R)); 73 static assert(isForwardRange!R); 74 static assert(isBidirectionalRange!R); 75 static assert(isRandomAccessRange!R); 76 } 77 78 @trusted unittest 79 { 80 import std.range: iota; 81 import std.parallelism; 82 83 enum testSize = 100; 84 85 auto eeRandom = iota(0, testSize).eeRandomRange; 86 auto randomRes = taskPool.amap!("a[0]", "a[1]")(eeRandom); 87 88 size_t[testSize] cnt; 89 90 foreach(r; randomRes) 91 { 92 cnt[r[0]]++; 93 cnt[r[1]]++; 94 } 95 96 foreach(r; cnt) 97 assert(r == testSize-1); 98 }