1 module lifetime.class_;
2 
3 pragma(LDC_no_moduleinfo);
4 
5 import lifetime.common;
6 
7 /// Allocate and initialise a class
8 extern(C) Object _d_newclass(const TypeInfo_Class ti) 
9 {
10 	auto buff = lwdrInternal_allocBytes(ti.m_init.length);
11 	foreach(i; 0 .. ti.m_init.length)
12 		buff[i] = ti.m_init[i];
13 	return cast(Object)buff.ptr;
14 }
15 
16 /// Finalize and deallocate a class
17 extern(C) void _d_delclass(Object* o) nothrow @nogc
18 {
19     if(*o)
20 	{
21         rt_finalize(cast(void*)*o);
22 
23 	    lwdrInternal_free(cast(void*)*o);
24 	    *o = null;
25     }
26 }
27 
28 /// Allocate and initialise a class
29 extern(C) Object _d_allocclass(TypeInfo_Class ti) 
30 { 
31 	auto buff = lwdrInternal_allocBytes(ti.m_init.length);
32 	foreach(i; 0 .. ti.m_init.length)
33 		buff[i] = ti.m_init[i];
34 	return cast(Object)buff.ptr;
35 }
36 
37 /******************************************
38 * Given a pointer:
39 *      If it is an Object, return that Object.
40 *      If it is an interface, return the Object implementing the interface.
41 *      If it is null, return null.
42 *      Else, undefined crash
43 */
44 extern(C) Object _d_toObject(return void* p) pure nothrow @nogc
45 {
46     if (!p)
47         return null;
48 
49     Object o = cast(Object) p;
50     ClassInfo oc = typeid(o);
51     Interface* pi = **cast(Interface***) p;
52 
53     /* Interface.offset lines up with ClassInfo.name.ptr,
54 	* so we rely on pointers never being less than 64K,
55 	* and Objects never being greater.
56 	*/
57     if (pi.offset < 0x10000)
58     {
59         debug(cast_) printf("\tpi.offset = %d\n", pi.offset);
60         return cast(Object)(p - pi.offset);
61     }
62     return o;
63 }
64 
65 /*************************************
66 * Attempts to cast Object o to class c.
67 * Returns o if successful, null if not.
68 */
69 extern(C) void* _d_interface_cast(void* p, ClassInfo c) pure nothrow @nogc
70 {
71     debug(cast_) printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name);
72     if (!p)
73         return null;
74 
75     Interface* pi = **cast(Interface***) p;
76 
77     debug(cast_) printf("\tpi.offset = %d\n", pi.offset);
78     return _d_dynamic_cast(cast(Object)(p - pi.offset), c);
79 }
80 
81 /// Cast an Object from one representation to another
82 extern(C) void* _d_dynamic_cast(Object o, ClassInfo c) pure nothrow @nogc
83 {
84     debug(cast_) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
85 
86     void* res = null;
87     size_t offset = 0;
88     if (o && _d_isbaseof2(typeid(o), c, offset))
89     {
90         debug(cast_) printf("\toffset = %d\n", offset);
91         res = cast(void*) o + offset;
92     }
93     debug(cast_) printf("\tresult = %p\n", res);
94     return res;
95 }
96 
97 /// Check if `c` is base of `oc`
98 extern(C) int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t offset) @safe pure nothrow @nogc
99 {
100     if (oc is c)
101         return true;
102 
103     do
104     {
105         if (oc.base is c)
106             return true;
107 
108         // Bugzilla 2013: Use depth-first search to calculate offset
109         // from the derived (oc) to the base (c).
110         foreach (iface; oc.interfaces)
111         {
112             if (iface.classinfo is c || _d_isbaseof2(iface.classinfo, c, offset))
113             {
114                 offset += iface.offset;
115                 return true;
116             }
117         }
118 
119         oc = oc.base;
120     } while (oc);
121 
122     return false;
123 }
124 
125 /// Check if `c` is base of `oc`
126 extern(C) int _d_isbaseof(scope ClassInfo oc, scope const ClassInfo c) @safe pure nothrow @nogc
127 {
128     if (oc is c)
129         return true;
130 
131     do
132     {
133         if (oc.base is c)
134             return true;
135 
136         foreach (iface; oc.interfaces)
137         {
138             if (iface.classinfo is c || _d_isbaseof(iface.classinfo, c))
139                 return true;
140         }
141 
142         oc = oc.base;
143     } while (oc);
144 
145     return false;
146 }