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