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 }