1 /// "Each with each other" random range
2 module eerange.randomrange;
3 
4 import eerange.base;
5 
6 @safe:
7 
8 ///
9 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) @nogc
19     {
20         base = EachWithEachOtherRangeBase!R(r);
21 
22         backIdx = length - 1;
23     }
24 
25     ///
26     bool empty() const @nogc
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 srcRange) pure
59 {
60     return EachWithEachOtherRandomAccessRange!(T)(srcRange);
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 }