1 /// Lazy filter-based range (destroy on function.)
2 module tern.algorithm.lazy_filter;
3 
4 // TODO: Barter?
5 import tern.traits;
6 import std.conv;
7 
8 /// Lazy filter-based range implementation.
9 public struct LazyFilter(alias F, T)
10     if (isForward!T && isCallable!F)
11 {
12     T _range;
13     alias _range this;
14 
15 private:
16 final:
17     size_t _length = -1;
18 
19 public:
20     string toString()
21     {
22         return this[0..length].to!string;
23     }
24 
25     /// Gets the internally held range after predication.
26     T range()
27     {
28         if (length == 0)
29             return T.init;
30             
31         return this[0..length];
32     }
33 
34     this(T range)
35     {
36         _range = range;
37     }
38 
39     size_t length()
40     {
41         if (_length != -1)
42             return _length;
43 
44         _length = 0;
45         foreach (u; _range)
46         {
47             if (F(u))
48                 _length++;
49         }
50         return _length;
51     }
52 
53     T opSlice(ptrdiff_t start, ptrdiff_t end)
54     {
55         T slice;
56         foreach (ref u; _range)
57         {
58             slice ~= opIndex(start++);        
59 
60             if (start >= end)
61                 break;
62         }
63         return slice;
64     }
65 
66     auto opSliceAssign(A)(A ahs, ptrdiff_t start, ptrdiff_t end) 
67     {
68         T slice;
69         foreach (ref u; _range)
70         {
71             slice ~= opIndex(ahs[start], start++);        
72 
73             if (start >= end)
74                 break;
75         }
76         return slice;
77     }
78 
79     ref auto opIndex(ptrdiff_t index)
80     {
81         foreach (ref u; _range)
82         {
83             if (F(u) && index-- <= 0)
84                 return u;
85         }
86         throw new Throwable("Lazy filter index out of bounds!");
87     }
88 
89     auto opIndexAssign(A)(A ahs, ptrdiff_t index) 
90     {
91         foreach (ref u; _range)
92         {
93             if (F(u) && index-- <= 0)
94                 return u = ahs;
95         }
96         throw new Throwable("Lazy filter index out of bounds!");
97     }
98 
99     size_t opDollar()
100     {
101         return length;
102     }
103 }