Mercurial > projects > dwt2
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/src/java/nonstandard/RuntimeTraits.d Sat Apr 18 09:25:29 2009 +0200 @@ -0,0 +1,609 @@ +/** + * Provides runtime traits, which provide much of the functionality of tango.core.Traits and + * is-expressions, as well as some functionality that is only available at runtime, using + * runtime type information. + * + * Authors: Chris Wright (dhasenan) <dhasenan@gmail.com> + * License: tango license, apache 2.0 + * Copyright (c) 2009, CHRISTOPHER WRIGHT + */ +module java.nonstandard.RuntimeTraits; +import java.lang.all; +// Only DWT +public bool isJavaPrimitive( TypeInfo type ){ + return isBool(type) || isInteger(type) || isCharacter(type) || isFloat(type); +} + +public TypeInfo_Class getTypeInfo( ClassInfo ci ){ + return null; +} + +public TypeInfo_Class getSuperclass( ClassInfo ci ){ + return getSuperclass(getTypeInfo(ci)); +} +public TypeInfo_Class getSuperclass( TypeInfo ti ){ + return null; +} + +public TypeInfo_Interface[] getInterfaces( ClassInfo ci ){ + return getInterfaces(getTypeInfo(ci)); +} +public TypeInfo_Interface[] getInterfaces( TypeInfo ti ){ + return null; +} + +public String getName( ClassInfo ci ){ + return ci.name; +} +public String getName( TypeInfo ti ){ + if( isClass(ti) ){ + return getName( asClass(ti)); + } + return null; +} + +// End DWT. Start Tango... +/// If the given type represents a typedef, return the actual type. +TypeInfo realType (TypeInfo type) +{ + // TypeInfo_Typedef.next() doesn't return the actual type. + // I think it returns TypeInfo_Typedef.base.next(). + // So, a slightly different method. + auto def = cast(TypeInfo_Typedef) type; + if (def !is null) + { + return def.base; + } + return type; +} + +/// If the given type represents a class, return its ClassInfo; else return null; +ClassInfo asClass (TypeInfo type) +{ + if (isInterface (type)) + { + auto klass = cast(TypeInfo_Interface) type; + return klass.info; + } + if (isClass (type)) + { + auto klass = cast(TypeInfo_Class) type; + return klass.info; + } + return null; +} + +/** Returns true iff one type is an ancestor of the other, or if the types are the same. + * If either is null, returns false. */ +bool isDerived (ClassInfo derived, ClassInfo base) +{ + if (derived is null || base is null) + return false; + do + if (derived is base) + return true; + while ((derived = derived.base) !is null) + return false; +} + +/** Returns true iff implementor implements the interface described + * by iface. This is an expensive operation (linear in the number of + * interfaces and base classes). + */ +bool implements (ClassInfo implementor, ClassInfo iface) +{ + foreach (info; applyInterfaces (implementor)) + { + if (iface is info) + return true; + } + return false; +} + +/** Returns true iff an instance of class test is implicitly castable to target. + * This is an expensive operation (isDerived + implements). */ +bool isImplicitly (ClassInfo test, ClassInfo target) +{ + // Keep isDerived first. + // isDerived will be much faster than implements. + return (isDerived (test, target) || implements (test, target)); +} + +/** Returns true iff an instance of type test is implicitly castable to target. + * If the types describe classes or interfaces, this is an expensive operation. */ +bool isImplicitly (TypeInfo test, TypeInfo target) +{ + // A lot of special cases. This is ugly. + if (test is target) + return true; + if (isStaticArray (test) && isDynamicArray (target) && valueType (test) is valueType (target)) + { + // you can implicitly cast static to dynamic (currently) if they + // have the same value type. Other casts should be forbidden. + return true; + } + auto klass1 = asClass (test); + auto klass2 = asClass (target); + if (isClass (test) && isClass (target)) + { + return isDerived (klass1, klass2); + } + if (isInterface (test) && isInterface (target)) + { + return isDerived (klass1, klass2); + } + if (klass1 && klass2) + { + return isImplicitly (klass1, klass2); + } + if (klass1 || klass2) + { + // no casts from class to non-class + return false; + } + if ((isSignedInteger (test) && isSignedInteger (target)) || (isUnsignedInteger (test) && isUnsignedInteger (target)) || (isFloat ( + test) && isFloat (target)) || (isCharacter (test) && isCharacter (target))) + { + return test.tsize () <= target.tsize (); + } + if (isSignedInteger (test) && isUnsignedInteger (target)) + { + // potential loss of data + return false; + } + if (isUnsignedInteger (test) && isSignedInteger (target)) + { + // if the sizes are the same, you could be losing data + // the upper half of the range wraps around to negatives + // if the target type is larger, you can safely hold it + return test.tsize () < target.tsize (); + } + // delegates and functions: no can do + // pointers: no + // structs: no + return false; +} + +/// +ClassInfo[] baseClasses (ClassInfo type) +{ + if (type is null) + return null; + ClassInfo[] types; + while ((type = type.base) !is null) + types ~= type; + return types; +} + +/** Returns a list of all interfaces that this type implements, directly + * or indirectly. This includes base interfaces of types the class implements, + * and interfaces that base classes implement, and base interfaces of interfaces + * that base classes implement. This is an expensive operation. */ +ClassInfo[] baseInterfaces (ClassInfo type) +{ + if (type is null) + return null; + ClassInfo[] types = directInterfaces (type); + while ((type = type.base) !is null) + { + types ~= interfaceGraph (type); + } + return types; +} + +/** Returns all the interfaces that this type directly implements, including + * inherited interfaces. This is an expensive operation. + * + * Examples: + * --- + * interface I1 {} + * interface I2 : I1 {} + * class A : I2 {} + * + * auto interfaces = interfaceGraph (A.classinfo); + * // interfaces = [I1.classinfo, I2.classinfo] + * --- + * + * --- + * interface I1 {} + * interface I2 {} + * class A : I1 {} + * class B : A, I2 {} + * + * auto interfaces = interfaceGraph (B.classinfo); + * // interfaces = [I2.classinfo] + * --- + */ +ClassInfo[] interfaceGraph (ClassInfo type) +{ + ClassInfo[] info; + foreach (iface; type.interfaces) + { + info ~= iface.classinfo; + info ~= interfaceGraph (iface.classinfo); + } + return info; +} + +/** Iterate through all interfaces that type implements, directly or indirectly, including base interfaces. */ +struct applyInterfaces +{ + /// + static applyInterfaces opCall (ClassInfo type) + { + applyInterfaces apply; + apply.type = type; + return apply; + } + + /// + int opApply (int delegate (ref ClassInfo) dg) + { + int result = 0; + for (; type; type = type.base) + { + foreach (iface; type.interfaces) + { + result = dg (iface.classinfo); + if (result) + return result; + result = applyInterfaces (iface.classinfo).opApply (dg); + if (result) + return result; + } + } + return result; + } + + ClassInfo type; +} + +/// +ClassInfo[] baseTypes (ClassInfo type) +{ + if (type is null) + return null; + return baseClasses (type) ~ baseInterfaces (type); +} + +/// +ModuleInfo moduleOf (ClassInfo type) +{ + foreach (modula; ModuleInfo) + foreach (klass; modula.localClasses) + if (klass is type) + return modula; + return null; +} + +/// Returns a list of interfaces that this class directly implements. +ClassInfo[] directInterfaces (ClassInfo type) +{ + ClassInfo[] types; + foreach (iface; type.interfaces) + types ~= iface.classinfo; + return types; +} + +/** Returns a list of all types that are derived from the given type. This does not + * count interfaces; that is, if type is an interface, you will only get derived + * interfaces back. It is an expensive operations. */ +ClassInfo[] derivedTypes (ClassInfo type) +{ + ClassInfo[] types; + foreach (modula; ModuleInfo) + foreach (klass; modula.localClasses) + if (isDerived (klass, type) && (klass !is type)) + types ~= klass; + return types; +} + +/// +bool isDynamicArray (TypeInfo type) +{ + // This implementation is evil. + // Array typeinfos are named TypeInfo_A?, and defined individually for each + // possible type aside from structs. For example, typeinfo for int[] is + // TypeInfo_Ai; for uint[], TypeInfo_Ak. + // So any TypeInfo with length 11 and starting with TypeInfo_A is an array + // type. + // Also, TypeInfo_Array is an array type. + type = realType (type); + return ((type.classinfo.name[9] == 'A') && (type.classinfo.name.length == 11)) || ((cast(TypeInfo_Array) type) !is null); +} + +/// +bool isStaticArray (TypeInfo type) +{ + type = realType (type); + return (cast(TypeInfo_StaticArray) type) !is null; +} + +/** Returns true iff the given type is a dynamic or static array (false for associative + * arrays and non-arrays). */ +bool isArray (TypeInfo type) +{ + type = realType (type); + return isDynamicArray (type) || isStaticArray (type); +} + +/// +bool isAssociativeArray (TypeInfo type) +{ + type = realType (type); + return (cast(TypeInfo_AssociativeArray) type) !is null; +} + +/// +bool isCharacter (TypeInfo type) +{ + type = realType (type); + return (type is typeid(char) || type is typeid(wchar) || type is typeid(dchar)); +} + +/// +bool isString (TypeInfo type) +{ + type = realType (type); + return isArray (type) && isCharacter (valueType (type)); +} + +/// +bool isUnsignedInteger (TypeInfo type) +{ + type = realType (type); + return (type is typeid(uint) || type is typeid(ulong) || type is typeid(ushort) || type is typeid(ubyte)); +} + +/// +bool isSignedInteger (TypeInfo type) +{ + type = realType (type); + return (type is typeid(int) || type is typeid(long) || type is typeid(short) || type is typeid(byte)); +} + +/// +bool isInteger (TypeInfo type) +{ + type = realType (type); + return isSignedInteger (type) || isUnsignedInteger (type); +} + +/// +bool isBool (TypeInfo type) +{ + type = realType (type); + return (type is typeid(bool)); +} + +/// +bool isFloat (TypeInfo type) +{ + type = realType (type); + return (type is typeid(float) || type is typeid(double) || type is typeid(real)); +} + +/// +bool isPrimitive (TypeInfo type) +{ + type = realType (type); + return (isArray (type) || isAssociativeArray (type) || isCharacter (type) || isFloat (type) || isInteger (type)); +} + +/// Returns true iff the given type represents an interface. +bool isInterface (TypeInfo type) +{ + return (cast(TypeInfo_Interface) type) !is null; +} + +/// +bool isPointer (TypeInfo type) +{ + type = realType (type); + return (cast(TypeInfo_Pointer) type) !is null; +} + +/// Returns true iff the type represents a class (false for interfaces). +bool isClass (TypeInfo type) +{ + type = realType (type); + return (cast(TypeInfo_Class) type) !is null; +} + +/// +bool isStruct (TypeInfo type) +{ + type = realType (type); + return (cast(TypeInfo_Struct) type) !is null; +} + +/// +bool isFunction (TypeInfo type) +{ + type = realType (type); + return ((cast(TypeInfo_Function) type) !is null) || ((cast(TypeInfo_Delegate) type) !is null); +} + +/** Returns true iff the given type is a reference type. */ +bool isReferenceType (TypeInfo type) +{ + return isClass (type) || isPointer (type) || isDynamicArray (type); +} + +/** Returns true iff the given type represents a user-defined type. + * This does not include functions, delegates, aliases, or typedefs. */ +bool isUserDefined (TypeInfo type) +{ + return isClass (type) || isStruct (type); +} + +/** Returns true for all value types, false for all reference types. + * For functions and delegates, returns false (is this the way it should be?). */ +bool isValueType (TypeInfo type) +{ + return !(isDynamicArray (type) || isAssociativeArray (type) || isPointer (type) || isClass (type) || isFunction ( + type)); +} + +/** The key type of the given type. For an array, size_t; for an associative + * array T[U], U. */ +TypeInfo keyType (TypeInfo type) +{ + type = realType (type); + auto assocArray = cast(TypeInfo_AssociativeArray) type; + if (assocArray) + return assocArray.key; + if (isArray (type)) + return typeid(size_t); + return null; +} + +/** The value type of the given type -- given T[] or T[n], T; given T[U], + * T; given T*, T; anything else, null. */ +TypeInfo valueType (TypeInfo type) +{ + type = realType (type); + if (isArray (type)) + return type.next; + auto assocArray = cast(TypeInfo_AssociativeArray) type; + if (assocArray) + return assocArray.value; + auto pointer = cast(TypeInfo_Pointer) type; + if (pointer) + return pointer.m_next; + return null; +} + +/** If the given type represents a delegate or function, the return type + * of that function. Otherwise, null. */ +TypeInfo returnType (TypeInfo type) +{ + type = realType (type); + auto delegat = cast(TypeInfo_Delegate) type; + if (delegat) + return delegat.next; + auto func = cast(TypeInfo_Function) type; + if (func) + return func.next; + return null; +} + +debug (UnitTest) +{ + + interface I1 + { + } + + interface I2 + { + } + + interface I3 + { + } + + interface I4 + { + } + + class A + { + } + + class B : A, I1 + { + } + + class C : B, I2, I3 + { + } + + class D : A, I1 + { + int foo (int i) + { + return i; + } + } + + struct S1 + { + } + + unittest { + // Struct-related stuff. + auto type = typeid(S1); + assert (isStruct (type)); + assert (isValueType (type)); + assert (isUserDefined (type)); + assert (!isClass (type)); + assert (!isPointer (type)); + assert (null is returnType (type)); + assert (!isPrimitive (type)); + assert (valueType (type) is null); + } + + unittest { + auto type = A.classinfo; + assert (baseTypes (type) == [Object.classinfo]); + assert (baseClasses (type) == [Object.classinfo]); + assert (baseInterfaces (type).length == 0); + type = C.classinfo; + assert (baseClasses (type) == [B.classinfo, A.classinfo, Object.classinfo]); + assert (baseInterfaces (type) == [I2.classinfo, I3.classinfo, I1.classinfo]); + assert (baseTypes (type) == [B.classinfo, A.classinfo, Object.classinfo, I2.classinfo, I3.classinfo, + I1.classinfo]); + } + + unittest { + assert (isPointer (typeid(S1*))); + assert (isArray (typeid(S1[]))); + assert (valueType (typeid(S1*)) is typeid(S1)); + auto d = new D; + assert (returnType (typeid(typeof(&d.foo))) is typeid(int)); + assert (isFloat (typeid(real))); + assert (isFloat (typeid(double))); + assert (isFloat (typeid(float))); + assert (!isFloat (typeid(creal))); + assert (!isFloat (typeid(cdouble))); + assert (!isInteger (typeid(float))); + assert (!isInteger (typeid(creal))); + assert (isInteger (typeid(ulong))); + assert (isInteger (typeid(ubyte))); + assert (isCharacter (typeid(char))); + assert (isCharacter (typeid(wchar))); + assert (isCharacter (typeid(dchar))); + assert (!isCharacter (typeid(ubyte))); + assert (isArray (typeid(typeof("hello")))); + assert (isCharacter (typeid(typeof("hello"[0])))); + assert (valueType (typeid(typeof("hello"))) is typeid(typeof('h'))); + assert (isString (typeid(typeof("hello"))), typeof("hello").stringof); + auto staticString = typeid(typeof("hello"d)); + auto dynamicString = typeid(typeof("hello"d[0 .. $])); + assert (isString (staticString)); + assert (isStaticArray (staticString)); + assert (isDynamicArray (dynamicString), dynamicString.toString () ~ dynamicString.classinfo.name); + assert (isString (dynamicString)); + + auto type = typeid(int[char[]]); + assert (valueType (type) is typeid(int), valueType (type).toString ()); + assert (keyType (type) is typeid(char[]), keyType (type).toString ()); + void delegate (int) dg = (int i) + { + }; + assert (returnType (typeid(typeof(dg))) is typeid(void)); + assert (returnType (typeid(int delegate (int))) is typeid(int)); + + assert (!isDynamicArray (typeid(int[4]))); + assert (isStaticArray (typeid(int[4]))); + } + + unittest { + typedef int myint; + assert (typeid(myint) !is null, "null typeid(myint)"); + assert (isInteger (typeid(myint))); + } + +} +