Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Fix Issue 20178 - Add TypeInfo_Class/TypeInfo_Interface.isBaseOf
Browse files Browse the repository at this point in the history
Equivalent to C#/Java isAssignableFrom. Naming the method
"isAssignableFrom" would be more familiar to people coming from C#/Java
but is potentially misleading: "alias this" and overloadable opAssign
mean that this would not actually indicate whether values of one type
could be assigned to another.

Adding qualifiers to rt.cast_ functions.
  • Loading branch information
n8sh committed Aug 30, 2019
1 parent a2ee5cc commit 125559e
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 3 deletions.
52 changes: 52 additions & 0 deletions src/object.d
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,8 @@ class TypeInfo_Delegate : TypeInfo
}

private extern (C) Object _d_newclass(const TypeInfo_Class ci);
private extern (C) int _d_isbaseof(scope TypeInfo_Class child,
scope const TypeInfo_Class parent) @nogc nothrow pure @safe; // rt.cast_

/**
* Runtime type information about a class.
Expand Down Expand Up @@ -1102,6 +1104,24 @@ class TypeInfo_Class : TypeInfo
}
return o;
}

/**
* Returns true if the class described by `child` derives from the class
* described by this `TypeInfo_Class`.
*
* Params:
* child = TypeInfo for some class
* Returns:
* true if the class described by `child` derives from the
* class described by this `TypeInfo_Class`.
*/
bool isBaseOf(scope const TypeInfo_Class child) const @nogc nothrow pure @trusted
{
for (auto ti = cast() child; ti !is null; ti = ti.base)
if (ti is this)
return true;
return false;
}
}

alias ClassInfo = TypeInfo_Class;
Expand Down Expand Up @@ -1191,6 +1211,38 @@ class TypeInfo_Interface : TypeInfo
override @property uint flags() nothrow pure const { return 1; }

TypeInfo_Class info;

/**
* Returns true if the class described by `child` derives from the interface
* described by this `TypeInfo_Interface`.
*
* Params:
* child = TypeInfo for some class
* Returns:
* true if the class described by `child` derives from the
* interface described by this `TypeInfo_Interface`.
*/
bool isBaseOf(scope const TypeInfo_Class child) const @nogc nothrow pure @trusted
{
auto child_ = cast() child;
return cast(bool) _d_isbaseof(child_, this.info);
}

/**
* Returns true if the interface described by `child` derives from the
* the interface described by this `TypeInfo_Interface`.
*
* Params:
* child = TypeInfo for some interface
* Returns:
* true if the interface described by `child` derives from the
* interface described by this `TypeInfo_Interface`.
*/
bool isBaseOf(scope const TypeInfo_Interface child) const @nogc nothrow pure @trusted
{
auto child_ = cast() child;
return child !is null && cast(bool) _d_isbaseof(child_.info, this.info);
}
}

class TypeInfo_Struct : TypeInfo
Expand Down
7 changes: 5 additions & 2 deletions src/rt/cast_.d
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
module rt.cast_;

extern (C):
@nogc:
nothrow:
pure:

/******************************************
* Given a pointer:
Expand Down Expand Up @@ -74,7 +77,7 @@ void* _d_dynamic_cast(Object o, ClassInfo c)
return res;
}

int _d_isbaseof2(ClassInfo oc, ClassInfo c, ref size_t offset)
int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t offset) @safe
{
if (oc is c)
return true;
Expand All @@ -101,7 +104,7 @@ int _d_isbaseof2(ClassInfo oc, ClassInfo c, ref size_t offset)
return false;
}

int _d_isbaseof(ClassInfo oc, ClassInfo c)
int _d_isbaseof(scope ClassInfo oc, scope const ClassInfo c) @safe
{
if (oc is c)
return true;
Expand Down
2 changes: 1 addition & 1 deletion test/typeinfo/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
include ../common.mak

TESTS:=comparison
TESTS:=comparison isbaseof

.PHONY: all clean
all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS)))
Expand Down
35 changes: 35 additions & 0 deletions test/typeinfo/src/isbaseof.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// https://issues.dlang.org/show_bug.cgi?id=20178

interface I {}
interface J : I {}
class C1 : I {}
class C2 : C1 {}
class C3 : J {}

void main() @nogc nothrow pure @safe
{
assert(typeid(C1).isBaseOf(typeid(C1)));
assert(typeid(C1).isBaseOf(typeid(C2)));

assert(!typeid(C2).isBaseOf(typeid(C1)));
assert(typeid(C2).isBaseOf(typeid(C2)));

assert(!typeid(C1).isBaseOf(typeid(Object)));
assert(!typeid(C2).isBaseOf(typeid(Object)));
assert(typeid(Object).isBaseOf(typeid(C1)));
assert(typeid(Object).isBaseOf(typeid(C2)));

assert(typeid(I).isBaseOf(typeid(I)));
assert(typeid(I).isBaseOf(typeid(J)));
assert(typeid(I).isBaseOf(typeid(C1)));
assert(typeid(I).isBaseOf(typeid(C2)));
assert(typeid(I).isBaseOf(typeid(C3)));
assert(!typeid(I).isBaseOf(typeid(Object)));

assert(!typeid(J).isBaseOf(typeid(I)));
assert(typeid(J).isBaseOf(typeid(J)));
assert(!typeid(J).isBaseOf(typeid(C1)));
assert(!typeid(J).isBaseOf(typeid(C2)));
assert(typeid(J).isBaseOf(typeid(C3)));
assert(!typeid(J).isBaseOf(typeid(Object)));
}

0 comments on commit 125559e

Please sign in to comment.