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