1 /// Library for iterating over stuff
2 module mecca.lib.iteration;
3 
4 // Licensed under the Boost license. Full copyright information in the AUTHORS file
5 
6 import std.traits;
7 import std.range;
8 
9 import mecca.lib.reflection;
10 
11 /**
12   Turn a Ref returning input range into a PTR one.
13 
14   This is useful for using ranges iterating `@disable this(this)` types with Phobos, that requires `front` to be
15   copyable in order to recognize a range as an input range.
16  */
17 auto ptrInputRange(Range)(Range range) if( isRefInputRange!Range ) {
18     struct PtrRange {
19         Range range;
20 
21         @property auto front() {
22             return &(range.front());
23         }
24 
25         alias range this;
26     }
27 
28     return PtrRange(range);
29 }
30 
31 /// ditto
32 auto ptrInputRange(T)(T[] slice) {
33     struct PtrRange {
34         T[] slice;
35 
36         @property bool empty() pure const @safe @nogc {
37             return slice.length == 0;
38         }
39 
40         void popFront() @safe @nogc {
41             slice = slice[1..$];
42         }
43 
44         @property T* front() pure @safe @nogc {
45             return &slice[0];
46         }
47     }
48 
49     return PtrRange(slice);
50 }
51 
52 unittest {
53     import std.algorithm : map, equal;
54 
55     struct Uncopyable {
56         uint a;
57 
58         @disable this(this);
59     }
60 
61     Uncopyable[5] arr;
62     foreach(i; 0..5) {
63         arr[i] = Uncopyable(i);
64     }
65 
66     assert( equal( arr.ptrInputRange.map!"(*a).a*2", [0, 2, 4, 6, 8] ) );
67 }
68 
69 auto derefRange(Range)(Range range) if( isInputRange!Range && is( isPointer!(elementType!Range) ) ) {
70     struct DerefRange {
71         Range range;
72 
73         @property ref auto front() {
74             return *range.front;
75         }
76 
77         alias range this;
78     }
79 
80     return DerefRange(range);
81 }