]>
Commit | Line | Data |
---|---|---|
b4c522fa IB |
1 | /** |
2 | * Implementation of array assignment support routines. | |
3 | * | |
4 | * Copyright: Copyright Digital Mars 2004 - 2010. | |
5fee5ec3 | 5 | * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). |
b4c522fa | 6 | * Authors: Walter Bright, Sean Kelly |
5fee5ec3 | 7 | * Source: $(DRUNTIMESRC rt/_cast_.d) |
b4c522fa IB |
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): | |
5fee5ec3 IB |
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 | } | |
b4c522fa IB |
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 | */ | |
5fee5ec3 | 39 | Object _d_toObject(return void* p) |
b4c522fa IB |
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 | ||
5fee5ec3 | 91 | int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t offset) @safe |
b4c522fa | 92 | { |
5fee5ec3 | 93 | if (areClassInfosEqual(oc, c)) |
b4c522fa IB |
94 | return true; |
95 | ||
96 | do | |
97 | { | |
5fee5ec3 | 98 | if (oc.base && areClassInfosEqual(oc.base, c)) |
b4c522fa IB |
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 | { | |
5fee5ec3 | 105 | if (areClassInfosEqual(iface.classinfo, c) || _d_isbaseof2(iface.classinfo, c, offset)) |
b4c522fa IB |
106 | { |
107 | offset += iface.offset; | |
108 | return true; | |
109 | } | |
110 | } | |
111 | ||
112 | oc = oc.base; | |
113 | } while (oc); | |
114 | ||
115 | return false; | |
116 | } | |
117 | ||
5fee5ec3 | 118 | int _d_isbaseof(scope ClassInfo oc, scope const ClassInfo c) @safe |
b4c522fa | 119 | { |
5fee5ec3 | 120 | if (areClassInfosEqual(oc, c)) |
b4c522fa IB |
121 | return true; |
122 | ||
123 | do | |
124 | { | |
5fee5ec3 | 125 | if (oc.base && areClassInfosEqual(oc.base, c)) |
b4c522fa IB |
126 | return true; |
127 | ||
128 | foreach (iface; oc.interfaces) | |
129 | { | |
5fee5ec3 | 130 | if (areClassInfosEqual(iface.classinfo, c) || _d_isbaseof(iface.classinfo, c)) |
b4c522fa IB |
131 | return true; |
132 | } | |
133 | ||
134 | oc = oc.base; | |
135 | } while (oc); | |
136 | ||
137 | return false; | |
138 | } |