From 424b6f67363438715a3c66f2e614629cc312a20e Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Mon, 6 Mar 2023 21:29:19 +0700 Subject: [PATCH] optimize ambiguous cast checks --- develop/cmake/SetupTargets.cmake | 3 +- develop/singles/headers/meta.hpp/meta_all.hpp | 142 +++++++++++------- develop/untests/meta_base/is_disjoint.cpp | 30 ++++ .../untests/meta_features/ambiguous_tests.cpp | 15 ++ .../untests/meta_features/diamond_tests.cpp | 54 +++---- .../untests/meta_features/multiple2_tests.cpp | 76 +++++----- .../untests/meta_features/multiple_tests.cpp | 84 +++++------ headers/meta.hpp/meta_base.hpp | 1 + headers/meta.hpp/meta_base/is_disjoint.hpp | 35 +++++ headers/meta.hpp/meta_binds/class_bind.hpp | 11 +- .../meta_detail/value_utilities/uarg.hpp | 6 +- .../meta_detail/value_utilities/uinst.hpp | 4 +- .../meta_detail/value_utilities/utraits.hpp | 35 ++--- headers/meta.hpp/meta_types.hpp | 19 ++- headers/meta.hpp/meta_types/class_type.hpp | 41 +++-- 15 files changed, 334 insertions(+), 222 deletions(-) create mode 100644 develop/untests/meta_base/is_disjoint.cpp create mode 100644 headers/meta.hpp/meta_base/is_disjoint.hpp diff --git a/develop/cmake/SetupTargets.cmake b/develop/cmake/SetupTargets.cmake index 4e6eca0..87b5573 100644 --- a/develop/cmake/SetupTargets.cmake +++ b/develop/cmake/SetupTargets.cmake @@ -5,7 +5,8 @@ target_compile_options(${PROJECT_NAME}.setup_targets INTERFACE $<$: /WX /W4 /bigobj> $<$: - -Werror -Wall -Wextra -Wpedantic> + -Werror -Wall -Wextra -Wpedantic + -Wno-inaccessible-base> $<$,$>: -Werror -Weverything -Wconversion -Wno-c++98-compat diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index c31356a..9ccd8e4 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -1168,6 +1168,32 @@ namespace std }; } +namespace meta_hpp::detail +{ + template < typename SortedContainerL, typename SortedContainerR, typename Compare > + bool is_disjoint(const SortedContainerL& l, const SortedContainerR& r, Compare compare) { + using std::begin; + using std::end; + + for ( auto iter_l{begin(l)}, iter_r{begin(r)}; iter_l != end(l) && iter_r != end(r); ) { + if ( compare(*iter_l, *iter_r) ) { + ++iter_l; + } else if ( compare(*iter_r, *iter_l) ) { + ++iter_r; + } else { + return false; + } + } + + return true; + } + + template < typename SortedContainerL, typename SortedContainerR > + bool is_disjoint(const SortedContainerL& l, const SortedContainerR& r) { + return is_disjoint(l, r, std::less<>{}); + } +} + namespace meta_hpp::detail { template < typename T > @@ -2809,9 +2835,11 @@ namespace meta_hpp::detail variable_set variables; struct upcast_func_t final { - void* (*upcast)(void*){}; - bool is_virtual_upcast{}; - class_type target_class{}; + using upcast_t = void* (*)(void*); + + upcast_t upcast{}; + class_type target{}; + bool is_virtual{}; template < typename Derived, typename Base > requires std::is_base_of_v @@ -2822,11 +2850,14 @@ namespace meta_hpp::detail }; struct upcast_func_list_t final { - class_set vbases; - std::vector upcasts; + using upcasts_t = std::vector; + + upcasts_t upcasts{}; + class_set vbases{}; + bool is_ambiguous{}; upcast_func_list_t(const upcast_func_t& _upcast); - upcast_func_list_t(class_set _vbases, std::vector _upcasts); + upcast_func_list_t(upcasts_t _upcasts, class_set _vbases); [[nodiscard]] void* apply(void* ptr) const noexcept; [[nodiscard]] const void* apply(const void* ptr) const noexcept; @@ -2835,7 +2866,7 @@ namespace meta_hpp::detail }; using base_upcasts_t = std::map>; - using deep_upcasts_t = std::multimap>; + using deep_upcasts_t = std::map>; base_upcasts_t base_upcasts; deep_upcasts_t deep_upcasts; @@ -4902,9 +4933,16 @@ namespace meta_hpp::detail::class_bind_impl const auto [deep_upcasts_db_iter, _] = deep_upcasts_db.try_emplace(derived_class, derived_class_data.deep_upcasts); deep_upcasts_t& derived_deep_upcasts = deep_upcasts_db_iter->second; + const auto add_derived_deep_upcast = [&derived_deep_upcasts](const class_type& deep_class, upcast_func_list_t&& upcasts) { + auto&& [position, emplaced] = derived_deep_upcasts.try_emplace(deep_class, std::move(upcasts)); + if ( !emplaced ) { + position->second.is_ambiguous = is_disjoint(position->second.vbases, upcasts.vbases); + } + }; + for ( auto&& [new_deep_class, new_base_to_deep] : new_base_class_data.deep_upcasts ) { upcast_func_list_t derived_to_new_deep = derived_to_new_base + new_base_to_deep; - derived_deep_upcasts.emplace(new_deep_class, std::move(derived_to_new_deep)); + add_derived_deep_upcast(new_deep_class, std::move(derived_to_new_deep)); } for ( const class_type& subderived_class : derived_class_data.derived_classes ) { @@ -4914,7 +4952,7 @@ namespace meta_hpp::detail::class_bind_impl update_deep_upcasts_db(subderived_class, new_base_class, std::move(subderived_to_new_base), deep_upcasts_db); } - derived_deep_upcasts.emplace(new_base_class, std::move(derived_to_new_base)); + add_derived_deep_upcast(new_base_class, std::move(derived_to_new_base)); } inline void updata_derived_classes_db( // @@ -5746,14 +5784,8 @@ namespace meta_hpp::detail const class_type_data& derived_data = *type_access(derived_class); const class_type_data::deep_upcasts_t& deep_upcasts = derived_data.deep_upcasts; - if ( const auto iter{deep_upcasts.lower_bound(base)}; iter != deep_upcasts.end() && iter->first == base ) { - if ( const auto next_iter{std::next(iter)}; next_iter == deep_upcasts.end() || next_iter->first != base ) { - return true; - } - - if ( base_class.is_virtual_base_of(derived_class) ) { - return true; - } + if ( auto iter{deep_upcasts.find(base)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) { + return true; } } @@ -5763,7 +5795,7 @@ namespace meta_hpp::detail namespace meta_hpp::detail { - [[nodiscard]] inline void* unchecked_pointer_upcast(void* ptr, const class_type& from, const class_type& to) { + [[nodiscard]] inline void* pointer_upcast(void* ptr, const class_type& from, const class_type& to) { if ( nullptr == ptr || !from || !to ) { return nullptr; } @@ -5773,23 +5805,24 @@ namespace meta_hpp::detail } const class_type_data& from_data = *type_access(from); + const class_type_data::deep_upcasts_t& deep_upcasts = from_data.deep_upcasts; - if ( auto iter{from_data.deep_upcasts.find(to)}; iter != from_data.deep_upcasts.end() ) { + if ( auto iter{deep_upcasts.find(to)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) { return iter->second.apply(ptr); } return nullptr; } - [[nodiscard]] inline const void* unchecked_pointer_upcast(const void* ptr, const class_type& from, const class_type& to) { + [[nodiscard]] inline const void* pointer_upcast(const void* ptr, const class_type& from, const class_type& to) { // NOLINTNEXTLINE(*-const-cast) - return unchecked_pointer_upcast(const_cast(ptr), from, to); + return pointer_upcast(const_cast(ptr), from, to); } } namespace meta_hpp::detail { - [[nodiscard]] inline void* unchecked_pointer_upcast(void* ptr, const any_type& from, const any_type& to) { + [[nodiscard]] inline void* pointer_upcast(void* ptr, const any_type& from, const any_type& to) { if ( nullptr == ptr || !from || !to ) { return nullptr; } @@ -5802,7 +5835,7 @@ namespace meta_hpp::detail const class_type& from_class = from.as_class(); if ( to_class && from_class ) { - if ( void* base_ptr = unchecked_pointer_upcast(ptr, from_class, to_class) ) { + if ( void* base_ptr = pointer_upcast(ptr, from_class, to_class) ) { return base_ptr; } } @@ -5810,17 +5843,17 @@ namespace meta_hpp::detail return nullptr; } - [[nodiscard]] inline const void* unchecked_pointer_upcast(const void* ptr, const any_type& from, const any_type& to) { + [[nodiscard]] inline const void* pointer_upcast(const void* ptr, const any_type& from, const any_type& to) { // NOLINTNEXTLINE(*-const-cast) - return unchecked_pointer_upcast(const_cast(ptr), from, to); + return pointer_upcast(const_cast(ptr), from, to); } } namespace meta_hpp::detail { template < typename To, typename From > - [[nodiscard]] To* unchecked_pointer_upcast(type_registry& registry, From* ptr) { - return static_cast(unchecked_pointer_upcast( // + [[nodiscard]] To* pointer_upcast(type_registry& registry, From* ptr) { + return static_cast(pointer_upcast( // ptr, registry.resolve_type(), registry.resolve_type() @@ -5828,8 +5861,8 @@ namespace meta_hpp::detail } template < typename To, typename From > - [[nodiscard]] const To* unchecked_pointer_upcast(type_registry& registry, const From* ptr) { - return static_cast(unchecked_pointer_upcast( // + [[nodiscard]] const To* pointer_upcast(type_registry& registry, const From* ptr) { + return static_cast(pointer_upcast( // ptr, registry.resolve_type(), registry.resolve_type() @@ -6082,7 +6115,7 @@ namespace meta_hpp::detail if ( from_type.is_array() ) { const array_type& from_type_array = from_type.as_array(); - void* to_ptr = unchecked_pointer_upcast( // + void* to_ptr = pointer_upcast( // data_, from_type_array.get_data_type(), to_type_ptr.get_data_type() @@ -6095,7 +6128,7 @@ namespace meta_hpp::detail if ( from_type.is_pointer() ) { const pointer_type& from_type_ptr = from_type.as_pointer(); - void* to_ptr = unchecked_pointer_upcast( // + void* to_ptr = pointer_upcast( // *static_cast(data_), from_type_ptr.get_data_type(), to_type_ptr.get_data_type() @@ -6123,7 +6156,7 @@ namespace meta_hpp::detail const any_type& from_type = get_raw_type(); const any_type& to_type = registry.resolve_type(); - void* to_ptr = unchecked_pointer_upcast(data_, from_type, to_type); + void* to_ptr = pointer_upcast(data_, from_type, to_type); META_HPP_ASSERT(to_ptr); if constexpr ( std::is_lvalue_reference_v ) { @@ -6591,7 +6624,7 @@ namespace meta_hpp::detail const any_type& to_type = registry.resolve_type(); if ( from_type.is_class() && to_type.is_class() ) { - void* to_ptr = unchecked_pointer_upcast( // + void* to_ptr = pointer_upcast( // data_, from_type.as_class(), to_type.as_class() @@ -6616,7 +6649,7 @@ namespace meta_hpp::detail const any_type& from_data_type = from_type_ptr.get_data_type(); if ( from_data_type.is_class() && to_type.is_class() ) { - void* to_ptr = unchecked_pointer_upcast( // + void* to_ptr = pointer_upcast( // *static_cast(data_), from_data_type.as_class(), to_type.as_class() @@ -8162,8 +8195,8 @@ namespace meta_hpp::detail requires std::is_base_of_v inline class_type_data::upcast_func_t::upcast_func_t(std::in_place_type_t, std::in_place_type_t) : upcast{[](void* from) -> void* { return static_cast(static_cast(from)); }} - , is_virtual_upcast{is_virtual_base_of_v} - , target_class{resolve_type()} {} + , target{resolve_type()} + , is_virtual{is_virtual_base_of_v} {} inline void* class_type_data::upcast_func_t::apply(void* ptr) const noexcept { return upcast(ptr); @@ -8180,15 +8213,15 @@ namespace meta_hpp::detail inline class_type_data::upcast_func_list_t::upcast_func_list_t(const upcast_func_t& _upcast) : upcasts{_upcast} { for ( const upcast_func_t& upcast : upcasts ) { - if ( upcast.is_virtual_upcast ) { - vbases.emplace(upcast.target_class); + if ( upcast.is_virtual ) { + vbases.emplace(upcast.target); } } } - inline class_type_data::upcast_func_list_t::upcast_func_list_t(class_set _vbases, std::vector _upcasts) - : vbases{std::move(_vbases)} - , upcasts{std::move(_upcasts)} {} + inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcasts_t _upcasts, class_set _vbases) + : upcasts{std::move(_upcasts)} + , vbases{std::move(_vbases)} {} inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept { for ( const upcast_func_t& upcast : upcasts ) { @@ -8206,16 +8239,16 @@ namespace meta_hpp::detail const class_type_data::upcast_func_list_t& l, const class_type_data::upcast_func_list_t& r ) { - class_set new_vbases; - new_vbases.insert(l.vbases.begin(), l.vbases.end()); - new_vbases.insert(r.vbases.begin(), r.vbases.end()); - - std::vector new_upcasts; + class_type_data::upcast_func_list_t::upcasts_t new_upcasts; new_upcasts.reserve(l.upcasts.size() + r.upcasts.size()); new_upcasts.insert(new_upcasts.end(), l.upcasts.begin(), l.upcasts.end()); new_upcasts.insert(new_upcasts.end(), r.upcasts.begin(), r.upcasts.end()); - return class_type_data::upcast_func_list_t{std::move(new_vbases), std::move(new_upcasts)}; + class_set new_vbases; + new_vbases.insert(l.vbases.begin(), l.vbases.end()); + new_vbases.insert(r.vbases.begin(), r.vbases.end()); + + return class_type_data::upcast_func_list_t{std::move(new_upcasts), std::move(new_vbases)}; } } @@ -8348,19 +8381,14 @@ namespace meta_hpp return false; } - const detail::class_type_data& derived_data = *derived.data_; - const auto upcasts_range = derived_data.deep_upcasts.equal_range(*this); + using deep_upcasts_t = detail::class_type_data::deep_upcasts_t; + const deep_upcasts_t& deep_upcasts = derived.data_->deep_upcasts; - if ( upcasts_range.first == upcasts_range.second ) { - return false; + if ( auto iter{deep_upcasts.find(*this)}; iter != deep_upcasts.end() ) { + return !iter->second.is_ambiguous && !iter->second.vbases.empty(); } - const class_set& first_vbases = upcasts_range.first->second.vbases; - return std::any_of(first_vbases.begin(), first_vbases.end(), [&upcasts_range](const class_type& vbase) { - return std::all_of(std::next(upcasts_range.first), upcasts_range.second, [&vbase](auto&& upcasts_p) { - return upcasts_p.second.vbases.contains(vbase); - }); - }); + return false; } template < detail::class_kind Base > diff --git a/develop/untests/meta_base/is_disjoint.cpp b/develop/untests/meta_base/is_disjoint.cpp new file mode 100644 index 0000000..c4ea291 --- /dev/null +++ b/develop/untests/meta_base/is_disjoint.cpp @@ -0,0 +1,30 @@ +/******************************************************************************* + * 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 + +TEST_CASE("meta/meta_base/is_disjoint") { + namespace meta = meta_hpp; + using meta::detail::is_disjoint; + + CHECK(is_disjoint(std::set{}, std::set{})); + + CHECK(is_disjoint(std::set{1}, std::set{})); + CHECK(is_disjoint(std::set{}, std::set{1})); + + CHECK_FALSE(is_disjoint(std::set{1}, std::set{1})); + + CHECK_FALSE(is_disjoint(std::set{1,2}, std::set{1})); + CHECK_FALSE(is_disjoint(std::set{1}, std::set{1,2})); + + CHECK_FALSE(is_disjoint(std::set{1,2}, std::set{1,3})); + CHECK_FALSE(is_disjoint(std::set{1,3}, std::set{1,2})); + + CHECK(is_disjoint(std::set{1,2}, std::set{3,4})); + CHECK(is_disjoint(std::set{2,3}, std::set{1,4,5})); + CHECK(is_disjoint(std::set{2,4}, std::set{1,3,5})); +} diff --git a/develop/untests/meta_features/ambiguous_tests.cpp b/develop/untests/meta_features/ambiguous_tests.cpp index 31f6c04..65267fa 100644 --- a/develop/untests/meta_features/ambiguous_tests.cpp +++ b/develop/untests/meta_features/ambiguous_tests.cpp @@ -47,7 +47,12 @@ TEST_CASE("meta/meta_features/ambiguous") { CHECK(meta::is_invocable_with(+[](const A1&){}, C1{})); CHECK_FALSE(meta::is_invocable_with(+[](const A1&){}, D1{})); + CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); + CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); + + CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); + CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); } { @@ -69,7 +74,12 @@ TEST_CASE("meta/meta_features/ambiguous") { CHECK(meta::is_invocable_with(+[](const A2&){}, C2{})); CHECK(meta::is_invocable_with(+[](const A2&){}, D2{})); + CHECK(meta::resolve_type().is_virtual_base_of()); + CHECK(meta::resolve_type().is_virtual_base_of()); CHECK(meta::resolve_type().is_virtual_base_of()); + + CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); + CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); } { @@ -91,6 +101,11 @@ TEST_CASE("meta/meta_features/ambiguous") { CHECK(meta::is_invocable_with(+[](const A3&){}, C3{})); CHECK_FALSE(meta::is_invocable_with(+[](const A3&){}, D3{})); + CHECK(meta::resolve_type().is_virtual_base_of()); + CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); + + CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); + CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); } } diff --git a/develop/untests/meta_features/diamond_tests.cpp b/develop/untests/meta_features/diamond_tests.cpp index adf6fd9..11384af 100644 --- a/develop/untests/meta_features/diamond_tests.cpp +++ b/develop/untests/meta_features/diamond_tests.cpp @@ -120,47 +120,47 @@ TEST_CASE("meta/meta_features/diamond") { CHECK(!E_type.is_derived_from(E_type)); } - SUBCASE("unchecked_pointer_upcast") { - using meta::detail::unchecked_pointer_upcast; + SUBCASE("pointer_upcast") { + using meta::detail::pointer_upcast; { A a; - CHECK(unchecked_pointer_upcast(r, &a) == &a); - CHECK_FALSE(unchecked_pointer_upcast(r, &a)); - CHECK_FALSE(unchecked_pointer_upcast(r, &a)); - CHECK_FALSE(unchecked_pointer_upcast(r, &a)); - CHECK_FALSE(unchecked_pointer_upcast(r, &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(unchecked_pointer_upcast(r, &b) == &b); - CHECK(unchecked_pointer_upcast(r, &b) == &b); - CHECK_FALSE(unchecked_pointer_upcast(r, &b)); - CHECK_FALSE(unchecked_pointer_upcast(r, &b)); - CHECK_FALSE(unchecked_pointer_upcast(r, &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(unchecked_pointer_upcast(r, &c) == &c); - CHECK_FALSE(unchecked_pointer_upcast(r, &c)); - CHECK(unchecked_pointer_upcast(r, &c) == &c); - CHECK_FALSE(unchecked_pointer_upcast(r, &c)); - CHECK_FALSE(unchecked_pointer_upcast(r, &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(unchecked_pointer_upcast(r, &d) == &d); - CHECK(unchecked_pointer_upcast(r, &d) == &d); - CHECK(unchecked_pointer_upcast(r, &d) == &d); - CHECK(unchecked_pointer_upcast(r, &d) == &d); - CHECK_FALSE(unchecked_pointer_upcast(r, &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(unchecked_pointer_upcast(r, &e)); - CHECK_FALSE(unchecked_pointer_upcast(r, &e)); - CHECK_FALSE(unchecked_pointer_upcast(r, &e)); - CHECK_FALSE(unchecked_pointer_upcast(r, &e)); - CHECK(unchecked_pointer_upcast(r, &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); } } diff --git a/develop/untests/meta_features/multiple2_tests.cpp b/develop/untests/meta_features/multiple2_tests.cpp index fd3533a..88cc309 100644 --- a/develop/untests/meta_features/multiple2_tests.cpp +++ b/develop/untests/meta_features/multiple2_tests.cpp @@ -135,70 +135,70 @@ TEST_CASE("meta/meta_features/multiple2") { CHECK(!E1_type.is_base_of(E1_type)); } - SUBCASE("unchecked_pointer_upcast") { + SUBCASE("pointer_upcast") { using meta::detail::type_registry; - using meta::detail::unchecked_pointer_upcast; + using meta::detail::pointer_upcast; type_registry& r{type_registry::instance()}; { A a; - CHECK(unchecked_pointer_upcast(r, &a) == &a); CHECK(unchecked_pointer_upcast(r, &a)->a == "a"); - CHECK_FALSE(unchecked_pointer_upcast(r, &a)); - CHECK_FALSE(unchecked_pointer_upcast(r, &a)); - CHECK_FALSE(unchecked_pointer_upcast(r, &a)); + CHECK(pointer_upcast(r, &a) == &a); CHECK(pointer_upcast(r, &a)->a == "a"); + CHECK_FALSE(pointer_upcast(r, &a)); + CHECK_FALSE(pointer_upcast(r, &a)); + CHECK_FALSE(pointer_upcast(r, &a)); } { B0 b0; - CHECK(unchecked_pointer_upcast(r, &b0) == &b0); CHECK(unchecked_pointer_upcast(r, &b0)->a == "a"); - CHECK(unchecked_pointer_upcast(r, &b0) == &b0); CHECK(unchecked_pointer_upcast(r, &b0)->b0 == "b0"); - CHECK_FALSE(unchecked_pointer_upcast(r, &b0)); - CHECK_FALSE(unchecked_pointer_upcast(r, &b0)); + CHECK(pointer_upcast(r, &b0) == &b0); CHECK(pointer_upcast(r, &b0)->a == "a"); + CHECK(pointer_upcast(r, &b0) == &b0); CHECK(pointer_upcast(r, &b0)->b0 == "b0"); + CHECK_FALSE(pointer_upcast(r, &b0)); + CHECK_FALSE(pointer_upcast(r, &b0)); } { B1 b1; - CHECK(unchecked_pointer_upcast(r, &b1) == &b1); CHECK(unchecked_pointer_upcast(r, &b1)->a == "a"); - CHECK_FALSE(unchecked_pointer_upcast(r, &b1)); - CHECK(unchecked_pointer_upcast(r, &b1) == &b1); CHECK(unchecked_pointer_upcast(r, &b1)->b1 == "b1"); - CHECK_FALSE(unchecked_pointer_upcast(r, &b1)); + CHECK(pointer_upcast(r, &b1) == &b1); CHECK(pointer_upcast(r, &b1)->a == "a"); + CHECK_FALSE(pointer_upcast(r, &b1)); + CHECK(pointer_upcast(r, &b1) == &b1); CHECK(pointer_upcast(r, &b1)->b1 == "b1"); + CHECK_FALSE(pointer_upcast(r, &b1)); } { C c; - CHECK(unchecked_pointer_upcast(r, &c) == &c); CHECK(unchecked_pointer_upcast(r, &c)->a == "a"); - CHECK(unchecked_pointer_upcast(r, &c) == &c); CHECK(unchecked_pointer_upcast(r, &c)->b0 == "b0"); - CHECK(unchecked_pointer_upcast(r, &c) == &c); CHECK(unchecked_pointer_upcast(r, &c)->b1 == "b1"); - CHECK(unchecked_pointer_upcast(r, &c) == &c); CHECK(unchecked_pointer_upcast(r, &c)->c == "c"); - CHECK_FALSE(unchecked_pointer_upcast(r, &c)); - CHECK_FALSE(unchecked_pointer_upcast(r, &c)); - CHECK_FALSE(unchecked_pointer_upcast(r, &c)); - CHECK_FALSE(unchecked_pointer_upcast(r, &c)); + CHECK(pointer_upcast(r, &c) == &c); CHECK(pointer_upcast(r, &c)->a == "a"); + CHECK(pointer_upcast(r, &c) == &c); CHECK(pointer_upcast(r, &c)->b0 == "b0"); + CHECK(pointer_upcast(r, &c) == &c); CHECK(pointer_upcast(r, &c)->b1 == "b1"); + CHECK(pointer_upcast(r, &c) == &c); CHECK(pointer_upcast(r, &c)->c == "c"); + CHECK_FALSE(pointer_upcast(r, &c)); + CHECK_FALSE(pointer_upcast(r, &c)); + CHECK_FALSE(pointer_upcast(r, &c)); + CHECK_FALSE(pointer_upcast(r, &c)); } { E0 e0; - CHECK(unchecked_pointer_upcast(r, &e0) == &e0); CHECK(unchecked_pointer_upcast(r, &e0)->a == "a"); - CHECK(unchecked_pointer_upcast(r, &e0) == &e0); CHECK(unchecked_pointer_upcast(r, &e0)->b0 == "b0"); - CHECK(unchecked_pointer_upcast(r, &e0) == &e0); CHECK(unchecked_pointer_upcast(r, &e0)->b1 == "b1"); - CHECK(unchecked_pointer_upcast(r, &e0) == &e0); CHECK(unchecked_pointer_upcast(r, &e0)->c == "c"); - CHECK(unchecked_pointer_upcast(r, &e0) == &e0); CHECK(unchecked_pointer_upcast(r, &e0)->d0 == "d0"); - CHECK_FALSE(unchecked_pointer_upcast(r, &e0)); - CHECK(unchecked_pointer_upcast(r, &e0) == &e0); CHECK(unchecked_pointer_upcast(r, &e0)->e0 == "e0"); - CHECK_FALSE(unchecked_pointer_upcast(r, &e0)); + CHECK(pointer_upcast(r, &e0) == &e0); CHECK(pointer_upcast(r, &e0)->a == "a"); + CHECK(pointer_upcast(r, &e0) == &e0); CHECK(pointer_upcast(r, &e0)->b0 == "b0"); + CHECK(pointer_upcast(r, &e0) == &e0); CHECK(pointer_upcast(r, &e0)->b1 == "b1"); + CHECK(pointer_upcast(r, &e0) == &e0); CHECK(pointer_upcast(r, &e0)->c == "c"); + CHECK(pointer_upcast(r, &e0) == &e0); CHECK(pointer_upcast(r, &e0)->d0 == "d0"); + CHECK_FALSE(pointer_upcast(r, &e0)); + CHECK(pointer_upcast(r, &e0) == &e0); CHECK(pointer_upcast(r, &e0)->e0 == "e0"); + CHECK_FALSE(pointer_upcast(r, &e0)); } { E1 e1; - CHECK(unchecked_pointer_upcast(r, &e1) == &e1); CHECK(unchecked_pointer_upcast(r, &e1)->a == "a"); - CHECK(unchecked_pointer_upcast(r, &e1) == &e1); CHECK(unchecked_pointer_upcast(r, &e1)->b0 == "b0"); - CHECK(unchecked_pointer_upcast(r, &e1) == &e1); CHECK(unchecked_pointer_upcast(r, &e1)->b1 == "b1"); - CHECK(unchecked_pointer_upcast(r, &e1) == &e1); CHECK(unchecked_pointer_upcast(r, &e1)->c == "c"); - CHECK_FALSE(unchecked_pointer_upcast(r, &e1)); - CHECK(unchecked_pointer_upcast(r, &e1) == &e1); CHECK(unchecked_pointer_upcast(r, &e1)->d1 == "d1"); - CHECK_FALSE(unchecked_pointer_upcast(r, &e1)); - CHECK(unchecked_pointer_upcast(r, &e1) == &e1); CHECK(unchecked_pointer_upcast(r, &e1)->e1 == "e1"); + CHECK(pointer_upcast(r, &e1) == &e1); CHECK(pointer_upcast(r, &e1)->a == "a"); + CHECK(pointer_upcast(r, &e1) == &e1); CHECK(pointer_upcast(r, &e1)->b0 == "b0"); + CHECK(pointer_upcast(r, &e1) == &e1); CHECK(pointer_upcast(r, &e1)->b1 == "b1"); + CHECK(pointer_upcast(r, &e1) == &e1); CHECK(pointer_upcast(r, &e1)->c == "c"); + CHECK_FALSE(pointer_upcast(r, &e1)); + CHECK(pointer_upcast(r, &e1) == &e1); CHECK(pointer_upcast(r, &e1)->d1 == "d1"); + CHECK_FALSE(pointer_upcast(r, &e1)); + CHECK(pointer_upcast(r, &e1) == &e1); CHECK(pointer_upcast(r, &e1)->e1 == "e1"); } } } diff --git a/develop/untests/meta_features/multiple_tests.cpp b/develop/untests/meta_features/multiple_tests.cpp index 22dc29d..25481f8 100644 --- a/develop/untests/meta_features/multiple_tests.cpp +++ b/develop/untests/meta_features/multiple_tests.cpp @@ -150,65 +150,65 @@ TEST_CASE("meta/meta_features/multiple") { CHECK(!F_type.is_derived_from(F_type)); } - SUBCASE("unchecked_pointer_upcast") { - using meta::detail::unchecked_pointer_upcast; + SUBCASE("pointer_upcast") { + using meta::detail::pointer_upcast; { A a; - CHECK(unchecked_pointer_upcast(r, &a) == &a); - CHECK_FALSE(unchecked_pointer_upcast(r, &a)); - CHECK_FALSE(unchecked_pointer_upcast(r, &a)); - CHECK_FALSE(unchecked_pointer_upcast(r, &a)); - CHECK_FALSE(unchecked_pointer_upcast(r, &a)); - CHECK_FALSE(unchecked_pointer_upcast(r, &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)); + CHECK_FALSE(pointer_upcast(r, &a)); } { const B b; - CHECK(unchecked_pointer_upcast(r, &b) == &b); - CHECK(unchecked_pointer_upcast(r, &b) == &b); - CHECK_FALSE(unchecked_pointer_upcast(r, &b)); - CHECK_FALSE(unchecked_pointer_upcast(r, &b)); - CHECK_FALSE(unchecked_pointer_upcast(r, &b)); - CHECK_FALSE(unchecked_pointer_upcast(r, &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)); + CHECK_FALSE(pointer_upcast(r, &b)); } { C c; - CHECK(unchecked_pointer_upcast(r, &c) == &c); - CHECK_FALSE(unchecked_pointer_upcast(r, &c)); - CHECK(unchecked_pointer_upcast(r, &c) == &c); - CHECK_FALSE(unchecked_pointer_upcast(r, &c)); - CHECK_FALSE(unchecked_pointer_upcast(r, &c)); - CHECK_FALSE(unchecked_pointer_upcast(r, &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)); + CHECK_FALSE(pointer_upcast(r, &c)); } { const D d; - // CHECK_FALSE(unchecked_pointer_upcast(r,&d)); // ambiguous - CHECK(unchecked_pointer_upcast(r, unchecked_pointer_upcast(r,&d)) == static_cast(static_cast(&d))); - CHECK(unchecked_pointer_upcast(r, unchecked_pointer_upcast(r,&d)) == static_cast(static_cast(&d))); - CHECK(unchecked_pointer_upcast(r, &d) == &d); - CHECK(unchecked_pointer_upcast(r, &d) == &d); - CHECK(unchecked_pointer_upcast(r, &d) == &d); - CHECK_FALSE(unchecked_pointer_upcast(r, &d)); - CHECK_FALSE(unchecked_pointer_upcast(r, &d)); + CHECK_FALSE(pointer_upcast(r,&d)); + CHECK(pointer_upcast(r, pointer_upcast(r,&d)) == static_cast(static_cast(&d))); + CHECK(pointer_upcast(r, pointer_upcast(r,&d)) == static_cast(static_cast(&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)); + CHECK_FALSE(pointer_upcast(r, &d)); } { const E e; - // CHECK_FALSE(unchecked_pointer_upcast(r,&e)); // ambiguous - CHECK(unchecked_pointer_upcast(r, unchecked_pointer_upcast(r,&e)) == static_cast(static_cast(&e))); - CHECK(unchecked_pointer_upcast(r, unchecked_pointer_upcast(r,&e)) == static_cast(static_cast(&e))); - CHECK(unchecked_pointer_upcast(r, &e) == &e); - CHECK(unchecked_pointer_upcast(r, &e) == &e); - CHECK(unchecked_pointer_upcast(r, &e) == &e); - CHECK(unchecked_pointer_upcast(r, &e) == &e); - CHECK_FALSE(unchecked_pointer_upcast(r, &e)); + CHECK_FALSE(pointer_upcast(r,&e)); + CHECK(pointer_upcast(r, pointer_upcast(r,&e)) == static_cast(static_cast(&e))); + CHECK(pointer_upcast(r, pointer_upcast(r,&e)) == static_cast(static_cast(&e))); + CHECK(pointer_upcast(r, &e) == &e); + CHECK(pointer_upcast(r, &e) == &e); + CHECK(pointer_upcast(r, &e) == &e); + CHECK(pointer_upcast(r, &e) == &e); + CHECK_FALSE(pointer_upcast(r, &e)); } { F f; - CHECK_FALSE(unchecked_pointer_upcast(r, &f)); - CHECK_FALSE(unchecked_pointer_upcast(r, &f)); - CHECK_FALSE(unchecked_pointer_upcast(r, &f)); - CHECK_FALSE(unchecked_pointer_upcast(r, &f)); - CHECK_FALSE(unchecked_pointer_upcast(r, &f)); - CHECK(unchecked_pointer_upcast(r, &f) == &f); + CHECK_FALSE(pointer_upcast(r, &f)); + CHECK_FALSE(pointer_upcast(r, &f)); + CHECK_FALSE(pointer_upcast(r, &f)); + CHECK_FALSE(pointer_upcast(r, &f)); + CHECK_FALSE(pointer_upcast(r, &f)); + CHECK(pointer_upcast(r, &f) == &f); } } } diff --git a/headers/meta.hpp/meta_base.hpp b/headers/meta.hpp/meta_base.hpp index 55c4c9c..150baae 100644 --- a/headers/meta.hpp/meta_base.hpp +++ b/headers/meta.hpp/meta_base.hpp @@ -18,6 +18,7 @@ #include "meta_base/hashed_string.hpp" #include "meta_base/insert_or_assign.hpp" #include "meta_base/intrusive_ptr.hpp" +#include "meta_base/is_disjoint.hpp" #include "meta_base/is_in_place_type.hpp" #include "meta_base/is_virtual_base_of.hpp" #include "meta_base/memory_buffer.hpp" diff --git a/headers/meta.hpp/meta_base/is_disjoint.hpp b/headers/meta.hpp/meta_base/is_disjoint.hpp new file mode 100644 index 0000000..b7e7435 --- /dev/null +++ b/headers/meta.hpp/meta_base/is_disjoint.hpp @@ -0,0 +1,35 @@ +/******************************************************************************* + * 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) + ******************************************************************************/ + +#pragma once + +#include "base.hpp" + +namespace meta_hpp::detail +{ + template < typename SortedContainerL, typename SortedContainerR, typename Compare > + bool is_disjoint(const SortedContainerL& l, const SortedContainerR& r, Compare compare) { + using std::begin; + using std::end; + + for ( auto iter_l{begin(l)}, iter_r{begin(r)}; iter_l != end(l) && iter_r != end(r); ) { + if ( compare(*iter_l, *iter_r) ) { + ++iter_l; + } else if ( compare(*iter_r, *iter_l) ) { + ++iter_r; + } else { + return false; + } + } + + return true; + } + + template < typename SortedContainerL, typename SortedContainerR > + bool is_disjoint(const SortedContainerL& l, const SortedContainerR& r) { + return is_disjoint(l, r, std::less<>{}); + } +} diff --git a/headers/meta.hpp/meta_binds/class_bind.hpp b/headers/meta.hpp/meta_binds/class_bind.hpp index 2f90528..2419364 100644 --- a/headers/meta.hpp/meta_binds/class_bind.hpp +++ b/headers/meta.hpp/meta_binds/class_bind.hpp @@ -45,9 +45,16 @@ namespace meta_hpp::detail::class_bind_impl const auto [deep_upcasts_db_iter, _] = deep_upcasts_db.try_emplace(derived_class, derived_class_data.deep_upcasts); deep_upcasts_t& derived_deep_upcasts = deep_upcasts_db_iter->second; + const auto add_derived_deep_upcast = [&derived_deep_upcasts](const class_type& deep_class, upcast_func_list_t&& upcasts) { + auto&& [position, emplaced] = derived_deep_upcasts.try_emplace(deep_class, std::move(upcasts)); + if ( !emplaced ) { + position->second.is_ambiguous = is_disjoint(position->second.vbases, upcasts.vbases); + } + }; + for ( auto&& [new_deep_class, new_base_to_deep] : new_base_class_data.deep_upcasts ) { upcast_func_list_t derived_to_new_deep = derived_to_new_base + new_base_to_deep; - derived_deep_upcasts.emplace(new_deep_class, std::move(derived_to_new_deep)); + add_derived_deep_upcast(new_deep_class, std::move(derived_to_new_deep)); } for ( const class_type& subderived_class : derived_class_data.derived_classes ) { @@ -57,7 +64,7 @@ namespace meta_hpp::detail::class_bind_impl update_deep_upcasts_db(subderived_class, new_base_class, std::move(subderived_to_new_base), deep_upcasts_db); } - derived_deep_upcasts.emplace(new_base_class, std::move(derived_to_new_base)); + add_derived_deep_upcast(new_base_class, std::move(derived_to_new_base)); } inline void updata_derived_classes_db( // diff --git a/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp b/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp index 4f7224f..a943201 100644 --- a/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp +++ b/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp @@ -258,7 +258,7 @@ namespace meta_hpp::detail if ( from_type.is_array() ) { const array_type& from_type_array = from_type.as_array(); - void* to_ptr = unchecked_pointer_upcast( // + void* to_ptr = pointer_upcast( // data_, from_type_array.get_data_type(), to_type_ptr.get_data_type() @@ -271,7 +271,7 @@ namespace meta_hpp::detail if ( from_type.is_pointer() ) { const pointer_type& from_type_ptr = from_type.as_pointer(); - void* to_ptr = unchecked_pointer_upcast( // + void* to_ptr = pointer_upcast( // *static_cast(data_), from_type_ptr.get_data_type(), to_type_ptr.get_data_type() @@ -299,7 +299,7 @@ namespace meta_hpp::detail const any_type& from_type = get_raw_type(); const any_type& to_type = registry.resolve_type(); - void* to_ptr = unchecked_pointer_upcast(data_, from_type, to_type); + void* to_ptr = pointer_upcast(data_, from_type, to_type); META_HPP_ASSERT(to_ptr); if constexpr ( std::is_lvalue_reference_v ) { diff --git a/headers/meta.hpp/meta_detail/value_utilities/uinst.hpp b/headers/meta.hpp/meta_detail/value_utilities/uinst.hpp index 6c88ae3..493e6c6 100644 --- a/headers/meta.hpp/meta_detail/value_utilities/uinst.hpp +++ b/headers/meta.hpp/meta_detail/value_utilities/uinst.hpp @@ -192,7 +192,7 @@ namespace meta_hpp::detail const any_type& to_type = registry.resolve_type(); if ( from_type.is_class() && to_type.is_class() ) { - void* to_ptr = unchecked_pointer_upcast( // + void* to_ptr = pointer_upcast( // data_, from_type.as_class(), to_type.as_class() @@ -217,7 +217,7 @@ namespace meta_hpp::detail const any_type& from_data_type = from_type_ptr.get_data_type(); if ( from_data_type.is_class() && to_type.is_class() ) { - void* to_ptr = unchecked_pointer_upcast( // + void* to_ptr = pointer_upcast( // *static_cast(data_), from_data_type.as_class(), to_type.as_class() diff --git a/headers/meta.hpp/meta_detail/value_utilities/utraits.hpp b/headers/meta.hpp/meta_detail/value_utilities/utraits.hpp index 5277000..68c78d0 100644 --- a/headers/meta.hpp/meta_detail/value_utilities/utraits.hpp +++ b/headers/meta.hpp/meta_detail/value_utilities/utraits.hpp @@ -109,14 +109,8 @@ namespace meta_hpp::detail const class_type_data& derived_data = *type_access(derived_class); const class_type_data::deep_upcasts_t& deep_upcasts = derived_data.deep_upcasts; - if ( const auto iter{deep_upcasts.lower_bound(base)}; iter != deep_upcasts.end() && iter->first == base ) { - if ( const auto next_iter{std::next(iter)}; next_iter == deep_upcasts.end() || next_iter->first != base ) { - return true; - } - - if ( base_class.is_virtual_base_of(derived_class) ) { - return true; - } + if ( auto iter{deep_upcasts.find(base)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) { + return true; } } @@ -126,7 +120,7 @@ namespace meta_hpp::detail namespace meta_hpp::detail { - [[nodiscard]] inline void* unchecked_pointer_upcast(void* ptr, const class_type& from, const class_type& to) { + [[nodiscard]] inline void* pointer_upcast(void* ptr, const class_type& from, const class_type& to) { if ( nullptr == ptr || !from || !to ) { return nullptr; } @@ -136,23 +130,24 @@ namespace meta_hpp::detail } const class_type_data& from_data = *type_access(from); + const class_type_data::deep_upcasts_t& deep_upcasts = from_data.deep_upcasts; - if ( auto iter{from_data.deep_upcasts.find(to)}; iter != from_data.deep_upcasts.end() ) { + if ( auto iter{deep_upcasts.find(to)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) { return iter->second.apply(ptr); } return nullptr; } - [[nodiscard]] inline const void* unchecked_pointer_upcast(const void* ptr, const class_type& from, const class_type& to) { + [[nodiscard]] inline const void* pointer_upcast(const void* ptr, const class_type& from, const class_type& to) { // NOLINTNEXTLINE(*-const-cast) - return unchecked_pointer_upcast(const_cast(ptr), from, to); + return pointer_upcast(const_cast(ptr), from, to); } } namespace meta_hpp::detail { - [[nodiscard]] inline void* unchecked_pointer_upcast(void* ptr, const any_type& from, const any_type& to) { + [[nodiscard]] inline void* pointer_upcast(void* ptr, const any_type& from, const any_type& to) { if ( nullptr == ptr || !from || !to ) { return nullptr; } @@ -165,7 +160,7 @@ namespace meta_hpp::detail const class_type& from_class = from.as_class(); if ( to_class && from_class ) { - if ( void* base_ptr = unchecked_pointer_upcast(ptr, from_class, to_class) ) { + if ( void* base_ptr = pointer_upcast(ptr, from_class, to_class) ) { return base_ptr; } } @@ -173,17 +168,17 @@ namespace meta_hpp::detail return nullptr; } - [[nodiscard]] inline const void* unchecked_pointer_upcast(const void* ptr, const any_type& from, const any_type& to) { + [[nodiscard]] inline const void* pointer_upcast(const void* ptr, const any_type& from, const any_type& to) { // NOLINTNEXTLINE(*-const-cast) - return unchecked_pointer_upcast(const_cast(ptr), from, to); + return pointer_upcast(const_cast(ptr), from, to); } } namespace meta_hpp::detail { template < typename To, typename From > - [[nodiscard]] To* unchecked_pointer_upcast(type_registry& registry, From* ptr) { - return static_cast(unchecked_pointer_upcast( // + [[nodiscard]] To* pointer_upcast(type_registry& registry, From* ptr) { + return static_cast(pointer_upcast( // ptr, registry.resolve_type(), registry.resolve_type() @@ -191,8 +186,8 @@ namespace meta_hpp::detail } template < typename To, typename From > - [[nodiscard]] const To* unchecked_pointer_upcast(type_registry& registry, const From* ptr) { - return static_cast(unchecked_pointer_upcast( // + [[nodiscard]] const To* pointer_upcast(type_registry& registry, const From* ptr) { + return static_cast(pointer_upcast( // ptr, registry.resolve_type(), registry.resolve_type() diff --git a/headers/meta.hpp/meta_types.hpp b/headers/meta.hpp/meta_types.hpp index c8aa04a..6a55006 100644 --- a/headers/meta.hpp/meta_types.hpp +++ b/headers/meta.hpp/meta_types.hpp @@ -419,9 +419,11 @@ namespace meta_hpp::detail variable_set variables; struct upcast_func_t final { - void* (*upcast)(void*){}; - bool is_virtual_upcast{}; - class_type target_class{}; + using upcast_t = void* (*)(void*); + + upcast_t upcast{}; + class_type target{}; + bool is_virtual{}; template < typename Derived, typename Base > requires std::is_base_of_v @@ -432,11 +434,14 @@ namespace meta_hpp::detail }; struct upcast_func_list_t final { - class_set vbases; - std::vector upcasts; + using upcasts_t = std::vector; + + upcasts_t upcasts{}; + class_set vbases{}; + bool is_ambiguous{}; upcast_func_list_t(const upcast_func_t& _upcast); - upcast_func_list_t(class_set _vbases, std::vector _upcasts); + upcast_func_list_t(upcasts_t _upcasts, class_set _vbases); [[nodiscard]] void* apply(void* ptr) const noexcept; [[nodiscard]] const void* apply(const void* ptr) const noexcept; @@ -445,7 +450,7 @@ namespace meta_hpp::detail }; using base_upcasts_t = std::map>; - using deep_upcasts_t = std::multimap>; + using deep_upcasts_t = std::map>; base_upcasts_t base_upcasts; deep_upcasts_t deep_upcasts; diff --git a/headers/meta.hpp/meta_types/class_type.hpp b/headers/meta.hpp/meta_types/class_type.hpp index 9984ca0..4842ed4 100644 --- a/headers/meta.hpp/meta_types/class_type.hpp +++ b/headers/meta.hpp/meta_types/class_type.hpp @@ -38,8 +38,8 @@ namespace meta_hpp::detail requires std::is_base_of_v inline class_type_data::upcast_func_t::upcast_func_t(std::in_place_type_t, std::in_place_type_t) : upcast{[](void* from) -> void* { return static_cast(static_cast(from)); }} - , is_virtual_upcast{is_virtual_base_of_v} - , target_class{resolve_type()} {} + , target{resolve_type()} + , is_virtual{is_virtual_base_of_v} {} inline void* class_type_data::upcast_func_t::apply(void* ptr) const noexcept { return upcast(ptr); @@ -56,15 +56,15 @@ namespace meta_hpp::detail inline class_type_data::upcast_func_list_t::upcast_func_list_t(const upcast_func_t& _upcast) : upcasts{_upcast} { for ( const upcast_func_t& upcast : upcasts ) { - if ( upcast.is_virtual_upcast ) { - vbases.emplace(upcast.target_class); + if ( upcast.is_virtual ) { + vbases.emplace(upcast.target); } } } - inline class_type_data::upcast_func_list_t::upcast_func_list_t(class_set _vbases, std::vector _upcasts) - : vbases{std::move(_vbases)} - , upcasts{std::move(_upcasts)} {} + inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcasts_t _upcasts, class_set _vbases) + : upcasts{std::move(_upcasts)} + , vbases{std::move(_vbases)} {} inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept { for ( const upcast_func_t& upcast : upcasts ) { @@ -82,16 +82,16 @@ namespace meta_hpp::detail const class_type_data::upcast_func_list_t& l, const class_type_data::upcast_func_list_t& r ) { - class_set new_vbases; - new_vbases.insert(l.vbases.begin(), l.vbases.end()); - new_vbases.insert(r.vbases.begin(), r.vbases.end()); - - std::vector new_upcasts; + class_type_data::upcast_func_list_t::upcasts_t new_upcasts; new_upcasts.reserve(l.upcasts.size() + r.upcasts.size()); new_upcasts.insert(new_upcasts.end(), l.upcasts.begin(), l.upcasts.end()); new_upcasts.insert(new_upcasts.end(), r.upcasts.begin(), r.upcasts.end()); - return class_type_data::upcast_func_list_t{std::move(new_vbases), std::move(new_upcasts)}; + class_set new_vbases; + new_vbases.insert(l.vbases.begin(), l.vbases.end()); + new_vbases.insert(r.vbases.begin(), r.vbases.end()); + + return class_type_data::upcast_func_list_t{std::move(new_upcasts), std::move(new_vbases)}; } } @@ -224,19 +224,14 @@ namespace meta_hpp return false; } - const detail::class_type_data& derived_data = *derived.data_; - const auto upcasts_range = derived_data.deep_upcasts.equal_range(*this); + using deep_upcasts_t = detail::class_type_data::deep_upcasts_t; + const deep_upcasts_t& deep_upcasts = derived.data_->deep_upcasts; - if ( upcasts_range.first == upcasts_range.second ) { - return false; + if ( auto iter{deep_upcasts.find(*this)}; iter != deep_upcasts.end() ) { + return !iter->second.is_ambiguous && !iter->second.vbases.empty(); } - const class_set& first_vbases = upcasts_range.first->second.vbases; - return std::any_of(first_vbases.begin(), first_vbases.end(), [&upcasts_range](const class_type& vbase) { - return std::all_of(std::next(upcasts_range.first), upcasts_range.second, [&vbase](auto&& upcasts_p) { - return upcasts_p.second.vbases.contains(vbase); - }); - }); + return false; } template < detail::class_kind Base >