comparison base/src/java/nonstandard/RuntimeTraits.d @ 84:fcf926c91ca4

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