1 /** 2 * Implementation of array assignment support routines. 3 * 4 * Copyright: Copyright Digital Mars 2004 - 2010. 5 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 * Authors: Walter Bright, Sean Kelly 7 * Source: $(DRUNTIMESRC rt/_cast_.d) 8 */ 9 10 /* Copyright Digital Mars 2004 - 2010. 11 * Distributed under the Boost Software License, Version 1.0. 12 * (See accompanying file LICENSE or copy at 13 * http://www.boost.org/LICENSE_1_0.txt) 14 */ 15 module rt.cast_; 16 17 extern (C): 18 @nogc: 19 nothrow: 20 pure: 21 22 // Needed because ClassInfo.opEquals(Object) does a dynamic cast, 23 // but we are trying to implement dynamic cast. 24 extern (D) private bool areClassInfosEqual(scope const ClassInfo a, scope const ClassInfo b) @safe 25 { 26 if (a is b) 27 return true; 28 // take care of potential duplicates across binaries 29 return a.name == b.name; 30 } 31 32 /****************************************** 33 * Given a pointer: 34 * If it is an Object, return that Object. 35 * If it is an interface, return the Object implementing the interface. 36 * If it is null, return null. 37 * Else, undefined crash 38 */ 39 Object _d_toObject(return scope void* p) 40 { 41 if (!p) 42 return null; 43 44 Object o = cast(Object) p; 45 ClassInfo oc = typeid(o); 46 Interface* pi = **cast(Interface***) p; 47 48 /* Interface.offset lines up with ClassInfo.name.ptr, 49 * so we rely on pointers never being less than 64K, 50 * and Objects never being greater. 51 */ 52 if (pi.offset < 0x10000) 53 { 54 debug(cast_) printf("\tpi.offset = %d\n", pi.offset); 55 return cast(Object)(p - pi.offset); 56 } 57 return o; 58 } 59 60 /************************************* 61 * Attempts to cast Object o to class c. 62 * Returns o if successful, null if not. 63 */ 64 void* _d_interface_cast(void* p, ClassInfo c) 65 { 66 debug(cast_) printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name); 67 if (!p) 68 return null; 69 70 Interface* pi = **cast(Interface***) p; 71 72 debug(cast_) printf("\tpi.offset = %d\n", pi.offset); 73 return _d_dynamic_cast(cast(Object)(p - pi.offset), c); 74 } 75 76 void* _d_dynamic_cast(Object o, ClassInfo c) 77 { 78 debug(cast_) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name); 79 80 void* res = null; 81 size_t offset = 0; 82 if (o && _d_isbaseof2(typeid(o), c, offset)) 83 { 84 debug(cast_) printf("\toffset = %d\n", offset); 85 res = cast(void*) o + offset; 86 } 87 debug(cast_) printf("\tresult = %p\n", res); 88 return res; 89 } 90 91 int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t offset) @safe 92 { 93 if (areClassInfosEqual(oc, c)) 94 return true; 95 96 do 97 { 98 if (oc.base && areClassInfosEqual(oc.base, c)) 99 return true; 100 101 // Bugzilla 2013: Use depth-first search to calculate offset 102 // from the derived (oc) to the base (c). 103 foreach (iface; oc.interfaces) 104 { 105 if (areClassInfosEqual(iface.classinfo, c) || _d_isbaseof2(iface.classinfo, c, offset)) 106 { 107 offset += iface.offset; 108 return true; 109 } 110 } 111 112 oc = oc.base; 113 } while (oc); 114 115 return false; 116 } 117 118 int _d_isbaseof(scope ClassInfo oc, scope const ClassInfo c) @safe 119 { 120 if (areClassInfosEqual(oc, c)) 121 return true; 122 123 do 124 { 125 if (oc.base && areClassInfosEqual(oc.base, c)) 126 return true; 127 128 foreach (iface; oc.interfaces) 129 { 130 if (areClassInfosEqual(iface.classinfo, c) || _d_isbaseof(iface.classinfo, c)) 131 return true; 132 } 133 134 oc = oc.base; 135 } while (oc); 136 137 return false; 138 }