xref: /netbsd-src/external/gpl3/gcc.old/dist/libphobos/src/std/internal/test/dummyrange.d (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
1 /**
2 For testing only.
3 Used with the dummy ranges for testing higher order ranges.
4 */
5 module std.internal.test.dummyrange;
6 
7 import std.meta;
8 import std.range.primitives;
9 import std.typecons;
10 
11 enum RangeType
12 {
13     Input,
14     Forward,
15     Bidirectional,
16     Random
17 }
18 
19 enum Length
20 {
21     Yes,
22     No
23 }
24 
25 enum ReturnBy
26 {
27     Reference,
28     Value
29 }
30 
31 import std.traits : isArray;
32 
33 // Range that's useful for testing other higher order ranges,
34 // can be parametrized with attributes.  It just dumbs down an array of
35 // numbers 1 .. 10.
36 struct DummyRange(ReturnBy _r, Length _l, RangeType _rt, T = uint[])
37 if (isArray!T)
38 {
39     private static immutable uinttestData =
40         [1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U];
41     // These enums are so that the template params are visible outside
42     // this instantiation.
43     enum r = _r;
44     enum l = _l;
45     enum rt = _rt;
46 
47     static if (is(T == uint[]))
48     {
49         T arr = uinttestData;
50     }
51     else
52     {
53         T arr;
54     }
55 
56     alias RetType = ElementType!(T);
57     alias RetTypeNoAutoDecoding = ElementEncodingType!(T);
58 
reinitDummyRange59     void reinit()
60     {
61         // Workaround for DMD bug 4378
62         static if (is(T == uint[]))
63         {
64             arr = uinttestData.dup;
65         }
66     }
67 
popFrontDummyRange68     void popFront()
69     {
70         arr = arr[1..$];
71     }
72 
emptyDummyRange73     @property bool empty() const
74     {
75         return arr.length == 0;
76     }
77 
78     static if (r == ReturnBy.Reference)
79     {
inoutDummyRange80         @property ref inout(RetType) front() inout
81         {
82             return arr[0];
83         }
84     }
85     else
86     {
frontDummyRange87         @property RetType front() const
88         {
89             return arr[0];
90         }
91 
frontDummyRange92         @property void front(RetTypeNoAutoDecoding val)
93         {
94             arr[0] = val;
95         }
96     }
97 
98     static if (rt >= RangeType.Forward)
99     {
saveDummyRange100         @property typeof(this) save()
101         {
102             return this;
103         }
104     }
105 
106     static if (rt >= RangeType.Bidirectional)
107     {
popBackDummyRange108         void popBack()
109         {
110             arr = arr[0..$ - 1];
111         }
112 
113         static if (r == ReturnBy.Reference)
114         {
inoutDummyRange115             @property ref inout(RetType) back() inout
116             {
117                 return arr[$ - 1];
118             }
119         }
120         else
121         {
backDummyRange122             @property RetType back() const
123             {
124                 return arr[$ - 1];
125             }
126 
backDummyRange127             @property void back(RetTypeNoAutoDecoding val)
128             {
129                 arr[$ - 1] = val;
130             }
131         }
132     }
133 
134     static if (rt >= RangeType.Random)
135     {
136         static if (r == ReturnBy.Reference)
137         {
inoutDummyRange138             ref inout(RetType) opIndex(size_t index) inout
139             {
140                 return arr[index];
141             }
142         }
143         else
144         {
opIndexDummyRange145             RetType opIndex(size_t index) const
146             {
147                 return arr[index];
148             }
149 
opIndexAssignDummyRange150             RetType opIndexAssign(RetTypeNoAutoDecoding val, size_t index)
151             {
152                 return arr[index] = val;
153             }
154 
opIndexOpAssignDummyRange155             RetType opIndexOpAssign(string op)(RetTypeNoAutoDecoding value, size_t index)
156             {
157                 mixin("return arr[index] " ~ op ~ "= value;");
158             }
159 
opIndexUnaryDummyRange160             RetType opIndexUnary(string op)(size_t index)
161             {
162                 mixin("return " ~ op ~ "arr[index];");
163             }
164         }
165 
opSliceDummyRange166         typeof(this) opSlice(size_t lower, size_t upper)
167         {
168             auto ret = this;
169             ret.arr = arr[lower .. upper];
170             return ret;
171         }
172 
opSliceDummyRange173         typeof(this) opSlice()
174         {
175             return this;
176         }
177     }
178 
179     static if (l == Length.Yes)
180     {
lengthDummyRange181         @property size_t length() const
182         {
183             return arr.length;
184         }
185 
186         alias opDollar = length;
187     }
188 }
189 
190 enum dummyLength = 10;
191 
192 alias AllDummyRanges = AliasSeq!(
193     DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
194     DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
195     DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
196     DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
197     DummyRange!(ReturnBy.Reference, Length.No, RangeType.Bidirectional),
198     DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input),
199     DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward),
200     DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional),
201     DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random),
202     DummyRange!(ReturnBy.Value, Length.No, RangeType.Input),
203     DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward),
204     DummyRange!(ReturnBy.Value, Length.No, RangeType.Bidirectional)
205 );
206 
AllDummyRangesType(T)207 template AllDummyRangesType(T)
208 {
209     alias AllDummyRangesType = AliasSeq!(
210         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward, T),
211         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional, T),
212         DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random, T),
213         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward, T),
214         DummyRange!(ReturnBy.Reference, Length.No, RangeType.Bidirectional, T),
215         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input, T),
216         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward, T),
217         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional, T),
218         DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random, T),
219         DummyRange!(ReturnBy.Value, Length.No, RangeType.Input, T),
220         DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward, T),
221         DummyRange!(ReturnBy.Value, Length.No, RangeType.Bidirectional, T)
222     );
223 }
224 
225 /**
226 Tests whether forward, bidirectional and random access properties are
227 propagated properly from the base range(s) R to the higher order range
228 H.  Useful in combination with DummyRange for testing several higher
229 order ranges.
230 */
propagatesRangeType(H,R...)231 template propagatesRangeType(H, R...)
232 {
233     static if (allSatisfy!(isRandomAccessRange, R))
234         enum bool propagatesRangeType = isRandomAccessRange!H;
235     else static if (allSatisfy!(isBidirectionalRange, R))
236         enum bool propagatesRangeType = isBidirectionalRange!H;
237     else static if (allSatisfy!(isForwardRange, R))
238         enum bool propagatesRangeType = isForwardRange!H;
239     else
240         enum bool propagatesRangeType = isInputRange!H;
241 }
242 
propagatesLength(H,R...)243 template propagatesLength(H, R...)
244 {
245     static if (allSatisfy!(hasLength, R))
246         enum bool propagatesLength = hasLength!H;
247     else
248         enum bool propagatesLength = !hasLength!H;
249 }
250 
251 /**
252 Reference type input range
253 */
ReferenceInputRange(T)254 class ReferenceInputRange(T)
255 {
256     import std.array : array;
257 
258     this(Range)(Range r) if (isInputRange!Range) {_payload = array(r);}
259     final @property ref T front(){return _payload.front;}
260     final void popFront(){_payload.popFront();}
261     final @property bool empty(){return _payload.empty;}
262     protected T[] _payload;
263 }
264 
265 /**
266 Infinite input range
267 */
ReferenceInfiniteInputRange(T)268 class ReferenceInfiniteInputRange(T)
269 {
270     this(T first = T.init) {_val = first;}
271     final @property T front(){return _val;}
272     final void popFront(){++_val;}
273     enum bool empty = false;
274     protected T _val;
275 }
276 
277 /**
278 Reference forward range
279 */
280 class ReferenceForwardRange(T) : ReferenceInputRange!T
281 {
282     this(Range)(Range r) if (isInputRange!Range) {super(r);}
save(this This)283     final @property auto save(this This)() {return new This( _payload);}
284 }
285 
286 /**
287 Infinite forward range
288 */
289 class ReferenceInfiniteForwardRange(T) : ReferenceInfiniteInputRange!T
290 {
291     this(T first = T.init) {super(first);}
save()292     final @property ReferenceInfiniteForwardRange save()
293     {return new ReferenceInfiniteForwardRange!T(_val);}
294 }
295 
296 /**
297 Reference bidirectional range
298 */
299 class ReferenceBidirectionalRange(T) : ReferenceForwardRange!T
300 {
301     this(Range)(Range r) if (isInputRange!Range) {super(r);}
back()302     final @property ref T back(){return _payload.back;}
popBack()303     final void popBack(){_payload.popBack();}
304 }
305 
306 @safe unittest
307 {
308     static assert(isInputRange!(ReferenceInputRange!int));
309     static assert(isInputRange!(ReferenceInfiniteInputRange!int));
310 
311     static assert(isForwardRange!(ReferenceForwardRange!int));
312     static assert(isForwardRange!(ReferenceInfiniteForwardRange!int));
313 
314     static assert(isBidirectionalRange!(ReferenceBidirectionalRange!int));
315 }
316 
317 private:
318 
319 pure struct Cmp(T)
320 if (is(T == uint))
321 {
322     static auto iota(size_t low = 1, size_t high = 11)
323     {
324         import std.range : iota;
325         return iota(cast(uint) low, cast(uint) high);
326     }
327 
initialize(ref uint[]arr)328     static void initialize(ref uint[] arr)
329     {
330         import std.array : array;
331         arr = iota().array;
332     }
333 
function(uint,uint)334     static bool function(uint,uint) cmp = function(uint a, uint b) { return a == b; };
335 
336     enum dummyValue = 1337U;
337     enum dummyValueRslt = 1337U * 2;
338 }
339 
340 pure struct Cmp(T)
341 if (is(T == double))
342 {
343     import std.math : approxEqual;
344 
345     static auto iota(size_t low = 1, size_t high = 11)
346     {
347         import std.range : iota;
348         return iota(cast(double) low, cast(double) high, 1.0);
349     }
350 
initialize(ref double[]arr)351     static void initialize(ref double[] arr)
352     {
353         import std.array : array;
354         arr = iota().array;
355     }
356 
357     alias cmp = approxEqual!(double,double);
358 
359     enum dummyValue = 1337.0;
360     enum dummyValueRslt = 1337.0 * 2.0;
361 }
362 
363 struct TestFoo
364 {
365     int a;
366 
opEqualsTestFoo367     bool opEquals(const ref TestFoo other) const
368     {
369         return this.a == other.a;
370     }
371 
opBinaryTestFoo372     TestFoo opBinary(string op)(TestFoo other)
373     {
374         TestFoo ret = this;
375         mixin("ret.a " ~ op ~ "= other.a;");
376         return ret;
377     }
378 
opOpAssignTestFoo379     TestFoo opOpAssign(string op)(TestFoo other)
380     {
381         mixin("this.a " ~ op ~ "= other.a;");
382         return this;
383     }
384 }
385 
Cmp(T)386 pure struct Cmp(T)
387 if (is(T == TestFoo))
388 {
389     import std.math : approxEqual;
390 
391     static auto iota(size_t low = 1, size_t high = 11)
392     {
393         import std.algorithm.iteration : map;
394         import std.range : iota;
395         return iota(cast(int) low, cast(int) high).map!(a => TestFoo(a));
396     }
397 
398     static void initialize(ref TestFoo[] arr)
399     {
400         import std.array : array;
401         arr = iota().array;
402     }
403 
404     static bool function(TestFoo,TestFoo) cmp = function(TestFoo a, TestFoo b)
405     {
406         return a.a == b.a;
407     };
408 
409     @property static TestFoo dummyValue()
410     {
411         return TestFoo(1337);
412     }
413 
414     @property static TestFoo dummyValueRslt()
415     {
416         return TestFoo(1337 * 2);
417     }
418 }
419 
420 @system unittest
421 {
422     import std.algorithm.comparison : equal;
423     import std.range : iota, retro, repeat;
424     import std.traits : Unqual;
425 
testInputRange(T,Cmp)426     static void testInputRange(T,Cmp)()
427     {
428         T it;
429         Cmp.initialize(it.arr);
430         for (size_t numRuns = 0; numRuns < 2; ++numRuns)
431         {
432             if (numRuns == 1)
433             {
434                 static if (is(Unqual!(ElementType!(T)) == uint))
435                 {
436                     it.reinit();
437                 }
438 
439                 Cmp.initialize(it.arr);
440             }
441 
442             assert(equal!(Cmp.cmp)(it, Cmp.iota(1, 11)));
443 
444             static if (hasLength!T)
445             {
446                 assert(it.length == 10);
447             }
448 
449             assert(!Cmp.cmp(it.front, Cmp.dummyValue));
450             auto s = it.front;
451             it.front = Cmp.dummyValue;
452             assert(Cmp.cmp(it.front, Cmp.dummyValue));
453             it.front = s;
454 
455             auto cmp = Cmp.iota(1,11);
456 
457             size_t jdx = 0;
458             while (!it.empty && !cmp.empty)
459             {
460                 static if (hasLength!T)
461                 {
462                     assert(it.length == 10 - jdx);
463                 }
464 
465                 assert(Cmp.cmp(it.front, cmp.front));
466                 it.popFront();
467                 cmp.popFront();
468 
469                 ++jdx;
470             }
471 
472             assert(it.empty);
473             assert(cmp.empty);
474         }
475 
476     }
477 
testForwardRange(T,Cmp)478     static void testForwardRange(T,Cmp)()
479     {
480         T it;
481         Cmp.initialize(it.arr);
482         auto s = it.save();
483         s.popFront();
484         assert(!Cmp.cmp(s.front, it.front));
485     }
486 
testBidirectionalRange(T,Cmp)487     static void testBidirectionalRange(T,Cmp)()
488     {
489         T it;
490         Cmp.initialize(it.arr);
491         assert(equal!(Cmp.cmp)(it.retro, Cmp.iota().retro));
492 
493         auto s = it.back;
494         assert(!Cmp.cmp(s, Cmp.dummyValue));
495         it.back = Cmp.dummyValue;
496         assert( Cmp.cmp(it.back, Cmp.dummyValue));
497         it.back = s;
498     }
499 
testRandomAccessRange(T,Cmp)500     static void testRandomAccessRange(T,Cmp)()
501     {
502         T it;
503         Cmp.initialize(it.arr);
504         size_t idx = 0;
505         foreach (jt; it)
506         {
507             assert(it[idx] == jt);
508 
509             T copy = it[idx .. $];
510             auto cmp = Cmp.iota(idx + 1, it.length + 1);
511             assert(equal!(Cmp.cmp)(copy, cmp));
512 
513             ++idx;
514         }
515 
516         {
517             auto copy = it;
518             copy.arr = it.arr.dup;
519             for (size_t i = 0; i < copy.length; ++i)
520             {
521                 copy[i] = Cmp.dummyValue;
522                 copy[i] += Cmp.dummyValue;
523             }
524             assert(equal!(Cmp.cmp)(copy, Cmp.dummyValueRslt.repeat(copy.length)));
525         }
526 
527         static if (it.r == ReturnBy.Reference)
528         {
529             T copy;
530             copy.arr = it.arr.dup;
531             for (size_t i = 0; i < copy.length; ++i)
532             {
533                 copy[i] = Cmp.dummyValue;
534                 copy[i] += Cmp.dummyValue;
535             }
536 
537             assert(equal!(Cmp.cmp)(copy, Cmp.dummyValueRslt.repeat(copy.length)));
538         }
539     }
540 
541     import std.meta : AliasSeq;
542 
543     foreach (S; AliasSeq!(uint, double, TestFoo))
544     {
545         foreach (T; AllDummyRangesType!(S[]))
546         {
547             testInputRange!(T,Cmp!S)();
548 
549             static if (isForwardRange!T)
550             {
551                 testForwardRange!(T,Cmp!S)();
552             }
553 
554             static if (isBidirectionalRange!T)
555             {
556                 testBidirectionalRange!(T,Cmp!S)();
557             }
558 
559             static if (isRandomAccessRange!T)
560             {
561                 testRandomAccessRange!(T,Cmp!S)();
562             }
563         }
564     }
565 }
566