Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

root/tags/releases/0.99.9/tango/core/RuntimeTraits.d

Revision 4503, 15.5 kB (checked in by fawzi, 3 years ago)

adding runtime traits of Chris Wright, closes #1474

  • Property svn:mime-type set to text/x-dsrc
  • Property svn:eol-style set to native
Line 
1 /**
2  * Provides runtime traits, which provide much of the functionality of tango.core.Traits and
3  * is-expressions, as well as some functionality that is only available at runtime, using
4  * runtime type information.
5  *
6  * Authors: Chris Wright (dhasenan) <dhasenan@gmail.com>
7  * License: tango license, apache 2.0
8  * Copyright (c) 2009, CHRISTOPHER WRIGHT
9  */
10 module tango.core.RuntimeTraits;
11
12 /// If the given type represents a typedef, return the actual type.
13 TypeInfo realType (TypeInfo type)
14 {
15     // TypeInfo_Typedef.next() doesn't return the actual type.
16     // I think it returns TypeInfo_Typedef.base.next().
17     // So, a slightly different method.
18     auto def = cast(TypeInfo_Typedef) type;
19     if (def !is null)
20     {
21         return def.base;
22     }
23     return type;
24 }
25
26 /// If the given type represents a class, return its ClassInfo; else return null;
27 ClassInfo asClass (TypeInfo type)
28 {
29     if (isInterface (type))
30     {
31         auto klass = cast(TypeInfo_Interface) type;
32         return klass.info;
33     }
34     if (isClass (type))
35     {
36         auto klass = cast(TypeInfo_Class) type;
37         return klass.info;
38     }
39     return null;
40 }
41
42 /** Returns true iff one type is an ancestor of the other, or if the types are the same.
43  * If either is null, returns false. */
44 bool isDerived (ClassInfo derived, ClassInfo base)
45 {
46     if (derived is null || base is null)
47         return false;
48     do
49         if (derived is base)
50             return true;
51     while ((derived = derived.base) !is null)
52     return false;
53 }
54
55 /** Returns true iff implementor implements the interface described
56  * by iface. This is an expensive operation (linear in the number of
57  * interfaces and base classes).
58  */
59 bool implements (ClassInfo implementor, ClassInfo iface)
60 {
61     foreach (info; applyInterfaces (implementor))
62     {
63         if (iface is info)
64             return true;
65     }
66     return false;
67 }
68
69 /** Returns true iff an instance of class test is implicitly castable to target.
70  * This is an expensive operation (isDerived + implements). */
71 bool isImplicitly (ClassInfo test, ClassInfo target)
72 {
73     // Keep isDerived first.
74     // isDerived will be much faster than implements.
75     return (isDerived (test, target) || implements (test, target));
76 }
77
78 /** Returns true iff an instance of type test is implicitly castable to target.
79  * If the types describe classes or interfaces, this is an expensive operation. */
80 bool isImplicitly (TypeInfo test, TypeInfo target)
81 {
82     // A lot of special cases. This is ugly.
83     if (test is target)
84         return true;
85     if (isStaticArray (test) && isDynamicArray (target) && valueType (test) is valueType (target))
86     {
87         // you can implicitly cast static to dynamic (currently) if they
88         // have the same value type. Other casts should be forbidden.
89         return true;
90     }
91     auto klass1 = asClass (test);
92     auto klass2 = asClass (target);
93     if (isClass (test) && isClass (target))
94     {
95         return isDerived (klass1, klass2);
96     }
97     if (isInterface (test) && isInterface (target))
98     {
99         return isDerived (klass1, klass2);
100     }
101     if (klass1 && klass2)
102     {
103         return isImplicitly (klass1, klass2);
104     }
105     if (klass1 || klass2)
106     {
107         // no casts from class to non-class
108         return false;
109     }
110     if ((isSignedInteger (test) && isSignedInteger (target)) || (isUnsignedInteger (test) && isUnsignedInteger (target)) || (isFloat (
111             test) && isFloat (target)) || (isCharacter (test) && isCharacter (target)))
112     {
113         return test.tsize () <= target.tsize ();
114     }
115     if (isSignedInteger (test) && isUnsignedInteger (target))
116     {
117         // potential loss of data
118         return false;
119     }
120     if (isUnsignedInteger (test) && isSignedInteger (target))
121     {
122         // if the sizes are the same, you could be losing data
123         // the upper half of the range wraps around to negatives
124         // if the target type is larger, you can safely hold it
125         return test.tsize () < target.tsize ();
126     }
127     // delegates and functions: no can do
128     // pointers: no
129     // structs: no
130     return false;
131 }
132
133 ///
134 ClassInfo[] baseClasses (ClassInfo type)
135 {
136     if (type is null)
137         return null;
138     ClassInfo[] types;
139     while ((type = type.base) !is null)
140         types ~= type;
141     return types;
142 }
143
144 /** Returns a list of all interfaces that this type implements, directly
145  * or indirectly. This includes base interfaces of types the class implements,
146  * and interfaces that base classes implement, and base interfaces of interfaces
147  * that base classes implement. This is an expensive operation. */
148 ClassInfo[] baseInterfaces (ClassInfo type)
149 {
150     if (type is null)
151         return null;
152     ClassInfo[] types = directInterfaces (type);
153     while ((type = type.base) !is null)
154     {
155         types ~= interfaceGraph (type);
156     }
157     return types;
158 }
159
160 /** Returns all the interfaces that this type directly implements, including
161  * inherited interfaces. This is an expensive operation.
162  *
163  * Examples:
164  * ---
165  * interface I1 {}
166  * interface I2 : I1 {}
167  * class A : I2 {}
168  *
169  * auto interfaces = interfaceGraph (A.classinfo);
170  * // interfaces = [I1.classinfo, I2.classinfo]
171  * ---
172  *
173  * ---
174  * interface I1 {}
175  * interface I2 {}
176  * class A : I1 {}
177  * class B : A, I2 {}
178  *
179  * auto interfaces = interfaceGraph (B.classinfo);
180  * // interfaces = [I2.classinfo]
181  * ---
182  */
183 ClassInfo[] interfaceGraph (ClassInfo type)
184 {
185     ClassInfo[] info;
186     foreach (iface; type.interfaces)
187     {
188         info ~= iface.classinfo;
189         info ~= interfaceGraph (iface.classinfo);
190     }
191     return info;
192 }
193
194 /** Iterate through all interfaces that type implements, directly or indirectly, including base interfaces. */
195 struct applyInterfaces
196 {
197     ///
198     static applyInterfaces opCall (ClassInfo type)
199     {
200         applyInterfaces apply;
201         apply.type = type;
202         return apply;
203     }
204
205     ///
206     int opApply (int delegate (ref ClassInfo) dg)
207     {
208         int result = 0;
209         for (; type; type = type.base)
210         {
211             foreach (iface; type.interfaces)
212             {
213                 result = dg (iface.classinfo);
214                 if (result)
215                     return result;
216                 result = applyInterfaces (iface.classinfo).opApply (dg);
217                 if (result)
218                     return result;
219             }
220         }
221         return result;
222     }
223
224     ClassInfo type;
225 }
226
227 ///
228 ClassInfo[] baseTypes (ClassInfo type)
229 {
230     if (type is null)
231         return null;
232     return baseClasses (type) ~ baseInterfaces (type);
233 }
234
235 ///
236 ModuleInfo moduleOf (ClassInfo type)
237 {
238     foreach (modula; ModuleInfo)
239         foreach (klass; modula.localClasses)
240             if (klass is type)
241                 return modula;
242     return null;
243 }
244
245 /// Returns a list of interfaces that this class directly implements.
246 ClassInfo[] directInterfaces (ClassInfo type)
247 {
248     ClassInfo[] types;
249     foreach (iface; type.interfaces)
250         types ~= iface.classinfo;
251     return types;
252 }
253
254 /** Returns a list of all types that are derived from the given type. This does not
255  * count interfaces; that is, if type is an interface, you will only get derived
256  * interfaces back. It is an expensive operations. */
257 ClassInfo[] derivedTypes (ClassInfo type)
258 {
259     ClassInfo[] types;
260     foreach (modula; ModuleInfo)
261         foreach (klass; modula.localClasses)
262             if (isDerived (klass, type) && (klass !is type))
263                 types ~= klass;
264     return types;
265 }
266
267 ///
268 bool isDynamicArray (TypeInfo type)
269 {
270     // This implementation is evil.
271     // Array typeinfos are named TypeInfo_A?, and defined individually for each
272     // possible type aside from structs. For example, typeinfo for int[] is
273     // TypeInfo_Ai; for uint[], TypeInfo_Ak.
274     // So any TypeInfo with length 11 and starting with TypeInfo_A is an array
275     // type.
276     // Also, TypeInfo_Array is an array type.
277     type = realType (type);
278     return ((type.classinfo.name[9] == 'A') && (type.classinfo.name.length == 11)) || ((cast(TypeInfo_Array) type) !is null);
279 }
280
281 ///
282 bool isStaticArray (TypeInfo type)
283 {
284     type = realType (type);
285     return (cast(TypeInfo_StaticArray) type) !is null;
286 }
287
288 /** Returns true iff the given type is a dynamic or static array (false for associative
289  * arrays and non-arrays). */
290 bool isArray (TypeInfo type)
291 {
292     type = realType (type);
293     return isDynamicArray (type) || isStaticArray (type);
294 }
295
296 ///
297 bool isAssociativeArray (TypeInfo type)
298 {
299     type = realType (type);
300     return (cast(TypeInfo_AssociativeArray) type) !is null;
301 }
302
303 ///
304 bool isCharacter (TypeInfo type)
305 {
306     type = realType (type);
307     return (type is typeid(char) || type is typeid(wchar) || type is typeid(dchar));
308 }
309
310 ///
311 bool isString (TypeInfo type)
312 {
313     type = realType (type);
314     return isArray (type) && isCharacter (valueType (type));
315 }
316
317 ///
318 bool isUnsignedInteger (TypeInfo type)
319 {
320     type = realType (type);
321     return (type is typeid(uint) || type is typeid(ulong) || type is typeid(ushort) || type is typeid(ubyte));
322 }
323
324 ///
325 bool isSignedInteger (TypeInfo type)
326 {
327     type = realType (type);
328     return (type is typeid(int) || type is typeid(long) || type is typeid(short) || type is typeid(byte));
329 }
330
331 ///
332 bool isInteger (TypeInfo type)
333 {
334     type = realType (type);
335     return isSignedInteger (type) || isUnsignedInteger (type);
336 }
337
338 ///
339 bool isBool (TypeInfo type)
340 {
341     type = realType (type);
342     return (type is typeid(bool));
343 }
344
345 ///
346 bool isFloat (TypeInfo type)
347 {
348     type = realType (type);
349     return (type is typeid(float) || type is typeid(double) || type is typeid(real));
350 }
351
352 ///
353 bool isPrimitive (TypeInfo type)
354 {
355     type = realType (type);
356     return (isArray (type) || isAssociativeArray (type) || isCharacter (type) || isFloat (type) || isInteger (type));
357 }
358
359 /// Returns true iff the given type represents an interface.
360 bool isInterface (TypeInfo type)
361 {
362     return (cast(TypeInfo_Interface) type) !is null;
363 }
364
365 ///
366 bool isPointer (TypeInfo type)
367 {
368     type = realType (type);
369     return (cast(TypeInfo_Pointer) type) !is null;
370 }
371
372 /// Returns true iff the type represents a class (false for interfaces).
373 bool isClass (TypeInfo type)
374 {
375     type = realType (type);
376     return (cast(TypeInfo_Class) type) !is null;
377 }
378
379 ///
380 bool isStruct (TypeInfo type)
381 {
382     type = realType (type);
383     return (cast(TypeInfo_Struct) type) !is null;
384 }
385
386 ///
387 bool isFunction (TypeInfo type)
388 {
389     type = realType (type);
390     return ((cast(TypeInfo_Function) type) !is null) || ((cast(TypeInfo_Delegate) type) !is null);
391 }
392
393 /** Returns true iff the given type is a reference type. */
394 bool isReferenceType (TypeInfo type)
395 {
396     return isClass (type) || isPointer (type) || isDynamicArray (type);
397 }
398
399 /** Returns true iff the given type represents a user-defined type.
400  * This does not include functions, delegates, aliases, or typedefs. */
401 bool isUserDefined (TypeInfo type)
402 {
403     return isClass (type) || isStruct (type);
404 }
405
406 /** Returns true for all value types, false for all reference types.
407  * For functions and delegates, returns false (is this the way it should be?). */
408 bool isValueType (TypeInfo type)
409 {
410     return !(isDynamicArray (type) || isAssociativeArray (type) || isPointer (type) || isClass (type) || isFunction (
411             type));
412 }
413
414 /** The key type of the given type. For an array, size_t; for an associative
415  * array T[U], U. */
416 TypeInfo keyType (TypeInfo type)
417 {
418     type = realType (type);
419     auto assocArray = cast(TypeInfo_AssociativeArray) type;
420     if (assocArray)
421         return assocArray.key;
422     if (isArray (type))
423         return typeid(size_t);
424     return null;
425 }
426
427 /** The value type of the given type -- given T[] or T[n], T; given T[U],
428  * T; given T*, T; anything else, null. */
429 TypeInfo valueType (TypeInfo type)
430 {
431     type = realType (type);
432     if (isArray (type))
433         return type.next;
434     auto assocArray = cast(TypeInfo_AssociativeArray) type;
435     if (assocArray)
436         return assocArray.value;
437     auto pointer = cast(TypeInfo_Pointer) type;
438     if (pointer)
439         return pointer.m_next;
440     return null;
441 }
442
443 /** If the given type represents a delegate or function, the return type
444  * of that function. Otherwise, null. */
445 TypeInfo returnType (TypeInfo type)
446 {
447     type = realType (type);
448     auto delegat = cast(TypeInfo_Delegate) type;
449     if (delegat)
450         return delegat.next;
451     auto func = cast(TypeInfo_Function) type;
452     if (func)
453         return func.next;
454     return null;
455 }
456
457 debug (UnitTest)
458 {
459
460     interface I1
461     {
462     }
463
464     interface I2
465     {
466     }
467
468     interface I3
469     {
470     }
471
472     interface I4
473     {
474     }
475
476     class A
477     {
478     }
479
480     class B : A, I1
481     {
482     }
483
484     class C : B, I2, I3
485     {
486     }
487
488     class D : A, I1
489     {
490         int foo (int i)
491         {
492             return i;
493         }
494     }
495
496     struct S1
497     {
498     }
499
500     unittest {
501         // Struct-related stuff.
502         auto type = typeid(S1);
503         assert (isStruct (type));
504         assert (isValueType (type));
505         assert (isUserDefined (type));
506         assert (!isClass (type));
507         assert (!isPointer (type));
508         assert (null is returnType (type));
509         assert (!isPrimitive (type));
510         assert (valueType (type) is null);
511     }
512
513     unittest {
514         auto type = A.classinfo;
515         assert (baseTypes (type) == [Object.classinfo]);
516         assert (baseClasses (type) == [Object.classinfo]);
517         assert (baseInterfaces (type).length == 0);
518         type = C.classinfo;
519         assert (baseClasses (type) == [B.classinfo, A.classinfo, Object.classinfo]);
520         assert (baseInterfaces (type) == [I2.classinfo, I3.classinfo, I1.classinfo]);
521         assert (baseTypes (type) == [B.classinfo, A.classinfo, Object.classinfo, I2.classinfo, I3.classinfo,
522                 I1.classinfo]);
523     }
524
525     unittest {
526         assert (isPointer (typeid(S1*)));
527         assert (isArray (typeid(S1[])));
528         assert (valueType (typeid(S1*)) is typeid(S1));
529         auto d = new D;
530         assert (returnType (typeid(typeof(&d.foo))) is typeid(int));
531         assert (isFloat (typeid(real)));
532         assert (isFloat (typeid(double)));
533         assert (isFloat (typeid(float)));
534         assert (!isFloat (typeid(creal)));
535         assert (!isFloat (typeid(cdouble)));
536         assert (!isInteger (typeid(float)));
537         assert (!isInteger (typeid(creal)));
538         assert (isInteger (typeid(ulong)));
539         assert (isInteger (typeid(ubyte)));
540         assert (isCharacter (typeid(char)));
541         assert (isCharacter (typeid(wchar)));
542         assert (isCharacter (typeid(dchar)));
543         assert (!isCharacter (typeid(ubyte)));
544         assert (isArray (typeid(typeof("hello"))));
545         assert (isCharacter (typeid(typeof("hello"[0]))));
546         assert (valueType (typeid(typeof("hello"))) is typeid(typeof('h')));
547         assert (isString (typeid(typeof("hello"))), typeof("hello").stringof);
548         auto staticString = typeid(typeof("hello"d));
549         auto dynamicString = typeid(typeof("hello"d[0 .. $]));
550         assert (isString (staticString));
551         assert (isStaticArray (staticString));
552         assert (isDynamicArray (dynamicString), dynamicString.toString () ~ dynamicString.classinfo.name);
553         assert (isString (dynamicString));
554
555         auto type = typeid(int[char[]]);
556         assert (valueType (type) is typeid(int), valueType (type).toString ());
557         assert (keyType (type) is typeid(char[]), keyType (type).toString ());
558         void delegate (int) dg = (int i)
559         {
560         };
561         assert (returnType (typeid(typeof(dg))) is typeid(void));
562         assert (returnType (typeid(int delegate (int))) is typeid(int));
563
564         assert (!isDynamicArray (typeid(int[4])));
565         assert (isStaticArray (typeid(int[4])));
566     }
567
568     unittest {
569         typedef int myint;
570         assert (typeid(myint) !is null, "null typeid(myint)");
571         assert (isInteger (typeid(myint)));
572     }
573
574 }
Note: See TracBrowser for help on using the browser.