From 1b77d20666aacd8560a57ebaa31893daa55be6ce Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Thu, 2 Mar 2023 23:52:46 +0700 Subject: [PATCH 1/9] add dev assets --- develop/cmake/SetupTargets.cmake | 3 + develop/singles/headers/meta.hpp/meta_all.hpp | 72 +++++++++++-------- headers/meta.hpp/meta_base/base.hpp | 6 ++ headers/meta.hpp/meta_base/fixed_function.hpp | 10 +-- .../meta_detail/value_utilities/uarg.hpp | 30 ++++---- .../meta_detail/value_utilities/uinst.hpp | 2 +- headers/meta.hpp/meta_states/constructor.hpp | 4 +- headers/meta.hpp/meta_states/function.hpp | 2 +- headers/meta.hpp/meta_states/method.hpp | 2 +- headers/meta.hpp/meta_uvalue/uvalue.hpp | 16 ++--- 10 files changed, 85 insertions(+), 62 deletions(-) diff --git a/develop/cmake/SetupTargets.cmake b/develop/cmake/SetupTargets.cmake index 5348cdb..4e6eca0 100644 --- a/develop/cmake/SetupTargets.cmake +++ b/develop/cmake/SetupTargets.cmake @@ -30,3 +30,6 @@ target_link_libraries(${PROJECT_NAME}.setup_targets INTERFACE meta.hpp::disable_exceptions> $<$: meta.hpp::disable_rtti>) + +target_compile_definitions(${PROJECT_NAME}.setup_targets INTERFACE + $<$:META_HPP_SANITIZERS>) diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index 882d773..bb116b6 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -52,6 +52,12 @@ # define META_HPP_ASSERT(...) assert(__VA_ARGS__) // NOLINT #endif +#if defined(META_HPP_SANITIZERS) +# define META_HPP_DEV_ASSERT(...) META_HPP_ASSERT(__VA_ARGS__) +#else +# define META_HPP_DEV_ASSERT(...) (void)0 +#endif + #if !defined(META_HPP_PP_CAT) # define META_HPP_PP_CAT(x, y) META_HPP_PP_CAT_I(x, y) # define META_HPP_PP_CAT_I(x, y) x##y @@ -634,15 +640,15 @@ namespace meta_hpp::detail static vtable_t table{ .call{[](const fixed_function& self, Args... args) -> R { - META_HPP_ASSERT(self); + META_HPP_DEV_ASSERT(self); const Fp& src = *buffer_cast(self.buffer_); return std::invoke(src, std::forward(args)...); }}, .move{[](fixed_function& from, fixed_function& to) noexcept { - META_HPP_ASSERT(!to); - META_HPP_ASSERT(from); + META_HPP_DEV_ASSERT(!to); + META_HPP_DEV_ASSERT(from); Fp& src = *buffer_cast(from.buffer_); std::construct_at(buffer_cast(to.buffer_), std::move(src)); @@ -653,7 +659,7 @@ namespace meta_hpp::detail }}, .destroy{[](fixed_function& self) { - META_HPP_ASSERT(self); + META_HPP_DEV_ASSERT(self); Fp& src = *buffer_cast(self.buffer_); std::destroy_at(&src); @@ -666,7 +672,7 @@ namespace meta_hpp::detail template < typename F, typename Fp = std::decay_t > static void construct(fixed_function& dst, F&& fun) { - META_HPP_ASSERT(!dst); + META_HPP_DEV_ASSERT(!dst); static_assert(sizeof(Fp) <= sizeof(buffer_t)); static_assert(alignof(buffer_t) % alignof(Fp) == 0); @@ -6000,7 +6006,7 @@ namespace meta_hpp::detail { template < pointer_kind To > [[nodiscard]] decltype(auto) uarg::cast(type_registry& registry) const { - META_HPP_ASSERT(can_cast_to(registry) && "bad argument cast"); + META_HPP_DEV_ASSERT(can_cast_to(registry) && "bad argument cast"); using to_raw_type = std::remove_cv_t; @@ -6036,7 +6042,7 @@ namespace meta_hpp::detail template < non_pointer_kind To > [[nodiscard]] decltype(auto) uarg::cast(type_registry& registry) const { - META_HPP_ASSERT(can_cast_to(registry) && "bad argument cast"); + META_HPP_DEV_ASSERT(can_cast_to(registry) && "bad argument cast"); using to_raw_type_cv = std::remove_reference_t; using to_raw_type = std::remove_cv_t; @@ -6089,18 +6095,11 @@ namespace meta_hpp::detail namespace meta_hpp::detail { - template < typename ArgTypeList, typename F > - auto call_with_uargs(type_registry& registry, std::span args, F&& f) { - META_HPP_ASSERT(args.size() == type_list_arity_v); - return [ args, ®istry, &f ](std::index_sequence) { - return f(args[Is].cast>(registry)...); - } - (std::make_index_sequence>()); - } - template < typename ArgTypeList > bool can_cast_all_uargs(type_registry& registry, std::span args) { - META_HPP_ASSERT(args.size() == type_list_arity_v); + if ( args.size() != type_list_arity_v ) { + return false; + } return [ args, ®istry ](std::index_sequence) { return (... && args[Is].can_cast_to>(registry)); } @@ -6109,12 +6108,23 @@ namespace meta_hpp::detail template < typename ArgTypeList > bool can_cast_all_uargs(type_registry& registry, std::span args) { - META_HPP_ASSERT(args.size() == type_list_arity_v); + if ( args.size() != type_list_arity_v ) { + return false; + } return [ args, ®istry ](std::index_sequence) { return (... && args[Is].can_cast_to>(registry)); } (std::make_index_sequence>()); } + + template < typename ArgTypeList, typename F > + auto unchecked_call_with_uargs(type_registry& registry, std::span args, F&& f) { + META_HPP_DEV_ASSERT(args.size() == type_list_arity_v); + return [ args, ®istry, &f ](std::index_sequence) { + return f(args[Is].cast>(registry)...); + } + (std::make_index_sequence>()); + } } namespace meta_hpp::detail @@ -6185,7 +6195,7 @@ namespace meta_hpp::detail && "an attempt to call a function with incorrect argument types" ); - return call_with_uargs(registry, args, [function_ptr](auto&&... all_args) { + return unchecked_call_with_uargs(registry, args, [function_ptr](auto&&... all_args) { if constexpr ( std::is_void_v ) { function_ptr(META_HPP_FWD(all_args)...); return uvalue{}; @@ -6503,7 +6513,7 @@ namespace meta_hpp::detail { template < inst_class_ref_kind Q > decltype(auto) uinst::cast(type_registry& registry) const { - META_HPP_ASSERT(can_cast_to(registry) && "bad instance cast"); + META_HPP_DEV_ASSERT(can_cast_to(registry) && "bad instance cast"); using inst_class_cv = std::remove_reference_t; using inst_class = std::remove_cv_t; @@ -6961,7 +6971,7 @@ namespace meta_hpp::detail && "an attempt to call a method with incorrect argument types" ); - return call_with_uargs(registry, args, [method_ptr, &inst, ®istry](auto&&... all_args) { + return unchecked_call_with_uargs(registry, args, [method_ptr, &inst, ®istry](auto&&... all_args) { if constexpr ( std::is_void_v ) { (inst.cast(registry).*method_ptr)(META_HPP_FWD(all_args)...); return uvalue{}; @@ -7352,7 +7362,7 @@ namespace meta_hpp::detail && "an attempt to call a constructor with incorrect argument types" ); - return call_with_uargs(registry, args, [](auto&&... all_args) -> uvalue { + return unchecked_call_with_uargs(registry, args, [](auto&&... all_args) -> uvalue { if constexpr ( as_object ) { return make_uvalue(META_HPP_FWD(all_args)...); } @@ -7383,7 +7393,7 @@ namespace meta_hpp::detail && "an attempt to call a constructor with incorrect argument types" ); - return call_with_uargs(registry, args, [mem](auto&&... all_args) { + return unchecked_call_with_uargs(registry, args, [mem](auto&&... all_args) { return std::construct_at(static_cast(mem), META_HPP_FWD(all_args)...); }); } @@ -8870,7 +8880,7 @@ namespace meta_hpp template < typename T, typename... Args, typename Tp = std::decay_t > static Tp& do_ctor(uvalue& dst, Args&&... args) { - META_HPP_ASSERT(!dst); + META_HPP_DEV_ASSERT(!dst); if constexpr ( in_internal_v ) { std::construct_at(storage_cast(dst.storage_), std::forward(args)...); @@ -8888,7 +8898,7 @@ namespace meta_hpp } static void do_move(uvalue&& self, uvalue& to) noexcept { - META_HPP_ASSERT(!to); + META_HPP_DEV_ASSERT(!to); auto&& [tag, vtable] = unpack_vtag(self); @@ -8907,7 +8917,7 @@ namespace meta_hpp } static void do_copy(const uvalue& self, uvalue& to) noexcept { - META_HPP_ASSERT(!to); + META_HPP_DEV_ASSERT(!to); auto&& [tag, vtable] = unpack_vtag(self); @@ -8969,8 +8979,8 @@ namespace meta_hpp .type = resolve_type(), .move{[](uvalue&& self, uvalue& to) noexcept { - META_HPP_ASSERT(!to); - META_HPP_ASSERT(self); + META_HPP_DEV_ASSERT(!to); + META_HPP_DEV_ASSERT(self); Tp* src = storage_cast(self.storage_); @@ -8985,8 +8995,8 @@ namespace meta_hpp }}, .copy{[](const uvalue& self, uvalue& to) { - META_HPP_ASSERT(!to); - META_HPP_ASSERT(self); + META_HPP_DEV_ASSERT(!to); + META_HPP_DEV_ASSERT(self); const Tp* src = storage_cast(self.storage_); @@ -9000,7 +9010,7 @@ namespace meta_hpp }}, .reset{[](uvalue& self) noexcept { - META_HPP_ASSERT(self); + META_HPP_DEV_ASSERT(self); Tp* src = storage_cast(self.storage_); diff --git a/headers/meta.hpp/meta_base/base.hpp b/headers/meta.hpp/meta_base/base.hpp index 5cae5f2..f07e52d 100644 --- a/headers/meta.hpp/meta_base/base.hpp +++ b/headers/meta.hpp/meta_base/base.hpp @@ -53,6 +53,12 @@ # define META_HPP_ASSERT(...) assert(__VA_ARGS__) // NOLINT #endif +#if defined(META_HPP_SANITIZERS) +# define META_HPP_DEV_ASSERT(...) META_HPP_ASSERT(__VA_ARGS__) +#else +# define META_HPP_DEV_ASSERT(...) (void)0 +#endif + #if !defined(META_HPP_PP_CAT) # define META_HPP_PP_CAT(x, y) META_HPP_PP_CAT_I(x, y) # define META_HPP_PP_CAT_I(x, y) x##y diff --git a/headers/meta.hpp/meta_base/fixed_function.hpp b/headers/meta.hpp/meta_base/fixed_function.hpp index a39275f..47c0727 100644 --- a/headers/meta.hpp/meta_base/fixed_function.hpp +++ b/headers/meta.hpp/meta_base/fixed_function.hpp @@ -126,15 +126,15 @@ namespace meta_hpp::detail static vtable_t table{ .call{[](const fixed_function& self, Args... args) -> R { - META_HPP_ASSERT(self); + META_HPP_DEV_ASSERT(self); const Fp& src = *buffer_cast(self.buffer_); return std::invoke(src, std::forward(args)...); }}, .move{[](fixed_function& from, fixed_function& to) noexcept { - META_HPP_ASSERT(!to); - META_HPP_ASSERT(from); + META_HPP_DEV_ASSERT(!to); + META_HPP_DEV_ASSERT(from); Fp& src = *buffer_cast(from.buffer_); std::construct_at(buffer_cast(to.buffer_), std::move(src)); @@ -145,7 +145,7 @@ namespace meta_hpp::detail }}, .destroy{[](fixed_function& self) { - META_HPP_ASSERT(self); + META_HPP_DEV_ASSERT(self); Fp& src = *buffer_cast(self.buffer_); std::destroy_at(&src); @@ -158,7 +158,7 @@ namespace meta_hpp::detail template < typename F, typename Fp = std::decay_t > static void construct(fixed_function& dst, F&& fun) { - META_HPP_ASSERT(!dst); + META_HPP_DEV_ASSERT(!dst); static_assert(sizeof(Fp) <= sizeof(buffer_t)); static_assert(alignof(buffer_t) % alignof(Fp) == 0); diff --git a/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp b/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp index d772f28..72dbffa 100644 --- a/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp +++ b/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp @@ -244,7 +244,7 @@ namespace meta_hpp::detail { template < pointer_kind To > [[nodiscard]] decltype(auto) uarg::cast(type_registry& registry) const { - META_HPP_ASSERT(can_cast_to(registry) && "bad argument cast"); + META_HPP_DEV_ASSERT(can_cast_to(registry) && "bad argument cast"); using to_raw_type = std::remove_cv_t; @@ -280,7 +280,7 @@ namespace meta_hpp::detail template < non_pointer_kind To > [[nodiscard]] decltype(auto) uarg::cast(type_registry& registry) const { - META_HPP_ASSERT(can_cast_to(registry) && "bad argument cast"); + META_HPP_DEV_ASSERT(can_cast_to(registry) && "bad argument cast"); using to_raw_type_cv = std::remove_reference_t; using to_raw_type = std::remove_cv_t; @@ -333,18 +333,11 @@ namespace meta_hpp::detail namespace meta_hpp::detail { - template < typename ArgTypeList, typename F > - auto call_with_uargs(type_registry& registry, std::span args, F&& f) { - META_HPP_ASSERT(args.size() == type_list_arity_v); - return [ args, ®istry, &f ](std::index_sequence) { - return f(args[Is].cast>(registry)...); - } - (std::make_index_sequence>()); - } - template < typename ArgTypeList > bool can_cast_all_uargs(type_registry& registry, std::span args) { - META_HPP_ASSERT(args.size() == type_list_arity_v); + if ( args.size() != type_list_arity_v ) { + return false; + } return [ args, ®istry ](std::index_sequence) { return (... && args[Is].can_cast_to>(registry)); } @@ -353,10 +346,21 @@ namespace meta_hpp::detail template < typename ArgTypeList > bool can_cast_all_uargs(type_registry& registry, std::span args) { - META_HPP_ASSERT(args.size() == type_list_arity_v); + if ( args.size() != type_list_arity_v ) { + return false; + } return [ args, ®istry ](std::index_sequence) { return (... && args[Is].can_cast_to>(registry)); } (std::make_index_sequence>()); } + + template < typename ArgTypeList, typename F > + auto unchecked_call_with_uargs(type_registry& registry, std::span args, F&& f) { + META_HPP_DEV_ASSERT(args.size() == type_list_arity_v); + return [ args, ®istry, &f ](std::index_sequence) { + return f(args[Is].cast>(registry)...); + } + (std::make_index_sequence>()); + } } diff --git a/headers/meta.hpp/meta_detail/value_utilities/uinst.hpp b/headers/meta.hpp/meta_detail/value_utilities/uinst.hpp index 89475f4..c20e7d6 100644 --- a/headers/meta.hpp/meta_detail/value_utilities/uinst.hpp +++ b/headers/meta.hpp/meta_detail/value_utilities/uinst.hpp @@ -183,7 +183,7 @@ namespace meta_hpp::detail { template < inst_class_ref_kind Q > decltype(auto) uinst::cast(type_registry& registry) const { - META_HPP_ASSERT(can_cast_to(registry) && "bad instance cast"); + META_HPP_DEV_ASSERT(can_cast_to(registry) && "bad instance cast"); using inst_class_cv = std::remove_reference_t; using inst_class = std::remove_cv_t; diff --git a/headers/meta.hpp/meta_states/constructor.hpp b/headers/meta.hpp/meta_states/constructor.hpp index 42d9890..99bead5 100644 --- a/headers/meta.hpp/meta_states/constructor.hpp +++ b/headers/meta.hpp/meta_states/constructor.hpp @@ -43,7 +43,7 @@ namespace meta_hpp::detail && "an attempt to call a constructor with incorrect argument types" ); - return call_with_uargs(registry, args, [](auto&&... all_args) -> uvalue { + return unchecked_call_with_uargs(registry, args, [](auto&&... all_args) -> uvalue { if constexpr ( as_object ) { return make_uvalue(META_HPP_FWD(all_args)...); } @@ -74,7 +74,7 @@ namespace meta_hpp::detail && "an attempt to call a constructor with incorrect argument types" ); - return call_with_uargs(registry, args, [mem](auto&&... all_args) { + return unchecked_call_with_uargs(registry, args, [mem](auto&&... all_args) { return std::construct_at(static_cast(mem), META_HPP_FWD(all_args)...); }); } diff --git a/headers/meta.hpp/meta_states/function.hpp b/headers/meta.hpp/meta_states/function.hpp index 7408383..92dc4dd 100644 --- a/headers/meta.hpp/meta_states/function.hpp +++ b/headers/meta.hpp/meta_states/function.hpp @@ -45,7 +45,7 @@ namespace meta_hpp::detail && "an attempt to call a function with incorrect argument types" ); - return call_with_uargs(registry, args, [function_ptr](auto&&... all_args) { + return unchecked_call_with_uargs(registry, args, [function_ptr](auto&&... all_args) { if constexpr ( std::is_void_v ) { function_ptr(META_HPP_FWD(all_args)...); return uvalue{}; diff --git a/headers/meta.hpp/meta_states/method.hpp b/headers/meta.hpp/meta_states/method.hpp index e9e385d..685e20b 100644 --- a/headers/meta.hpp/meta_states/method.hpp +++ b/headers/meta.hpp/meta_states/method.hpp @@ -52,7 +52,7 @@ namespace meta_hpp::detail && "an attempt to call a method with incorrect argument types" ); - return call_with_uargs(registry, args, [method_ptr, &inst, ®istry](auto&&... all_args) { + return unchecked_call_with_uargs(registry, args, [method_ptr, &inst, ®istry](auto&&... all_args) { if constexpr ( std::is_void_v ) { (inst.cast(registry).*method_ptr)(META_HPP_FWD(all_args)...); return uvalue{}; diff --git a/headers/meta.hpp/meta_uvalue/uvalue.hpp b/headers/meta.hpp/meta_uvalue/uvalue.hpp index 4ee0bf6..0232a82 100644 --- a/headers/meta.hpp/meta_uvalue/uvalue.hpp +++ b/headers/meta.hpp/meta_uvalue/uvalue.hpp @@ -73,7 +73,7 @@ namespace meta_hpp template < typename T, typename... Args, typename Tp = std::decay_t > static Tp& do_ctor(uvalue& dst, Args&&... args) { - META_HPP_ASSERT(!dst); + META_HPP_DEV_ASSERT(!dst); if constexpr ( in_internal_v ) { std::construct_at(storage_cast(dst.storage_), std::forward(args)...); @@ -91,7 +91,7 @@ namespace meta_hpp } static void do_move(uvalue&& self, uvalue& to) noexcept { - META_HPP_ASSERT(!to); + META_HPP_DEV_ASSERT(!to); auto&& [tag, vtable] = unpack_vtag(self); @@ -110,7 +110,7 @@ namespace meta_hpp } static void do_copy(const uvalue& self, uvalue& to) noexcept { - META_HPP_ASSERT(!to); + META_HPP_DEV_ASSERT(!to); auto&& [tag, vtable] = unpack_vtag(self); @@ -172,8 +172,8 @@ namespace meta_hpp .type = resolve_type(), .move{[](uvalue&& self, uvalue& to) noexcept { - META_HPP_ASSERT(!to); - META_HPP_ASSERT(self); + META_HPP_DEV_ASSERT(!to); + META_HPP_DEV_ASSERT(self); Tp* src = storage_cast(self.storage_); @@ -188,8 +188,8 @@ namespace meta_hpp }}, .copy{[](const uvalue& self, uvalue& to) { - META_HPP_ASSERT(!to); - META_HPP_ASSERT(self); + META_HPP_DEV_ASSERT(!to); + META_HPP_DEV_ASSERT(self); const Tp* src = storage_cast(self.storage_); @@ -203,7 +203,7 @@ namespace meta_hpp }}, .reset{[](uvalue& self) noexcept { - META_HPP_ASSERT(self); + META_HPP_DEV_ASSERT(self); Tp* src = storage_cast(self.storage_); From 8e34cfdda169de149279920cfefc68c2ecde98bb Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 3 Mar 2023 01:03:19 +0700 Subject: [PATCH 2/9] add ambiguous conversions issue --- .../untests/meta_issues/random_issue_1.cpp | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 develop/untests/meta_issues/random_issue_1.cpp diff --git a/develop/untests/meta_issues/random_issue_1.cpp b/develop/untests/meta_issues/random_issue_1.cpp new file mode 100644 index 0000000..67c2879 --- /dev/null +++ b/develop/untests/meta_issues/random_issue_1.cpp @@ -0,0 +1,38 @@ +/******************************************************************************* + * 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 {}; + struct B : A {}; + struct C : A {}; + struct D : B, C {}; + + // A * <- B <- * + // D + // A * <- C <- * +} + +TEST_CASE("meta/meta_issues/random/1") { + namespace meta = meta_hpp; + + meta::class_().base_(); + meta::class_().base_(); + meta::class_().base_(); + + CHECK(meta::is_invocable_with(+[](const D&){ return true; }, D{})); + CHECK(meta::is_invocable_with(+[](const C&){ return true; }, D{})); + CHECK(meta::is_invocable_with(+[](const B&){ return true; }, D{})); + CHECK_FALSE(meta::is_invocable_with(+[](const A&){ return true; }, D{})); + + CHECK(meta::invoke(+[](const D&){ return true; }, D{})); + CHECK(meta::invoke(+[](const C&){ return true; }, D{})); + CHECK(meta::invoke(+[](const B&){ return true; }, D{})); + CHECK_THROWS(meta::invoke(+[](const A&){ return true; }, D{})); +} From aa587c6c121bbb074045f2b5054edb18526ab141 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 3 Mar 2023 17:55:01 +0700 Subject: [PATCH 3/9] simplify class cast bindings --- develop/singles/headers/meta.hpp/meta_all.hpp | 74 +++++++++++++------ headers/meta.hpp/meta_binds/class_bind.hpp | 22 ++---- .../meta_detail/value_utilities/utraits.hpp | 9 +-- headers/meta.hpp/meta_types.hpp | 14 +++- headers/meta.hpp/meta_types/class_type.hpp | 29 ++++++++ 5 files changed, 102 insertions(+), 46 deletions(-) diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index bb116b6..e319ef4 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -2761,7 +2761,19 @@ namespace meta_hpp::detail variable_set variables; using upcast_func_t = void* (*)(void*); - using upcast_func_list_t = std::vector; + + struct upcast_func_list_t final { + std::vector upcasts; + + upcast_func_list_t() = default; + upcast_func_list_t(upcast_func_t _upcast); + upcast_func_list_t(std::vector _upcasts); + + void* apply(void* ptr) const noexcept; + const void* apply(const void* ptr) const noexcept; + + friend upcast_func_list_t operator+(const upcast_func_list_t& l, const upcast_func_list_t& r); + }; using base_upcasts_t = std::map>; using deep_upcasts_t = std::multimap>; @@ -4821,7 +4833,7 @@ namespace meta_hpp::detail::class_bind_impl inline void update_deep_upcasts_db( // const class_type& derived_class, const class_type& new_base_class, - const upcast_func_list_t& derived_to_new_base, + upcast_func_list_t&& derived_to_new_base, deep_upcasts_db_t& deep_upcasts_db ) { const class_type_data& derived_class_data = *type_access(derived_class); @@ -4829,26 +4841,20 @@ 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; - derived_deep_upcasts.emplace(new_base_class, derived_to_new_base); 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_deep.reserve(derived_to_new_base.size() + new_base_to_deep.size()); - derived_to_new_deep.insert(derived_to_new_deep.end(), derived_to_new_base.begin(), derived_to_new_base.end()); - derived_to_new_deep.insert(derived_to_new_deep.end(), new_base_to_deep.begin(), new_base_to_deep.end()); + 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)); } for ( const class_type& subderived_class : derived_class_data.derived_classes ) { const class_type_data& subderived_data = *type_access(subderived_class); - - upcast_func_list_t subderived_to_new_base; - subderived_to_new_base.reserve(derived_to_new_base.size() + 1); - subderived_to_new_base.insert(subderived_to_new_base.end(), subderived_data.base_upcasts.at(derived_class)); - subderived_to_new_base.insert(subderived_to_new_base.end(), derived_to_new_base.begin(), derived_to_new_base.end()); - - update_deep_upcasts_db(subderived_class, new_base_class, subderived_to_new_base, deep_upcasts_db); + upcast_func_t subderived_to_derived = subderived_data.base_upcasts.at(derived_class); + upcast_func_list_t subderived_to_new_base = subderived_to_derived + derived_to_new_base; + 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)); } inline void updata_derived_classes_db( // @@ -4902,7 +4908,7 @@ namespace meta_hpp continue; } - update_deep_upcasts_db(*this, new_base_class, {self_to_new_base}, deep_upcasts_db); + update_deep_upcasts_db(*this, new_base_class, self_to_new_base, deep_upcasts_db); updata_derived_classes_db(*this, new_base_class, derived_classes_db); new_base_classes.emplace(new_base_class); @@ -5701,14 +5707,7 @@ namespace meta_hpp::detail class_type_data::deep_upcasts_t& deep_upcasts = from_data.deep_upcasts; for ( auto iter{deep_upcasts.lower_bound(to)}; iter != deep_upcasts.end() && iter->first == to; ++iter ) { - void* new_base_ptr = [ptr, iter]() mutable { - for ( class_type_data::upcast_func_t upcast : iter->second ) { - ptr = upcast(ptr); - } - return ptr; - }(); - - if ( base_ptr == nullptr ) { + if ( void* new_base_ptr{iter->second.apply(ptr)}; base_ptr == nullptr ) { base_ptr = new_base_ptr; } else if ( base_ptr != new_base_ptr ) { // ambiguous conversions @@ -8017,6 +8016,35 @@ namespace meta_hpp::detail , size{class_traits::size} , align{class_traits::align} , argument_types{resolve_types(typename class_traits::argument_types{})} {} + + inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcast_func_t _upcast) + : upcasts{_upcast} {} + + inline class_type_data::upcast_func_list_t::upcast_func_list_t(std::vector _upcasts) + : upcasts{std::move(_upcasts)} {} + + inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept { + for ( upcast_func_t upcast : upcasts ) { + ptr = upcast(ptr); + } + return ptr; + } + + inline const void* class_type_data::upcast_func_list_t::apply(const void* ptr) const noexcept { + // NOLINTNEXTLINE(*-const-cast) + return apply(const_cast(ptr)); + } + + inline class_type_data::upcast_func_list_t operator+( // + const class_type_data::upcast_func_list_t& l, + const class_type_data::upcast_func_list_t& r + ) { + std::vector 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_upcasts)}; + } } namespace meta_hpp diff --git a/headers/meta.hpp/meta_binds/class_bind.hpp b/headers/meta.hpp/meta_binds/class_bind.hpp index dcbaf52..1fd71b4 100644 --- a/headers/meta.hpp/meta_binds/class_bind.hpp +++ b/headers/meta.hpp/meta_binds/class_bind.hpp @@ -35,7 +35,7 @@ namespace meta_hpp::detail::class_bind_impl inline void update_deep_upcasts_db( // const class_type& derived_class, const class_type& new_base_class, - const upcast_func_list_t& derived_to_new_base, + upcast_func_list_t&& derived_to_new_base, deep_upcasts_db_t& deep_upcasts_db ) { const class_type_data& derived_class_data = *type_access(derived_class); @@ -43,26 +43,20 @@ 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; - derived_deep_upcasts.emplace(new_base_class, derived_to_new_base); 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_deep.reserve(derived_to_new_base.size() + new_base_to_deep.size()); - derived_to_new_deep.insert(derived_to_new_deep.end(), derived_to_new_base.begin(), derived_to_new_base.end()); - derived_to_new_deep.insert(derived_to_new_deep.end(), new_base_to_deep.begin(), new_base_to_deep.end()); + 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)); } for ( const class_type& subderived_class : derived_class_data.derived_classes ) { const class_type_data& subderived_data = *type_access(subderived_class); - - upcast_func_list_t subderived_to_new_base; - subderived_to_new_base.reserve(derived_to_new_base.size() + 1); - subderived_to_new_base.insert(subderived_to_new_base.end(), subderived_data.base_upcasts.at(derived_class)); - subderived_to_new_base.insert(subderived_to_new_base.end(), derived_to_new_base.begin(), derived_to_new_base.end()); - - update_deep_upcasts_db(subderived_class, new_base_class, subderived_to_new_base, deep_upcasts_db); + upcast_func_t subderived_to_derived = subderived_data.base_upcasts.at(derived_class); + upcast_func_list_t subderived_to_new_base = subderived_to_derived + derived_to_new_base; + 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)); } inline void updata_derived_classes_db( // @@ -116,7 +110,7 @@ namespace meta_hpp continue; } - update_deep_upcasts_db(*this, new_base_class, {self_to_new_base}, deep_upcasts_db); + update_deep_upcasts_db(*this, new_base_class, self_to_new_base, deep_upcasts_db); updata_derived_classes_db(*this, new_base_class, derived_classes_db); new_base_classes.emplace(new_base_class); diff --git a/headers/meta.hpp/meta_detail/value_utilities/utraits.hpp b/headers/meta.hpp/meta_detail/value_utilities/utraits.hpp index 8d8ed5a..01986ff 100644 --- a/headers/meta.hpp/meta_detail/value_utilities/utraits.hpp +++ b/headers/meta.hpp/meta_detail/value_utilities/utraits.hpp @@ -130,14 +130,7 @@ namespace meta_hpp::detail class_type_data::deep_upcasts_t& deep_upcasts = from_data.deep_upcasts; for ( auto iter{deep_upcasts.lower_bound(to)}; iter != deep_upcasts.end() && iter->first == to; ++iter ) { - void* new_base_ptr = [ptr, iter]() mutable { - for ( class_type_data::upcast_func_t upcast : iter->second ) { - ptr = upcast(ptr); - } - return ptr; - }(); - - if ( base_ptr == nullptr ) { + if ( void* new_base_ptr{iter->second.apply(ptr)}; base_ptr == nullptr ) { base_ptr = new_base_ptr; } else if ( base_ptr != new_base_ptr ) { // ambiguous conversions diff --git a/headers/meta.hpp/meta_types.hpp b/headers/meta.hpp/meta_types.hpp index 9d109f0..f344832 100644 --- a/headers/meta.hpp/meta_types.hpp +++ b/headers/meta.hpp/meta_types.hpp @@ -403,7 +403,19 @@ namespace meta_hpp::detail variable_set variables; using upcast_func_t = void* (*)(void*); - using upcast_func_list_t = std::vector; + + struct upcast_func_list_t final { + std::vector upcasts; + + upcast_func_list_t() = default; + upcast_func_list_t(upcast_func_t _upcast); + upcast_func_list_t(std::vector _upcasts); + + void* apply(void* ptr) const noexcept; + const void* apply(const void* ptr) const noexcept; + + friend upcast_func_list_t operator+(const upcast_func_list_t& l, const upcast_func_list_t& r); + }; using base_upcasts_t = std::map>; using deep_upcasts_t = std::multimap>; diff --git a/headers/meta.hpp/meta_types/class_type.hpp b/headers/meta.hpp/meta_types/class_type.hpp index 5718aeb..e9e05b8 100644 --- a/headers/meta.hpp/meta_types/class_type.hpp +++ b/headers/meta.hpp/meta_types/class_type.hpp @@ -30,6 +30,35 @@ namespace meta_hpp::detail , size{class_traits::size} , align{class_traits::align} , argument_types{resolve_types(typename class_traits::argument_types{})} {} + + inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcast_func_t _upcast) + : upcasts{_upcast} {} + + inline class_type_data::upcast_func_list_t::upcast_func_list_t(std::vector _upcasts) + : upcasts{std::move(_upcasts)} {} + + inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept { + for ( upcast_func_t upcast : upcasts ) { + ptr = upcast(ptr); + } + return ptr; + } + + inline const void* class_type_data::upcast_func_list_t::apply(const void* ptr) const noexcept { + // NOLINTNEXTLINE(*-const-cast) + return apply(const_cast(ptr)); + } + + inline class_type_data::upcast_func_list_t operator+( // + const class_type_data::upcast_func_list_t& l, + const class_type_data::upcast_func_list_t& r + ) { + std::vector 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_upcasts)}; + } } namespace meta_hpp From 3465e961f265a92d5b2a44ed7110a47b830bfb71 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 3 Mar 2023 21:22:21 +0700 Subject: [PATCH 4/9] add is_virtual_base_of trait --- develop/singles/headers/meta.hpp/meta_all.hpp | 32 ++++++++ .../meta_base/is_virtual_base_of_tests.cpp | 77 +++++++++++++++++++ headers/meta.hpp/meta_base.hpp | 1 + .../meta.hpp/meta_base/is_virtual_base_of.hpp | 41 ++++++++++ 4 files changed, 151 insertions(+) create mode 100644 develop/untests/meta_base/is_virtual_base_of_tests.cpp create mode 100644 headers/meta.hpp/meta_base/is_virtual_base_of.hpp diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index e319ef4..f2cc73d 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -1180,6 +1180,38 @@ namespace meta_hpp::detail inline constexpr bool is_in_place_type_v = is_in_place_type::value; } +namespace meta_hpp::detail +{ + namespace impl + { + template < typename From, typename To > + constexpr bool is_virtual_base_of_impl(...) noexcept { + return false; + } + + template < + typename From, + typename To, + decltype(static_cast(std::declval())) = nullptr > + constexpr bool is_virtual_base_of_impl(int) noexcept { + return true; + } + } + + // clang-format off + + template < typename Base, typename Derived > + struct is_virtual_base_of : std::integral_constant && + impl::is_virtual_base_of_impl(0) && + !impl::is_virtual_base_of_impl(0)> {}; + + // clang-format on + + template < typename Base, typename Derived > + inline constexpr bool is_virtual_base_of_v = is_virtual_base_of::value; +} + namespace meta_hpp::detail { class memory_buffer final { diff --git a/develop/untests/meta_base/is_virtual_base_of_tests.cpp b/develop/untests/meta_base/is_virtual_base_of_tests.cpp new file mode 100644 index 0000000..a9f88b1 --- /dev/null +++ b/develop/untests/meta_base/is_virtual_base_of_tests.cpp @@ -0,0 +1,77 @@ +/******************************************************************************* + * 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 {}; + struct B : virtual A {}; + struct C : virtual A {}; + struct D : B, C {}; + struct E {}; + + struct I {}; + struct J : virtual I {}; + struct K : J {}; +} + +TEST_CASE("meta/meta_base/is_virtual_base_of") { + namespace meta = meta_hpp; + using meta::detail::is_virtual_base_of; + using meta::detail::is_virtual_base_of_v; + + { + static_assert(!is_virtual_base_of_v); + static_assert(is_virtual_base_of_v); + static_assert(is_virtual_base_of_v); + + static_assert(is_virtual_base_of_v); + static_assert(!is_virtual_base_of_v); + static_assert(!is_virtual_base_of_v); + + static_assert(!is_virtual_base_of_v); + static_assert(!is_virtual_base_of_v); + + static_assert(!is_virtual_base_of_v); + static_assert(!is_virtual_base_of_v); + } + + { + static_assert(!is_virtual_base_of_v); + static_assert(is_virtual_base_of_v); + static_assert(is_virtual_base_of_v); + + static_assert(!is_virtual_base_of_v); + static_assert(!is_virtual_base_of_v); + static_assert(!is_virtual_base_of_v); + + static_assert(!is_virtual_base_of_v); + static_assert(!is_virtual_base_of_v); + static_assert(!is_virtual_base_of_v); + } + + { + static_assert(is_virtual_base_of_v); + + static_assert(is_virtual_base_of_v); + static_assert(is_virtual_base_of_v); + static_assert(is_virtual_base_of_v); + + static_assert(is_virtual_base_of_v); + static_assert(is_virtual_base_of_v); + static_assert(is_virtual_base_of_v); + + static_assert(is_virtual_base_of_v); + static_assert(is_virtual_base_of_v); + static_assert(is_virtual_base_of_v); + + static_assert(is_virtual_base_of_v); + static_assert(is_virtual_base_of_v); + static_assert(is_virtual_base_of_v); + } +} diff --git a/headers/meta.hpp/meta_base.hpp b/headers/meta.hpp/meta_base.hpp index 8aceaf6..55c4c9c 100644 --- a/headers/meta.hpp/meta_base.hpp +++ b/headers/meta.hpp/meta_base.hpp @@ -19,6 +19,7 @@ #include "meta_base/insert_or_assign.hpp" #include "meta_base/intrusive_ptr.hpp" #include "meta_base/is_in_place_type.hpp" +#include "meta_base/is_virtual_base_of.hpp" #include "meta_base/memory_buffer.hpp" #include "meta_base/noncopyable.hpp" #include "meta_base/nonesuch.hpp" diff --git a/headers/meta.hpp/meta_base/is_virtual_base_of.hpp b/headers/meta.hpp/meta_base/is_virtual_base_of.hpp new file mode 100644 index 0000000..99b8f44 --- /dev/null +++ b/headers/meta.hpp/meta_base/is_virtual_base_of.hpp @@ -0,0 +1,41 @@ +/******************************************************************************* + * 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 +{ + namespace impl + { + template < typename From, typename To > + constexpr bool is_virtual_base_of_impl(...) noexcept { + return false; + } + + template < + typename From, + typename To, + decltype(static_cast(std::declval())) = nullptr > + constexpr bool is_virtual_base_of_impl(int) noexcept { + return true; + } + } + + // clang-format off + + template < typename Base, typename Derived > + struct is_virtual_base_of : std::integral_constant && + impl::is_virtual_base_of_impl(0) && + !impl::is_virtual_base_of_impl(0)> {}; + + // clang-format on + + template < typename Base, typename Derived > + inline constexpr bool is_virtual_base_of_v = is_virtual_base_of::value; +} From f264391fc2cebc421ff25791582802b19aa9aebb Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 3 Mar 2023 21:22:42 +0700 Subject: [PATCH 5/9] style fixes --- develop/singles/headers/meta.hpp/meta_all.hpp | 76 +++++++++---------- headers/meta.hpp/meta_base/defer.hpp | 68 ++++++++--------- .../meta_detail/type_traits/class_traits.hpp | 8 +- 3 files changed, 76 insertions(+), 76 deletions(-) diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index f2cc73d..41f1e20 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -308,42 +308,42 @@ namespace meta_hpp::detail using copy_cvref_t = typename copy_cvref::type; } -namespace meta_hpp::detail::impl -{ - template < typename F, typename... Args > - class defer_impl { - public: - defer_impl() = delete; - defer_impl(defer_impl&&) = delete; - defer_impl(const defer_impl&) = delete; - defer_impl& operator=(defer_impl&&) = delete; - defer_impl& operator=(const defer_impl&) = delete; - - template < typename UF > - explicit defer_impl(UF&& f, std::tuple&& args) - : f_{std::forward(f)} - , args_{std::move(args)} {} - - void dismiss() noexcept { - dismissed_ = true; - } - - protected: - ~defer_impl() noexcept { - if ( !dismissed_ ) { - std::apply(std::move(f_), std::move(args_)); - } - } - - private: - F f_; - std::tuple args_; - bool dismissed_{}; - }; -} - namespace meta_hpp::detail { + namespace impl + { + template < typename F, typename... Args > + class defer_impl { + public: + defer_impl() = delete; + defer_impl(defer_impl&&) = delete; + defer_impl(const defer_impl&) = delete; + defer_impl& operator=(defer_impl&&) = delete; + defer_impl& operator=(const defer_impl&) = delete; + + template < typename UF > + explicit defer_impl(UF&& f, std::tuple&& args) + : f_{std::forward(f)} + , args_{std::move(args)} {} + + void dismiss() noexcept { + dismissed_ = true; + } + + protected: + ~defer_impl() noexcept { + if ( !dismissed_ ) { + std::apply(std::move(f_), std::move(args_)); + } + } + + private: + F f_; + std::tuple args_; + bool dismissed_{}; + }; + } + template < typename F, typename... Args > class defer final : public impl::defer_impl { public: @@ -1851,7 +1851,7 @@ namespace meta_hpp::detail namespace impl { template < class_kind Class > - struct class_traits_base { + struct class_traits_impl { static constexpr std::size_t arity{0}; using argument_types = type_list<>; @@ -1862,7 +1862,7 @@ namespace meta_hpp::detail }; template < template < typename... > typename Class, typename... Args > - struct class_traits_base> { + struct class_traits_impl> { static constexpr std::size_t arity{sizeof...(Args)}; using argument_types = type_list; @@ -1874,7 +1874,7 @@ namespace meta_hpp::detail } template < class_kind Class > - struct class_traits : impl::class_traits_base { + struct class_traits : impl::class_traits_impl { static constexpr std::size_t size{sizeof(Class)}; static constexpr std::size_t align{alignof(Class)}; @@ -1897,7 +1897,7 @@ namespace meta_hpp::detail flags.set(class_flags::is_polymorphic); } - return flags | impl::class_traits_base::make_flags(); + return flags | impl::class_traits_impl::make_flags(); } }; } diff --git a/headers/meta.hpp/meta_base/defer.hpp b/headers/meta.hpp/meta_base/defer.hpp index 7764070..7450244 100644 --- a/headers/meta.hpp/meta_base/defer.hpp +++ b/headers/meta.hpp/meta_base/defer.hpp @@ -8,42 +8,42 @@ #include "base.hpp" -namespace meta_hpp::detail::impl -{ - template < typename F, typename... Args > - class defer_impl { - public: - defer_impl() = delete; - defer_impl(defer_impl&&) = delete; - defer_impl(const defer_impl&) = delete; - defer_impl& operator=(defer_impl&&) = delete; - defer_impl& operator=(const defer_impl&) = delete; - - template < typename UF > - explicit defer_impl(UF&& f, std::tuple&& args) - : f_{std::forward(f)} - , args_{std::move(args)} {} - - void dismiss() noexcept { - dismissed_ = true; - } - - protected: - ~defer_impl() noexcept { - if ( !dismissed_ ) { - std::apply(std::move(f_), std::move(args_)); - } - } - - private: - F f_; - std::tuple args_; - bool dismissed_{}; - }; -} - namespace meta_hpp::detail { + namespace impl + { + template < typename F, typename... Args > + class defer_impl { + public: + defer_impl() = delete; + defer_impl(defer_impl&&) = delete; + defer_impl(const defer_impl&) = delete; + defer_impl& operator=(defer_impl&&) = delete; + defer_impl& operator=(const defer_impl&) = delete; + + template < typename UF > + explicit defer_impl(UF&& f, std::tuple&& args) + : f_{std::forward(f)} + , args_{std::move(args)} {} + + void dismiss() noexcept { + dismissed_ = true; + } + + protected: + ~defer_impl() noexcept { + if ( !dismissed_ ) { + std::apply(std::move(f_), std::move(args_)); + } + } + + private: + F f_; + std::tuple args_; + bool dismissed_{}; + }; + } + template < typename F, typename... Args > class defer final : public impl::defer_impl { public: diff --git a/headers/meta.hpp/meta_detail/type_traits/class_traits.hpp b/headers/meta.hpp/meta_detail/type_traits/class_traits.hpp index 3e8eb70..faef0f4 100644 --- a/headers/meta.hpp/meta_detail/type_traits/class_traits.hpp +++ b/headers/meta.hpp/meta_detail/type_traits/class_traits.hpp @@ -27,7 +27,7 @@ namespace meta_hpp::detail namespace impl { template < class_kind Class > - struct class_traits_base { + struct class_traits_impl { static constexpr std::size_t arity{0}; using argument_types = type_list<>; @@ -38,7 +38,7 @@ namespace meta_hpp::detail }; template < template < typename... > typename Class, typename... Args > - struct class_traits_base> { + struct class_traits_impl> { static constexpr std::size_t arity{sizeof...(Args)}; using argument_types = type_list; @@ -50,7 +50,7 @@ namespace meta_hpp::detail } template < class_kind Class > - struct class_traits : impl::class_traits_base { + struct class_traits : impl::class_traits_impl { static constexpr std::size_t size{sizeof(Class)}; static constexpr std::size_t align{alignof(Class)}; @@ -73,7 +73,7 @@ namespace meta_hpp::detail flags.set(class_flags::is_polymorphic); } - return flags | impl::class_traits_base::make_flags(); + return flags | impl::class_traits_impl::make_flags(); } }; } From 78c6773cedb15ae1630a317e25fad3a7b391be31 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 3 Mar 2023 22:36:06 +0700 Subject: [PATCH 6/9] add is_direct_base_of and is_direct_derived_from --- develop/singles/headers/meta.hpp/meta_all.hpp | 38 +++++++++------ .../untests/meta_types/class_type_tests.cpp | 46 +++++++++++++++++++ headers/meta.hpp/meta_types.hpp | 8 ++++ headers/meta.hpp/meta_types/class_type.hpp | 30 ++++++------ 4 files changed, 94 insertions(+), 28 deletions(-) diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index 41f1e20..f3c3da2 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -2570,10 +2570,18 @@ namespace meta_hpp [[nodiscard]] bool is_base_of() const noexcept; [[nodiscard]] bool is_base_of(const class_type& derived) const noexcept; + template < detail::class_kind Derived > + [[nodiscard]] bool is_direct_base_of() const noexcept; + [[nodiscard]] bool is_direct_base_of(const class_type& derived) const noexcept; + template < detail::class_kind Base > [[nodiscard]] bool is_derived_from() const noexcept; [[nodiscard]] bool is_derived_from(const class_type& base) const noexcept; + template < detail::class_kind Base > + [[nodiscard]] bool is_direct_derived_from() const noexcept; + [[nodiscard]] bool is_direct_derived_from(const class_type& base) const noexcept; + [[nodiscard]] function get_function(std::string_view name) const noexcept; [[nodiscard]] member get_member(std::string_view name) const noexcept; [[nodiscard]] method get_method(std::string_view name) const noexcept; @@ -8186,15 +8194,16 @@ namespace meta_hpp } inline bool class_type::is_base_of(const class_type& derived) const noexcept { - if ( !is_valid() || !derived.is_valid() ) { - return false; - } + return is_valid() && derived.is_valid() && derived.data_->deep_upcasts.contains(*this); + } - if ( derived.data_->deep_upcasts.contains(*this) ) { - return true; - } + template < detail::class_kind Derived > + bool class_type::is_direct_base_of() const noexcept { + return is_direct_base_of(resolve_type()); + } - return false; + inline bool class_type::is_direct_base_of(const class_type& derived) const noexcept { + return is_valid() && derived.is_valid() && derived.data_->base_upcasts.contains(*this); } template < detail::class_kind Base > @@ -8203,15 +8212,16 @@ namespace meta_hpp } inline bool class_type::is_derived_from(const class_type& base) const noexcept { - if ( !is_valid() || !base.is_valid() ) { - return false; - } + return is_valid() && base.is_valid() && data_->deep_upcasts.contains(base); + } - if ( data_->deep_upcasts.contains(base) ) { - return true; - } + template < detail::class_kind Base > + bool class_type::is_direct_derived_from() const noexcept { + return is_direct_derived_from(resolve_type()); + } - return false; + inline bool class_type::is_direct_derived_from(const class_type& base) const noexcept { + return is_valid() && base.is_valid() && data_->base_upcasts.contains(base); } inline function class_type::get_function(std::string_view name) const noexcept { diff --git a/develop/untests/meta_types/class_type_tests.cpp b/develop/untests/meta_types/class_type_tests.cpp index 7ab1db3..e31eb6a 100644 --- a/develop/untests/meta_types/class_type_tests.cpp +++ b/develop/untests/meta_types/class_type_tests.cpp @@ -248,40 +248,62 @@ TEST_CASE("meta/meta_types/class_type") { { CHECK_FALSE(base_clazz_1_type.is_base_of()); CHECK_FALSE(base_clazz_1_type.is_base_of(base_clazz_1_type)); + CHECK_FALSE(base_clazz_1_type.is_direct_base_of()); + CHECK_FALSE(base_clazz_1_type.is_direct_base_of(base_clazz_1_type)); CHECK_FALSE(base_clazz_1_type.is_base_of()); CHECK_FALSE(base_clazz_1_type.is_base_of(base_clazz_2_type)); + CHECK_FALSE(base_clazz_1_type.is_direct_base_of()); + CHECK_FALSE(base_clazz_1_type.is_direct_base_of(base_clazz_2_type)); CHECK(base_clazz_1_type.is_base_of()); CHECK(base_clazz_1_type.is_base_of(derived_clazz_type)); + CHECK(base_clazz_1_type.is_direct_base_of()); + CHECK(base_clazz_1_type.is_direct_base_of(derived_clazz_type)); CHECK(base_clazz_1_type.is_base_of()); CHECK(base_clazz_1_type.is_base_of(final_derived_clazz_type)); + CHECK_FALSE(base_clazz_1_type.is_direct_base_of()); + CHECK_FALSE(base_clazz_1_type.is_direct_base_of(final_derived_clazz_type)); } { CHECK_FALSE(base_clazz_2_type.is_base_of()); CHECK_FALSE(base_clazz_2_type.is_base_of(base_clazz_1_type)); + CHECK_FALSE(base_clazz_2_type.is_direct_base_of()); + CHECK_FALSE(base_clazz_2_type.is_direct_base_of(base_clazz_1_type)); CHECK_FALSE(base_clazz_2_type.is_base_of()); CHECK_FALSE(base_clazz_2_type.is_base_of(base_clazz_2_type)); + CHECK_FALSE(base_clazz_2_type.is_direct_base_of()); + CHECK_FALSE(base_clazz_2_type.is_direct_base_of(base_clazz_2_type)); CHECK(base_clazz_2_type.is_base_of()); CHECK(base_clazz_2_type.is_base_of(derived_clazz_type)); + CHECK(base_clazz_2_type.is_direct_base_of()); + CHECK(base_clazz_2_type.is_direct_base_of(derived_clazz_type)); CHECK(base_clazz_2_type.is_base_of()); CHECK(base_clazz_2_type.is_base_of(final_derived_clazz_type)); + CHECK_FALSE(base_clazz_2_type.is_direct_base_of()); + CHECK_FALSE(base_clazz_2_type.is_direct_base_of(final_derived_clazz_type)); } { CHECK_FALSE(derived_clazz_type.is_base_of()); CHECK_FALSE(derived_clazz_type.is_base_of(base_clazz_1_type)); + CHECK_FALSE(derived_clazz_type.is_direct_base_of()); + CHECK_FALSE(derived_clazz_type.is_direct_base_of(base_clazz_1_type)); CHECK_FALSE(derived_clazz_type.is_base_of()); CHECK_FALSE(derived_clazz_type.is_base_of(base_clazz_2_type)); + CHECK_FALSE(derived_clazz_type.is_direct_base_of()); + CHECK_FALSE(derived_clazz_type.is_direct_base_of(base_clazz_2_type)); CHECK_FALSE(derived_clazz_type.is_base_of()); CHECK_FALSE(derived_clazz_type.is_base_of(derived_clazz_type)); + CHECK_FALSE(derived_clazz_type.is_direct_base_of()); + CHECK_FALSE(derived_clazz_type.is_direct_base_of(derived_clazz_type)); } } @@ -289,45 +311,69 @@ TEST_CASE("meta/meta_types/class_type") { { CHECK_FALSE(base_clazz_1_type.is_derived_from()); CHECK_FALSE(base_clazz_1_type.is_derived_from(base_clazz_1_type)); + CHECK_FALSE(base_clazz_1_type.is_direct_derived_from()); + CHECK_FALSE(base_clazz_1_type.is_direct_derived_from(base_clazz_1_type)); CHECK_FALSE(base_clazz_1_type.is_derived_from()); CHECK_FALSE(base_clazz_1_type.is_derived_from(base_clazz_2_type)); + CHECK_FALSE(base_clazz_1_type.is_direct_derived_from()); + CHECK_FALSE(base_clazz_1_type.is_direct_derived_from(base_clazz_2_type)); CHECK_FALSE(base_clazz_1_type.is_derived_from()); CHECK_FALSE(base_clazz_1_type.is_derived_from(derived_clazz_type)); + CHECK_FALSE(base_clazz_1_type.is_direct_derived_from()); + CHECK_FALSE(base_clazz_1_type.is_direct_derived_from(derived_clazz_type)); } { CHECK_FALSE(base_clazz_2_type.is_derived_from()); CHECK_FALSE(base_clazz_2_type.is_derived_from(base_clazz_1_type)); + CHECK_FALSE(base_clazz_2_type.is_direct_derived_from()); + CHECK_FALSE(base_clazz_2_type.is_direct_derived_from(base_clazz_1_type)); CHECK_FALSE(base_clazz_2_type.is_derived_from()); CHECK_FALSE(base_clazz_2_type.is_derived_from(base_clazz_2_type)); + CHECK_FALSE(base_clazz_2_type.is_direct_derived_from()); + CHECK_FALSE(base_clazz_2_type.is_direct_derived_from(base_clazz_2_type)); CHECK_FALSE(base_clazz_2_type.is_derived_from()); CHECK_FALSE(base_clazz_2_type.is_derived_from(derived_clazz_type)); + CHECK_FALSE(base_clazz_2_type.is_direct_derived_from()); + CHECK_FALSE(base_clazz_2_type.is_direct_derived_from(derived_clazz_type)); } { CHECK(derived_clazz_type.is_derived_from()); CHECK(derived_clazz_type.is_derived_from(base_clazz_1_type)); + CHECK(derived_clazz_type.is_direct_derived_from()); + CHECK(derived_clazz_type.is_direct_derived_from(base_clazz_1_type)); CHECK(derived_clazz_type.is_derived_from()); CHECK(derived_clazz_type.is_derived_from(base_clazz_2_type)); + CHECK(derived_clazz_type.is_direct_derived_from()); + CHECK(derived_clazz_type.is_direct_derived_from(base_clazz_2_type)); CHECK_FALSE(derived_clazz_type.is_derived_from()); CHECK_FALSE(derived_clazz_type.is_derived_from(derived_clazz_type)); + CHECK_FALSE(derived_clazz_type.is_direct_derived_from()); + CHECK_FALSE(derived_clazz_type.is_direct_derived_from(derived_clazz_type)); } { CHECK(final_derived_clazz_type.is_derived_from()); CHECK(final_derived_clazz_type.is_derived_from(base_clazz_1_type)); + CHECK_FALSE(final_derived_clazz_type.is_direct_derived_from()); + CHECK_FALSE(final_derived_clazz_type.is_direct_derived_from(base_clazz_1_type)); CHECK(final_derived_clazz_type.is_derived_from()); CHECK(final_derived_clazz_type.is_derived_from(base_clazz_2_type)); + CHECK_FALSE(final_derived_clazz_type.is_direct_derived_from()); + CHECK_FALSE(final_derived_clazz_type.is_direct_derived_from(base_clazz_2_type)); CHECK(final_derived_clazz_type.is_derived_from()); CHECK(final_derived_clazz_type.is_derived_from(derived_clazz_type)); + CHECK(final_derived_clazz_type.is_direct_derived_from()); + CHECK(final_derived_clazz_type.is_direct_derived_from(derived_clazz_type)); } } diff --git a/headers/meta.hpp/meta_types.hpp b/headers/meta.hpp/meta_types.hpp index f344832..26661ac 100644 --- a/headers/meta.hpp/meta_types.hpp +++ b/headers/meta.hpp/meta_types.hpp @@ -180,10 +180,18 @@ namespace meta_hpp [[nodiscard]] bool is_base_of() const noexcept; [[nodiscard]] bool is_base_of(const class_type& derived) const noexcept; + template < detail::class_kind Derived > + [[nodiscard]] bool is_direct_base_of() const noexcept; + [[nodiscard]] bool is_direct_base_of(const class_type& derived) const noexcept; + template < detail::class_kind Base > [[nodiscard]] bool is_derived_from() const noexcept; [[nodiscard]] bool is_derived_from(const class_type& base) const noexcept; + template < detail::class_kind Base > + [[nodiscard]] bool is_direct_derived_from() const noexcept; + [[nodiscard]] bool is_direct_derived_from(const class_type& base) const noexcept; + [[nodiscard]] function get_function(std::string_view name) const noexcept; [[nodiscard]] member get_member(std::string_view name) const noexcept; [[nodiscard]] method get_method(std::string_view name) const noexcept; diff --git a/headers/meta.hpp/meta_types/class_type.hpp b/headers/meta.hpp/meta_types/class_type.hpp index e9e05b8..bdff667 100644 --- a/headers/meta.hpp/meta_types/class_type.hpp +++ b/headers/meta.hpp/meta_types/class_type.hpp @@ -168,15 +168,16 @@ namespace meta_hpp } inline bool class_type::is_base_of(const class_type& derived) const noexcept { - if ( !is_valid() || !derived.is_valid() ) { - return false; - } + return is_valid() && derived.is_valid() && derived.data_->deep_upcasts.contains(*this); + } - if ( derived.data_->deep_upcasts.contains(*this) ) { - return true; - } + template < detail::class_kind Derived > + bool class_type::is_direct_base_of() const noexcept { + return is_direct_base_of(resolve_type()); + } - return false; + inline bool class_type::is_direct_base_of(const class_type& derived) const noexcept { + return is_valid() && derived.is_valid() && derived.data_->base_upcasts.contains(*this); } template < detail::class_kind Base > @@ -185,15 +186,16 @@ namespace meta_hpp } inline bool class_type::is_derived_from(const class_type& base) const noexcept { - if ( !is_valid() || !base.is_valid() ) { - return false; - } + return is_valid() && base.is_valid() && data_->deep_upcasts.contains(base); + } - if ( data_->deep_upcasts.contains(base) ) { - return true; - } + template < detail::class_kind Base > + bool class_type::is_direct_derived_from() const noexcept { + return is_direct_derived_from(resolve_type()); + } - return false; + inline bool class_type::is_direct_derived_from(const class_type& base) const noexcept { + return is_valid() && base.is_valid() && data_->base_upcasts.contains(base); } inline function class_type::get_function(std::string_view name) const noexcept { From 956293a9ae07d02500d6b6c90b94b5caa56090fb Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 3 Mar 2023 23:55:16 +0700 Subject: [PATCH 7/9] add free-standing try_invoke --- develop/singles/headers/meta.hpp/meta_all.hpp | 65 +++++++++++++++++++ .../untests/meta_issues/random_issue_1.cpp | 8 +-- .../untests/meta_utilities/invoke_tests.cpp | 21 ++++++ headers/meta.hpp/meta_invoke/invoke.hpp | 65 +++++++++++++++++++ 4 files changed, 155 insertions(+), 4 deletions(-) diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index f3c3da2..c92873a 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -7175,6 +7175,11 @@ namespace meta_hpp return function.invoke(std::forward(args)...); } + template < typename... Args > + uresult try_invoke(const function& function, Args&&... args) { + return function.try_invoke(std::forward(args)...); + } + template < detail::function_pointer_kind Function, typename... Args > uvalue invoke(Function function_ptr, Args&&... args) { using namespace detail; @@ -7182,6 +7187,22 @@ namespace meta_hpp const std::array vargs{uarg{registry, std::forward(args)}...}; return raw_function_invoke(registry, function_ptr, vargs); } + + template < detail::function_pointer_kind Function, typename... Args > + uresult try_invoke(Function function_ptr, Args&&... args) { + using namespace detail; + type_registry& registry{type_registry::instance()}; + + { + const std::array vargs{uarg_base{registry, std::forward(args)}...}; + if ( const uerror err = raw_function_invoke_error(registry, vargs) ) { + return err; + } + } + + const std::array vargs{uarg{registry, std::forward(args)}...}; + return raw_function_invoke(registry, function_ptr, vargs); + } } namespace meta_hpp @@ -7191,6 +7212,11 @@ namespace meta_hpp return member.get(std::forward(instance)); } + template < typename Instance > + uresult try_invoke(const member& member, Instance&& instance) { + return member.try_get(std::forward(instance)); + } + template < detail::member_pointer_kind Member, typename Instance > uvalue invoke(Member member_ptr, Instance&& instance) { using namespace detail; @@ -7198,6 +7224,22 @@ namespace meta_hpp const uinst vinst{registry, std::forward(instance)}; return raw_member_getter(registry, member_ptr, vinst); } + + template < detail::member_pointer_kind Member, typename Instance > + uresult try_invoke(Member member_ptr, Instance&& instance) { + using namespace detail; + type_registry& registry{type_registry::instance()}; + + { + const uinst_base vinst{registry, std::forward(instance)}; + if ( const uerror err = raw_member_getter_error(registry, vinst) ) { + return err; + } + } + + const uinst vinst{registry, std::forward(instance)}; + return raw_member_getter(registry, member_ptr, vinst); + } } namespace meta_hpp @@ -7207,6 +7249,11 @@ namespace meta_hpp return method.invoke(std::forward(instance), std::forward(args)...); } + template < typename Instance, typename... Args > + uresult try_invoke(const method& method, Instance&& instance, Args&&... args) { + return method.try_invoke(std::forward(instance), std::forward(args)...); + } + template < detail::method_pointer_kind Method, typename Instance, typename... Args > uvalue invoke(Method method_ptr, Instance&& instance, Args&&... args) { using namespace detail; @@ -7215,6 +7262,24 @@ namespace meta_hpp const std::array vargs{uarg{registry, std::forward(args)}...}; return raw_method_invoke(registry, method_ptr, vinst, vargs); } + + template < detail::method_pointer_kind Method, typename Instance, typename... Args > + uresult try_invoke(Method method_ptr, Instance&& instance, Args&&... args) { + using namespace detail; + type_registry& registry{type_registry::instance()}; + + { + const uinst_base vinst{registry, std::forward(instance)}; + const std::array vargs{uarg_base{registry, std::forward(args)}...}; + if ( const uerror err = raw_method_invoke_error(registry, vinst, vargs) ) { + return err; + } + } + + const uinst vinst{registry, std::forward(instance)}; + const std::array vargs{uarg{registry, std::forward(args)}...}; + return raw_method_invoke(registry, method_ptr, vinst, vargs); + } } namespace meta_hpp diff --git a/develop/untests/meta_issues/random_issue_1.cpp b/develop/untests/meta_issues/random_issue_1.cpp index 67c2879..dc9e875 100644 --- a/develop/untests/meta_issues/random_issue_1.cpp +++ b/develop/untests/meta_issues/random_issue_1.cpp @@ -31,8 +31,8 @@ TEST_CASE("meta/meta_issues/random/1") { CHECK(meta::is_invocable_with(+[](const B&){ return true; }, D{})); CHECK_FALSE(meta::is_invocable_with(+[](const A&){ return true; }, D{})); - CHECK(meta::invoke(+[](const D&){ return true; }, D{})); - CHECK(meta::invoke(+[](const C&){ return true; }, D{})); - CHECK(meta::invoke(+[](const B&){ return true; }, D{})); - CHECK_THROWS(meta::invoke(+[](const A&){ return true; }, D{})); + CHECK(meta::try_invoke(+[](const D&){ return true; }, D{})); + CHECK(meta::try_invoke(+[](const C&){ return true; }, D{})); + CHECK(meta::try_invoke(+[](const B&){ return true; }, D{})); + CHECK_FALSE(meta::try_invoke(+[](const A&){ return true; }, D{})); } diff --git a/develop/untests/meta_utilities/invoke_tests.cpp b/develop/untests/meta_utilities/invoke_tests.cpp index ccc3f2c..bb40a4c 100644 --- a/develop/untests/meta_utilities/invoke_tests.cpp +++ b/develop/untests/meta_utilities/invoke_tests.cpp @@ -40,6 +40,13 @@ TEST_CASE("meta/meta_utilities/invoke") { CHECK(meta::invoke(clazz_function, meta::uvalue{3}).as() == 3); CHECK(meta::invoke(clazz_function, meta::uresult{3}).as() == 3); + CHECK(meta::try_invoke(&clazz::function, 3)->as() == 3); + CHECK(meta::try_invoke(&clazz::function, meta::uvalue{3})->as() == 3); + CHECK(meta::try_invoke(&clazz::function, meta::uresult{3})->as() == 3); + CHECK(meta::try_invoke(clazz_function, 3)->as() == 3); + CHECK(meta::try_invoke(clazz_function, meta::uvalue{3})->as() == 3); + CHECK(meta::try_invoke(clazz_function, meta::uresult{3})->as() == 3); + CHECK(meta::is_invocable_with(clazz_function, 3)); CHECK(meta::is_invocable_with(clazz_function, meta::uvalue{3})); CHECK(meta::is_invocable_with(clazz_function, meta::uresult{3})); @@ -61,6 +68,13 @@ TEST_CASE("meta/meta_utilities/invoke") { CHECK(meta::invoke(clazz_member, meta::uvalue{cl}).as() == 1); CHECK(meta::invoke(clazz_member, meta::uresult{cl}).as() == 1); + CHECK(meta::try_invoke(&clazz::member, cl)->as() == 1); + CHECK(meta::try_invoke(&clazz::member, meta::uvalue{cl})->as() == 1); + CHECK(meta::try_invoke(&clazz::member, meta::uresult{cl})->as() == 1); + CHECK(meta::try_invoke(clazz_member, cl)->as() == 1); + CHECK(meta::try_invoke(clazz_member, meta::uvalue{cl})->as() == 1); + CHECK(meta::try_invoke(clazz_member, meta::uresult{cl})->as() == 1); + CHECK(meta::is_invocable_with(clazz_member, cl)); CHECK(meta::is_invocable_with(clazz_member, meta::uvalue{cl})); CHECK(meta::is_invocable_with(clazz_member, meta::uresult{cl})); @@ -82,6 +96,13 @@ TEST_CASE("meta/meta_utilities/invoke") { CHECK(meta::invoke(clazz_method, meta::uvalue{cl}, meta::uvalue{2}).as() == 2); CHECK(meta::invoke(clazz_method, meta::uresult{cl}, meta::uresult{2}).as() == 2); + CHECK(meta::try_invoke(&clazz::method, cl, 2)->as() == 2); + CHECK(meta::try_invoke(&clazz::method, meta::uvalue{cl}, meta::uvalue{2})->as() == 2); + CHECK(meta::try_invoke(&clazz::method, meta::uresult{cl}, meta::uresult{2})->as() == 2); + CHECK(meta::try_invoke(clazz_method, cl, 2)->as() == 2); + CHECK(meta::try_invoke(clazz_method, meta::uvalue{cl}, meta::uvalue{2})->as() == 2); + CHECK(meta::try_invoke(clazz_method, meta::uresult{cl}, meta::uresult{2})->as() == 2); + CHECK(meta::is_invocable_with(clazz_method, cl, 2)); CHECK(meta::is_invocable_with(clazz_method, meta::uvalue{cl}, meta::uvalue{2})); CHECK(meta::is_invocable_with(clazz_method, meta::uresult{cl}, meta::uresult{2})); diff --git a/headers/meta.hpp/meta_invoke/invoke.hpp b/headers/meta.hpp/meta_invoke/invoke.hpp index cefa5c2..2a079b4 100644 --- a/headers/meta.hpp/meta_invoke/invoke.hpp +++ b/headers/meta.hpp/meta_invoke/invoke.hpp @@ -24,6 +24,11 @@ namespace meta_hpp return function.invoke(std::forward(args)...); } + template < typename... Args > + uresult try_invoke(const function& function, Args&&... args) { + return function.try_invoke(std::forward(args)...); + } + template < detail::function_pointer_kind Function, typename... Args > uvalue invoke(Function function_ptr, Args&&... args) { using namespace detail; @@ -31,6 +36,22 @@ namespace meta_hpp const std::array vargs{uarg{registry, std::forward(args)}...}; return raw_function_invoke(registry, function_ptr, vargs); } + + template < detail::function_pointer_kind Function, typename... Args > + uresult try_invoke(Function function_ptr, Args&&... args) { + using namespace detail; + type_registry& registry{type_registry::instance()}; + + { + const std::array vargs{uarg_base{registry, std::forward(args)}...}; + if ( const uerror err = raw_function_invoke_error(registry, vargs) ) { + return err; + } + } + + const std::array vargs{uarg{registry, std::forward(args)}...}; + return raw_function_invoke(registry, function_ptr, vargs); + } } namespace meta_hpp @@ -40,6 +61,11 @@ namespace meta_hpp return member.get(std::forward(instance)); } + template < typename Instance > + uresult try_invoke(const member& member, Instance&& instance) { + return member.try_get(std::forward(instance)); + } + template < detail::member_pointer_kind Member, typename Instance > uvalue invoke(Member member_ptr, Instance&& instance) { using namespace detail; @@ -47,6 +73,22 @@ namespace meta_hpp const uinst vinst{registry, std::forward(instance)}; return raw_member_getter(registry, member_ptr, vinst); } + + template < detail::member_pointer_kind Member, typename Instance > + uresult try_invoke(Member member_ptr, Instance&& instance) { + using namespace detail; + type_registry& registry{type_registry::instance()}; + + { + const uinst_base vinst{registry, std::forward(instance)}; + if ( const uerror err = raw_member_getter_error(registry, vinst) ) { + return err; + } + } + + const uinst vinst{registry, std::forward(instance)}; + return raw_member_getter(registry, member_ptr, vinst); + } } namespace meta_hpp @@ -56,6 +98,11 @@ namespace meta_hpp return method.invoke(std::forward(instance), std::forward(args)...); } + template < typename Instance, typename... Args > + uresult try_invoke(const method& method, Instance&& instance, Args&&... args) { + return method.try_invoke(std::forward(instance), std::forward(args)...); + } + template < detail::method_pointer_kind Method, typename Instance, typename... Args > uvalue invoke(Method method_ptr, Instance&& instance, Args&&... args) { using namespace detail; @@ -64,6 +111,24 @@ namespace meta_hpp const std::array vargs{uarg{registry, std::forward(args)}...}; return raw_method_invoke(registry, method_ptr, vinst, vargs); } + + template < detail::method_pointer_kind Method, typename Instance, typename... Args > + uresult try_invoke(Method method_ptr, Instance&& instance, Args&&... args) { + using namespace detail; + type_registry& registry{type_registry::instance()}; + + { + const uinst_base vinst{registry, std::forward(instance)}; + const std::array vargs{uarg_base{registry, std::forward(args)}...}; + if ( const uerror err = raw_method_invoke_error(registry, vinst, vargs) ) { + return err; + } + } + + const uinst vinst{registry, std::forward(instance)}; + const std::array vargs{uarg{registry, std::forward(args)}...}; + return raw_method_invoke(registry, method_ptr, vinst, vargs); + } } namespace meta_hpp From de7e853360f4394df2fd55b09ebe8f68c1c0b673 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Mon, 6 Mar 2023 05:18:21 +0700 Subject: [PATCH 8/9] fix ambiguous casts issues --- develop/singles/headers/meta.hpp/meta_all.hpp | 217 +++++++++++++----- .../untests/meta_features/ambiguous_tests.cpp | 96 ++++++++ .../untests/meta_features/diamond_tests.cpp | 54 ++--- .../untests/meta_features/multiple2_tests.cpp | 76 +++--- .../untests/meta_features/multiple_tests.cpp | 84 +++---- .../untests/meta_issues/random_issue_1.cpp | 97 ++++++-- headers/meta.hpp/meta_binds/class_bind.hpp | 9 +- .../meta_detail/value_utilities/uarg.hpp | 17 +- .../meta_detail/value_utilities/uinst.hpp | 21 +- .../meta_detail/value_utilities/utraits.hpp | 53 +++-- headers/meta.hpp/meta_types.hpp | 31 ++- headers/meta.hpp/meta_types/class_type.hpp | 86 ++++++- 12 files changed, 600 insertions(+), 241 deletions(-) create mode 100644 develop/untests/meta_features/ambiguous_tests.cpp diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index c92873a..c31356a 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -2574,6 +2574,10 @@ namespace meta_hpp [[nodiscard]] bool is_direct_base_of() const noexcept; [[nodiscard]] bool is_direct_base_of(const class_type& derived) const noexcept; + template < detail::class_kind Derived > + [[nodiscard]] bool is_virtual_base_of() const noexcept; + [[nodiscard]] bool is_virtual_base_of(const class_type& derived) const noexcept; + template < detail::class_kind Base > [[nodiscard]] bool is_derived_from() const noexcept; [[nodiscard]] bool is_derived_from(const class_type& base) const noexcept; @@ -2582,6 +2586,10 @@ namespace meta_hpp [[nodiscard]] bool is_direct_derived_from() const noexcept; [[nodiscard]] bool is_direct_derived_from(const class_type& base) const noexcept; + template < detail::class_kind Base > + [[nodiscard]] bool is_virtual_derived_from() const noexcept; + [[nodiscard]] bool is_virtual_derived_from(const class_type& base) const noexcept; + [[nodiscard]] function get_function(std::string_view name) const noexcept; [[nodiscard]] member get_member(std::string_view name) const noexcept; [[nodiscard]] method get_method(std::string_view name) const noexcept; @@ -2800,17 +2808,28 @@ namespace meta_hpp::detail typedef_map typedefs; variable_set variables; - using upcast_func_t = void* (*)(void*); + struct upcast_func_t final { + void* (*upcast)(void*){}; + bool is_virtual_upcast{}; + class_type target_class{}; + + template < typename Derived, typename Base > + requires std::is_base_of_v + upcast_func_t(std::in_place_type_t, std::in_place_type_t); + + [[nodiscard]] void* apply(void* ptr) const noexcept; + [[nodiscard]] const void* apply(const void* ptr) const noexcept; + }; struct upcast_func_list_t final { + class_set vbases; std::vector upcasts; - upcast_func_list_t() = default; - upcast_func_list_t(upcast_func_t _upcast); - upcast_func_list_t(std::vector _upcasts); + upcast_func_list_t(const upcast_func_t& _upcast); + upcast_func_list_t(class_set _vbases, std::vector _upcasts); - void* apply(void* ptr) const noexcept; - const void* apply(const void* ptr) const noexcept; + [[nodiscard]] void* apply(void* ptr) const noexcept; + [[nodiscard]] const void* apply(const void* ptr) const noexcept; friend upcast_func_list_t operator+(const upcast_func_list_t& l, const upcast_func_list_t& r); }; @@ -4861,13 +4880,14 @@ namespace meta_hpp::detail::class_bind_impl using derived_classes_db_t = std::map>; template < class_kind Class, class_kind Base > - requires detail::class_bind_base_kind + requires std::is_base_of_v void update_new_bases_db( // new_bases_db_t& new_bases_db ) { - new_bases_db.emplace(resolve_type(), [](void* from) { - return static_cast(static_cast(static_cast(from))); - }); + new_bases_db.try_emplace( // + resolve_type(), + std::in_place_type, + std::in_place_type); } inline void update_deep_upcasts_db( // @@ -5722,8 +5742,19 @@ namespace meta_hpp::detail const class_type& base_class = base.as_class(); const class_type& derived_class = derived.as_class(); - if ( base_class && derived_class && base_class.is_base_of(derived_class) ) { - return true; + if ( base_class && derived_class ) { + 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; + } + } } return false; @@ -5732,7 +5763,7 @@ namespace meta_hpp::detail namespace meta_hpp::detail { - [[nodiscard]] inline void* pointer_upcast(void* ptr, const class_type& from, const class_type& to) { + [[nodiscard]] inline void* unchecked_pointer_upcast(void* ptr, const class_type& from, const class_type& to) { if ( nullptr == ptr || !from || !to ) { return nullptr; } @@ -5741,32 +5772,24 @@ namespace meta_hpp::detail return ptr; } - void* base_ptr = nullptr; + const class_type_data& from_data = *type_access(from); - class_type_data& from_data = *type_access(from); - class_type_data::deep_upcasts_t& deep_upcasts = from_data.deep_upcasts; - - for ( auto iter{deep_upcasts.lower_bound(to)}; iter != deep_upcasts.end() && iter->first == to; ++iter ) { - if ( void* new_base_ptr{iter->second.apply(ptr)}; base_ptr == nullptr ) { - base_ptr = new_base_ptr; - } else if ( base_ptr != new_base_ptr ) { - // ambiguous conversions - return nullptr; - } + if ( auto iter{from_data.deep_upcasts.find(to)}; iter != from_data.deep_upcasts.end() ) { + return iter->second.apply(ptr); } - return base_ptr; + return nullptr; } - [[nodiscard]] inline const void* pointer_upcast(const void* ptr, const class_type& from, const class_type& to) { + [[nodiscard]] inline const void* unchecked_pointer_upcast(const void* ptr, const class_type& from, const class_type& to) { // NOLINTNEXTLINE(*-const-cast) - return pointer_upcast(const_cast(ptr), from, to); + return unchecked_pointer_upcast(const_cast(ptr), from, to); } } namespace meta_hpp::detail { - [[nodiscard]] inline void* pointer_upcast(void* ptr, const any_type& from, const any_type& to) { + [[nodiscard]] inline void* unchecked_pointer_upcast(void* ptr, const any_type& from, const any_type& to) { if ( nullptr == ptr || !from || !to ) { return nullptr; } @@ -5779,7 +5802,7 @@ namespace meta_hpp::detail const class_type& from_class = from.as_class(); if ( to_class && from_class ) { - if ( void* base_ptr = pointer_upcast(ptr, from_class, to_class) ) { + if ( void* base_ptr = unchecked_pointer_upcast(ptr, from_class, to_class) ) { return base_ptr; } } @@ -5787,17 +5810,17 @@ namespace meta_hpp::detail return nullptr; } - [[nodiscard]] inline const void* pointer_upcast(const void* ptr, const any_type& from, const any_type& to) { + [[nodiscard]] inline const void* unchecked_pointer_upcast(const void* ptr, const any_type& from, const any_type& to) { // NOLINTNEXTLINE(*-const-cast) - return pointer_upcast(const_cast(ptr), from, to); + return unchecked_pointer_upcast(const_cast(ptr), from, to); } } namespace meta_hpp::detail { template < typename To, typename From > - [[nodiscard]] To* pointer_upcast(type_registry& registry, From* ptr) { - return static_cast(pointer_upcast( // + [[nodiscard]] To* unchecked_pointer_upcast(type_registry& registry, From* ptr) { + return static_cast(unchecked_pointer_upcast( // ptr, registry.resolve_type(), registry.resolve_type() @@ -5805,8 +5828,8 @@ namespace meta_hpp::detail } template < typename To, typename From > - [[nodiscard]] const To* pointer_upcast(type_registry& registry, const From* ptr) { - return static_cast(pointer_upcast( // + [[nodiscard]] const To* unchecked_pointer_upcast(type_registry& registry, const From* ptr) { + return static_cast(unchecked_pointer_upcast( // ptr, registry.resolve_type(), registry.resolve_type() @@ -6059,21 +6082,27 @@ namespace meta_hpp::detail if ( from_type.is_array() ) { const array_type& from_type_array = from_type.as_array(); - return static_cast(pointer_upcast( // + void* to_ptr = unchecked_pointer_upcast( // data_, from_type_array.get_data_type(), to_type_ptr.get_data_type() - )); + ); + META_HPP_ASSERT(to_ptr); + + return static_cast(to_ptr); } if ( from_type.is_pointer() ) { const pointer_type& from_type_ptr = from_type.as_pointer(); - return static_cast(pointer_upcast( // + void* to_ptr = unchecked_pointer_upcast( // *static_cast(data_), from_type_ptr.get_data_type(), to_type_ptr.get_data_type() - )); + ); + META_HPP_ASSERT(to_ptr); + + return static_cast(to_ptr); } throw_exception(error_code::bad_argument_cast); @@ -6094,7 +6123,8 @@ namespace meta_hpp::detail const any_type& from_type = get_raw_type(); const any_type& to_type = registry.resolve_type(); - void* to_ptr = pointer_upcast(data_, from_type, to_type); + void* to_ptr = unchecked_pointer_upcast(data_, from_type, to_type); + META_HPP_ASSERT(to_ptr); if constexpr ( std::is_lvalue_reference_v ) { return *static_cast(to_ptr); @@ -6561,10 +6591,12 @@ namespace meta_hpp::detail const any_type& to_type = registry.resolve_type(); if ( from_type.is_class() && to_type.is_class() ) { - const class_type& from_class = from_type.as_class(); - const class_type& to_class = to_type.as_class(); - - void* to_ptr = pointer_upcast(data_, from_class, to_class); + void* to_ptr = unchecked_pointer_upcast( // + data_, + from_type.as_class(), + to_type.as_class() + ); + META_HPP_ASSERT(to_ptr); if constexpr ( !std::is_reference_v ) { return *static_cast(to_ptr); @@ -6584,11 +6616,12 @@ 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() ) { - const class_type& from_data_class = from_data_type.as_class(); - const class_type& to_class = to_type.as_class(); - - void** from_data_ptr = static_cast(data_); - void* to_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_class); + void* to_ptr = unchecked_pointer_upcast( // + *static_cast(data_), + from_data_type.as_class(), + to_type.as_class() + ); + META_HPP_ASSERT(to_ptr); if constexpr ( !std::is_reference_v ) { return *static_cast(to_ptr); @@ -8121,16 +8154,45 @@ namespace meta_hpp::detail , size{class_traits::size} , align{class_traits::align} , argument_types{resolve_types(typename class_traits::argument_types{})} {} +} - inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcast_func_t _upcast) - : upcasts{_upcast} {} +namespace meta_hpp::detail +{ + template < typename Derived, typename Base > + 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()} {} - inline class_type_data::upcast_func_list_t::upcast_func_list_t(std::vector _upcasts) - : upcasts{std::move(_upcasts)} {} + inline void* class_type_data::upcast_func_t::apply(void* ptr) const noexcept { + return upcast(ptr); + } + + inline const void* class_type_data::upcast_func_t::apply(const void* ptr) const noexcept { + // NOLINTNEXTLINE(*-const-cast) + return apply(const_cast(ptr)); + } +} + +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); + } + } + } + + 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 void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept { - for ( upcast_func_t upcast : upcasts ) { - ptr = upcast(ptr); + for ( const upcast_func_t& upcast : upcasts ) { + ptr = upcast.apply(ptr); } return ptr; } @@ -8144,11 +8206,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; 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_upcasts)}; + + return class_type_data::upcast_func_list_t{std::move(new_vbases), std::move(new_upcasts)}; } } @@ -8271,13 +8338,38 @@ namespace meta_hpp return is_valid() && derived.is_valid() && derived.data_->base_upcasts.contains(*this); } + template < detail::class_kind Derived > + bool class_type::is_virtual_base_of() const noexcept { + return is_virtual_base_of(resolve_type()); + } + + inline bool class_type::is_virtual_base_of(const class_type& derived) const noexcept { + if ( !is_valid() || !derived.is_valid() ) { + return false; + } + + const detail::class_type_data& derived_data = *derived.data_; + const auto upcasts_range = derived_data.deep_upcasts.equal_range(*this); + + if ( upcasts_range.first == upcasts_range.second ) { + return false; + } + + 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); + }); + }); + } + template < detail::class_kind Base > bool class_type::is_derived_from() const noexcept { return is_derived_from(resolve_type()); } inline bool class_type::is_derived_from(const class_type& base) const noexcept { - return is_valid() && base.is_valid() && data_->deep_upcasts.contains(base); + return base.is_base_of(*this); } template < detail::class_kind Base > @@ -8286,7 +8378,16 @@ namespace meta_hpp } inline bool class_type::is_direct_derived_from(const class_type& base) const noexcept { - return is_valid() && base.is_valid() && data_->base_upcasts.contains(base); + return base.is_direct_base_of(*this); + } + + template < detail::class_kind Base > + bool class_type::is_virtual_derived_from() const noexcept { + return is_virtual_derived_from(resolve_type()); + } + + inline bool class_type::is_virtual_derived_from(const class_type& base) const noexcept { + return base.is_virtual_base_of(*this); } inline function class_type::get_function(std::string_view name) const noexcept { diff --git a/develop/untests/meta_features/ambiguous_tests.cpp b/develop/untests/meta_features/ambiguous_tests.cpp new file mode 100644 index 0000000..31f6c04 --- /dev/null +++ b/develop/untests/meta_features/ambiguous_tests.cpp @@ -0,0 +1,96 @@ +/******************************************************************************* + * 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 A1 { std::string a1{"a1"}; }; + struct B1 : A1 { std::string b1{"b1"}; }; + struct C1 : A1 { std::string c1{"c1"}; }; + struct D1 : B1, C1 { std::string d1{"d1"}; }; + + struct A2 { std::string a2{"a2"}; }; + struct B2 : virtual A2 { std::string b2{"b2"}; }; + struct C2 : virtual A2 { std::string c2{"c2"}; }; + struct D2 : B2, C2 { std::string d2{"d2"}; }; + + struct A3 { std::string a3{"a3"}; }; + struct B3 : virtual A3 { std::string b3{"b3"}; }; + struct C3 : A3 { std::string c3{"c3"}; }; + struct D3 : B3, C3 { std::string d3{"d3"}; }; +} + +TEST_CASE("meta/meta_features/ambiguous") { + namespace meta = meta_hpp; + + { + meta::class_().base_(); + meta::class_().base_(); + meta::class_().base_(); + + // A1 < B1 + // < D1 + // A1 < C1 + + static_assert(std::is_invocable_v); + static_assert(std::is_invocable_v); + static_assert(std::is_invocable_v); + static_assert(!std::is_invocable_v); + + CHECK(meta::is_invocable_with(+[](const A1&){}, A1{})); + CHECK(meta::is_invocable_with(+[](const A1&){}, B1{})); + 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()); + } + + { + meta::class_().base_(); + meta::class_().base_(); + meta::class_().base_(); + + // A2 <= B2 + // < D2 + // A2 <= C2 + + static_assert(std::is_invocable_v); + static_assert(std::is_invocable_v); + static_assert(std::is_invocable_v); + static_assert(std::is_invocable_v); + + CHECK(meta::is_invocable_with(+[](const A2&){}, A2{})); + CHECK(meta::is_invocable_with(+[](const A2&){}, B2{})); + CHECK(meta::is_invocable_with(+[](const A2&){}, C2{})); + CHECK(meta::is_invocable_with(+[](const A2&){}, D2{})); + + CHECK(meta::resolve_type().is_virtual_base_of()); + } + + { + meta::class_().base_(); + meta::class_().base_(); + meta::class_().base_(); + + // A3 <= B3 + // < D3 + // A3 < C3 + + static_assert(std::is_invocable_v); + static_assert(std::is_invocable_v); + static_assert(std::is_invocable_v); + static_assert(!std::is_invocable_v); + + CHECK(meta::is_invocable_with(+[](const A3&){}, A3{})); + CHECK(meta::is_invocable_with(+[](const A3&){}, B3{})); + CHECK(meta::is_invocable_with(+[](const A3&){}, C3{})); + CHECK_FALSE(meta::is_invocable_with(+[](const A3&){}, D3{})); + + 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 11384af..adf6fd9 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("pointer_upcast") { - using meta::detail::pointer_upcast; + SUBCASE("unchecked_pointer_upcast") { + using meta::detail::unchecked_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)); + 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)); } { 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)); + 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)); } { 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)); + 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)); } { 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)); + 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)); } { 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); + 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); } } diff --git a/develop/untests/meta_features/multiple2_tests.cpp b/develop/untests/meta_features/multiple2_tests.cpp index 88cc309..fd3533a 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("pointer_upcast") { + SUBCASE("unchecked_pointer_upcast") { using meta::detail::type_registry; - using meta::detail::pointer_upcast; + using meta::detail::unchecked_pointer_upcast; type_registry& r{type_registry::instance()}; { A 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)); + 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)); } { B0 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)); + 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)); } { B1 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)); + 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)); } { C 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)); + 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)); } { E0 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)); + 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)); } { 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"); + 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"); } } } diff --git a/develop/untests/meta_features/multiple_tests.cpp b/develop/untests/meta_features/multiple_tests.cpp index 25481f8..22dc29d 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("pointer_upcast") { - using meta::detail::pointer_upcast; + SUBCASE("unchecked_pointer_upcast") { + using meta::detail::unchecked_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)); - CHECK_FALSE(pointer_upcast(r, &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)); } { 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)); - CHECK_FALSE(pointer_upcast(r, &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)); } { 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)); - CHECK_FALSE(pointer_upcast(r, &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)); } { const D 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)); + // 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)); } { const E 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)); + // 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)); } { 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); + 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); } } } diff --git a/develop/untests/meta_issues/random_issue_1.cpp b/develop/untests/meta_issues/random_issue_1.cpp index dc9e875..39c918e 100644 --- a/develop/untests/meta_issues/random_issue_1.cpp +++ b/develop/untests/meta_issues/random_issue_1.cpp @@ -9,30 +9,91 @@ namespace { - struct A {}; - struct B : A {}; - struct C : A {}; - struct D : B, C {}; + struct A1 {}; + struct B1 : A1 {}; + struct C1 : A1 {}; + struct D1 : B1, C1 {}; + + // A1 <- B1 <- * + // D1 + // A1 <- C1 <- * + + struct A2 {}; + struct B2 : virtual A2 {}; + struct C2 : virtual B2 {}; + struct D2 : virtual B2 {}; + struct E2 : C2, D2 {}; + + // A2 <= B2 <= C2 <- * + // E2 + // A2 <= B2 <= D2 <- * + + struct A3 {}; + struct B3 : virtual A3 {}; + struct C3 : A3 {}; + struct D3 : B3, C3 {}; + + // A3 <= B3 <- * + // D3 + // A3 <- C3 <- * - // A * <- B <- * - // D - // A * <- C <- * } TEST_CASE("meta/meta_issues/random/1") { namespace meta = meta_hpp; - meta::class_().base_(); - meta::class_().base_(); - meta::class_().base_(); + { + meta::class_().base_(); + meta::class_().base_(); + meta::class_().base_(); - CHECK(meta::is_invocable_with(+[](const D&){ return true; }, D{})); - CHECK(meta::is_invocable_with(+[](const C&){ return true; }, D{})); - CHECK(meta::is_invocable_with(+[](const B&){ return true; }, D{})); - CHECK_FALSE(meta::is_invocable_with(+[](const A&){ return true; }, D{})); + CHECK(meta::is_invocable_with(+[](const D1&){ return true; }, D1{})); + CHECK(meta::is_invocable_with(+[](const C1&){ return true; }, D1{})); + CHECK(meta::is_invocable_with(+[](const B1&){ return true; }, D1{})); + CHECK_FALSE(meta::is_invocable_with(+[](const A1&){ return true; }, D1{})); - CHECK(meta::try_invoke(+[](const D&){ return true; }, D{})); - CHECK(meta::try_invoke(+[](const C&){ return true; }, D{})); - CHECK(meta::try_invoke(+[](const B&){ return true; }, D{})); - CHECK_FALSE(meta::try_invoke(+[](const A&){ return true; }, D{})); + CHECK(meta::try_invoke(+[](const D1&){ return true; }, D1{})); + CHECK(meta::try_invoke(+[](const C1&){ return true; }, D1{})); + CHECK(meta::try_invoke(+[](const B1&){ return true; }, D1{})); + CHECK_FALSE(meta::try_invoke(+[](const A1&){ return true; }, D1{})); + + CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); + } + + { + meta::class_().base_(); + meta::class_().base_(); + meta::class_().base_(); + meta::class_().base_(); + + CHECK(meta::is_invocable_with(+[](const A2&){ return true; }, E2{})); + CHECK(meta::is_invocable_with(+[](const B2&){ return true; }, E2{})); + CHECK(meta::is_invocable_with(+[](const C2&){ return true; }, E2{})); + CHECK(meta::is_invocable_with(+[](const D2&){ return true; }, E2{})); + + CHECK(meta::try_invoke(+[](const A2&){ return true; }, E2{})); + CHECK(meta::try_invoke(+[](const B2&){ return true; }, E2{})); + CHECK(meta::try_invoke(+[](const C2&){ return true; }, E2{})); + CHECK(meta::try_invoke(+[](const D2&){ return true; }, E2{})); + + CHECK(meta::resolve_type().is_virtual_base_of()); + } + + { + meta::class_().base_(); + meta::class_().base_(); + meta::class_().base_(); + + static_assert(std::is_invocable_v); + static_assert(std::is_invocable_v); + static_assert(std::is_invocable_v); + static_assert(!std::is_invocable_v); + + CHECK(meta::is_invocable_with(+[](const A3&){ return true; }, A3{})); + CHECK(meta::is_invocable_with(+[](const A3&){ return true; }, B3{})); + CHECK(meta::is_invocable_with(+[](const A3&){ return true; }, C3{})); + CHECK_FALSE(meta::is_invocable_with(+[](const A3&){ return true; }, D3{})); + + CHECK_FALSE(meta::resolve_type().is_virtual_base_of()); + } } diff --git a/headers/meta.hpp/meta_binds/class_bind.hpp b/headers/meta.hpp/meta_binds/class_bind.hpp index 1fd71b4..2f90528 100644 --- a/headers/meta.hpp/meta_binds/class_bind.hpp +++ b/headers/meta.hpp/meta_binds/class_bind.hpp @@ -23,13 +23,14 @@ namespace meta_hpp::detail::class_bind_impl using derived_classes_db_t = std::map>; template < class_kind Class, class_kind Base > - requires detail::class_bind_base_kind + requires std::is_base_of_v void update_new_bases_db( // new_bases_db_t& new_bases_db ) { - new_bases_db.emplace(resolve_type(), [](void* from) { - return static_cast(static_cast(static_cast(from))); - }); + new_bases_db.try_emplace( // + resolve_type(), + std::in_place_type, + std::in_place_type); } inline void update_deep_upcasts_db( // diff --git a/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp b/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp index 72dbffa..4f7224f 100644 --- a/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp +++ b/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp @@ -258,21 +258,27 @@ namespace meta_hpp::detail if ( from_type.is_array() ) { const array_type& from_type_array = from_type.as_array(); - return static_cast(pointer_upcast( // + void* to_ptr = unchecked_pointer_upcast( // data_, from_type_array.get_data_type(), to_type_ptr.get_data_type() - )); + ); + META_HPP_ASSERT(to_ptr); + + return static_cast(to_ptr); } if ( from_type.is_pointer() ) { const pointer_type& from_type_ptr = from_type.as_pointer(); - return static_cast(pointer_upcast( // + void* to_ptr = unchecked_pointer_upcast( // *static_cast(data_), from_type_ptr.get_data_type(), to_type_ptr.get_data_type() - )); + ); + META_HPP_ASSERT(to_ptr); + + return static_cast(to_ptr); } throw_exception(error_code::bad_argument_cast); @@ -293,7 +299,8 @@ namespace meta_hpp::detail const any_type& from_type = get_raw_type(); const any_type& to_type = registry.resolve_type(); - void* to_ptr = pointer_upcast(data_, from_type, to_type); + void* to_ptr = unchecked_pointer_upcast(data_, from_type, to_type); + META_HPP_ASSERT(to_ptr); if constexpr ( std::is_lvalue_reference_v ) { return *static_cast(to_ptr); diff --git a/headers/meta.hpp/meta_detail/value_utilities/uinst.hpp b/headers/meta.hpp/meta_detail/value_utilities/uinst.hpp index c20e7d6..6c88ae3 100644 --- a/headers/meta.hpp/meta_detail/value_utilities/uinst.hpp +++ b/headers/meta.hpp/meta_detail/value_utilities/uinst.hpp @@ -192,10 +192,12 @@ namespace meta_hpp::detail const any_type& to_type = registry.resolve_type(); if ( from_type.is_class() && to_type.is_class() ) { - const class_type& from_class = from_type.as_class(); - const class_type& to_class = to_type.as_class(); - - void* to_ptr = pointer_upcast(data_, from_class, to_class); + void* to_ptr = unchecked_pointer_upcast( // + data_, + from_type.as_class(), + to_type.as_class() + ); + META_HPP_ASSERT(to_ptr); if constexpr ( !std::is_reference_v ) { return *static_cast(to_ptr); @@ -215,11 +217,12 @@ 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() ) { - const class_type& from_data_class = from_data_type.as_class(); - const class_type& to_class = to_type.as_class(); - - void** from_data_ptr = static_cast(data_); - void* to_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_class); + void* to_ptr = unchecked_pointer_upcast( // + *static_cast(data_), + from_data_type.as_class(), + to_type.as_class() + ); + META_HPP_ASSERT(to_ptr); if constexpr ( !std::is_reference_v ) { return *static_cast(to_ptr); diff --git a/headers/meta.hpp/meta_detail/value_utilities/utraits.hpp b/headers/meta.hpp/meta_detail/value_utilities/utraits.hpp index 01986ff..5277000 100644 --- a/headers/meta.hpp/meta_detail/value_utilities/utraits.hpp +++ b/headers/meta.hpp/meta_detail/value_utilities/utraits.hpp @@ -105,8 +105,19 @@ namespace meta_hpp::detail const class_type& base_class = base.as_class(); const class_type& derived_class = derived.as_class(); - if ( base_class && derived_class && base_class.is_base_of(derived_class) ) { - return true; + if ( base_class && derived_class ) { + 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; + } + } } return false; @@ -115,7 +126,7 @@ namespace meta_hpp::detail namespace meta_hpp::detail { - [[nodiscard]] inline void* pointer_upcast(void* ptr, const class_type& from, const class_type& to) { + [[nodiscard]] inline void* unchecked_pointer_upcast(void* ptr, const class_type& from, const class_type& to) { if ( nullptr == ptr || !from || !to ) { return nullptr; } @@ -124,32 +135,24 @@ namespace meta_hpp::detail return ptr; } - void* base_ptr = nullptr; + const class_type_data& from_data = *type_access(from); - class_type_data& from_data = *type_access(from); - class_type_data::deep_upcasts_t& deep_upcasts = from_data.deep_upcasts; - - for ( auto iter{deep_upcasts.lower_bound(to)}; iter != deep_upcasts.end() && iter->first == to; ++iter ) { - if ( void* new_base_ptr{iter->second.apply(ptr)}; base_ptr == nullptr ) { - base_ptr = new_base_ptr; - } else if ( base_ptr != new_base_ptr ) { - // ambiguous conversions - return nullptr; - } + if ( auto iter{from_data.deep_upcasts.find(to)}; iter != from_data.deep_upcasts.end() ) { + return iter->second.apply(ptr); } - return base_ptr; + return nullptr; } - [[nodiscard]] inline const void* pointer_upcast(const void* ptr, const class_type& from, const class_type& to) { + [[nodiscard]] inline const void* unchecked_pointer_upcast(const void* ptr, const class_type& from, const class_type& to) { // NOLINTNEXTLINE(*-const-cast) - return pointer_upcast(const_cast(ptr), from, to); + return unchecked_pointer_upcast(const_cast(ptr), from, to); } } namespace meta_hpp::detail { - [[nodiscard]] inline void* pointer_upcast(void* ptr, const any_type& from, const any_type& to) { + [[nodiscard]] inline void* unchecked_pointer_upcast(void* ptr, const any_type& from, const any_type& to) { if ( nullptr == ptr || !from || !to ) { return nullptr; } @@ -162,7 +165,7 @@ namespace meta_hpp::detail const class_type& from_class = from.as_class(); if ( to_class && from_class ) { - if ( void* base_ptr = pointer_upcast(ptr, from_class, to_class) ) { + if ( void* base_ptr = unchecked_pointer_upcast(ptr, from_class, to_class) ) { return base_ptr; } } @@ -170,17 +173,17 @@ namespace meta_hpp::detail return nullptr; } - [[nodiscard]] inline const void* pointer_upcast(const void* ptr, const any_type& from, const any_type& to) { + [[nodiscard]] inline const void* unchecked_pointer_upcast(const void* ptr, const any_type& from, const any_type& to) { // NOLINTNEXTLINE(*-const-cast) - return pointer_upcast(const_cast(ptr), from, to); + return unchecked_pointer_upcast(const_cast(ptr), from, to); } } namespace meta_hpp::detail { template < typename To, typename From > - [[nodiscard]] To* pointer_upcast(type_registry& registry, From* ptr) { - return static_cast(pointer_upcast( // + [[nodiscard]] To* unchecked_pointer_upcast(type_registry& registry, From* ptr) { + return static_cast(unchecked_pointer_upcast( // ptr, registry.resolve_type(), registry.resolve_type() @@ -188,8 +191,8 @@ namespace meta_hpp::detail } template < typename To, typename From > - [[nodiscard]] const To* pointer_upcast(type_registry& registry, const From* ptr) { - return static_cast(pointer_upcast( // + [[nodiscard]] const To* unchecked_pointer_upcast(type_registry& registry, const From* ptr) { + return static_cast(unchecked_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 26661ac..c8aa04a 100644 --- a/headers/meta.hpp/meta_types.hpp +++ b/headers/meta.hpp/meta_types.hpp @@ -184,6 +184,10 @@ namespace meta_hpp [[nodiscard]] bool is_direct_base_of() const noexcept; [[nodiscard]] bool is_direct_base_of(const class_type& derived) const noexcept; + template < detail::class_kind Derived > + [[nodiscard]] bool is_virtual_base_of() const noexcept; + [[nodiscard]] bool is_virtual_base_of(const class_type& derived) const noexcept; + template < detail::class_kind Base > [[nodiscard]] bool is_derived_from() const noexcept; [[nodiscard]] bool is_derived_from(const class_type& base) const noexcept; @@ -192,6 +196,10 @@ namespace meta_hpp [[nodiscard]] bool is_direct_derived_from() const noexcept; [[nodiscard]] bool is_direct_derived_from(const class_type& base) const noexcept; + template < detail::class_kind Base > + [[nodiscard]] bool is_virtual_derived_from() const noexcept; + [[nodiscard]] bool is_virtual_derived_from(const class_type& base) const noexcept; + [[nodiscard]] function get_function(std::string_view name) const noexcept; [[nodiscard]] member get_member(std::string_view name) const noexcept; [[nodiscard]] method get_method(std::string_view name) const noexcept; @@ -410,17 +418,28 @@ namespace meta_hpp::detail typedef_map typedefs; variable_set variables; - using upcast_func_t = void* (*)(void*); + struct upcast_func_t final { + void* (*upcast)(void*){}; + bool is_virtual_upcast{}; + class_type target_class{}; + + template < typename Derived, typename Base > + requires std::is_base_of_v + upcast_func_t(std::in_place_type_t, std::in_place_type_t); + + [[nodiscard]] void* apply(void* ptr) const noexcept; + [[nodiscard]] const void* apply(const void* ptr) const noexcept; + }; struct upcast_func_list_t final { + class_set vbases; std::vector upcasts; - upcast_func_list_t() = default; - upcast_func_list_t(upcast_func_t _upcast); - upcast_func_list_t(std::vector _upcasts); + upcast_func_list_t(const upcast_func_t& _upcast); + upcast_func_list_t(class_set _vbases, std::vector _upcasts); - void* apply(void* ptr) const noexcept; - const void* apply(const void* ptr) const noexcept; + [[nodiscard]] void* apply(void* ptr) const noexcept; + [[nodiscard]] const void* apply(const void* ptr) const noexcept; friend upcast_func_list_t operator+(const upcast_func_list_t& l, const upcast_func_list_t& r); }; diff --git a/headers/meta.hpp/meta_types/class_type.hpp b/headers/meta.hpp/meta_types/class_type.hpp index bdff667..9984ca0 100644 --- a/headers/meta.hpp/meta_types/class_type.hpp +++ b/headers/meta.hpp/meta_types/class_type.hpp @@ -30,16 +30,45 @@ namespace meta_hpp::detail , size{class_traits::size} , align{class_traits::align} , argument_types{resolve_types(typename class_traits::argument_types{})} {} +} - inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcast_func_t _upcast) - : upcasts{_upcast} {} +namespace meta_hpp::detail +{ + template < typename Derived, typename Base > + 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()} {} - inline class_type_data::upcast_func_list_t::upcast_func_list_t(std::vector _upcasts) - : upcasts{std::move(_upcasts)} {} + inline void* class_type_data::upcast_func_t::apply(void* ptr) const noexcept { + return upcast(ptr); + } + + inline const void* class_type_data::upcast_func_t::apply(const void* ptr) const noexcept { + // NOLINTNEXTLINE(*-const-cast) + return apply(const_cast(ptr)); + } +} + +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); + } + } + } + + 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 void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept { - for ( upcast_func_t upcast : upcasts ) { - ptr = upcast(ptr); + for ( const upcast_func_t& upcast : upcasts ) { + ptr = upcast.apply(ptr); } return ptr; } @@ -53,11 +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; 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_upcasts)}; + + return class_type_data::upcast_func_list_t{std::move(new_vbases), std::move(new_upcasts)}; } } @@ -180,13 +214,38 @@ namespace meta_hpp return is_valid() && derived.is_valid() && derived.data_->base_upcasts.contains(*this); } + template < detail::class_kind Derived > + bool class_type::is_virtual_base_of() const noexcept { + return is_virtual_base_of(resolve_type()); + } + + inline bool class_type::is_virtual_base_of(const class_type& derived) const noexcept { + if ( !is_valid() || !derived.is_valid() ) { + return false; + } + + const detail::class_type_data& derived_data = *derived.data_; + const auto upcasts_range = derived_data.deep_upcasts.equal_range(*this); + + if ( upcasts_range.first == upcasts_range.second ) { + return false; + } + + 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); + }); + }); + } + template < detail::class_kind Base > bool class_type::is_derived_from() const noexcept { return is_derived_from(resolve_type()); } inline bool class_type::is_derived_from(const class_type& base) const noexcept { - return is_valid() && base.is_valid() && data_->deep_upcasts.contains(base); + return base.is_base_of(*this); } template < detail::class_kind Base > @@ -195,7 +254,16 @@ namespace meta_hpp } inline bool class_type::is_direct_derived_from(const class_type& base) const noexcept { - return is_valid() && base.is_valid() && data_->base_upcasts.contains(base); + return base.is_direct_base_of(*this); + } + + template < detail::class_kind Base > + bool class_type::is_virtual_derived_from() const noexcept { + return is_virtual_derived_from(resolve_type()); + } + + inline bool class_type::is_virtual_derived_from(const class_type& base) const noexcept { + return base.is_virtual_base_of(*this); } inline function class_type::get_function(std::string_view name) const noexcept { From 424b6f67363438715a3c66f2e614629cc312a20e Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Mon, 6 Mar 2023 21:29:19 +0700 Subject: [PATCH 9/9] 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 >