Mercurial > projects > dwt2
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 |