/******************************************************************************* * 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-2023, by Matvey Cherevko (blackmatov@gmail.com) ******************************************************************************/ #include #include namespace { struct A { A() = default; A(A&&) = default; A(const A&) = default; A& operator=(A&&) = delete; A& operator=(const A&) = delete; virtual ~A() = default; META_HPP_ENABLE_POLY_INFO() }; struct B : virtual A { META_HPP_ENABLE_POLY_INFO(A) }; struct C : virtual A { META_HPP_ENABLE_POLY_INFO(A) }; struct D : B, C { META_HPP_ENABLE_POLY_INFO(B, C) }; struct E {}; } TEST_CASE("meta/meta_features/diamond") { namespace meta = meta_hpp; using meta::detail::uarg; using meta::detail::uinst; using meta::detail::type_registry; type_registry& r{type_registry::instance()}; // * <- 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(r, &a) == &a); CHECK_FALSE(pointer_upcast(r, &a)); CHECK_FALSE(pointer_upcast(r, &a)); CHECK_FALSE(pointer_upcast(r, &a)); CHECK_FALSE(pointer_upcast(r, &a)); } { const B b; CHECK(pointer_upcast(r, &b) == &b); CHECK(pointer_upcast(r, &b) == &b); CHECK_FALSE(pointer_upcast(r, &b)); CHECK_FALSE(pointer_upcast(r, &b)); CHECK_FALSE(pointer_upcast(r, &b)); } { C c; CHECK(pointer_upcast(r, &c) == &c); CHECK_FALSE(pointer_upcast(r, &c)); CHECK(pointer_upcast(r, &c) == &c); CHECK_FALSE(pointer_upcast(r, &c)); CHECK_FALSE(pointer_upcast(r, &c)); } { const D d; CHECK(pointer_upcast(r, &d) == &d); CHECK(pointer_upcast(r, &d) == &d); CHECK(pointer_upcast(r, &d) == &d); CHECK(pointer_upcast(r, &d) == &d); CHECK_FALSE(pointer_upcast(r, &d)); } { E e; CHECK_FALSE(pointer_upcast(r, &e)); CHECK_FALSE(pointer_upcast(r, &e)); CHECK_FALSE(pointer_upcast(r, &e)); CHECK_FALSE(pointer_upcast(r, &e)); CHECK(pointer_upcast(r, &e) == &e); } } SUBCASE("arg/cast") { { A a; meta::uvalue a_val{&a}; CHECK(*static_cast(a_val.get_data()) == &a); uarg a_arg{r, a_val}; CHECK(a_arg.can_cast_to(r)); CHECK(!a_arg.can_cast_to(r)); CHECK(!a_arg.can_cast_to(r)); CHECK(!a_arg.can_cast_to(r)); CHECK(!a_arg.can_cast_to(r)); CHECK(a_arg.cast(r) == static_cast(&a)); } { B b; meta::uvalue b_val{&b}; CHECK(*static_cast(b_val.get_data()) == &b); uarg b_arg{r, b_val}; CHECK(b_arg.can_cast_to(r)); CHECK(b_arg.can_cast_to(r)); CHECK(!b_arg.can_cast_to(r)); CHECK(!b_arg.can_cast_to(r)); CHECK(!b_arg.can_cast_to(r)); CHECK(b_arg.cast(r) == static_cast(&b)); CHECK(b_arg.cast(r) == static_cast(&b)); } { C c; meta::uvalue c_val{&c}; CHECK(*static_cast(c_val.get_data()) == &c); uarg c_arg{r, c_val}; CHECK(c_arg.can_cast_to(r)); CHECK(!c_arg.can_cast_to(r)); CHECK(c_arg.can_cast_to(r)); CHECK(!c_arg.can_cast_to(r)); CHECK(!c_arg.can_cast_to(r)); CHECK(c_arg.cast(r) == static_cast(&c)); CHECK(c_arg.cast(r) == static_cast(&c)); } { D d; meta::uvalue d_val{&d}; CHECK(*static_cast(d_val.get_data()) == &d); uarg d_arg{r, d_val}; CHECK(d_arg.can_cast_to(r)); CHECK(d_arg.can_cast_to(r)); CHECK(d_arg.can_cast_to(r)); CHECK(d_arg.can_cast_to(r)); CHECK(!d_arg.can_cast_to(r)); CHECK(d_arg.cast(r) == static_cast(&d)); CHECK(d_arg.cast(r) == static_cast(&d)); CHECK(d_arg.cast(r) == static_cast(&d)); CHECK(d_arg.cast(r) == static_cast(&d)); } { E e; meta::uvalue e_val{&e}; CHECK(*static_cast(e_val.get_data()) == &e); uarg e_arg{r, e_val}; CHECK(!e_arg.can_cast_to(r)); CHECK(!e_arg.can_cast_to(r)); CHECK(!e_arg.can_cast_to(r)); CHECK(!e_arg.can_cast_to(r)); CHECK(e_arg.can_cast_to(r)); CHECK(e_arg.cast(r) == static_cast(&e)); } } SUBCASE("inst/cast") { { meta::uvalue a_val{A{}}; uinst a_inst{r, a_val}; CHECK(a_inst.can_cast_to(r)); CHECK_FALSE(a_inst.can_cast_to(r)); CHECK_FALSE(a_inst.can_cast_to(r)); CHECK_FALSE(a_inst.can_cast_to(r)); CHECK_FALSE(a_inst.can_cast_to(r)); CHECK(&a_inst.cast(r) == &a_val.as()); } { meta::uvalue b_val{B{}}; uinst b_inst{r, b_val}; CHECK(b_inst.can_cast_to(r)); CHECK(b_inst.can_cast_to(r)); CHECK_FALSE(b_inst.can_cast_to(r)); CHECK_FALSE(b_inst.can_cast_to(r)); CHECK_FALSE(b_inst.can_cast_to(r)); CHECK(&b_inst.cast(r) == &b_val.as()); CHECK(&b_inst.cast(r) == &b_val.as()); CHECK(&b_inst.cast(r) == &b_val.as()); } { meta::uvalue c_val{C{}}; uinst c_inst{r, c_val}; CHECK(c_inst.can_cast_to(r)); CHECK_FALSE(c_inst.can_cast_to(r)); CHECK(c_inst.can_cast_to(r)); CHECK_FALSE(c_inst.can_cast_to(r)); CHECK_FALSE(c_inst.can_cast_to(r)); CHECK(&c_inst.cast(r) == &c_val.as()); CHECK(&c_inst.cast(r) == &c_val.as()); } { meta::uvalue d_val{D{}}; uinst d_inst{r, d_val}; CHECK(d_inst.can_cast_to(r)); CHECK(d_inst.can_cast_to(r)); CHECK(d_inst.can_cast_to(r)); CHECK(d_inst.can_cast_to(r)); CHECK_FALSE(d_inst.can_cast_to(r)); CHECK(&d_inst.cast(r) == &d_val.as()); CHECK(&d_inst.cast(r) == &d_val.as()); CHECK(&d_inst.cast(r) == &d_val.as()); CHECK(&d_inst.cast(r) == &d_val.as()); CHECK(&d_inst.cast(r) == &d_val.as()); CHECK(&d_inst.cast(r) == &d_val.as()); CHECK(&d_inst.cast(r) == &d_val.as()); CHECK(&d_inst.cast(r) == &d_val.as()); } { meta::uvalue e_val{E{}}; uinst e_inst{r, e_val}; CHECK_FALSE(e_inst.can_cast_to(r)); CHECK_FALSE(e_inst.can_cast_to(r)); CHECK_FALSE(e_inst.can_cast_to(r)); CHECK_FALSE(e_inst.can_cast_to(r)); CHECK(e_inst.can_cast_to(r)); CHECK(&e_inst.cast(r) == &e_val.as()); } } SUBCASE("resolve_type") { D d; A& ad = d; B& bd = d; C& cd = d; D& dd = d; CHECK(meta::resolve_type(A{}) == meta::resolve_type()); CHECK(meta::resolve_type(B{}) == meta::resolve_type()); CHECK(meta::resolve_type(C{}) == meta::resolve_type()); CHECK(meta::resolve_type(D{}) == meta::resolve_type()); 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_type(std::move(ad)) == meta::resolve_type()); CHECK(meta::resolve_type(std::move(bd)) == meta::resolve_type()); CHECK(meta::resolve_type(std::move(cd)) == meta::resolve_type()); CHECK(meta::resolve_type(std::move(dd)) == meta::resolve_type()); CHECK(meta::resolve_type(std::as_const(ad)) == meta::resolve_type()); CHECK(meta::resolve_type(std::as_const(bd)) == meta::resolve_type()); CHECK(meta::resolve_type(std::as_const(cd)) == meta::resolve_type()); CHECK(meta::resolve_type(std::as_const(dd)) == meta::resolve_type()); } }