84
|
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 ///
|
112
|
270 version(Tango){
|
|
271 ModuleInfo moduleOf (ClassInfo type)
|
|
272 {
|
|
273 foreach (modula; ModuleInfo)
|
|
274 foreach (klass; modula.localClasses)
|
|
275 if (klass is type)
|
|
276 return modula;
|
|
277 return null;
|
|
278 }
|
|
279 } else { // Phobos
|
|
280 ModuleInfo* moduleOf (ClassInfo type)
|
|
281 {
|
|
282 foreach (modula; ModuleInfo)
|
|
283 foreach (klass; modula.localClasses)
|
|
284 if (klass is type)
|
|
285 return modula;
|
|
286 return null;
|
|
287 }
|
84
|
288 }
|
|
289
|
|
290 /// Returns a list of interfaces that this class directly implements.
|
|
291 ClassInfo[] directInterfaces (ClassInfo type)
|
|
292 {
|
|
293 ClassInfo[] types;
|
|
294 foreach (iface; type.interfaces)
|
|
295 types ~= iface.classinfo;
|
|
296 return types;
|
|
297 }
|
|
298
|
|
299 /** Returns a list of all types that are derived from the given type. This does not
|
|
300 * count interfaces; that is, if type is an interface, you will only get derived
|
|
301 * interfaces back. It is an expensive operations. */
|
|
302 ClassInfo[] derivedTypes (ClassInfo type)
|
|
303 {
|
|
304 ClassInfo[] types;
|
|
305 foreach (modula; ModuleInfo)
|
|
306 foreach (klass; modula.localClasses)
|
|
307 if (isDerived (klass, type) && (klass !is type))
|
|
308 types ~= klass;
|
|
309 return types;
|
|
310 }
|
|
311
|
|
312 ///
|
|
313 bool isDynamicArray (TypeInfo type)
|
|
314 {
|
|
315 // This implementation is evil.
|
|
316 // Array typeinfos are named TypeInfo_A?, and defined individually for each
|
|
317 // possible type aside from structs. For example, typeinfo for int[] is
|
|
318 // TypeInfo_Ai; for uint[], TypeInfo_Ak.
|
|
319 // So any TypeInfo with length 11 and starting with TypeInfo_A is an array
|
|
320 // type.
|
|
321 // Also, TypeInfo_Array is an array type.
|
|
322 type = realType (type);
|
|
323 return ((type.classinfo.name[9] == 'A') && (type.classinfo.name.length == 11)) || ((cast(TypeInfo_Array) type) !is null);
|
|
324 }
|
|
325
|
|
326 ///
|
|
327 bool isStaticArray (TypeInfo type)
|
|
328 {
|
|
329 type = realType (type);
|
|
330 return (cast(TypeInfo_StaticArray) type) !is null;
|
|
331 }
|
|
332
|
|
333 /** Returns true iff the given type is a dynamic or static array (false for associative
|
|
334 * arrays and non-arrays). */
|
|
335 bool isArray (TypeInfo type)
|
|
336 {
|
|
337 type = realType (type);
|
|
338 return isDynamicArray (type) || isStaticArray (type);
|
|
339 }
|
|
340
|
|
341 ///
|
|
342 bool isAssociativeArray (TypeInfo type)
|
|
343 {
|
|
344 type = realType (type);
|
|
345 return (cast(TypeInfo_AssociativeArray) type) !is null;
|
|
346 }
|
|
347
|
|
348 ///
|
|
349 bool isCharacter (TypeInfo type)
|
|
350 {
|
|
351 type = realType (type);
|
|
352 return (type is typeid(char) || type is typeid(wchar) || type is typeid(dchar));
|
|
353 }
|
|
354
|
|
355 ///
|
|
356 bool isString (TypeInfo type)
|
|
357 {
|
|
358 type = realType (type);
|
|
359 return isArray (type) && isCharacter (valueType (type));
|
|
360 }
|
|
361
|
|
362 ///
|
|
363 bool isUnsignedInteger (TypeInfo type)
|
|
364 {
|
|
365 type = realType (type);
|
|
366 return (type is typeid(uint) || type is typeid(ulong) || type is typeid(ushort) || type is typeid(ubyte));
|
|
367 }
|
|
368
|
|
369 ///
|
|
370 bool isSignedInteger (TypeInfo type)
|
|
371 {
|
|
372 type = realType (type);
|
|
373 return (type is typeid(int) || type is typeid(long) || type is typeid(short) || type is typeid(byte));
|
|
374 }
|
|
375
|
|
376 ///
|
|
377 bool isInteger (TypeInfo type)
|
|
378 {
|
|
379 type = realType (type);
|
|
380 return isSignedInteger (type) || isUnsignedInteger (type);
|
|
381 }
|
|
382
|
|
383 ///
|
|
384 bool isBool (TypeInfo type)
|
|
385 {
|
|
386 type = realType (type);
|
|
387 return (type is typeid(bool));
|
|
388 }
|
|
389
|
|
390 ///
|
|
391 bool isFloat (TypeInfo type)
|
|
392 {
|
|
393 type = realType (type);
|
|
394 return (type is typeid(float) || type is typeid(double) || type is typeid(real));
|
|
395 }
|
|
396
|
|
397 ///
|
|
398 bool isPrimitive (TypeInfo type)
|
|
399 {
|
|
400 type = realType (type);
|
|
401 return (isArray (type) || isAssociativeArray (type) || isCharacter (type) || isFloat (type) || isInteger (type));
|
|
402 }
|
|
403
|
|
404 /// Returns true iff the given type represents an interface.
|
|
405 bool isInterface (TypeInfo type)
|
|
406 {
|
|
407 return (cast(TypeInfo_Interface) type) !is null;
|
|
408 }
|
|
409
|
|
410 ///
|
|
411 bool isPointer (TypeInfo type)
|
|
412 {
|
|
413 type = realType (type);
|
|
414 return (cast(TypeInfo_Pointer) type) !is null;
|
|
415 }
|
|
416
|
|
417 /// Returns true iff the type represents a class (false for interfaces).
|
|
418 bool isClass (TypeInfo type)
|
|
419 {
|
|
420 type = realType (type);
|
|
421 return (cast(TypeInfo_Class) type) !is null;
|
|
422 }
|
|
423
|
|
424 ///
|
|
425 bool isStruct (TypeInfo type)
|
|
426 {
|
|
427 type = realType (type);
|
|
428 return (cast(TypeInfo_Struct) type) !is null;
|
|
429 }
|
|
430
|
|
431 ///
|
|
432 bool isFunction (TypeInfo type)
|
|
433 {
|
|
434 type = realType (type);
|
|
435 return ((cast(TypeInfo_Function) type) !is null) || ((cast(TypeInfo_Delegate) type) !is null);
|
|
436 }
|
|
437
|
|
438 /** Returns true iff the given type is a reference type. */
|
|
439 bool isReferenceType (TypeInfo type)
|
|
440 {
|
|
441 return isClass (type) || isPointer (type) || isDynamicArray (type);
|
|
442 }
|
|
443
|
|
444 /** Returns true iff the given type represents a user-defined type.
|
|
445 * This does not include functions, delegates, aliases, or typedefs. */
|
|
446 bool isUserDefined (TypeInfo type)
|
|
447 {
|
|
448 return isClass (type) || isStruct (type);
|
|
449 }
|
|
450
|
|
451 /** Returns true for all value types, false for all reference types.
|
|
452 * For functions and delegates, returns false (is this the way it should be?). */
|
|
453 bool isValueType (TypeInfo type)
|
|
454 {
|
|
455 return !(isDynamicArray (type) || isAssociativeArray (type) || isPointer (type) || isClass (type) || isFunction (
|
|
456 type));
|
|
457 }
|
|
458
|
|
459 /** The key type of the given type. For an array, size_t; for an associative
|
|
460 * array T[U], U. */
|
|
461 TypeInfo keyType (TypeInfo type)
|
|
462 {
|
|
463 type = realType (type);
|
|
464 auto assocArray = cast(TypeInfo_AssociativeArray) type;
|
|
465 if (assocArray)
|
|
466 return assocArray.key;
|
|
467 if (isArray (type))
|
|
468 return typeid(size_t);
|
|
469 return null;
|
|
470 }
|
|
471
|
|
472 /** The value type of the given type -- given T[] or T[n], T; given T[U],
|
|
473 * T; given T*, T; anything else, null. */
|
|
474 TypeInfo valueType (TypeInfo type)
|
|
475 {
|
|
476 type = realType (type);
|
|
477 if (isArray (type))
|
|
478 return type.next;
|
|
479 auto assocArray = cast(TypeInfo_AssociativeArray) type;
|
|
480 if (assocArray)
|
|
481 return assocArray.value;
|
|
482 auto pointer = cast(TypeInfo_Pointer) type;
|
|
483 if (pointer)
|
|
484 return pointer.m_next;
|
|
485 return null;
|
|
486 }
|
|
487
|
|
488 /** If the given type represents a delegate or function, the return type
|
|
489 * of that function. Otherwise, null. */
|
|
490 TypeInfo returnType (TypeInfo type)
|
|
491 {
|
|
492 type = realType (type);
|
|
493 auto delegat = cast(TypeInfo_Delegate) type;
|
|
494 if (delegat)
|
|
495 return delegat.next;
|
|
496 auto func = cast(TypeInfo_Function) type;
|
|
497 if (func)
|
|
498 return func.next;
|
|
499 return null;
|
|
500 }
|
|
501
|
|
502 debug (UnitTest)
|
|
503 {
|
|
504
|
|
505 interface I1
|
|
506 {
|
|
507 }
|
|
508
|
|
509 interface I2
|
|
510 {
|
|
511 }
|
|
512
|
|
513 interface I3
|
|
514 {
|
|
515 }
|
|
516
|
|
517 interface I4
|
|
518 {
|
|
519 }
|
|
520
|
|
521 class A
|
|
522 {
|
|
523 }
|
|
524
|
|
525 class B : A, I1
|
|
526 {
|
|
527 }
|
|
528
|
|
529 class C : B, I2, I3
|
|
530 {
|
|
531 }
|
|
532
|
|
533 class D : A, I1
|
|
534 {
|
|
535 int foo (int i)
|
|
536 {
|
|
537 return i;
|
|
538 }
|
|
539 }
|
|
540
|
|
541 struct S1
|
|
542 {
|
|
543 }
|
|
544
|
|
545 unittest {
|
|
546 // Struct-related stuff.
|
|
547 auto type = typeid(S1);
|
|
548 assert (isStruct (type));
|
|
549 assert (isValueType (type));
|
|
550 assert (isUserDefined (type));
|
|
551 assert (!isClass (type));
|
|
552 assert (!isPointer (type));
|
|
553 assert (null is returnType (type));
|
|
554 assert (!isPrimitive (type));
|
|
555 assert (valueType (type) is null);
|
|
556 }
|
|
557
|
|
558 unittest {
|
|
559 auto type = A.classinfo;
|
|
560 assert (baseTypes (type) == [Object.classinfo]);
|
|
561 assert (baseClasses (type) == [Object.classinfo]);
|
|
562 assert (baseInterfaces (type).length == 0);
|
|
563 type = C.classinfo;
|
|
564 assert (baseClasses (type) == [B.classinfo, A.classinfo, Object.classinfo]);
|
|
565 assert (baseInterfaces (type) == [I2.classinfo, I3.classinfo, I1.classinfo]);
|
|
566 assert (baseTypes (type) == [B.classinfo, A.classinfo, Object.classinfo, I2.classinfo, I3.classinfo,
|
|
567 I1.classinfo]);
|
|
568 }
|
|
569
|
|
570 unittest {
|
|
571 assert (isPointer (typeid(S1*)));
|
|
572 assert (isArray (typeid(S1[])));
|
|
573 assert (valueType (typeid(S1*)) is typeid(S1));
|
|
574 auto d = new D;
|
|
575 assert (returnType (typeid(typeof(&d.foo))) is typeid(int));
|
|
576 assert (isFloat (typeid(real)));
|
|
577 assert (isFloat (typeid(double)));
|
|
578 assert (isFloat (typeid(float)));
|
|
579 assert (!isFloat (typeid(creal)));
|
|
580 assert (!isFloat (typeid(cdouble)));
|
|
581 assert (!isInteger (typeid(float)));
|
|
582 assert (!isInteger (typeid(creal)));
|
|
583 assert (isInteger (typeid(ulong)));
|
|
584 assert (isInteger (typeid(ubyte)));
|
|
585 assert (isCharacter (typeid(char)));
|
|
586 assert (isCharacter (typeid(wchar)));
|
|
587 assert (isCharacter (typeid(dchar)));
|
|
588 assert (!isCharacter (typeid(ubyte)));
|
|
589 assert (isArray (typeid(typeof("hello"))));
|
|
590 assert (isCharacter (typeid(typeof("hello"[0]))));
|
|
591 assert (valueType (typeid(typeof("hello"))) is typeid(typeof('h')));
|
|
592 assert (isString (typeid(typeof("hello"))), typeof("hello").stringof);
|
|
593 auto staticString = typeid(typeof("hello"d));
|
|
594 auto dynamicString = typeid(typeof("hello"d[0 .. $]));
|
|
595 assert (isString (staticString));
|
|
596 assert (isStaticArray (staticString));
|
|
597 assert (isDynamicArray (dynamicString), dynamicString.toString () ~ dynamicString.classinfo.name);
|
|
598 assert (isString (dynamicString));
|
|
599
|
|
600 auto type = typeid(int[char[]]);
|
|
601 assert (valueType (type) is typeid(int), valueType (type).toString ());
|
|
602 assert (keyType (type) is typeid(char[]), keyType (type).toString ());
|
|
603 void delegate (int) dg = (int i)
|
|
604 {
|
|
605 };
|
|
606 assert (returnType (typeid(typeof(dg))) is typeid(void));
|
|
607 assert (returnType (typeid(int delegate (int))) is typeid(int));
|
|
608
|
|
609 assert (!isDynamicArray (typeid(int[4])));
|
|
610 assert (isStaticArray (typeid(int[4])));
|
|
611 }
|
|
612
|
|
613 unittest {
|
|
614 typedef int myint;
|
|
615 assert (typeid(myint) !is null, "null typeid(myint)");
|
|
616 assert (isInteger (typeid(myint)));
|
|
617 }
|
|
618
|
|
619 }
|
|
620
|