Skip to content

Commit

Permalink
poly: refined inheritance support - close #1184
Browse files Browse the repository at this point in the history
  • Loading branch information
skypjack committed Oct 16, 2024
1 parent 04bdcf4 commit cc693e0
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 31 deletions.
7 changes: 3 additions & 4 deletions docs/md/poly.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,8 @@ For a deduced concept, inheritance is achieved in a few steps:
```cpp
struct DrawableAndErasable: entt::type_list<> {
template<typename Base>
struct type: typename Drawable::template type<Base> {
static constexpr auto base = std::tuple_size_v<typename entt::poly_vtable<Drawable>::type>;
struct type: typename Drawable::type<Base> {
static constexpr auto base = Drawable::impl<Drawable::type<entt::poly_inspector>>::size;
void erase() { entt::poly_call<base + 0>(*this); }
};
Expand Down Expand Up @@ -267,8 +267,7 @@ a `decltype` as it follows:
```cpp
struct DrawableAndErasable: entt::type_list_cat_t<
decltype(as_type_list(std::declval<Drawable>())),
entt::type_list<void()>
> {
entt::type_list<void()>> {
// ...
};
```
Expand Down
21 changes: 11 additions & 10 deletions src/entt/poly/poly.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,21 @@ template<typename Concept, std::size_t Len, std::size_t Align>
class poly_vtable {
using inspector = typename Concept::template type<poly_inspector>;

template<typename Ret, typename... Args>
static auto vtable_entry(Ret (*)(inspector &, Args...)) -> Ret (*)(basic_any<Len, Align> &, Args...);
template<typename Ret, typename Clazz, typename... Args>
static auto vtable_entry(Ret (*)(Clazz &, Args...))
-> std::enable_if_t<std::is_base_of_v<std::remove_const_t<Clazz>, inspector>, Ret (*)(constness_as_t<basic_any<Len, Align>, Clazz> &, Args...)>;

template<typename Ret, typename... Args>
static auto vtable_entry(Ret (*)(const inspector &, Args...)) -> Ret (*)(const basic_any<Len, Align> &, Args...);
static auto vtable_entry(Ret (*)(Args...))
-> Ret (*)(const basic_any<Len, Align> &, Args...);

template<typename Ret, typename... Args>
static auto vtable_entry(Ret (*)(Args...)) -> Ret (*)(const basic_any<Len, Align> &, Args...);
template<typename Ret, typename Clazz, typename... Args>
static auto vtable_entry(Ret (Clazz::*)(Args...))
-> std::enable_if_t<std::is_base_of_v<Clazz, inspector>, Ret (*)(basic_any<Len, Align> &, Args...)>;

template<typename Ret, typename... Args>
static auto vtable_entry(Ret (inspector::*)(Args...)) -> Ret (*)(basic_any<Len, Align> &, Args...);

template<typename Ret, typename... Args>
static auto vtable_entry(Ret (inspector::*)(Args...) const) -> Ret (*)(const basic_any<Len, Align> &, Args...);
template<typename Ret, typename Clazz, typename... Args>
static auto vtable_entry(Ret (Clazz::*)(Args...) const)
-> std::enable_if_t<std::is_base_of_v<Clazz, inspector>, Ret (*)(const basic_any<Len, Align> &, Args...)>;

template<auto... Candidate>
static auto make_vtable(value_list<Candidate...>) noexcept
Expand Down
90 changes: 73 additions & 17 deletions test/entt/poly/poly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,17 @@ struct common_members {

namespace {

template<typename... Type>
entt::type_list<Type...> as_type_list(const entt::type_list<Type...> &);

[[nodiscard]] int absolutely_random() {
return 4;
}

[[nodiscard]] int three_is_a_magic_number() {
return 3;
}

} // namespace

template<typename Type>
Expand Down Expand Up @@ -127,6 +134,38 @@ struct DefinedEmbedded
using impl = entt::value_list<&Type::get>;
};

struct DeducedDerived
: entt::type_list<> {
template<typename Base>
struct type: Deduced::type<Base> {
static constexpr auto base = Deduced::impl<Deduced::type<entt::poly_inspector>>::size;

int three_is_a_magic_number() {
return entt::poly_call<base + 0>(*this);
}
};

template<typename Type>
using impl = entt::value_list_cat_t<typename Deduced::impl<Type>, entt::value_list<&three_is_a_magic_number>>;
};

struct DefinedDerived
: entt::type_list_cat_t<
decltype(as_type_list(std::declval<Defined>())),
entt::type_list<int()>> {
template<typename Base>
struct type: Defined::type<Base> {
static constexpr auto base = Defined::impl<Defined::type<entt::poly_inspector>>::size;

int three_is_a_magic_number() {
return entt::poly_call<base + 0>(*this);
}
};

template<typename Type>
using impl = entt::value_list_cat_t<typename Defined::impl<Type>, entt::value_list<&three_is_a_magic_number>>;
};

struct impl {
impl() = default;

Expand Down Expand Up @@ -173,6 +212,15 @@ using PolyEmbeddedTypes = ::testing::Types<DeducedEmbedded, DefinedEmbedded>;

TYPED_TEST_SUITE(PolyEmbedded, PolyEmbeddedTypes, );

template<typename Type>
struct PolyDerived: testing::Test {
using type = entt::basic_poly<Type>;
};

using PolyDerivedTypes = ::testing::Types<DeducedDerived, DefinedDerived>;

TYPED_TEST_SUITE(PolyDerived, PolyDerivedTypes, );

TYPED_TEST(Poly, Functionalities) {
using poly_type = typename TestFixture::template type<>;

Expand All @@ -196,7 +244,7 @@ TYPED_TEST(Poly, Functionalities) {
ASSERT_EQ(alias.data(), &instance);
ASSERT_EQ(std::as_const(alias).data(), &instance);

ASSERT_EQ(value->rand(), 4);
ASSERT_EQ(value->rand(), absolutely_random());

empty = impl{};

Expand Down Expand Up @@ -243,22 +291,6 @@ TYPED_TEST(Poly, Functionalities) {
ASSERT_EQ(move.type(), entt::type_id<void>());
}

TYPED_TEST(PolyEmbedded, EmbeddedVtable) {
using poly_type = typename TestFixture::type;

poly_type poly{impl{}};
auto *ptr = static_cast<impl *>(poly.data());

ASSERT_TRUE(poly);
ASSERT_NE(poly.data(), nullptr);
ASSERT_NE(std::as_const(poly).data(), nullptr);
ASSERT_EQ(poly->get(), 0);

ptr->value = 2;

ASSERT_EQ(poly->get(), 2);
}

TYPED_TEST(Poly, Owned) {
using poly_type = typename TestFixture::template type<>;

Expand Down Expand Up @@ -440,3 +472,27 @@ TYPED_TEST(Poly, NoSboAlignment) {

ASSERT_EQ(data, nosbo[1].data());
}

TYPED_TEST(PolyEmbedded, EmbeddedVtable) {
using poly_type = typename TestFixture::type;

poly_type poly{impl{}};
auto *ptr = static_cast<impl *>(poly.data());

ASSERT_TRUE(poly);
ASSERT_NE(poly.data(), nullptr);
ASSERT_NE(std::as_const(poly).data(), nullptr);
ASSERT_EQ(poly->get(), 0);

ptr->value = 2;

ASSERT_EQ(poly->get(), 2);
}

TYPED_TEST(PolyDerived, InheritanceSupport) {
using poly_type = typename TestFixture::type;

poly_type poly{impl{}};

ASSERT_EQ(poly->three_is_a_magic_number(), three_is_a_magic_number());
}

0 comments on commit cc693e0

Please sign in to comment.