Skip to content

Commit

Permalink
Reflection system handles multi-level inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthew Reid committed Aug 24, 2024
1 parent 61301d0 commit 8e15e6c
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 2 deletions.
12 changes: 12 additions & 0 deletions src/Skybolt/SkyboltReflection/Reflection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,22 @@ void Type::addSuperType(const TypePtr& super, std::ptrdiff_t offsetFromThisToSup

std::optional<std::ptrdiff_t> Type::getOffsetFromThisToSuper(const std::type_index& super) const
{
// Look for direct super types
if (auto i = mSuperTypes.find(super); i != mSuperTypes.end())
{
return i->second.second;
}

// Walk tree to find indirect super types
for (const auto& [typeIndex, typeAndOffset] : mSuperTypes)
{
if (auto offset = typeAndOffset.first->getOffsetFromThisToSuper(super); offset)
{
return typeAndOffset.second + *offset;
}
}

// No super type found
return std::nullopt;
}

Expand Down
17 changes: 16 additions & 1 deletion src/Skybolt/SkyboltReflection/Reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,22 @@ class Type
template <typename T>
bool isDerivedFrom() const
{
return mSuperTypes.find(typeid(T)) != mSuperTypes.end();
// Look for direct super type
if (auto i = mSuperTypes.find(typeid(T)); i != mSuperTypes.end())
{
return true;
}

// Look for indirect super types
for (const auto& [typeIndex, typeAndOffset] : mSuperTypes)
{
const TypePtr& superType = typeAndOffset.first;
if (auto result = superType->isDerivedFrom<T>(); result)
{
return true;
}
}
return false;
}

const std::string& getName() const { return mName; }
Expand Down
61 changes: 61 additions & 0 deletions src/Skybolt/SkyboltReflectionTests/PolymorphicReflectionTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ struct Derived : public BaseA, BaseB
int intC = 0;
};

struct MultiLevelDerived : public Derived
{
~MultiLevelDerived() override = default;

int intD = 0;
};

SKYBOLT_REFLECT_BEGIN(BaseA)
{
registry.type<BaseA>("BaseA")
Expand All @@ -53,6 +60,14 @@ SKYBOLT_REFLECT_BEGIN(Derived)
}
SKYBOLT_REFLECT_END

SKYBOLT_REFLECT_BEGIN(MultiLevelDerived)
{
registry.type<MultiLevelDerived>("MultiLevelDerived")
.superType<Derived>()
.property("intD", &MultiLevelDerived::intD);
}
SKYBOLT_REFLECT_END

TEST_CASE("Derived type has super type properties")
{
TypeRegistry registry;
Expand All @@ -66,6 +81,21 @@ TEST_CASE("Derived type has super type properties")
CHECK(type->getProperty("intC"));
}

TEST_CASE("Multi-level derived type has super type properties")
{
TypeRegistry registry;

auto type = registry.getTypeByName("MultiLevelDerived");
REQUIRE(type);
CHECK(type->isDerivedFrom<Derived>());
CHECK(type->isDerivedFrom<BaseA>());
CHECK(type->isDerivedFrom<BaseB>());
CHECK(type->getProperty("intA"));
CHECK(type->getProperty("intB"));
CHECK(type->getProperty("intC"));
CHECK(type->getProperty("intD"));
}

TEST_CASE("Access properties of type with multiple super classes")
{
TypeRegistry registry;
Expand Down Expand Up @@ -127,3 +157,34 @@ TEST_CASE("Access properties of type with multiple super classes")
CHECK(derivedObj.intB == 3);
}
}


TEST_CASE("Access properties of multi-level derived type")
{
TypeRegistry registry;

auto type = registry.getTypeByName("MultiLevelDerived");
REQUIRE(type);
auto multiLevelDerivedClassProperty = type->getProperty("intD");
REQUIRE(multiLevelDerivedClassProperty);
auto derivedClassProperty = type->getProperty("intC");
REQUIRE(derivedClassProperty);
auto baseClassProperty = type->getProperty("intA");
REQUIRE(baseClassProperty);

MultiLevelDerived derivedObj;

SECTION("Set proeprty values on instance created from multi-level derived class")
{
auto instance = createNonOwningInstance(&registry, &derivedObj);

multiLevelDerivedClassProperty->setValue(instance, createOwningInstance(&registry, 1));
CHECK(derivedObj.intD == 1);

derivedClassProperty->setValue(instance, createOwningInstance(&registry, 2));
CHECK(derivedObj.intC == 2);

baseClassProperty->setValue(instance, createOwningInstance(&registry, 3));
CHECK(derivedObj.intA == 3);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class NullCameraController : public CameraController
SKYBOLT_REFLECT_BEGIN(NullCameraController)
{
registry.type<NullCameraController>("NullCameraController")
.superType<NullCameraController>();
.superType<CameraController>();
}
SKYBOLT_REFLECT_END

Expand Down

0 comments on commit 8e15e6c

Please sign in to comment.