optimize ambiguous cast checks

This commit is contained in:
BlackMATov
2023-03-06 21:29:19 +07:00
parent de7e853360
commit 424b6f6736
15 changed files with 334 additions and 222 deletions

View File

@@ -5,7 +5,8 @@ target_compile_options(${PROJECT_NAME}.setup_targets INTERFACE
$<$<CXX_COMPILER_ID:MSVC>: $<$<CXX_COMPILER_ID:MSVC>:
/WX /W4 /bigobj> /WX /W4 /bigobj>
$<$<CXX_COMPILER_ID:GNU>: $<$<CXX_COMPILER_ID:GNU>:
-Werror -Wall -Wextra -Wpedantic> -Werror -Wall -Wextra -Wpedantic
-Wno-inaccessible-base>
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>: $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:
-Werror -Weverything -Wconversion -Werror -Weverything -Wconversion
-Wno-c++98-compat -Wno-c++98-compat

View File

@@ -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 namespace meta_hpp::detail
{ {
template < typename T > template < typename T >
@@ -2809,9 +2835,11 @@ namespace meta_hpp::detail
variable_set variables; variable_set variables;
struct upcast_func_t final { struct upcast_func_t final {
void* (*upcast)(void*){}; using upcast_t = void* (*)(void*);
bool is_virtual_upcast{};
class_type target_class{}; upcast_t upcast{};
class_type target{};
bool is_virtual{};
template < typename Derived, typename Base > template < typename Derived, typename Base >
requires std::is_base_of_v<Base, Derived> requires std::is_base_of_v<Base, Derived>
@@ -2822,11 +2850,14 @@ namespace meta_hpp::detail
}; };
struct upcast_func_list_t final { struct upcast_func_list_t final {
class_set vbases; using upcasts_t = std::vector<upcast_func_t>;
std::vector<upcast_func_t> upcasts;
upcasts_t upcasts{};
class_set vbases{};
bool is_ambiguous{};
upcast_func_list_t(const upcast_func_t& _upcast); upcast_func_list_t(const upcast_func_t& _upcast);
upcast_func_list_t(class_set _vbases, std::vector<upcast_func_t> _upcasts); upcast_func_list_t(upcasts_t _upcasts, class_set _vbases);
[[nodiscard]] void* apply(void* ptr) const noexcept; [[nodiscard]] void* apply(void* ptr) const noexcept;
[[nodiscard]] const void* apply(const 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<class_type, upcast_func_t, std::less<>>; using base_upcasts_t = std::map<class_type, upcast_func_t, std::less<>>;
using deep_upcasts_t = std::multimap<class_type, upcast_func_list_t, std::less<>>; using deep_upcasts_t = std::map<class_type, upcast_func_list_t, std::less<>>;
base_upcasts_t base_upcasts; base_upcasts_t base_upcasts;
deep_upcasts_t deep_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); 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; 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 ) { 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; 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 ) { 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); 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( // 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& derived_data = *type_access(derived_class);
const class_type_data::deep_upcasts_t& deep_upcasts = derived_data.deep_upcasts; 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 ( auto iter{deep_upcasts.find(base)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) {
if ( const auto next_iter{std::next(iter)}; next_iter == deep_upcasts.end() || next_iter->first != base ) { return true;
return true;
}
if ( base_class.is_virtual_base_of(derived_class) ) {
return true;
}
} }
} }
@@ -5763,7 +5795,7 @@ namespace meta_hpp::detail
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 ) { if ( nullptr == ptr || !from || !to ) {
return nullptr; return nullptr;
} }
@@ -5773,23 +5805,24 @@ namespace meta_hpp::detail
} }
const class_type_data& from_data = *type_access(from); 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 iter->second.apply(ptr);
} }
return nullptr; 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) // NOLINTNEXTLINE(*-const-cast)
return unchecked_pointer_upcast(const_cast<void*>(ptr), from, to); return pointer_upcast(const_cast<void*>(ptr), from, to);
} }
} }
namespace meta_hpp::detail 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 ) { if ( nullptr == ptr || !from || !to ) {
return nullptr; return nullptr;
} }
@@ -5802,7 +5835,7 @@ namespace meta_hpp::detail
const class_type& from_class = from.as_class(); const class_type& from_class = from.as_class();
if ( to_class && from_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; return base_ptr;
} }
} }
@@ -5810,17 +5843,17 @@ namespace meta_hpp::detail
return nullptr; 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) // NOLINTNEXTLINE(*-const-cast)
return unchecked_pointer_upcast(const_cast<void*>(ptr), from, to); return pointer_upcast(const_cast<void*>(ptr), from, to);
} }
} }
namespace meta_hpp::detail namespace meta_hpp::detail
{ {
template < typename To, typename From > template < typename To, typename From >
[[nodiscard]] To* unchecked_pointer_upcast(type_registry& registry, From* ptr) { [[nodiscard]] To* pointer_upcast(type_registry& registry, From* ptr) {
return static_cast<To*>(unchecked_pointer_upcast( // return static_cast<To*>(pointer_upcast( //
ptr, ptr,
registry.resolve_type<From>(), registry.resolve_type<From>(),
registry.resolve_type<To>() registry.resolve_type<To>()
@@ -5828,8 +5861,8 @@ namespace meta_hpp::detail
} }
template < typename To, typename From > template < typename To, typename From >
[[nodiscard]] const To* unchecked_pointer_upcast(type_registry& registry, const From* ptr) { [[nodiscard]] const To* pointer_upcast(type_registry& registry, const From* ptr) {
return static_cast<const To*>(unchecked_pointer_upcast( // return static_cast<const To*>(pointer_upcast( //
ptr, ptr,
registry.resolve_type<From>(), registry.resolve_type<From>(),
registry.resolve_type<To>() registry.resolve_type<To>()
@@ -6082,7 +6115,7 @@ namespace meta_hpp::detail
if ( from_type.is_array() ) { if ( from_type.is_array() ) {
const array_type& from_type_array = from_type.as_array(); const array_type& from_type_array = from_type.as_array();
void* to_ptr = unchecked_pointer_upcast( // void* to_ptr = pointer_upcast( //
data_, data_,
from_type_array.get_data_type(), from_type_array.get_data_type(),
to_type_ptr.get_data_type() to_type_ptr.get_data_type()
@@ -6095,7 +6128,7 @@ namespace meta_hpp::detail
if ( from_type.is_pointer() ) { if ( from_type.is_pointer() ) {
const pointer_type& from_type_ptr = from_type.as_pointer(); const pointer_type& from_type_ptr = from_type.as_pointer();
void* to_ptr = unchecked_pointer_upcast( // void* to_ptr = pointer_upcast( //
*static_cast<void**>(data_), *static_cast<void**>(data_),
from_type_ptr.get_data_type(), from_type_ptr.get_data_type(),
to_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& from_type = get_raw_type();
const any_type& to_type = registry.resolve_type<to_raw_type>(); const any_type& to_type = registry.resolve_type<to_raw_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); META_HPP_ASSERT(to_ptr);
if constexpr ( std::is_lvalue_reference_v<To> ) { if constexpr ( std::is_lvalue_reference_v<To> ) {
@@ -6591,7 +6624,7 @@ namespace meta_hpp::detail
const any_type& to_type = registry.resolve_type<inst_class>(); const any_type& to_type = registry.resolve_type<inst_class>();
if ( from_type.is_class() && to_type.is_class() ) { if ( from_type.is_class() && to_type.is_class() ) {
void* to_ptr = unchecked_pointer_upcast( // void* to_ptr = pointer_upcast( //
data_, data_,
from_type.as_class(), from_type.as_class(),
to_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(); const any_type& from_data_type = from_type_ptr.get_data_type();
if ( from_data_type.is_class() && to_type.is_class() ) { if ( from_data_type.is_class() && to_type.is_class() ) {
void* to_ptr = unchecked_pointer_upcast( // void* to_ptr = pointer_upcast( //
*static_cast<void**>(data_), *static_cast<void**>(data_),
from_data_type.as_class(), from_data_type.as_class(),
to_type.as_class() to_type.as_class()
@@ -8162,8 +8195,8 @@ namespace meta_hpp::detail
requires std::is_base_of_v<Base, Derived> requires std::is_base_of_v<Base, Derived>
inline class_type_data::upcast_func_t::upcast_func_t(std::in_place_type_t<Derived>, std::in_place_type_t<Base>) inline class_type_data::upcast_func_t::upcast_func_t(std::in_place_type_t<Derived>, std::in_place_type_t<Base>)
: upcast{[](void* from) -> void* { return static_cast<Base*>(static_cast<Derived*>(from)); }} : upcast{[](void* from) -> void* { return static_cast<Base*>(static_cast<Derived*>(from)); }}
, is_virtual_upcast{is_virtual_base_of_v<Base, Derived>} , target{resolve_type<Base>()}
, target_class{resolve_type<Base>()} {} , is_virtual{is_virtual_base_of_v<Base, Derived>} {}
inline void* class_type_data::upcast_func_t::apply(void* ptr) const noexcept { inline void* class_type_data::upcast_func_t::apply(void* ptr) const noexcept {
return upcast(ptr); 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) inline class_type_data::upcast_func_list_t::upcast_func_list_t(const upcast_func_t& _upcast)
: upcasts{_upcast} { : upcasts{_upcast} {
for ( const upcast_func_t& upcast : upcasts ) { for ( const upcast_func_t& upcast : upcasts ) {
if ( upcast.is_virtual_upcast ) { if ( upcast.is_virtual ) {
vbases.emplace(upcast.target_class); vbases.emplace(upcast.target);
} }
} }
} }
inline class_type_data::upcast_func_list_t::upcast_func_list_t(class_set _vbases, std::vector<upcast_func_t> _upcasts) inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcasts_t _upcasts, class_set _vbases)
: vbases{std::move(_vbases)} : upcasts{std::move(_upcasts)}
, upcasts{std::move(_upcasts)} {} , vbases{std::move(_vbases)} {}
inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept { inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept {
for ( const upcast_func_t& upcast : upcasts ) { 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& l,
const class_type_data::upcast_func_list_t& r const class_type_data::upcast_func_list_t& r
) { ) {
class_set new_vbases; class_type_data::upcast_func_list_t::upcasts_t new_upcasts;
new_vbases.insert(l.vbases.begin(), l.vbases.end());
new_vbases.insert(r.vbases.begin(), r.vbases.end());
std::vector<class_type_data::upcast_func_t> new_upcasts;
new_upcasts.reserve(l.upcasts.size() + r.upcasts.size()); 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(), l.upcasts.begin(), l.upcasts.end());
new_upcasts.insert(new_upcasts.end(), r.upcasts.begin(), r.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; return false;
} }
const detail::class_type_data& derived_data = *derived.data_; using deep_upcasts_t = detail::class_type_data::deep_upcasts_t;
const auto upcasts_range = derived_data.deep_upcasts.equal_range(*this); const deep_upcasts_t& deep_upcasts = derived.data_->deep_upcasts;
if ( upcasts_range.first == upcasts_range.second ) { if ( auto iter{deep_upcasts.find(*this)}; iter != deep_upcasts.end() ) {
return false; return !iter->second.is_ambiguous && !iter->second.vbases.empty();
} }
const class_set& first_vbases = upcasts_range.first->second.vbases; return false;
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 > template < detail::class_kind Base >

View File

@@ -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 <meta.hpp/meta_all.hpp>
#include <doctest/doctest.h>
TEST_CASE("meta/meta_base/is_disjoint") {
namespace meta = meta_hpp;
using meta::detail::is_disjoint;
CHECK(is_disjoint(std::set<int>{}, std::set<int>{}));
CHECK(is_disjoint(std::set<int>{1}, std::set<int>{}));
CHECK(is_disjoint(std::set<int>{}, std::set<int>{1}));
CHECK_FALSE(is_disjoint(std::set<int>{1}, std::set<int>{1}));
CHECK_FALSE(is_disjoint(std::set<int>{1,2}, std::set<int>{1}));
CHECK_FALSE(is_disjoint(std::set<int>{1}, std::set<int>{1,2}));
CHECK_FALSE(is_disjoint(std::set<int>{1,2}, std::set<int>{1,3}));
CHECK_FALSE(is_disjoint(std::set<int>{1,3}, std::set<int>{1,2}));
CHECK(is_disjoint(std::set<int>{1,2}, std::set<int>{3,4}));
CHECK(is_disjoint(std::set<int>{2,3}, std::set<int>{1,4,5}));
CHECK(is_disjoint(std::set<int>{2,4}, std::set<int>{1,3,5}));
}

View File

@@ -47,7 +47,12 @@ TEST_CASE("meta/meta_features/ambiguous") {
CHECK(meta::is_invocable_with(+[](const A1&){}, C1{})); CHECK(meta::is_invocable_with(+[](const A1&){}, C1{}));
CHECK_FALSE(meta::is_invocable_with(+[](const A1&){}, D1{})); CHECK_FALSE(meta::is_invocable_with(+[](const A1&){}, D1{}));
CHECK_FALSE(meta::resolve_type<A1>().is_virtual_base_of<B1>());
CHECK_FALSE(meta::resolve_type<A1>().is_virtual_base_of<C1>());
CHECK_FALSE(meta::resolve_type<A1>().is_virtual_base_of<D1>()); CHECK_FALSE(meta::resolve_type<A1>().is_virtual_base_of<D1>());
CHECK_FALSE(meta::resolve_type<B1>().is_virtual_base_of<D1>());
CHECK_FALSE(meta::resolve_type<C1>().is_virtual_base_of<D1>());
} }
{ {
@@ -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&){}, C2{}));
CHECK(meta::is_invocable_with(+[](const A2&){}, D2{})); CHECK(meta::is_invocable_with(+[](const A2&){}, D2{}));
CHECK(meta::resolve_type<A2>().is_virtual_base_of<B2>());
CHECK(meta::resolve_type<A2>().is_virtual_base_of<C2>());
CHECK(meta::resolve_type<A2>().is_virtual_base_of<D2>()); CHECK(meta::resolve_type<A2>().is_virtual_base_of<D2>());
CHECK_FALSE(meta::resolve_type<B2>().is_virtual_base_of<D2>());
CHECK_FALSE(meta::resolve_type<C2>().is_virtual_base_of<D2>());
} }
{ {
@@ -91,6 +101,11 @@ TEST_CASE("meta/meta_features/ambiguous") {
CHECK(meta::is_invocable_with(+[](const A3&){}, C3{})); CHECK(meta::is_invocable_with(+[](const A3&){}, C3{}));
CHECK_FALSE(meta::is_invocable_with(+[](const A3&){}, D3{})); CHECK_FALSE(meta::is_invocable_with(+[](const A3&){}, D3{}));
CHECK(meta::resolve_type<A3>().is_virtual_base_of<B3>());
CHECK_FALSE(meta::resolve_type<A3>().is_virtual_base_of<C3>());
CHECK_FALSE(meta::resolve_type<A3>().is_virtual_base_of<D3>()); CHECK_FALSE(meta::resolve_type<A3>().is_virtual_base_of<D3>());
CHECK_FALSE(meta::resolve_type<B3>().is_virtual_base_of<D3>());
CHECK_FALSE(meta::resolve_type<C3>().is_virtual_base_of<D3>());
} }
} }

View File

@@ -120,47 +120,47 @@ TEST_CASE("meta/meta_features/diamond") {
CHECK(!E_type.is_derived_from(E_type)); CHECK(!E_type.is_derived_from(E_type));
} }
SUBCASE("unchecked_pointer_upcast") { SUBCASE("pointer_upcast") {
using meta::detail::unchecked_pointer_upcast; using meta::detail::pointer_upcast;
{ {
A a; A a;
CHECK(unchecked_pointer_upcast<A>(r, &a) == &a); CHECK(pointer_upcast<A>(r, &a) == &a);
CHECK_FALSE(unchecked_pointer_upcast<B>(r, &a)); CHECK_FALSE(pointer_upcast<B>(r, &a));
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &a)); CHECK_FALSE(pointer_upcast<C>(r, &a));
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &a)); CHECK_FALSE(pointer_upcast<D>(r, &a));
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &a)); CHECK_FALSE(pointer_upcast<E>(r, &a));
} }
{ {
const B b; const B b;
CHECK(unchecked_pointer_upcast<A>(r, &b) == &b); CHECK(pointer_upcast<A>(r, &b) == &b);
CHECK(unchecked_pointer_upcast<B>(r, &b) == &b); CHECK(pointer_upcast<B>(r, &b) == &b);
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &b)); CHECK_FALSE(pointer_upcast<C>(r, &b));
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &b)); CHECK_FALSE(pointer_upcast<D>(r, &b));
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &b)); CHECK_FALSE(pointer_upcast<E>(r, &b));
} }
{ {
C c; C c;
CHECK(unchecked_pointer_upcast<A>(r, &c) == &c); CHECK(pointer_upcast<A>(r, &c) == &c);
CHECK_FALSE(unchecked_pointer_upcast<B>(r, &c)); CHECK_FALSE(pointer_upcast<B>(r, &c));
CHECK(unchecked_pointer_upcast<C>(r, &c) == &c); CHECK(pointer_upcast<C>(r, &c) == &c);
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &c)); CHECK_FALSE(pointer_upcast<D>(r, &c));
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &c)); CHECK_FALSE(pointer_upcast<E>(r, &c));
} }
{ {
const D d; const D d;
CHECK(unchecked_pointer_upcast<A>(r, &d) == &d); CHECK(pointer_upcast<A>(r, &d) == &d);
CHECK(unchecked_pointer_upcast<B>(r, &d) == &d); CHECK(pointer_upcast<B>(r, &d) == &d);
CHECK(unchecked_pointer_upcast<C>(r, &d) == &d); CHECK(pointer_upcast<C>(r, &d) == &d);
CHECK(unchecked_pointer_upcast<D>(r, &d) == &d); CHECK(pointer_upcast<D>(r, &d) == &d);
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &d)); CHECK_FALSE(pointer_upcast<E>(r, &d));
} }
{ {
E e; E e;
CHECK_FALSE(unchecked_pointer_upcast<A>(r, &e)); CHECK_FALSE(pointer_upcast<A>(r, &e));
CHECK_FALSE(unchecked_pointer_upcast<B>(r, &e)); CHECK_FALSE(pointer_upcast<B>(r, &e));
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &e)); CHECK_FALSE(pointer_upcast<C>(r, &e));
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &e)); CHECK_FALSE(pointer_upcast<D>(r, &e));
CHECK(unchecked_pointer_upcast<E>(r, &e) == &e); CHECK(pointer_upcast<E>(r, &e) == &e);
} }
} }

View File

@@ -135,70 +135,70 @@ TEST_CASE("meta/meta_features/multiple2") {
CHECK(!E1_type.is_base_of(E1_type)); CHECK(!E1_type.is_base_of(E1_type));
} }
SUBCASE("unchecked_pointer_upcast") { SUBCASE("pointer_upcast") {
using meta::detail::type_registry; using meta::detail::type_registry;
using meta::detail::unchecked_pointer_upcast; using meta::detail::pointer_upcast;
type_registry& r{type_registry::instance()}; type_registry& r{type_registry::instance()};
{ {
A a; A a;
CHECK(unchecked_pointer_upcast<A>(r, &a) == &a); CHECK(unchecked_pointer_upcast<A>(r, &a)->a == "a"); CHECK(pointer_upcast<A>(r, &a) == &a); CHECK(pointer_upcast<A>(r, &a)->a == "a");
CHECK_FALSE(unchecked_pointer_upcast<B0>(r, &a)); CHECK_FALSE(pointer_upcast<B0>(r, &a));
CHECK_FALSE(unchecked_pointer_upcast<B1>(r, &a)); CHECK_FALSE(pointer_upcast<B1>(r, &a));
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &a)); CHECK_FALSE(pointer_upcast<C>(r, &a));
} }
{ {
B0 b0; B0 b0;
CHECK(unchecked_pointer_upcast<A>(r, &b0) == &b0); CHECK(unchecked_pointer_upcast<A>(r, &b0)->a == "a"); CHECK(pointer_upcast<A>(r, &b0) == &b0); CHECK(pointer_upcast<A>(r, &b0)->a == "a");
CHECK(unchecked_pointer_upcast<B0>(r, &b0) == &b0); CHECK(unchecked_pointer_upcast<B0>(r, &b0)->b0 == "b0"); CHECK(pointer_upcast<B0>(r, &b0) == &b0); CHECK(pointer_upcast<B0>(r, &b0)->b0 == "b0");
CHECK_FALSE(unchecked_pointer_upcast<B1>(r, &b0)); CHECK_FALSE(pointer_upcast<B1>(r, &b0));
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &b0)); CHECK_FALSE(pointer_upcast<C>(r, &b0));
} }
{ {
B1 b1; B1 b1;
CHECK(unchecked_pointer_upcast<A>(r, &b1) == &b1); CHECK(unchecked_pointer_upcast<A>(r, &b1)->a == "a"); CHECK(pointer_upcast<A>(r, &b1) == &b1); CHECK(pointer_upcast<A>(r, &b1)->a == "a");
CHECK_FALSE(unchecked_pointer_upcast<B0>(r, &b1)); CHECK_FALSE(pointer_upcast<B0>(r, &b1));
CHECK(unchecked_pointer_upcast<B1>(r, &b1) == &b1); CHECK(unchecked_pointer_upcast<B1>(r, &b1)->b1 == "b1"); CHECK(pointer_upcast<B1>(r, &b1) == &b1); CHECK(pointer_upcast<B1>(r, &b1)->b1 == "b1");
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &b1)); CHECK_FALSE(pointer_upcast<C>(r, &b1));
} }
{ {
C c; C c;
CHECK(unchecked_pointer_upcast<A>(r, &c) == &c); CHECK(unchecked_pointer_upcast<A>(r, &c)->a == "a"); CHECK(pointer_upcast<A>(r, &c) == &c); CHECK(pointer_upcast<A>(r, &c)->a == "a");
CHECK(unchecked_pointer_upcast<B0>(r, &c) == &c); CHECK(unchecked_pointer_upcast<B0>(r, &c)->b0 == "b0"); CHECK(pointer_upcast<B0>(r, &c) == &c); CHECK(pointer_upcast<B0>(r, &c)->b0 == "b0");
CHECK(unchecked_pointer_upcast<B1>(r, &c) == &c); CHECK(unchecked_pointer_upcast<B1>(r, &c)->b1 == "b1"); CHECK(pointer_upcast<B1>(r, &c) == &c); CHECK(pointer_upcast<B1>(r, &c)->b1 == "b1");
CHECK(unchecked_pointer_upcast<C>(r, &c) == &c); CHECK(unchecked_pointer_upcast<C>(r, &c)->c == "c"); CHECK(pointer_upcast<C>(r, &c) == &c); CHECK(pointer_upcast<C>(r, &c)->c == "c");
CHECK_FALSE(unchecked_pointer_upcast<D0>(r, &c)); CHECK_FALSE(pointer_upcast<D0>(r, &c));
CHECK_FALSE(unchecked_pointer_upcast<D1>(r, &c)); CHECK_FALSE(pointer_upcast<D1>(r, &c));
CHECK_FALSE(unchecked_pointer_upcast<E0>(r, &c)); CHECK_FALSE(pointer_upcast<E0>(r, &c));
CHECK_FALSE(unchecked_pointer_upcast<E1>(r, &c)); CHECK_FALSE(pointer_upcast<E1>(r, &c));
} }
{ {
E0 e0; E0 e0;
CHECK(unchecked_pointer_upcast<A>(r, &e0) == &e0); CHECK(unchecked_pointer_upcast<A>(r, &e0)->a == "a"); CHECK(pointer_upcast<A>(r, &e0) == &e0); CHECK(pointer_upcast<A>(r, &e0)->a == "a");
CHECK(unchecked_pointer_upcast<B0>(r, &e0) == &e0); CHECK(unchecked_pointer_upcast<B0>(r, &e0)->b0 == "b0"); CHECK(pointer_upcast<B0>(r, &e0) == &e0); CHECK(pointer_upcast<B0>(r, &e0)->b0 == "b0");
CHECK(unchecked_pointer_upcast<B1>(r, &e0) == &e0); CHECK(unchecked_pointer_upcast<B1>(r, &e0)->b1 == "b1"); CHECK(pointer_upcast<B1>(r, &e0) == &e0); CHECK(pointer_upcast<B1>(r, &e0)->b1 == "b1");
CHECK(unchecked_pointer_upcast<C>(r, &e0) == &e0); CHECK(unchecked_pointer_upcast<C>(r, &e0)->c == "c"); CHECK(pointer_upcast<C>(r, &e0) == &e0); CHECK(pointer_upcast<C>(r, &e0)->c == "c");
CHECK(unchecked_pointer_upcast<D0>(r, &e0) == &e0); CHECK(unchecked_pointer_upcast<D0>(r, &e0)->d0 == "d0"); CHECK(pointer_upcast<D0>(r, &e0) == &e0); CHECK(pointer_upcast<D0>(r, &e0)->d0 == "d0");
CHECK_FALSE(unchecked_pointer_upcast<D1>(r, &e0)); CHECK_FALSE(pointer_upcast<D1>(r, &e0));
CHECK(unchecked_pointer_upcast<E0>(r, &e0) == &e0); CHECK(unchecked_pointer_upcast<E0>(r, &e0)->e0 == "e0"); CHECK(pointer_upcast<E0>(r, &e0) == &e0); CHECK(pointer_upcast<E0>(r, &e0)->e0 == "e0");
CHECK_FALSE(unchecked_pointer_upcast<E1>(r, &e0)); CHECK_FALSE(pointer_upcast<E1>(r, &e0));
} }
{ {
E1 e1; E1 e1;
CHECK(unchecked_pointer_upcast<A>(r, &e1) == &e1); CHECK(unchecked_pointer_upcast<A>(r, &e1)->a == "a"); CHECK(pointer_upcast<A>(r, &e1) == &e1); CHECK(pointer_upcast<A>(r, &e1)->a == "a");
CHECK(unchecked_pointer_upcast<B0>(r, &e1) == &e1); CHECK(unchecked_pointer_upcast<B0>(r, &e1)->b0 == "b0"); CHECK(pointer_upcast<B0>(r, &e1) == &e1); CHECK(pointer_upcast<B0>(r, &e1)->b0 == "b0");
CHECK(unchecked_pointer_upcast<B1>(r, &e1) == &e1); CHECK(unchecked_pointer_upcast<B1>(r, &e1)->b1 == "b1"); CHECK(pointer_upcast<B1>(r, &e1) == &e1); CHECK(pointer_upcast<B1>(r, &e1)->b1 == "b1");
CHECK(unchecked_pointer_upcast<C>(r, &e1) == &e1); CHECK(unchecked_pointer_upcast<C>(r, &e1)->c == "c"); CHECK(pointer_upcast<C>(r, &e1) == &e1); CHECK(pointer_upcast<C>(r, &e1)->c == "c");
CHECK_FALSE(unchecked_pointer_upcast<D0>(r, &e1)); CHECK_FALSE(pointer_upcast<D0>(r, &e1));
CHECK(unchecked_pointer_upcast<D1>(r, &e1) == &e1); CHECK(unchecked_pointer_upcast<D1>(r, &e1)->d1 == "d1"); CHECK(pointer_upcast<D1>(r, &e1) == &e1); CHECK(pointer_upcast<D1>(r, &e1)->d1 == "d1");
CHECK_FALSE(unchecked_pointer_upcast<E0>(r, &e1)); CHECK_FALSE(pointer_upcast<E0>(r, &e1));
CHECK(unchecked_pointer_upcast<E1>(r, &e1) == &e1); CHECK(unchecked_pointer_upcast<E1>(r, &e1)->e1 == "e1"); CHECK(pointer_upcast<E1>(r, &e1) == &e1); CHECK(pointer_upcast<E1>(r, &e1)->e1 == "e1");
} }
} }
} }

View File

@@ -150,65 +150,65 @@ TEST_CASE("meta/meta_features/multiple") {
CHECK(!F_type.is_derived_from(F_type)); CHECK(!F_type.is_derived_from(F_type));
} }
SUBCASE("unchecked_pointer_upcast") { SUBCASE("pointer_upcast") {
using meta::detail::unchecked_pointer_upcast; using meta::detail::pointer_upcast;
{ {
A a; A a;
CHECK(unchecked_pointer_upcast<A>(r, &a) == &a); CHECK(pointer_upcast<A>(r, &a) == &a);
CHECK_FALSE(unchecked_pointer_upcast<B>(r, &a)); CHECK_FALSE(pointer_upcast<B>(r, &a));
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &a)); CHECK_FALSE(pointer_upcast<C>(r, &a));
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &a)); CHECK_FALSE(pointer_upcast<D>(r, &a));
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &a)); CHECK_FALSE(pointer_upcast<E>(r, &a));
CHECK_FALSE(unchecked_pointer_upcast<F>(r, &a)); CHECK_FALSE(pointer_upcast<F>(r, &a));
} }
{ {
const B b; const B b;
CHECK(unchecked_pointer_upcast<A>(r, &b) == &b); CHECK(pointer_upcast<A>(r, &b) == &b);
CHECK(unchecked_pointer_upcast<B>(r, &b) == &b); CHECK(pointer_upcast<B>(r, &b) == &b);
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &b)); CHECK_FALSE(pointer_upcast<C>(r, &b));
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &b)); CHECK_FALSE(pointer_upcast<D>(r, &b));
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &b)); CHECK_FALSE(pointer_upcast<E>(r, &b));
CHECK_FALSE(unchecked_pointer_upcast<F>(r, &b)); CHECK_FALSE(pointer_upcast<F>(r, &b));
} }
{ {
C c; C c;
CHECK(unchecked_pointer_upcast<A>(r, &c) == &c); CHECK(pointer_upcast<A>(r, &c) == &c);
CHECK_FALSE(unchecked_pointer_upcast<B>(r, &c)); CHECK_FALSE(pointer_upcast<B>(r, &c));
CHECK(unchecked_pointer_upcast<C>(r, &c) == &c); CHECK(pointer_upcast<C>(r, &c) == &c);
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &c)); CHECK_FALSE(pointer_upcast<D>(r, &c));
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &c)); CHECK_FALSE(pointer_upcast<E>(r, &c));
CHECK_FALSE(unchecked_pointer_upcast<F>(r, &c)); CHECK_FALSE(pointer_upcast<F>(r, &c));
} }
{ {
const D d; const D d;
// CHECK_FALSE(unchecked_pointer_upcast<A>(r,&d)); // ambiguous CHECK_FALSE(pointer_upcast<A>(r,&d));
CHECK(unchecked_pointer_upcast<A>(r, unchecked_pointer_upcast<B>(r,&d)) == static_cast<const A*>(static_cast<const B*>(&d))); CHECK(pointer_upcast<A>(r, pointer_upcast<B>(r,&d)) == static_cast<const A*>(static_cast<const B*>(&d)));
CHECK(unchecked_pointer_upcast<A>(r, unchecked_pointer_upcast<C>(r,&d)) == static_cast<const A*>(static_cast<const C*>(&d))); CHECK(pointer_upcast<A>(r, pointer_upcast<C>(r,&d)) == static_cast<const A*>(static_cast<const C*>(&d)));
CHECK(unchecked_pointer_upcast<B>(r, &d) == &d); CHECK(pointer_upcast<B>(r, &d) == &d);
CHECK(unchecked_pointer_upcast<C>(r, &d) == &d); CHECK(pointer_upcast<C>(r, &d) == &d);
CHECK(unchecked_pointer_upcast<D>(r, &d) == &d); CHECK(pointer_upcast<D>(r, &d) == &d);
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &d)); CHECK_FALSE(pointer_upcast<E>(r, &d));
CHECK_FALSE(unchecked_pointer_upcast<F>(r, &d)); CHECK_FALSE(pointer_upcast<F>(r, &d));
} }
{ {
const E e; const E e;
// CHECK_FALSE(unchecked_pointer_upcast<A>(r,&e)); // ambiguous CHECK_FALSE(pointer_upcast<A>(r,&e));
CHECK(unchecked_pointer_upcast<A>(r, unchecked_pointer_upcast<B>(r,&e)) == static_cast<const A*>(static_cast<const B*>(&e))); CHECK(pointer_upcast<A>(r, pointer_upcast<B>(r,&e)) == static_cast<const A*>(static_cast<const B*>(&e)));
CHECK(unchecked_pointer_upcast<A>(r, unchecked_pointer_upcast<C>(r,&e)) == static_cast<const A*>(static_cast<const C*>(&e))); CHECK(pointer_upcast<A>(r, pointer_upcast<C>(r,&e)) == static_cast<const A*>(static_cast<const C*>(&e)));
CHECK(unchecked_pointer_upcast<B>(r, &e) == &e); CHECK(pointer_upcast<B>(r, &e) == &e);
CHECK(unchecked_pointer_upcast<C>(r, &e) == &e); CHECK(pointer_upcast<C>(r, &e) == &e);
CHECK(unchecked_pointer_upcast<D>(r, &e) == &e); CHECK(pointer_upcast<D>(r, &e) == &e);
CHECK(unchecked_pointer_upcast<E>(r, &e) == &e); CHECK(pointer_upcast<E>(r, &e) == &e);
CHECK_FALSE(unchecked_pointer_upcast<F>(r, &e)); CHECK_FALSE(pointer_upcast<F>(r, &e));
} }
{ {
F f; F f;
CHECK_FALSE(unchecked_pointer_upcast<A>(r, &f)); CHECK_FALSE(pointer_upcast<A>(r, &f));
CHECK_FALSE(unchecked_pointer_upcast<B>(r, &f)); CHECK_FALSE(pointer_upcast<B>(r, &f));
CHECK_FALSE(unchecked_pointer_upcast<C>(r, &f)); CHECK_FALSE(pointer_upcast<C>(r, &f));
CHECK_FALSE(unchecked_pointer_upcast<D>(r, &f)); CHECK_FALSE(pointer_upcast<D>(r, &f));
CHECK_FALSE(unchecked_pointer_upcast<E>(r, &f)); CHECK_FALSE(pointer_upcast<E>(r, &f));
CHECK(unchecked_pointer_upcast<F>(r, &f) == &f); CHECK(pointer_upcast<F>(r, &f) == &f);
} }
} }
} }

View File

@@ -18,6 +18,7 @@
#include "meta_base/hashed_string.hpp" #include "meta_base/hashed_string.hpp"
#include "meta_base/insert_or_assign.hpp" #include "meta_base/insert_or_assign.hpp"
#include "meta_base/intrusive_ptr.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_in_place_type.hpp"
#include "meta_base/is_virtual_base_of.hpp" #include "meta_base/is_virtual_base_of.hpp"
#include "meta_base/memory_buffer.hpp" #include "meta_base/memory_buffer.hpp"

View File

@@ -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<>{});
}
}

View File

@@ -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); 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; 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 ) { 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; 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 ) { 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); 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( // inline void updata_derived_classes_db( //

View File

@@ -258,7 +258,7 @@ namespace meta_hpp::detail
if ( from_type.is_array() ) { if ( from_type.is_array() ) {
const array_type& from_type_array = from_type.as_array(); const array_type& from_type_array = from_type.as_array();
void* to_ptr = unchecked_pointer_upcast( // void* to_ptr = pointer_upcast( //
data_, data_,
from_type_array.get_data_type(), from_type_array.get_data_type(),
to_type_ptr.get_data_type() to_type_ptr.get_data_type()
@@ -271,7 +271,7 @@ namespace meta_hpp::detail
if ( from_type.is_pointer() ) { if ( from_type.is_pointer() ) {
const pointer_type& from_type_ptr = from_type.as_pointer(); const pointer_type& from_type_ptr = from_type.as_pointer();
void* to_ptr = unchecked_pointer_upcast( // void* to_ptr = pointer_upcast( //
*static_cast<void**>(data_), *static_cast<void**>(data_),
from_type_ptr.get_data_type(), from_type_ptr.get_data_type(),
to_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& from_type = get_raw_type();
const any_type& to_type = registry.resolve_type<to_raw_type>(); const any_type& to_type = registry.resolve_type<to_raw_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); META_HPP_ASSERT(to_ptr);
if constexpr ( std::is_lvalue_reference_v<To> ) { if constexpr ( std::is_lvalue_reference_v<To> ) {

View File

@@ -192,7 +192,7 @@ namespace meta_hpp::detail
const any_type& to_type = registry.resolve_type<inst_class>(); const any_type& to_type = registry.resolve_type<inst_class>();
if ( from_type.is_class() && to_type.is_class() ) { if ( from_type.is_class() && to_type.is_class() ) {
void* to_ptr = unchecked_pointer_upcast( // void* to_ptr = pointer_upcast( //
data_, data_,
from_type.as_class(), from_type.as_class(),
to_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(); const any_type& from_data_type = from_type_ptr.get_data_type();
if ( from_data_type.is_class() && to_type.is_class() ) { if ( from_data_type.is_class() && to_type.is_class() ) {
void* to_ptr = unchecked_pointer_upcast( // void* to_ptr = pointer_upcast( //
*static_cast<void**>(data_), *static_cast<void**>(data_),
from_data_type.as_class(), from_data_type.as_class(),
to_type.as_class() to_type.as_class()

View File

@@ -109,14 +109,8 @@ namespace meta_hpp::detail
const class_type_data& derived_data = *type_access(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; 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 ( auto iter{deep_upcasts.find(base)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) {
if ( const auto next_iter{std::next(iter)}; next_iter == deep_upcasts.end() || next_iter->first != base ) { return true;
return true;
}
if ( base_class.is_virtual_base_of(derived_class) ) {
return true;
}
} }
} }
@@ -126,7 +120,7 @@ namespace meta_hpp::detail
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 ) { if ( nullptr == ptr || !from || !to ) {
return nullptr; return nullptr;
} }
@@ -136,23 +130,24 @@ namespace meta_hpp::detail
} }
const class_type_data& from_data = *type_access(from); 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 iter->second.apply(ptr);
} }
return nullptr; 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) // NOLINTNEXTLINE(*-const-cast)
return unchecked_pointer_upcast(const_cast<void*>(ptr), from, to); return pointer_upcast(const_cast<void*>(ptr), from, to);
} }
} }
namespace meta_hpp::detail 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 ) { if ( nullptr == ptr || !from || !to ) {
return nullptr; return nullptr;
} }
@@ -165,7 +160,7 @@ namespace meta_hpp::detail
const class_type& from_class = from.as_class(); const class_type& from_class = from.as_class();
if ( to_class && from_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; return base_ptr;
} }
} }
@@ -173,17 +168,17 @@ namespace meta_hpp::detail
return nullptr; 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) // NOLINTNEXTLINE(*-const-cast)
return unchecked_pointer_upcast(const_cast<void*>(ptr), from, to); return pointer_upcast(const_cast<void*>(ptr), from, to);
} }
} }
namespace meta_hpp::detail namespace meta_hpp::detail
{ {
template < typename To, typename From > template < typename To, typename From >
[[nodiscard]] To* unchecked_pointer_upcast(type_registry& registry, From* ptr) { [[nodiscard]] To* pointer_upcast(type_registry& registry, From* ptr) {
return static_cast<To*>(unchecked_pointer_upcast( // return static_cast<To*>(pointer_upcast( //
ptr, ptr,
registry.resolve_type<From>(), registry.resolve_type<From>(),
registry.resolve_type<To>() registry.resolve_type<To>()
@@ -191,8 +186,8 @@ namespace meta_hpp::detail
} }
template < typename To, typename From > template < typename To, typename From >
[[nodiscard]] const To* unchecked_pointer_upcast(type_registry& registry, const From* ptr) { [[nodiscard]] const To* pointer_upcast(type_registry& registry, const From* ptr) {
return static_cast<const To*>(unchecked_pointer_upcast( // return static_cast<const To*>(pointer_upcast( //
ptr, ptr,
registry.resolve_type<From>(), registry.resolve_type<From>(),
registry.resolve_type<To>() registry.resolve_type<To>()

View File

@@ -419,9 +419,11 @@ namespace meta_hpp::detail
variable_set variables; variable_set variables;
struct upcast_func_t final { struct upcast_func_t final {
void* (*upcast)(void*){}; using upcast_t = void* (*)(void*);
bool is_virtual_upcast{};
class_type target_class{}; upcast_t upcast{};
class_type target{};
bool is_virtual{};
template < typename Derived, typename Base > template < typename Derived, typename Base >
requires std::is_base_of_v<Base, Derived> requires std::is_base_of_v<Base, Derived>
@@ -432,11 +434,14 @@ namespace meta_hpp::detail
}; };
struct upcast_func_list_t final { struct upcast_func_list_t final {
class_set vbases; using upcasts_t = std::vector<upcast_func_t>;
std::vector<upcast_func_t> upcasts;
upcasts_t upcasts{};
class_set vbases{};
bool is_ambiguous{};
upcast_func_list_t(const upcast_func_t& _upcast); upcast_func_list_t(const upcast_func_t& _upcast);
upcast_func_list_t(class_set _vbases, std::vector<upcast_func_t> _upcasts); upcast_func_list_t(upcasts_t _upcasts, class_set _vbases);
[[nodiscard]] void* apply(void* ptr) const noexcept; [[nodiscard]] void* apply(void* ptr) const noexcept;
[[nodiscard]] const void* apply(const 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<class_type, upcast_func_t, std::less<>>; using base_upcasts_t = std::map<class_type, upcast_func_t, std::less<>>;
using deep_upcasts_t = std::multimap<class_type, upcast_func_list_t, std::less<>>; using deep_upcasts_t = std::map<class_type, upcast_func_list_t, std::less<>>;
base_upcasts_t base_upcasts; base_upcasts_t base_upcasts;
deep_upcasts_t deep_upcasts; deep_upcasts_t deep_upcasts;

View File

@@ -38,8 +38,8 @@ namespace meta_hpp::detail
requires std::is_base_of_v<Base, Derived> requires std::is_base_of_v<Base, Derived>
inline class_type_data::upcast_func_t::upcast_func_t(std::in_place_type_t<Derived>, std::in_place_type_t<Base>) inline class_type_data::upcast_func_t::upcast_func_t(std::in_place_type_t<Derived>, std::in_place_type_t<Base>)
: upcast{[](void* from) -> void* { return static_cast<Base*>(static_cast<Derived*>(from)); }} : upcast{[](void* from) -> void* { return static_cast<Base*>(static_cast<Derived*>(from)); }}
, is_virtual_upcast{is_virtual_base_of_v<Base, Derived>} , target{resolve_type<Base>()}
, target_class{resolve_type<Base>()} {} , is_virtual{is_virtual_base_of_v<Base, Derived>} {}
inline void* class_type_data::upcast_func_t::apply(void* ptr) const noexcept { inline void* class_type_data::upcast_func_t::apply(void* ptr) const noexcept {
return upcast(ptr); 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) inline class_type_data::upcast_func_list_t::upcast_func_list_t(const upcast_func_t& _upcast)
: upcasts{_upcast} { : upcasts{_upcast} {
for ( const upcast_func_t& upcast : upcasts ) { for ( const upcast_func_t& upcast : upcasts ) {
if ( upcast.is_virtual_upcast ) { if ( upcast.is_virtual ) {
vbases.emplace(upcast.target_class); vbases.emplace(upcast.target);
} }
} }
} }
inline class_type_data::upcast_func_list_t::upcast_func_list_t(class_set _vbases, std::vector<upcast_func_t> _upcasts) inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcasts_t _upcasts, class_set _vbases)
: vbases{std::move(_vbases)} : upcasts{std::move(_upcasts)}
, upcasts{std::move(_upcasts)} {} , vbases{std::move(_vbases)} {}
inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept { inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept {
for ( const upcast_func_t& upcast : upcasts ) { 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& l,
const class_type_data::upcast_func_list_t& r const class_type_data::upcast_func_list_t& r
) { ) {
class_set new_vbases; class_type_data::upcast_func_list_t::upcasts_t new_upcasts;
new_vbases.insert(l.vbases.begin(), l.vbases.end());
new_vbases.insert(r.vbases.begin(), r.vbases.end());
std::vector<class_type_data::upcast_func_t> new_upcasts;
new_upcasts.reserve(l.upcasts.size() + r.upcasts.size()); 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(), l.upcasts.begin(), l.upcasts.end());
new_upcasts.insert(new_upcasts.end(), r.upcasts.begin(), r.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; return false;
} }
const detail::class_type_data& derived_data = *derived.data_; using deep_upcasts_t = detail::class_type_data::deep_upcasts_t;
const auto upcasts_range = derived_data.deep_upcasts.equal_range(*this); const deep_upcasts_t& deep_upcasts = derived.data_->deep_upcasts;
if ( upcasts_range.first == upcasts_range.second ) { if ( auto iter{deep_upcasts.find(*this)}; iter != deep_upcasts.end() ) {
return false; return !iter->second.is_ambiguous && !iter->second.vbases.empty();
} }
const class_set& first_vbases = upcasts_range.first->second.vbases; return false;
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 > template < detail::class_kind Base >