comparison dstep/internal/Reflection.d @ 26:6825fcc47e39

Added dstep.internal.Reflection
author Jacob Carlborg <doob@me.com>
date Tue, 06 Apr 2010 11:38:08 +0200
parents
children
comparison
equal deleted inserted replaced
25:b9de51448c6b 26:6825fcc47e39
1 /**
2 * Copyright: Copyright (c) 2010 Jacob Carlborg.
3 * Authors: Jacob Carlborg
4 * Version: Initial created: Mar 8, 2010
5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6 */
7 module dstep.internal.Reflection;
8
9 import dstep.objc.bridge.Bridge;
10 import dstep.internal.String;
11
12 /**
13 * Returns the name of the given function
14 *
15 * Params:
16 * func = the function alias to get the name of
17 *
18 * Returns: the name of the function
19 */
20 template functionNameOf (alias func)
21 {
22 version(LDC)
23 const functionNameOf = (&func).stringof[1 .. $];
24
25 else
26 const functionNameOf = (&func).stringof[2 .. $];
27 }
28
29 /**
30 * Returns the parameter names of the given function
31 *
32 * Params:
33 * func = the function alias to get the parameter names of
34 *
35 * Returns: an array of strings containing the parameter names
36 */
37 template parameterNamesOf (alias func)
38 {
39 const parameterNamesOf = parameterNamesOfImpl!(func);
40 }
41
42 private string[] parameterNamesOfImpl (alias func) ()
43 {
44 string funcStr = typeof(&func).stringof;
45
46 auto start = funcStr.indexOf('(');
47 auto end = funcStr.indexOf(')');
48
49 const firstPattern = ' ';
50 const secondPattern = ',';
51
52 funcStr = funcStr[start + 1 .. end];
53
54 if (funcStr == "")
55 return null;
56
57 funcStr ~= secondPattern;
58
59 string token;
60 string[] arr;
61
62 foreach (c ; funcStr)
63 {
64 if (c != firstPattern && c != secondPattern)
65 token ~= c;
66
67 else
68 {
69 if (token)
70 arr ~= token;
71
72 token = null;
73 }
74 }
75
76 if (arr.length == 1)
77 return arr;
78
79 string[] result;
80 bool skip = false;
81
82 foreach (str ; arr)
83 {
84 skip = !skip;
85
86 if (skip)
87 continue;
88
89 result ~= str;
90 }
91
92 return result;
93 }
94
95 /**
96 * Compile-time function to get the index of the give element.
97 *
98 * Performs a linear scan, returning the index of the first occurrence
99 * of the specified element in the array, or U.max if the array does
100 * not contain the element.
101 *
102 * Params:
103 * arr = the array to get the index of the element from
104 * element = the element to find
105 *
106 * Returns: the index of the element or size_t.max if the element was not found.
107 */
108 private size_t indexOf (T) (T[] arr, T element)
109 {
110 foreach (i, e ; arr)
111 if (e == element)
112 return i;
113
114 return size_t.max;
115 }
116
117 //FIXME fix this when http://d.puremagic.com/issues/show_bug.cgi?id=3512 is fixed
118 version (none)
119 {
120
121 /**
122 * Compile-time function to get the index of the give element.
123 *
124 * Performs a linear scan, returning the index of the first occurrence
125 * of the specified element in the array, or U.max if the array does
126 * not contain the element.
127 *
128 * Params:
129 * arr = the array to get the index of the element from
130 * element = the element to find
131 *
132 * Returns: the index of the element or size_t.max if the element was not found.
133 */
134 private size_t indexOf (T) (T[] arr, dchar element)
135 {
136 static assert(is(T == char) || is(T == wchar) || is(T == dchar), `dstep.internal.Traits.indexOf: The given type "` ~ T.stringof ~ `" is not valid, it has to be char, wchar or dchar`);
137
138 foreach (i, dchar e ; arr)
139 if (e == element)
140 return i;
141
142 return size_t.max;
143 }
144 }
145
146 /**
147 * Evaluates to true if $(D_PARAM T) has a instance method with the given name
148 *
149 * Params:
150 * T = the type of the class/struct
151 * method = the name of the method
152 */
153 template hasInstanceMethod (T, string method)
154 {
155 const hasInstanceMethod = is(typeof({
156 T t;
157 mixin("auto f = &t." ~ method ~ ";");
158 }));
159 }
160
161 /**
162 * Evaluates to true if $(D_PARAM T) has a class method with the given name
163 *
164 * Params:
165 * T = the type of the class/struct
166 * method = the name of the method
167 */
168 template hasClassMethod (T, string method)
169 {
170 const hasClassMethod = is(typeof({
171 mixin("auto f = &T." ~ method ~ ";");
172 }));
173 }
174
175 /**
176 * Evaluates to true if $(D_PARAM T) has a either a class method or a instance method
177 * with the given name.
178 *
179 * Params:
180 * T = the type of the class/struct
181 * method = the name of the method
182 */
183 template hasMethod (T, string method)
184 {
185 const hasMethod = hasClassMethod!(T, method) || hasInstanceMethod!(T, method);
186 }
187
188 /**
189 * Evaluates to true if T has a field with the given name
190 *
191 * Params:
192 * T = the type of the class/struct
193 * field = the name of the field
194 */
195 template hasField (T, string field)
196 {
197 const hasField = hasFieldImpl!(T, field, 0);
198 }
199
200 private template hasFieldImpl (T, string field, size_t i)
201 {
202 static if (T.tupleof.length == i)
203 const hasFieldImpl = false;
204
205 else static if (T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] == field)
206 const hasFieldImpl = true;
207
208 else
209 const hasFieldImpl = hasFieldImpl!(T, field, i + 1);
210 }
211
212 /// Evaluates to true if $(D_PARAM T) has binded methods
213 template hasBindedMethods (T)
214 {
215 const bool hasBindedMethods = hasField!(T, Bridge.objcClassMethodDeclarationVar) || hasField!(T, Bridge.objcMethodDeclarationVar);
216 }
217
218
219
220 /**
221 * Sets the given value to the filed with the given name
222 *
223 * Params:
224 * t = an instance of the type that has the field
225 * value = the value to set
226 */
227 void setValueOfField (string field, T, U) (ref T t, U value)
228 in
229 {
230 static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
231 }
232 body
233 {
234 const len = T.stringof.length;
235
236 foreach (i, dummy ; typeof(T.tupleof))
237 {
238 const f = T.tupleof[i].stringof[1 + len + 2 .. $];
239
240 static if (f == field)
241 {
242 t.tupleof[i] = value;
243 break;
244 }
245 }
246 }
247
248 /**
249 * Evaluates to the type of the field with the given name
250 *
251 * Params:
252 * T = the type of the class/struct
253 * field = the name of the field
254 */
255 template TypeOfField (T, string field)
256 {
257 static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
258
259 alias TypeOfFieldImpl!(T, field, 0) TypeOfField;
260 }
261
262 private template TypeOfFieldImpl (T, string field, size_t i)
263 {
264 static if (T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] == field)
265 alias typeof(T.tupleof[i]) TypeOfFieldImpl;
266
267 else
268 alias TypeOfFieldImpl!(T, field, i + 1) TypeOfFieldImpl;
269 }
270
271 /**
272 * Creates a new instance of class with the given name
273 *
274 * Params:
275 * name = the fully qualified name of the class
276 * args = the arguments to the constructor
277 *
278 * Returns: the newly created instance or null
279 */
280 T factory (T : Object, ARGS...) (string name, ARGS args)
281 {
282 auto classInfo = ClassInfo.find(name);
283
284 if (!classInfo)
285 return null;
286
287 auto object = newInstance(classInfo);
288
289 if (classInfo.flags & 8 && classInfo.defaultConstructor is null)
290 {
291 auto o = cast(T) object;
292
293 static if (is(typeof(o._ctor(args))))
294 return o._ctor(args);
295
296 else
297 return null;
298 }
299
300 else
301 {
302 if (classInfo.flags & 8 && classInfo.defaultConstructor !is null)
303 {
304 Object delegate () ctor;
305 ctor.ptr = cast(void*) object;
306 ctor.funcptr = cast(Object function()) classInfo.defaultConstructor;
307
308 return cast(T) ctor();
309 }
310
311 else
312 return cast(T) object;
313 }
314 }
315
316 private
317 {
318 version (LDC)
319 extern (C) Object _d_allocclass(ClassInfo);
320
321 else
322 extern (C) Object _d_newclass(ClassInfo);
323 }
324
325 /**
326 * Creates a new instance of the given ClassInfo
327 *
328 * Params:
329 * classInfo = the class to create a new instance of
330 *
331 * Returns: the new instance
332 */
333 Object newInstance (ClassInfo classInfo)
334 {
335 version (LDC)
336 {
337 Object object = _d_allocclass(classInfo);
338 (cast(byte*) object)[0 .. classInfo.init.length] = classInfo.init[];
339
340 return object;
341 }
342
343 else
344 return _d_newclass(classInfo);
345 }