diff lphobos/internal/cast.d @ 113:27b9f749d9fe trunk

[svn r117] Initial working implementation of interfaces. Groundwork for all the different types of class/interface casts laid out.
author lindquist
date Sat, 24 Nov 2007 06:33:00 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/internal/cast.d	Sat Nov 24 06:33:00 2007 +0100
@@ -0,0 +1,182 @@
+/*
+ *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+
+import object;
+import std.c.stdio;
+
+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)
+{   Object o;
+
+    if (p)
+    {
+	o = cast(Object)p;
+	//ClassInfo oc = o.classinfo;
+	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)
+	{
+	    //printf("\tpi.offset = %d\n", pi.offset);
+	    o = cast(Object)(p - pi.offset);
+	}
+    }
+    return o;
+}
+
+
+/*************************************
+ * Attempts to cast Object o to class c.
+ * Returns o if successful, null if not.
+ */
+
+Object _d_interface_cast(void* p, ClassInfo c)
+{   Object o;
+
+    //printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name);
+    if (p)
+    {
+	Interface *pi = **cast(Interface ***)p;
+
+	//printf("\tpi.offset = %d\n", pi.offset);
+	o = cast(Object)(p - pi.offset);
+	return _d_dynamic_cast(o, c);
+    }
+    return o;
+}
+
+Object _d_dynamic_cast(Object o, ClassInfo c)
+{   ClassInfo oc;
+    uint offset = 0;
+
+    //printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
+
+    if (o)
+    {
+	oc = o.classinfo;
+	if (_d_isbaseof2(oc, c, offset))
+	{
+	    //printf("\toffset = %d\n", offset);
+	    o = cast(Object)(cast(void*)o + offset);
+	}
+	else
+	    o = null;
+    }
+    //printf("\tresult = %p\n", o);
+    return o;
+}
+
+int _d_isbaseof2(ClassInfo oc, ClassInfo c, inout uint offset)
+{   int i;
+
+    if (oc is c)
+	return 1;
+    do
+    {
+	if (oc.base is c)
+	    return 1;
+	for (i = 0; i < oc.interfaces.length; i++)
+	{
+	    ClassInfo ic;
+
+	    ic = oc.interfaces[i].classinfo;
+	    if (ic is c)
+	    {	offset = oc.interfaces[i].offset;
+		return 1;
+	    }
+	}
+	for (i = 0; i < oc.interfaces.length; i++)
+	{
+	    ClassInfo ic;
+
+	    ic = oc.interfaces[i].classinfo;
+	    if (_d_isbaseof2(ic, c, offset))
+	    {	offset = oc.interfaces[i].offset;
+		return 1;
+	    }
+	}
+	oc = oc.base;
+    } while (oc);
+    return 0;
+}
+
+int _d_isbaseof(ClassInfo oc, ClassInfo c)
+{   int i;
+
+    if (oc is c)
+	return 1;
+    do
+    {
+	if (oc.base is c)
+	    return 1;
+	for (i = 0; i < oc.interfaces.length; i++)
+	{
+	    ClassInfo ic;
+
+	    ic = oc.interfaces[i].classinfo;
+	    if (ic is c || _d_isbaseof(ic, c))
+		return 1;
+	}
+	oc = oc.base;
+    } while (oc);
+    return 0;
+}
+
+/*********************************
+ * Find the vtbl[] associated with Interface ic.
+ */
+
+void *_d_interface_vtbl(ClassInfo ic, Object o)
+{   int i;
+    ClassInfo oc;
+
+    //printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic);
+
+    assert(o);
+
+    oc = o.classinfo;
+    for (i = 0; i < oc.interfaces.length; i++)
+    {
+	ClassInfo oic;
+
+	oic = oc.interfaces[i].classinfo;
+	if (oic is ic)
+	{
+	    return cast(void *)oc.interfaces[i].vtbl;
+	}
+    }
+    assert(0);
+}