/******************************************************************************* * This file is part of the "https://github.com/blackmatov/meta.hpp" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com) ******************************************************************************/ #include "../meta_untests.hpp" namespace { struct A { A() = default; A(A&&) = default; A(const A&) = default; A& operator=(A&&) = delete; A& operator=(const A&) = delete; virtual ~A() = default; }; struct B : virtual A {}; struct C : virtual A {}; struct D : B, C {}; struct E {}; } TEST_CASE("meta/meta_features/diamond") { namespace meta = meta_hpp; meta::class_(); meta::class_().base_(); meta::class_().base_(); meta::class_().base_().base_(); meta::class_(); // * <- B <- * // A D // * <- C <- * const meta::class_type A_type = meta::resolve_type(); const meta::class_type B_type = meta::resolve_type(); const meta::class_type C_type = meta::resolve_type(); const meta::class_type D_type = meta::resolve_type(); const meta::class_type E_type = meta::resolve_type(); REQUIRE(A_type); REQUIRE(B_type); REQUIRE(C_type); REQUIRE(D_type); REQUIRE(E_type); SUBCASE("is_base_of") { CHECK(!A_type.is_base_of(A_type)); CHECK(A_type.is_base_of(B_type)); CHECK(A_type.is_base_of(C_type)); CHECK(A_type.is_base_of(D_type)); CHECK(!A_type.is_base_of(E_type)); CHECK(!B_type.is_base_of(A_type)); CHECK(!B_type.is_base_of(B_type)); CHECK(!B_type.is_base_of(C_type)); CHECK(B_type.is_base_of(D_type)); CHECK(!B_type.is_base_of(E_type)); CHECK(!C_type.is_base_of(A_type)); CHECK(!C_type.is_base_of(B_type)); CHECK(!C_type.is_base_of(C_type)); CHECK(C_type.is_base_of(D_type)); CHECK(!C_type.is_base_of(E_type)); CHECK(!D_type.is_base_of(A_type)); CHECK(!D_type.is_base_of(B_type)); CHECK(!D_type.is_base_of(C_type)); CHECK(!D_type.is_base_of(D_type)); CHECK(!D_type.is_base_of(E_type)); CHECK(!E_type.is_base_of(A_type)); CHECK(!E_type.is_base_of(B_type)); CHECK(!E_type.is_base_of(C_type)); CHECK(!E_type.is_base_of(D_type)); CHECK(!E_type.is_base_of(E_type)); } SUBCASE("is_derived_from") { CHECK(!A_type.is_derived_from(A_type)); CHECK(!A_type.is_derived_from(B_type)); CHECK(!A_type.is_derived_from(C_type)); CHECK(!A_type.is_derived_from(D_type)); CHECK(!A_type.is_derived_from(E_type)); CHECK(B_type.is_derived_from(A_type)); CHECK(!B_type.is_derived_from(B_type)); CHECK(!B_type.is_derived_from(C_type)); CHECK(!B_type.is_derived_from(D_type)); CHECK(!B_type.is_derived_from(E_type)); CHECK(C_type.is_derived_from(A_type)); CHECK(!C_type.is_derived_from(B_type)); CHECK(!C_type.is_derived_from(C_type)); CHECK(!C_type.is_derived_from(D_type)); CHECK(!C_type.is_derived_from(E_type)); CHECK(D_type.is_derived_from(A_type)); CHECK(D_type.is_derived_from(B_type)); CHECK(D_type.is_derived_from(C_type)); CHECK(!D_type.is_derived_from(D_type)); CHECK(!D_type.is_derived_from(E_type)); CHECK(!E_type.is_derived_from(A_type)); CHECK(!E_type.is_derived_from(B_type)); CHECK(!E_type.is_derived_from(C_type)); CHECK(!E_type.is_derived_from(D_type)); CHECK(!E_type.is_derived_from(E_type)); } SUBCASE("pointer_upcast") { using meta::detail::pointer_upcast; { A a; CHECK(pointer_upcast(&a) == &a); CHECK_FALSE(pointer_upcast(&a)); CHECK_FALSE(pointer_upcast(&a)); CHECK_FALSE(pointer_upcast(&a)); CHECK_FALSE(pointer_upcast(&a)); } { const B b; CHECK(pointer_upcast(&b) == &b); CHECK(pointer_upcast(&b) == &b); CHECK_FALSE(pointer_upcast(&b)); CHECK_FALSE(pointer_upcast(&b)); CHECK_FALSE(pointer_upcast(&b)); } { C c; CHECK(pointer_upcast(&c) == &c); CHECK_FALSE(pointer_upcast(&c)); CHECK(pointer_upcast(&c) == &c); CHECK_FALSE(pointer_upcast(&c)); CHECK_FALSE(pointer_upcast(&c)); } { const D d; CHECK(pointer_upcast(&d) == &d); CHECK(pointer_upcast(&d) == &d); CHECK(pointer_upcast(&d) == &d); CHECK(pointer_upcast(&d) == &d); CHECK_FALSE(pointer_upcast(&d)); } { E e; CHECK_FALSE(pointer_upcast(&e)); CHECK_FALSE(pointer_upcast(&e)); CHECK_FALSE(pointer_upcast(&e)); CHECK_FALSE(pointer_upcast(&e)); CHECK(pointer_upcast(&e) == &e); } } SUBCASE("arg/cast") { { A a; meta::value a_val{&a}; CHECK(*static_cast(a_val.data()) == &a); meta::detail::arg a_arg{a_val}; CHECK(a_arg.can_cast_to()); CHECK(!a_arg.can_cast_to()); CHECK(!a_arg.can_cast_to()); CHECK(!a_arg.can_cast_to()); CHECK(!a_arg.can_cast_to()); CHECK(a_arg.cast() == static_cast(&a)); } { B b; meta::value b_val{&b}; CHECK(*static_cast(b_val.data()) == &b); meta::detail::arg b_arg{b_val}; CHECK(b_arg.can_cast_to()); CHECK(b_arg.can_cast_to()); CHECK(!b_arg.can_cast_to()); CHECK(!b_arg.can_cast_to()); CHECK(!b_arg.can_cast_to()); CHECK(b_arg.cast() == static_cast(&b)); CHECK(b_arg.cast() == static_cast(&b)); } { C c; meta::value c_val{&c}; CHECK(*static_cast(c_val.data()) == &c); meta::detail::arg c_arg{c_val}; CHECK(c_arg.can_cast_to()); CHECK(!c_arg.can_cast_to()); CHECK(c_arg.can_cast_to()); CHECK(!c_arg.can_cast_to()); CHECK(!c_arg.can_cast_to()); CHECK(c_arg.cast() == static_cast(&c)); CHECK(c_arg.cast() == static_cast(&c)); } { D d; meta::value d_val{&d}; CHECK(*static_cast(d_val.data()) == &d); meta::detail::arg d_arg{d_val}; CHECK(d_arg.can_cast_to()); CHECK(d_arg.can_cast_to()); CHECK(d_arg.can_cast_to()); CHECK(d_arg.can_cast_to()); CHECK(!d_arg.can_cast_to()); CHECK(d_arg.cast() == static_cast(&d)); CHECK(d_arg.cast() == static_cast(&d)); CHECK(d_arg.cast() == static_cast(&d)); CHECK(d_arg.cast() == static_cast(&d)); } { E e; meta::value e_val{&e}; CHECK(*static_cast(e_val.data()) == &e); meta::detail::arg e_arg{e_val}; CHECK(!e_arg.can_cast_to()); CHECK(!e_arg.can_cast_to()); CHECK(!e_arg.can_cast_to()); CHECK(!e_arg.can_cast_to()); CHECK(e_arg.can_cast_to()); CHECK(e_arg.cast() == static_cast(&e)); } } SUBCASE("inst/cast") { { meta::value a_val{A{}}; meta::detail::inst a_inst{a_val}; CHECK(a_inst.can_cast_to()); CHECK_FALSE(a_inst.can_cast_to()); CHECK_FALSE(a_inst.can_cast_to()); CHECK_FALSE(a_inst.can_cast_to()); CHECK_FALSE(a_inst.can_cast_to()); CHECK(&a_inst.cast() == a_val.try_cast()); } { meta::value b_val{B{}}; meta::detail::inst b_inst{b_val}; CHECK(b_inst.can_cast_to()); CHECK(b_inst.can_cast_to()); CHECK_FALSE(b_inst.can_cast_to()); CHECK_FALSE(b_inst.can_cast_to()); CHECK_FALSE(b_inst.can_cast_to()); CHECK(&b_inst.cast() == b_val.try_cast()); CHECK(&b_inst.cast() == b_val.try_cast()); CHECK(&b_inst.cast() == b_val.try_cast()); } { meta::value c_val{C{}}; meta::detail::inst c_inst{c_val}; CHECK(c_inst.can_cast_to()); CHECK_FALSE(c_inst.can_cast_to()); CHECK(c_inst.can_cast_to()); CHECK_FALSE(c_inst.can_cast_to()); CHECK_FALSE(c_inst.can_cast_to()); CHECK(&c_inst.cast() == c_val.try_cast()); CHECK(&c_inst.cast() == c_val.try_cast()); } { meta::value d_val{D{}}; meta::detail::inst d_inst{d_val}; CHECK(d_inst.can_cast_to()); CHECK(d_inst.can_cast_to()); CHECK(d_inst.can_cast_to()); CHECK(d_inst.can_cast_to()); CHECK_FALSE(d_inst.can_cast_to()); CHECK(&d_inst.cast() == d_val.try_cast()); CHECK(&d_inst.cast() == d_val.try_cast()); CHECK(&d_inst.cast() == d_val.try_cast()); CHECK(&d_inst.cast() == d_val.try_cast()); CHECK(&d_inst.cast() == d_val.try_cast()); CHECK(&d_inst.cast() == d_val.try_cast()); CHECK(&d_inst.cast() == d_val.try_cast()); CHECK(&d_inst.cast() == d_val.try_cast()); } { meta::value e_val{E{}}; meta::detail::inst e_inst{e_val}; CHECK_FALSE(e_inst.can_cast_to()); CHECK_FALSE(e_inst.can_cast_to()); CHECK_FALSE(e_inst.can_cast_to()); CHECK_FALSE(e_inst.can_cast_to()); CHECK(e_inst.can_cast_to()); CHECK(&e_inst.cast() == e_val.try_cast()); } } SUBCASE("resolve_polymorphic_type") { const D d; const A& ad = d; const B& bd = d; const C& cd = d; const D& dd = d; CHECK(meta::resolve_type(ad) == meta::resolve_type()); CHECK(meta::resolve_type(bd) == meta::resolve_type()); CHECK(meta::resolve_type(cd) == meta::resolve_type()); CHECK(meta::resolve_type(dd) == meta::resolve_type()); CHECK(meta::resolve_polymorphic_type(ad) == meta::resolve_type()); CHECK(meta::resolve_polymorphic_type(bd) == meta::resolve_type()); CHECK(meta::resolve_polymorphic_type(cd) == meta::resolve_type()); CHECK(meta::resolve_polymorphic_type(dd) == meta::resolve_type()); } }