blob: f34d82eed91a19ec51e96ec034e8a07680e00524 [file] [log] [blame]
/**
* Implementation of array assignment support routines.
*
* Copyright: Copyright Digital Mars 2004 - 2010.
* License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
* Authors: Walter Bright, Sean Kelly
*/
/* Copyright Digital Mars 2004 - 2010.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module rt.cast_;
extern (C):
/******************************************
* Given a pointer:
* If it is an Object, return that Object.
* If it is an interface, return the Object implementing the interface.
* If it is null, return null.
* Else, undefined crash
*/
Object _d_toObject(void* p)
{
if (!p)
return null;
Object o = cast(Object) p;
ClassInfo oc = typeid(o);
Interface* pi = **cast(Interface***) p;
/* Interface.offset lines up with ClassInfo.name.ptr,
* so we rely on pointers never being less than 64K,
* and Objects never being greater.
*/
if (pi.offset < 0x10000)
{
debug(cast_) printf("\tpi.offset = %d\n", pi.offset);
return cast(Object)(p - pi.offset);
}
return o;
}
/*************************************
* Attempts to cast Object o to class c.
* Returns o if successful, null if not.
*/
void* _d_interface_cast(void* p, ClassInfo c)
{
debug(cast_) printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name);
if (!p)
return null;
Interface* pi = **cast(Interface***) p;
debug(cast_) printf("\tpi.offset = %d\n", pi.offset);
return _d_dynamic_cast(cast(Object)(p - pi.offset), c);
}
void* _d_dynamic_cast(Object o, ClassInfo c)
{
debug(cast_) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
void* res = null;
size_t offset = 0;
if (o && _d_isbaseof2(typeid(o), c, offset))
{
debug(cast_) printf("\toffset = %d\n", offset);
res = cast(void*) o + offset;
}
debug(cast_) printf("\tresult = %p\n", res);
return res;
}
int _d_isbaseof2(ClassInfo oc, ClassInfo c, ref size_t offset)
{
if (oc is c)
return true;
do
{
if (oc.base is c)
return true;
// Bugzilla 2013: Use depth-first search to calculate offset
// from the derived (oc) to the base (c).
foreach (iface; oc.interfaces)
{
if (iface.classinfo is c || _d_isbaseof2(iface.classinfo, c, offset))
{
offset += iface.offset;
return true;
}
}
oc = oc.base;
} while (oc);
return false;
}
int _d_isbaseof(ClassInfo oc, ClassInfo c)
{
if (oc is c)
return true;
do
{
if (oc.base is c)
return true;
foreach (iface; oc.interfaces)
{
if (iface.classinfo is c || _d_isbaseof(iface.classinfo, c))
return true;
}
oc = oc.base;
} while (oc);
return false;
}
/*********************************
* Find the vtbl[] associated with Interface ic.
*/
void* _d_interface_vtbl(ClassInfo ic, Object o)
{
debug(cast_) printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic);
assert(o);
foreach (iface; typeid(o).interfaces)
{
if (iface.classinfo is ic)
return cast(void*) iface.vtbl;
}
assert(0);
}