1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 module tanya.range.tests.primitive;
5 
6 import tanya.range;
7 import tanya.test.stub;
8 
9 private struct AssertPostblit
10 {
11     this(this) @nogc nothrow pure @safe
12     {
13         assert(false);
14     }
15 }
16 
17 @nogc nothrow pure @safe unittest
18 {
19     static struct Range1(T)
20     {
21         mixin InputRangeStub;
22 
23         T empty() const
24         {
25             return true;
26         }
27     }
28     static assert(!isInputRange!(Range1!int));
29     static assert(!isInputRange!(Range1!(const bool)));
30 
31     static struct Range2
32     {
33         mixin InputRangeStub;
34 
35         int popFront() @nogc nothrow pure @safe
36         {
37             return 100;
38         }
39     }
40     static assert(isInputRange!Range2);
41 
42     static struct Range3
43     {
44         mixin InputRangeStub;
45 
46         void front() @nogc nothrow pure @safe
47         {
48         }
49     }
50     static assert(!isInputRange!Range3);
51 
52     static struct Range4
53     {
54         mixin InputRangeStub;
55 
56         enum bool empty = false;
57     }
58     static assert(isInputRange!Range4);
59 }
60 
61 // Ranges with non-copyable elements can be input ranges
62 @nogc nothrow pure @safe unittest
63 {
64     @WithLvalueElements
65     static struct R
66     {
67         mixin InputRangeStub!NonCopyable;
68     }
69     static assert(isInputRange!R);
70 }
71 
72 // Ranges with const non-copyable elements can be input ranges
73 @nogc nothrow pure @safe unittest
74 {
75     @WithLvalueElements
76     static struct R
77     {
78         mixin InputRangeStub!(const(NonCopyable));
79     }
80     static assert(isInputRange!R);
81 }
82 
83 @nogc nothrow pure @safe unittest
84 {
85     static struct Range1
86     {
87     }
88     static struct Range2
89     {
90         mixin InputRangeStub;
91 
92         Range1 save() @nogc nothrow pure @safe
93         {
94             return Range1();
95         }
96     }
97     static assert(!isForwardRange!Range2);
98 
99     static struct Range3
100     {
101         mixin InputRangeStub;
102 
103         const(typeof(this)) save() const @nogc nothrow pure @safe
104         {
105             return this;
106         }
107     }
108     static assert(!isForwardRange!Range3);
109 }
110 
111 @nogc nothrow pure @safe unittest
112 {
113     static struct Range(T, U)
114     {
115         mixin BidirectionalRangeStub;
116 
117         @property T front() @nogc nothrow pure @safe
118         {
119             return T.init;
120         }
121 
122         @property U back() @nogc nothrow pure @safe
123         {
124             return U.init;
125         }
126     }
127     static assert(!isBidirectionalRange!(Range!(int, uint)));
128     static assert(!isBidirectionalRange!(Range!(int, const int)));
129 }
130 
131 // Ranges with non-copyable elements can be bidirectional ranges
132 @nogc nothrow pure @safe unittest
133 {
134     @WithLvalueElements
135     static struct R
136     {
137         mixin BidirectionalRangeStub!NonCopyable;
138     }
139     static assert(isBidirectionalRange!R);
140 }
141 
142 @nogc nothrow pure @safe unittest
143 {
144     static struct Range1
145     {
146         mixin BidirectionalRangeStub;
147         mixin RandomAccessRangeStub;
148     }
149     static assert(!isRandomAccessRange!Range1);
150 
151     @Length
152     static struct Range2(Args...)
153     {
154         mixin BidirectionalRangeStub;
155 
156         int opIndex(Args) @nogc nothrow pure @safe
157         {
158             return 0;
159         }
160     }
161     static assert(isRandomAccessRange!(Range2!size_t));
162     static assert(!isRandomAccessRange!(Range2!()));
163     static assert(!isRandomAccessRange!(Range2!(size_t, size_t)));
164 
165     @Length
166     static struct Range3
167     {
168         mixin BidirectionalRangeStub;
169 
170         int opIndex(const size_t pos1, const size_t pos2 = 0)
171         @nogc nothrow pure @safe
172         {
173             return 0;
174         }
175     }
176     static assert(isRandomAccessRange!Range3);
177 
178     static struct Range4
179     {
180         mixin BidirectionalRangeStub;
181         mixin RandomAccessRangeStub;
182 
183         size_t opDollar() const @nogc nothrow pure @safe
184         {
185             return 0;
186         }
187     }
188     static assert(!isRandomAccessRange!Range4);
189 }
190 
191 // Ranges with non-copyable elements can be random-access ranges
192 @nogc nothrow pure @safe unittest
193 {
194     @WithLvalueElements @Infinite
195     static struct R
196     {
197         mixin RandomAccessRangeStub!NonCopyable;
198     }
199     static assert(isRandomAccessRange!R);
200 }
201 
202 @nogc nothrow pure @safe unittest
203 {
204     @Infinite
205     static struct StaticConstRange
206     {
207         mixin InputRangeStub;
208 
209         static bool empty = false;
210     }
211     static assert(!isInfinite!StaticConstRange);
212 
213     @Infinite
214     static struct TrueRange
215     {
216         mixin InputRangeStub;
217 
218         static const bool empty = true;
219     }
220     static assert(!isInfinite!TrueRange);
221 }
222 
223 @nogc nothrow pure @safe unittest
224 {
225     @Infinite
226     static struct InfiniteRange
227     {
228         mixin ForwardRangeStub;
229         private int i;
230 
231         void popFront() @nogc nothrow pure @safe
232         {
233             ++this.i;
234         }
235 
236         void popBack() @nogc nothrow pure @safe
237         {
238             --this.i;
239         }
240 
241         @property int front() const @nogc nothrow pure @safe
242         {
243             return this.i;
244         }
245 
246         @property int back() const @nogc nothrow pure @safe
247         {
248             return this.i;
249         }
250     }
251     {
252         InfiniteRange range;
253         popFrontExactly(range, 2);
254         assert(range.front == 2);
255         popFrontN(range, 2);
256         assert(range.front == 4);
257     }
258     {
259         InfiniteRange range;
260         popBackExactly(range, 2);
261         assert(range.back == -2);
262         popBackN(range, 2);
263         assert(range.back == -4);
264     }
265 }
266 
267 @nogc nothrow pure @safe unittest
268 {
269     static struct Range
270     {
271         private int[5] a = [1, 2, 3, 4, 5];
272         private size_t begin = 0, end = 5;
273 
274         Range save() @nogc nothrow pure @safe
275         {
276             return this;
277         }
278 
279         void popFront() @nogc nothrow pure @safe
280         {
281             ++this.begin;
282         }
283 
284         void popBack() @nogc nothrow pure @safe
285         {
286             --this.end;
287         }
288 
289         @property int front() const @nogc nothrow pure @safe
290         {
291             return this.a[this.begin];
292         }
293 
294         @property int back() const @nogc nothrow pure @safe
295         {
296             return this.a[this.end - 1];
297         }
298 
299         @property bool empty() const @nogc nothrow pure @safe
300         {
301             return this.begin >= this.end;
302         }
303     }
304     {
305         Range range;
306 
307         popFrontN(range, 3);
308         assert(range.front == 4);
309         assert(range.back == 5);
310 
311         popFrontN(range, 20);
312         assert(range.empty);
313     }
314     {
315         Range range;
316 
317         popBackN(range, 3);
318         assert(range.front == 1);
319         assert(range.back == 2);
320 
321         popBackN(range, 20);
322         assert(range.empty);
323     }
324 }
325 
326 @nogc nothrow pure @safe unittest
327 {
328     // Returns its elements by reference.
329     @Infinite @WithLvalueElements
330     static struct R1
331     {
332         mixin InputRangeStub!AssertPostblit;
333     }
334     static assert(is(typeof(moveFront(R1()))));
335 
336     // Returns elements with a postblit constructor by value. moveFront fails.
337     @Infinite
338     static struct R2
339     {
340         mixin InputRangeStub!AssertPostblit;
341     }
342     static assert(!is(typeof(moveFront(R2()))));
343 }
344 
345 @nogc nothrow pure @safe unittest
346 {
347     // Returns its elements by reference.
348     @Infinite @WithLvalueElements
349     static struct R1
350     {
351         mixin BidirectionalRangeStub!AssertPostblit;
352     }
353     static assert(is(typeof(moveBack(R1()))));
354 
355     // Returns elements with a postblit constructor by value. moveBack fails.
356     @Infinite
357     static struct R2
358     {
359         mixin BidirectionalRangeStub!AssertPostblit;
360     }
361     static assert(!is(typeof(moveBack(R2()))));
362 }
363 
364 @nogc nothrow pure @safe unittest
365 {
366     // Returns its elements by reference.
367     @Infinite @WithLvalueElements
368     static struct R1
369     {
370         mixin RandomAccessRangeStub!AssertPostblit;
371     }
372     static assert(is(typeof(moveAt(R1(), 0))));
373 
374     // Returns elements with a postblit constructor by value. moveAt fails.
375     @Infinite
376     static struct R2
377     {
378         mixin RandomAccessRangeStub!AssertPostblit;
379     }
380     static assert(!is(typeof(moveAt(R2(), 0))));
381 }
382 
383 // Works with non-copyable elements
384 @nogc nothrow pure @safe unittest
385 {
386     static assert(hasLvalueElements!(NonCopyable[]));
387 }