1 // Written in the D programming language.
2 /*
3 NYSL Version 0.9982
4 
5 A. This software is "Everyone'sWare". It means:
6   Anybody who has this software can use it as if he/she is
7   the author.
8 
9   A-1. Freeware. No fee is required.
10   A-2. You can freely redistribute this software.
11   A-3. You can freely modify this software. And the source
12       may be used in any software with no limitation.
13   A-4. When you release a modified version to public, you
14       must publish it with your name.
15 
16 B. The author is not responsible for any kind of damages or loss
17   while using or misusing this software, which is distributed
18   "AS IS". No warranty of any kind is expressed or implied.
19   You use AT YOUR OWN RISK.
20 
21 C. Copyrighted to Kazuki KOMATSU
22 
23 D. Above three clauses are applied both to source and binary
24   form of this software.
25 */
26 
27 /**
28 このモジュールは、標準ライブラリのstd.traitsを強化します。
29 */
30 
31 module carbon.traits;
32 
33 import carbon.templates;
34 
35 import std.range,
36        std.traits,
37        std.typetuple;
38 
39 
40 struct FuncAttr 
41 {
42   static:
43     /*
44     proxy std.traits.functionAttributes
45     */
46     private template hasFA(FunctionAttribute fa, func...)
47     if(func.length == 1 && isCallable!func)
48     {
49         enum bool hasFA = !!(functionAttributes!func & fa);
50     }
51 
52 
53     /**
54     true if func is pure
55     */
56     template isPure(func...)
57     if(func.length == 1 && isCallable!func)
58     {
59         enum isPure = hasFA!(FunctionAttribute.pure_, func);
60     }
61 
62     unittest
63     {
64         void foo() pure {}
65         void bar() {}
66 
67         static assert(isPure!foo);
68         static assert(!isPure!bar);
69 
70         static void hoge() pure {}
71         static void hage() {}
72 
73         static assert(isPure!hoge);
74         static assert(!isPure!hage);
75     }
76 
77 
78     /**
79     true if func is nothrow
80     */
81     template isNothrow(func...)
82     if(func.length == 1 && isCallable!func)
83     {
84         enum isNothrow = hasFA!(FunctionAttribute.nothrow_, func);
85     }
86 
87 
88     /**
89     true if func is ref
90     */
91     template isRef(func...)
92     if(func.length == 1 && isCallable!func)
93     {
94         enum isNothrow = hasFA!(FunctionAttribute.ref_, func);
95     }
96 
97 
98     /**
99     true if func is property
100     */
101     template isProperty(func...)
102     if(func.length == 1 && isCallable!func)
103     {
104         enum isNothrow = hasFA!(FunctionAttribute.property_, func);
105     }
106 
107 
108     /**
109     true if func is trusted
110     */
111     template isTrusted(func...)
112     if(func.length == 1 && isCallable!func)
113     {
114         enum isNothrow = hasFA!(FunctionAttribute.trusted, func);
115     }
116 }
117 
118 
119 /**
120 This template return arity of a function.
121 
122 Example:
123 ---
124 template Generator0(size_t N)
125 {
126     alias TypeNuple!(int, N) Generator0;
127 }
128 
129 alias argumentInfo!(( (a, b, c) => a), Generator0) Result0;
130 
131 static assert(Result0.arity == 3);
132 static assert(Result0.endN == 3);
133 static assert(is(Result0.ParameterTypeTuple == Generator0!3));
134 static assert(is(Result0.ReturnType == int));
135 
136 
137 template Generator1(size_t N)
138 {
139     alias TypeTuple!(int, ushort, long, double*, uint, real[])[N] Generator1;
140 }
141 
142 static assert(Result1.arity == 1);
143 static assert(Result1.endN == 3);
144 static assert(is(Result1.ParameterTypeTuple == double*));
145 static assert(is(Result1.ReturnType == double*));
146 ---
147 
148 Authors: Kazuki Komatsu(k3_kaimu)
149 */
150 template argumentInfo(alias templateFun, alias ParamGenRange)
151 if(isTemplateRange!ParamGenRange && !ParamGenRange.empty)
152 {
153     template checkArity(alias pgr)
154     {
155         static if(!pgr.empty)
156         {
157             static if(is(typeof(templateFun(pgr.front.init))))
158                 alias checkArity = pgr.front;
159             else
160                 alias checkArity = checkArity!(pgr.tail!());
161         }
162         else
163             static assert(0, "arity Error : " ~ templateFun.stringof);
164     }
165 
166 
167     alias ParameterTypeTuple = TypeTuple!(checkArity!(ParamGenRange));
168     enum size_t arity = ParameterTypeTuple.length;
169     alias ReturnType = typeof(templateFun(ParameterTypeTuple.init));
170 }
171 
172 unittest 
173 {
174     template Generator0(T...)
175     {
176         enum bool empty = false;
177 
178         alias front = T;
179 
180         template tail()
181         {
182             alias tail = Generator0!(T, int);
183         }
184     }
185 
186     alias argumentInfo!(( (a, b, c) => a), Generator0!()) Result0;
187 
188     static assert(Result0.arity == 3);
189     static assert(is(Result0.ParameterTypeTuple == TypeTuple!(int, int, int)));
190     static assert(is(Result0.ReturnType == int));
191 
192 
193     template Generator1(size_t idx)
194     {
195         enum bool empty = idx >= 6;
196 
197       static if(!empty)
198       {
199         alias front = TypeTuple!(int, ushort, long, double*, uint, real[])[idx];
200 
201         template tail()
202         {
203             alias tail = Generator1!(idx+1);
204         }
205       }
206     }
207 
208     alias argumentInfo!(((double* a) => a), Generator1!0) Result1;
209 
210     static assert(Result1.arity == 1);
211     static assert(is(Result1.ParameterTypeTuple[0] == double*));
212     static assert(is(Result1.ReturnType == double*));
213 }
214 
215 
216 /**
217 */
218 template isVersion(string identifier)
219 {
220     mixin(mixin(Lstr!q{
221       version(%[identifier%])
222         enum isVersion = true;
223       else
224         enum isVersion = false;
225     }));
226 }
227 
228 ///
229 unittest
230 {
231   version(Windows)
232     static assert(isVersion!"Windows");
233 
234   version(OSX)
235     static assert(isVersion!"OSX");
236 
237   version(linux)
238     static assert(isVersion!"linux");
239 }
240 
241 
242 /**
243 InputRangeのチェックを簡単にします
244 
245 Examples:
246 --------------
247 isIRangeEx!(int[], int) == isInputRange!(int[]) && is(ElementType!(int[]) : int)
248 --------------
249 */
250 enum bool isIRange(T) = isInputRange!T;
251 enum bool isIRange(T, E) = isInputRange!T && is(ElementType!T : E);
252 enum bool isFRange(T) = isForwardRange!T;
253 enum bool isFRange(T, E) = isForwardRange!T && is(ElementType!T : E);
254 enum bool isBRange(T) = isBidirectionalRange!T;
255 enum bool isBRange(T, E) = isBidirectionalRange!T && is(ElementType!T : E);
256 enum bool isRRange(T) = isRandomAccessRange!T;
257 enum bool isRRange(T, E) = isRandomAccessRange!T && is(ElementType!T : E);