fix deep is_base_of and is_derived_from

This commit is contained in:
BlackMATov
2021-11-25 18:57:53 +07:00
parent e17c8a4206
commit 78e45607dd
3 changed files with 72 additions and 4 deletions

View File

@@ -23,6 +23,7 @@ namespace meta_hpp
template < class_kind Class >
template < typename... Args >
class_bind<Class>& class_bind<Class>::ctor_() {
static_assert(std::is_constructible_v<Class, Args...>);
auto ctor_state = detail::ctor_state::make<Class, Args...>();
data_->ctors.emplace(ctor_state->index, std::move(ctor_state));
return *this;
@@ -31,6 +32,7 @@ namespace meta_hpp
template < class_kind Class >
template < class_kind Base >
class_bind<Class>& class_bind<Class>::base_() {
static_assert(std::is_base_of_v<Base, Class>);
auto base_data = detail::class_type_data::get<Base>();
data_->bases.emplace(base_data);
return *this;
@@ -47,6 +49,7 @@ namespace meta_hpp
template < class_kind Class >
template < member_kind Member >
class_bind<Class>& class_bind<Class>::member_(std::string name, Member member) {
static_assert(std::same_as<Class, typename detail::member_traits<Member>::class_type>);
auto member_state = detail::member_state::make<Member>(std::move(name), std::move(member));
data_->members.emplace(member_state->index, std::move(member_state));
return *this;
@@ -55,6 +58,7 @@ namespace meta_hpp
template < class_kind Class >
template < method_kind Method >
class_bind<Class>& class_bind<Class>::method_(std::string name, Method method) {
static_assert(std::same_as<Class, typename detail::method_traits<Method>::class_type>);
auto method_state = detail::method_state::make<Method>(std::move(name), std::move(method));
data_->methods.emplace(method_state->index, std::move(method_state));
return *this;

View File

@@ -97,7 +97,21 @@ namespace meta_hpp
}
inline bool class_type::is_base_of(const class_type& derived) const noexcept {
return derived.data_ && derived.data_->bases.contains(*this);
if ( !is_valid() || !derived.is_valid() ) {
return false;
}
if ( derived.data_->bases.contains(*this) ) {
return true;
}
for ( auto&& derived_base : derived.data_->bases ) {
if ( is_base_of(derived_base) ) {
return true;
}
}
return false;
}
template < class_kind Base >
@@ -106,7 +120,21 @@ namespace meta_hpp
}
inline bool class_type::is_derived_from(const class_type& base) const noexcept {
return data_ && data_->bases.contains(base);
if ( !is_valid() || !base.is_valid() ) {
return false;
}
if ( data_->bases.contains(base) ) {
return true;
}
for ( auto&& self_base : data_->bases ) {
if ( self_base.is_derived_from(base) ) {
return true;
}
}
return false;
}
inline function class_type::get_function(std::string_view name) const noexcept {

View File

@@ -38,7 +38,7 @@ namespace
float base_clazz_2::base_variable_2 = 2.0f;
struct derived_clazz final : base_clazz_1, base_clazz_2 {
struct derived_clazz : base_clazz_1, base_clazz_2 {
derived_clazz(int i, float f)
: base_clazz_1{i}
, base_clazz_2{f} {}
@@ -50,6 +50,10 @@ namespace
static constexpr double derived_variable = 3.0;
};
struct final_derived_clazz final : derived_clazz {
using derived_clazz::derived_clazz;
};
template < typename... Args >
struct variadic_clazz {};
}
@@ -84,6 +88,10 @@ TEST_CASE("meta/meta_types/class_type") {
.function_("derived_function", &derived_clazz::derived_function)
.variable_("derived_variable", &derived_clazz::derived_variable);
meta::class_<final_derived_clazz>()
.ctor_<int, float>()
.base_<derived_clazz>();
const meta::class_type base_clazz_1_type = meta::resolve_type<base_clazz_1>();
REQUIRE(base_clazz_1_type);
@@ -93,6 +101,9 @@ TEST_CASE("meta/meta_types/class_type") {
const meta::class_type derived_clazz_type = meta::resolve_type<const derived_clazz>();
REQUIRE(derived_clazz_type);
const meta::class_type final_derived_clazz_type = meta::resolve_type<const final_derived_clazz>();
REQUIRE(final_derived_clazz_type);
const meta::class_type variadic_clazz_int_type = meta::resolve_type<variadic_clazz<int>>();
REQUIRE(variadic_clazz_int_type);
@@ -102,7 +113,8 @@ TEST_CASE("meta/meta_types/class_type") {
SUBCASE("get_flags") {
CHECK(base_clazz_1_type.get_flags() == meta::class_flags{});
CHECK(base_clazz_2_type.get_flags() == meta::class_flags{});
CHECK(derived_clazz_type.get_flags() == meta::class_flags::is_final);
CHECK(derived_clazz_type.get_flags() == meta::class_flags{});
CHECK(final_derived_clazz_type.get_flags() == meta::class_flags::is_final);
CHECK(variadic_clazz_int_type.get_flags() == (meta::class_flags::is_empty | meta::class_flags::is_template_instantiation));
CHECK(variadic_clazz_int_float_type.get_flags() == (meta::class_flags::is_empty | meta::class_flags::is_template_instantiation));
}
@@ -111,6 +123,7 @@ TEST_CASE("meta/meta_types/class_type") {
CHECK(base_clazz_1_type.get_size() == sizeof(base_clazz_1));
CHECK(base_clazz_2_type.get_size() == sizeof(base_clazz_2));
CHECK(derived_clazz_type.get_size() == sizeof(derived_clazz));
CHECK(final_derived_clazz_type.get_size() == sizeof(final_derived_clazz));
}
SUBCASE("get_arity") {
@@ -174,36 +187,42 @@ TEST_CASE("meta/meta_types/class_type") {
CHECK(base_clazz_1_type.get_ctors().size() == 1);
CHECK(base_clazz_2_type.get_ctors().size() == 1);
CHECK(derived_clazz_type.get_ctors().size() == 1);
CHECK(final_derived_clazz_type.get_ctors().size() == 1);
}
SUBCASE("get_bases") {
CHECK(base_clazz_1_type.get_bases() == meta::class_set{});
CHECK(base_clazz_2_type.get_bases() == meta::class_set{});
CHECK(derived_clazz_type.get_bases() == meta::class_set{base_clazz_1_type, base_clazz_2_type});
CHECK(final_derived_clazz_type.get_bases() == meta::class_set{derived_clazz_type});
}
SUBCASE("get_functions") {
CHECK(base_clazz_1_type.get_functions().size() == 3);
CHECK(base_clazz_2_type.get_functions().size() == 1);
CHECK(derived_clazz_type.get_functions().size() == 1);
CHECK(final_derived_clazz_type.get_functions().size() == 0);
}
SUBCASE("get_members") {
CHECK(base_clazz_1_type.get_members().size() == 1);
CHECK(base_clazz_2_type.get_members().size() == 1);
CHECK(derived_clazz_type.get_members().size() == 1);
CHECK(final_derived_clazz_type.get_members().size() == 0);
}
SUBCASE("get_methods") {
CHECK(base_clazz_1_type.get_methods().size() == 3);
CHECK(base_clazz_2_type.get_methods().size() == 1);
CHECK(derived_clazz_type.get_methods().size() == 1);
CHECK(final_derived_clazz_type.get_methods().size() == 0);
}
SUBCASE("get_variables") {
CHECK(base_clazz_1_type.get_variables().size() == 1);
CHECK(base_clazz_2_type.get_variables().size() == 1);
CHECK(derived_clazz_type.get_variables().size() == 1);
CHECK(final_derived_clazz_type.get_variables().size() == 0);
}
SUBCASE("is_base_of") {
@@ -216,6 +235,9 @@ TEST_CASE("meta/meta_types/class_type") {
CHECK(base_clazz_1_type.is_base_of<derived_clazz>());
CHECK(base_clazz_1_type.is_base_of(derived_clazz_type));
CHECK(base_clazz_1_type.is_base_of<final_derived_clazz>());
CHECK(base_clazz_1_type.is_base_of(final_derived_clazz_type));
}
{
@@ -227,6 +249,9 @@ TEST_CASE("meta/meta_types/class_type") {
CHECK(base_clazz_2_type.is_base_of<derived_clazz>());
CHECK(base_clazz_2_type.is_base_of(derived_clazz_type));
CHECK(base_clazz_2_type.is_base_of<final_derived_clazz>());
CHECK(base_clazz_2_type.is_base_of(final_derived_clazz_type));
}
{
@@ -274,6 +299,17 @@ TEST_CASE("meta/meta_types/class_type") {
CHECK_FALSE(derived_clazz_type.is_derived_from<derived_clazz>());
CHECK_FALSE(derived_clazz_type.is_derived_from(derived_clazz_type));
}
{
CHECK(final_derived_clazz_type.is_derived_from<base_clazz_1>());
CHECK(final_derived_clazz_type.is_derived_from(base_clazz_1_type));
CHECK(final_derived_clazz_type.is_derived_from<base_clazz_2>());
CHECK(final_derived_clazz_type.is_derived_from(base_clazz_2_type));
CHECK(final_derived_clazz_type.is_derived_from<derived_clazz>());
CHECK(final_derived_clazz_type.is_derived_from(derived_clazz_type));
}
}
SUBCASE("get_function") {