1 /**
2 *   Copyright: © 2014-2015 Anton Gushcha
3 *   License: Subject to the terms of the Boost 1.0 license as specified in LICENSE file
4 *   Authors: Anton Gushcha <ncrashed@gmail.com>
5 *
6 *   Template filters - extension of std.typecons;
7 */
8 module stribog.meta.filter;
9 
10 import std.conv : text;
11 
12 import stribog.meta.base;
13 
14 /**
15 *   Performs filtering of expression tuple $(B T) one by one by function or template $(B F). If $(B F)
16 *   returns $(B true) the resulted element goes to returned expression tuple, else it is discarded.
17 */
18 template staticFilter(alias F, T...)
19 {
20     static if(T.length == 0)
21     {
22         alias staticFilter = ExpressionList!();
23     }
24     else
25     {
26         static if(__traits(compiles, F(T[0]))  && F(T[0]) 
27                || __traits(compiles, F!(T[0])) && F!(T[0])) 
28         {
29             alias staticFilter = ExpressionList!(T[0], staticFilter!(F, T[1 .. $]));
30         }
31         else
32         {
33             alias staticFilter = ExpressionList!(staticFilter!(F, T[1 .. $]));
34         }
35     }
36 }
37 /// Example
38 unittest
39 {
40     import std.conv;
41     
42     bool testFunc(int val)
43     { 
44         return val <= 15;
45     }
46     
47     template testTemplate(int val)
48     {
49         enum testTemplate = val <= 15;
50     }
51     
52     static assert(staticFilter!(testFunc, ExpressionList!(42, 108, 15, 2)) == ExpressionList!(15, 2));
53     static assert(staticFilter!(testTemplate, ExpressionList!(42, 108, 15, 2)) == ExpressionList!(15, 2));
54 }
55 
56 /**
57 *   Performs filtering of expression tuple $(B T) passing $(B i) elements to function or template $(B F). If $(B F)
58 *   returns $(B true) the resulted elements go to returned expression tuple, else it is discarded.
59 */
60 template staticFilterN(size_t i, alias F, T...)
61 {
62     static assert(i != 0, "staticFilterN: N is zero");
63     static assert(T.length % i == 0, text("Wrong size of ExpressionList in filter, expected ", i, " but got ", T.length));
64     
65     static if(T.length < i)
66     {
67         alias staticFilterN = ExpressionList!();
68     }
69     else
70     {
71         static if(__traits(compiles, F(T[0 .. i]))  && F(T[0 .. i]) 
72                || __traits(compiles, F!(T[0 .. i])) && F!(T[0 .. i])) 
73         {
74             alias staticFilterN = ExpressionList!(T[0 .. i], staticFilterN!(i, F, T[i .. $]));
75         } 
76         else
77         {
78             alias staticFilterN = ExpressionList!(staticFilterN!(i, F, T[i .. $]));
79         }
80     }
81 }
82 /// Example
83 unittest
84 {
85     template isNineSumm(int a, int b, int c) { enum isNineSumm = a + b + c == 9; }
86     static assert( staticEqual!( StrictExpressionList!(staticFilterN!(3, isNineSumm, 3, 3, 3, 1, 1, 1, 2, 4, 3)), StrictExpressionList!(ExpressionList!(3, 3, 3, 2, 4, 3)) ) );
87 }
88 
89 /// Alias of staticFilterN for 2 arguments
90 alias staticFilter2(alias F, T...) = staticFilterN!(2, F, T);
91 /// Alias of staticFilterN for 3 arguments
92 alias staticFilter3(alias F, T...) = staticFilterN!(3, F, T);
93 /// Alias of staticFilterN for 4 arguments
94 alias staticFilter4(alias F, T...) = staticFilterN!(4, F, T);
95 /// Alias of staticFilterN for 5 arguments
96 alias staticFilter5(alias F, T...) = staticFilterN!(5, F, T);
97 /// Alias of staticFilterN for 6 arguments
98 alias staticFilter6(alias F, T...) = staticFilterN!(6, F, T);
99 /// Alias of staticFilterN for 7 arguments
100 alias staticFilter7(alias F, T...) = staticFilterN!(7, F, T);
101 /// Alias of staticFilterN for 8 arguments
102 alias staticFilter8(alias F, T...) = staticFilterN!(8, F, T);
103 /// Alias of staticFilterN for 9 arguments
104 alias staticFilter9(alias F, T...) = staticFilterN!(9, F, T);
105 
106 /**
107 *   Performs filtering of expression tuple $(B T) passing $(B i) elements to function or template $(B F). If $(B F)
108 *   returns $(B true) the first element go to returned expression tuple and "window" is moved over T by 1 element.
109 *   Last i-1 elements goes to resulted tuple without checks.
110 */
111 template staticFilterLookaheadN(size_t i, alias F, T...)
112 {
113     static assert(i != 0, "staticFilterLookaheadN: N is zero");
114      
115     static if(T.length < i)
116     {
117         alias staticFilterLookaheadN = ExpressionList!(T);
118     }
119     else
120     {
121         static if(__traits(compiles, F(T[0 .. i]))  && F(T[0 .. i]) 
122                || __traits(compiles, F!(T[0 .. i])) && F!(T[0 .. i])) 
123         {
124             alias staticFilterLookaheadN = ExpressionList!(T[0], staticFilterLookaheadN!(i, F, T[1 .. $]));
125         } 
126         else
127         {
128             alias staticFilterLookaheadN = ExpressionList!(staticFilterLookaheadN!(i, F, T[1 .. $]));
129         }
130     }
131 }
132 /// Example
133 unittest
134 {
135     template isFibonachi(int a, int b, int c) { enum isFibonachi = a == b + c; }
136     static assert( staticEqual!( StrictExpressionList!(staticFilterLookaheadN!(3, isFibonachi, 9, 5, 3, 2, 1, 1)), StrictExpressionList!(ExpressionList!(5, 3, 2, 1, 1)) ) );
137 }
138 
139 /// Alias of staticFilterLookaheadN for 1 argument
140 alias staticFilterLookahead(alias F, T...) = staticFilterLookaheadN!(1, F, T);
141 /// Alias of staticFilterLookaheadN for 2 arguments
142 alias staticFilterLookahead2(alias F, T...) = staticFilterLookaheadN!(2, F, T);
143 /// Alias of staticFilterLookaheadN for 3 arguments
144 alias staticFilterLookahead3(alias F, T...) = staticFilterLookaheadN!(3, F, T);
145 /// Alias of staticFilterLookaheadN for 4 arguments
146 alias staticFilterLookahead4(alias F, T...) = staticFilterLookaheadN!(4, F, T);
147 /// Alias of staticFilterLookaheadN for 5 arguments
148 alias staticFilterLookahead5(alias F, T...) = staticFilterLookaheadN!(5, F, T);
149 /// Alias of staticFilterLookaheadN for 6 arguments
150 alias staticFilterLookahead6(alias F, T...) = staticFilterLookaheadN!(6, F, T);
151 /// Alias of staticFilterLookaheadN for 7 arguments
152 alias staticFilterLookahead7(alias F, T...) = staticFilterLookaheadN!(7, F, T);
153 /// Alias of staticFilterLookaheadN for 8 arguments
154 alias staticFilterLookahead8(alias F, T...) = staticFilterLookaheadN!(8, F, T);
155 /// Alias of staticFilterLookaheadN for 9 arguments
156 alias staticFilterLookahead9(alias F, T...) = staticFilterLookaheadN!(9, F, T);
157 
158 /**
159 *   Performs filtering of expression tuple $(B T) passing $(B i) elements to function or template $(B F). If $(B F)
160 *   returns $(B true) the last element go to returned expression tuple and "window" is moved behind T by 1 element.
161 *   First i-1 elements goes to resulted tuple without checks.
162 *   
163 *   Filtering starts from last element.
164 */
165 template staticFilterLookbehindN(size_t i, alias F, T...) 
166 {
167     static assert(i != 0, "staticFilterLookbehindN: N is zero");
168      
169     static if(T.length < i)
170     {
171         alias staticFilterLookbehindN = ExpressionList!(T);
172     }
173     else
174     {
175         static if(__traits(compiles, F(T[$-i .. $]))  && F(T[$-i .. $]) 
176                || __traits(compiles, F!(T[$-i .. $])) && F!(T[$-i .. $])) 
177         {
178             alias staticFilterLookbehindN = ExpressionList!(staticFilterLookbehindN!(i, F, T[0 .. $-1]), T[$-1]);
179         } 
180         else
181         {
182             alias staticFilterLookbehindN = ExpressionList!(staticFilterLookbehindN!(i, F, T[0 .. $-1]));
183         }
184     }
185 }
186 /// Example
187 unittest
188 {
189     template isFibonachi(int a, int b, int c) { enum isFibonachi = a + b == c; }
190     static assert( staticEqual!( StrictExpressionList!(staticFilterLookbehindN!(3, isFibonachi, 1, 1, 2, 3, 5, 9)), StrictExpressionList!(ExpressionList!(1, 1, 2, 3, 5)) ) );
191 }
192 
193 /// Alias of staticFilterLookbehindN for 1 argument
194 alias staticFilterLookbehind(alias F, T...) = staticFilterLookbehindN!(1, F, T);
195 /// Alias of staticFilterLookbehindN for 2 arguments
196 alias staticFilterLookbehind2(alias F, T...) = staticFilterLookbehindN!(2, F, T);
197 /// Alias of staticFilterLookbehindN for 3 arguments
198 alias staticFilterLookbehind3(alias F, T...) = staticFilterLookbehindN!(3, F, T);
199 /// Alias of staticFilterLookbehindN for 4 arguments
200 alias staticFilterLookbehind4(alias F, T...) = staticFilterLookbehindN!(4, F, T);
201 /// Alias of staticFilterLookbehindN for 5 arguments
202 alias staticFilterLookbehind5(alias F, T...) = staticFilterLookbehindN!(5, F, T);
203 /// Alias of staticFilterLookbehindN for 6 arguments
204 alias staticFilterLookbehind6(alias F, T...) = staticFilterLookbehindN!(6, F, T);
205 /// Alias of staticFilterLookbehindN for 7 arguments
206 alias staticFilterLookbehind7(alias F, T...) = staticFilterLookbehindN!(7, F, T);
207 /// Alias of staticFilterLookbehindN for 8 arguments
208 alias staticFilterLookbehind8(alias F, T...) = staticFilterLookbehindN!(8, F, T);
209 /// Alias of staticFilterLookbehindN for 9 arguments
210 alias staticFilterLookbehind9(alias F, T...) = staticFilterLookbehindN!(9, F, T);