1 /// "Each with each other" random range 2 module eerange.randomrange; 3 4 import eerange.base; 5 6 @safe: 7 8 /// 9 struct EachWithEachOtherRandomAccessRange 10 { 11 @nogc: 12 13 EachWithEachOtherRangeBase base; 14 15 private size_t fwdIdx; 16 private ptrdiff_t backIdx; 17 private size_t sliceStart; /// slice index start 18 private size_t sliceEnd; /// slice index end 19 20 /// 21 this(size_t srcLen, size_t _sliceStart = 0, size_t _sliceEnd = 0) pure nothrow 22 { 23 base = EachWithEachOtherRangeBase(srcLen); 24 25 sliceStart = _sliceStart; 26 sliceEnd = _sliceEnd ? _sliceEnd : base.length; 27 28 assert(sliceStart <= sliceEnd); 29 //~ import std.conv: to; 30 //~ assert(sliceStart <= sliceEnd, "srcLen="~srcLen.to!string~" sliceStart="~sliceStart.to!string~" sliceEnd="~sliceEnd.to!string); 31 32 fwdIdx = sliceStart; 33 backIdx = sliceEnd - 1; 34 } 35 36 /// 37 size_t length() pure const nothrow 38 { 39 return sliceEnd - sliceStart; 40 } 41 42 /// 43 size_t[2] opIndex(size_t idx) pure 44 { 45 return base.opIndex(sliceStart + idx); 46 } 47 48 /// 49 bool empty() const @nogc 50 { 51 return fwdIdx >= sliceEnd || backIdx < sliceStart; 52 } 53 54 private void checkEmpty() 55 { 56 version(D_NoBoundsChecks){} 57 else 58 { 59 import core.exception: RangeError; 60 61 if(empty) 62 throw new RangeError; 63 } 64 } 65 66 auto front() { 67 checkEmpty(); 68 69 return base.opIndex(fwdIdx); 70 } 71 72 auto back() { 73 checkEmpty(); 74 75 return base.opIndex(backIdx); 76 } 77 78 /// 79 void popFront() { fwdIdx++; } 80 81 /// 82 void popBack() { backIdx--; } 83 84 /// 85 EachWithEachOtherRandomAccessRange save() { return this; } 86 87 /// 88 EachWithEachOtherRandomAccessRange opSlice(size_t from, size_t to) 89 { 90 return EachWithEachOtherRandomAccessRange(base.srcLength, sliceStart + from, sliceStart + to); 91 } 92 93 /// 94 size_t opDollar(size_t pos)() 95 if(pos == 0) 96 { 97 return length; 98 } 99 } 100 101 unittest 102 { 103 import std.range.primitives; 104 import std.traits; 105 106 alias R = EachWithEachOtherRandomAccessRange; 107 108 static assert(hasLength!R); 109 static assert(is(typeof(lvalueOf!R[1]) == ElementType!R)); 110 static assert(isInputRange!R); 111 static assert(!isNarrowString!R); 112 static assert(is(ReturnType!((R r) => r.save) == R)); 113 static assert(isForwardRange!R); 114 static assert(isBidirectionalRange!R); 115 static assert(isRandomAccessRange!R); 116 } 117 118 /// 119 alias eweo = EachWithEachOtherRandomAccessRange; 120 121 @trusted unittest 122 { 123 import std.parallelism; 124 import std.format; 125 126 enum ubyte testSize = 100; 127 128 auto eeRandom = eweo(testSize); 129 auto slice1 = eeRandom[0 .. 50]; 130 auto slice2 = eeRandom[50 .. $]; 131 132 auto randomRes1 = taskPool.amap!("a[0]", "a[1]")(slice1); 133 auto randomRes2 = taskPool.amap!("a[0]", "a[1]")(slice2); 134 135 size_t[testSize] cnt; 136 137 foreach(r; randomRes1) 138 { 139 cnt[r[0]]++; 140 cnt[r[1]]++; 141 } 142 143 foreach(r; randomRes2) 144 { 145 cnt[r[0]]++; 146 cnt[r[1]]++; 147 } 148 149 foreach(i, r; cnt) 150 assert(r == testSize-1, format("%d %d", i, r)); 151 } 152 153 unittest 154 { 155 auto eeRandom = eweo(4); 156 157 auto slice = eeRandom[0 .. $]; 158 159 assert(slice.length == eeRandom.length); 160 } 161 162 unittest 163 { 164 auto zero = eweo(0); 165 166 assert(zero.empty); 167 168 auto single = eweo(1); 169 170 assert(single.empty); 171 }