// Copyright (c) 2018-2025 Jean-Louis Leroy // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) #include #include #define BOOST_TEST_MODULE core #include #include using namespace boost::openmethod; using namespace boost::openmethod::detail; namespace mp11 = boost::mp11; #include #include #include #include "test_util.hpp" namespace test_virtual { struct base { virtual ~base() { } }; struct a : base {}; struct b : base {}; struct c : base {}; struct d : base {}; struct e : base {}; struct f : base {}; static_assert(std::is_same_v< virtual_traits::virtual_type, base>); static_assert( std::is_same_v< virtual_traits::virtual_type, base>); static_assert(std::is_same_v< virtual_traits::virtual_type, base>); static_assert(std::is_same_v< mp11::mp_filter< is_virtual, mp11::mp_list, b, virtual_>>, mp11::mp_list, virtual_>>); static_assert(std::is_same_v>, a&>); static_assert(std::is_same_v, a>); static_assert( std::is_same_v< virtual_types>, b, virtual_>>>, mp11::mp_list, std::shared_ptr>>); static_assert(std::is_same_v< overrider_virtual_types< mp11::mp_list, b, virtual_>, mp11::mp_list, default_registry>, mp11::mp_list>); static_assert( std::is_same_v, default_registry>, a>); static_assert( std::is_same_v< virtual_traits, default_registry>::virtual_type, a>); static_assert(std::is_same_v< select_overrider_virtual_type_aux< virtual_ptr, virtual_ptr, default_registry>::type, a>); static_assert( std::is_same_v< overrider_virtual_types< mp11::mp_list, b, virtual_ptr>, mp11::mp_list, e, virtual_ptr>, default_registry>, mp11::mp_list>); static_assert( std::is_same_v< overrider_virtual_types< mp11::mp_list< const virtual_ptr&, b, const virtual_ptr&>, mp11::mp_list&, e, const virtual_ptr&>, default_registry>, mp11::mp_list>); static_assert( std::is_same_v< overrider_virtual_types< mp11::mp_list< virtual_>, b, virtual_>>, mp11::mp_list, e, std::shared_ptr>, default_registry>, mp11::mp_list>); static_assert(std::is_same_v< mp11::mp_transform< remove_virtual_, mp11::mp_list, virtual_>>, mp11::mp_list>); static_assert( std::is_same_v< mp11::mp_transform_q< mp11::mp_bind_back, mp11::mp_transform< remove_virtual_, mp11::mp_list, virtual_>>>, mp11::mp_list>); static_assert( std::is_same_v< mp11::mp_transform_q< mp11::mp_bind_back, mp11::mp_transform< remove_virtual_, mp11::mp_filter< is_virtual, mp11::mp_list, b, virtual_>>>>, mp11::mp_list>); struct registry1 : default_registry::with> {}; struct registry2 : default_registry::with> {}; struct non_polymorphic_inplace_vptr {}; auto boost_openmethod_vptr(const non_polymorphic_inplace_vptr&, void*) -> vptr_type; // clang-format on static_assert(std::is_same_v< virtual_types, b, virtual_>>, mp11::mp_list>); static_assert(detail::is_registry); struct not_a_policy {}; static_assert(!detail::is_registry); BOOST_AUTO_TEST_CASE(test_init_type_ids) { type_id ids[2]; auto last = init_type_ids>::fn(ids); BOOST_TEST_REQUIRE(last - ids == 2); BOOST_TEST_REQUIRE(ids[0] == type_id(&typeid(a))); BOOST_TEST_REQUIRE(ids[1] == type_id(&typeid(b))); } } // namespace test_virtual namespace test_macros { // Check that macros can handle commas in parameter and return types. struct Animal { virtual ~Animal() = default; }; BOOST_OPENMETHOD(poke, (virtual_), std::tuple); } // namespace test_macros namespace casts { struct Animal { virtual ~Animal() { } int a{1}; }; struct Mammal : virtual Animal { int m{2}; }; struct Carnivore : virtual Animal { int c{3}; }; struct Dog : Mammal, Carnivore { int d{4}; }; auto mammal_this(const Mammal& obj) -> const void* { return &obj; } auto carnivore_this(const Carnivore& obj) -> const void* { return &obj; } auto dog_this(const Dog& obj) -> const void* { return &obj; } BOOST_AUTO_TEST_CASE(casts) { Dog dog; const Animal& animal = dog; const Mammal& mammal = dog; const Carnivore& carnivore = dog; BOOST_TEST( (&virtual_traits::cast( animal) .m) == &dog.m); BOOST_TEST( (&virtual_traits::cast< const Carnivore&>(animal) .c) == &dog.c); BOOST_TEST( (&virtual_traits::cast( animal) .m) == &dog.m); BOOST_TEST( (&virtual_traits::cast( animal) .d) == &dog.d); BOOST_TEST( (&virtual_traits::cast( mammal) .d) == &dog.d); BOOST_TEST( (&virtual_traits::cast( carnivore) .c) == &dog.c); using virtual_animal_t = virtual_type; static_assert(std::is_same_v, "animal"); using virtual_mammal_t = virtual_type; static_assert(std::is_same_v, "mammal"); } } // namespace casts namespace test_use_classes { struct Animal {}; struct Dog : public Animal {}; struct Bulldog : public Dog {}; struct Cat : public Animal {}; struct Dolphin : public Animal {}; static_assert( std::is_same_v< inheritance_map, mp11::mp_list< mp11::mp_list, mp11::mp_list, mp11::mp_list, mp11::mp_list, mp11::mp_list>>); static_assert( std::is_same_v< detail::use_classes_tuple_type, std::tuple< use_class_aux>, use_class_aux>, use_class_aux< default_registry, mp11::mp_list>, use_class_aux>, use_class_aux< default_registry, mp11::mp_list>>>); } // namespace test_use_classes namespace TEST_NS { struct Animal { friend auto boost_openmethod_vptr(const Animal&, void*) -> vptr_type; }; static_assert(detail::has_vptr_fn); } // namespace TEST_NS namespace TEST_NS { using test_registry = test_registry_<__COUNTER__>; const detail::word value; struct Animal { friend auto boost_openmethod_vptr(const Animal&, test_registry*) { return &value; } }; static_assert(detail::has_vptr_fn); static_assert(!detail::has_vptr_fn); BOOST_AUTO_TEST_CASE(vptr_from_function) { initialize(); BOOST_TEST(detail::acquire_vptr(Animal{}) == &value); } } // namespace TEST_NS