mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-13 19:18:01 +07:00
new deep upcasts, remove is_virtual_base_of
This commit is contained in:
@@ -1157,38 +1157,6 @@ namespace meta_hpp::detail
|
||||
inline constexpr bool is_in_place_type_v = is_in_place_type<T>::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<const volatile To*>(std::declval<const volatile From*>())) = 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<bool,
|
||||
std::is_base_of_v<Base, Derived> &&
|
||||
impl::is_virtual_base_of_impl<Derived, Base>(0) &&
|
||||
!impl::is_virtual_base_of_impl<Base, Derived>(0)> {};
|
||||
|
||||
// clang-format on
|
||||
|
||||
template < typename Base, typename Derived >
|
||||
inline constexpr bool is_virtual_base_of_v = is_virtual_base_of<Base, Derived>::value;
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
class memory_buffer final {
|
||||
@@ -1456,7 +1424,13 @@ namespace meta_hpp::detail
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename... Types >
|
||||
struct type_list {};
|
||||
struct type_list {
|
||||
template < typename F >
|
||||
// NOLINTNEXTLINE(*-missing-std-forward)
|
||||
static void for_each(F&& f) {
|
||||
(f.template operator()<Types>(), ...);
|
||||
}
|
||||
};
|
||||
|
||||
template < std::size_t I >
|
||||
using size_constant = std::integral_constant<std::size_t, I>;
|
||||
@@ -2587,6 +2561,10 @@ namespace meta_hpp
|
||||
return id_type{data_};
|
||||
}
|
||||
|
||||
[[nodiscard]] explicit operator id_type() const noexcept {
|
||||
return get_id();
|
||||
}
|
||||
|
||||
[[nodiscard]] type_kind get_kind() const noexcept {
|
||||
return data_->kind;
|
||||
}
|
||||
@@ -2697,10 +2675,6 @@ 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;
|
||||
@@ -2709,10 +2683,6 @@ 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, bool recursively = true) const noexcept;
|
||||
[[nodiscard]] member get_member(std::string_view name, bool recursively = true) const noexcept;
|
||||
[[nodiscard]] method get_method(std::string_view name, bool recursively = true) const noexcept;
|
||||
@@ -2975,39 +2945,14 @@ namespace meta_hpp::detail
|
||||
struct upcast_func_t final {
|
||||
using upcast_t = void* (*)(void*);
|
||||
|
||||
type_id target{};
|
||||
upcast_t upcast{};
|
||||
class_type target{};
|
||||
bool is_virtual{};
|
||||
|
||||
template < typename Derived, typename Base >
|
||||
requires std::is_base_of_v<Base, Derived>
|
||||
upcast_func_t(std::in_place_type_t<Derived>, std::in_place_type_t<Base>);
|
||||
|
||||
[[nodiscard]] void* apply(void* ptr) const noexcept;
|
||||
[[nodiscard]] const void* apply(const void* ptr) const noexcept;
|
||||
};
|
||||
|
||||
struct upcast_func_list_t final {
|
||||
using upcasts_t = std::vector<upcast_func_t>;
|
||||
using vbases_t = std::set<class_type, std::less<>>;
|
||||
|
||||
upcasts_t upcasts{};
|
||||
vbases_t vbases{};
|
||||
bool is_ambiguous{};
|
||||
|
||||
explicit upcast_func_list_t(const upcast_func_t& in_upcast);
|
||||
upcast_func_list_t(upcasts_t in_upcasts, vbases_t in_vbases);
|
||||
|
||||
[[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);
|
||||
};
|
||||
|
||||
using base_upcasts_t = std::map<class_type, upcast_func_t, std::less<>>;
|
||||
using deep_upcasts_t = std::map<class_type, upcast_func_list_t, std::less<>>;
|
||||
|
||||
base_upcasts_t base_upcasts;
|
||||
using deep_upcasts_t = std::vector<upcast_func_t>;
|
||||
deep_upcasts_t deep_upcasts;
|
||||
|
||||
template < class_kind Class >
|
||||
@@ -5762,8 +5707,10 @@ 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 ( auto iter{deep_upcasts.find(base)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) {
|
||||
return true;
|
||||
for ( const auto& upcast : deep_upcasts ) {
|
||||
if ( upcast.target == base_class ) {
|
||||
return upcast.upcast != nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5785,8 +5732,10 @@ 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{deep_upcasts.find(to)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) {
|
||||
return iter->second.apply(ptr);
|
||||
for ( const auto& upcast : deep_upcasts ) {
|
||||
if ( upcast.target == to ) {
|
||||
return upcast.upcast != nullptr ? upcast.apply(ptr) : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -8358,59 +8307,52 @@ namespace meta_hpp::detail
|
||||
, size{class_traits<Class>::size}
|
||||
, align{class_traits<Class>::align}
|
||||
, argument_types{resolve_types(typename class_traits<Class>::argument_types{})} {
|
||||
if constexpr ( check_base_info_enabled<Class> ) {
|
||||
using meta_base_info = typename Class::meta_base_info;
|
||||
struct {
|
||||
class_list base_classes;
|
||||
deep_upcasts_t deep_upcasts;
|
||||
} new_base_data;
|
||||
|
||||
[this]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
struct {
|
||||
class_list base_classes;
|
||||
base_upcasts_t base_upcasts;
|
||||
deep_upcasts_t deep_upcasts;
|
||||
} new_base_data;
|
||||
const auto add_new_base = [&new_base_data]<class_kind Base, class_kind Derived>(auto&& recur) {
|
||||
const class_type& base_class = resolve_type<Base>();
|
||||
|
||||
[[maybe_unused]] const auto add_base_class = [&new_base_data]<class_kind Base>() {
|
||||
const class_type& base_class = resolve_type<Base>();
|
||||
const class_type_data& base_data = *type_access(base_class);
|
||||
|
||||
upcast_func_t self_to_base{std::in_place_type<Class>, std::in_place_type<Base>};
|
||||
upcast_func_list_t self_to_base_list{self_to_base};
|
||||
|
||||
new_base_data.base_classes.emplace_back(base_class);
|
||||
new_base_data.base_upcasts.emplace(base_class, self_to_base);
|
||||
|
||||
for ( const auto& [deep_class, base_to_deep] : base_data.deep_upcasts ) {
|
||||
upcast_func_list_t self_to_deep = self_to_base_list + base_to_deep;
|
||||
|
||||
const auto& [position, emplaced] = new_base_data.deep_upcasts.try_emplace(
|
||||
deep_class, std::move(self_to_deep)
|
||||
);
|
||||
|
||||
if ( !emplaced ) {
|
||||
position->second.is_ambiguous = is_disjoint(position->second.vbases, self_to_deep.vbases);
|
||||
}
|
||||
new_base_data.deep_upcasts.push_back(upcast_func_t{
|
||||
.target{base_class},
|
||||
.upcast{[]() {
|
||||
if constexpr ( requires { static_cast<Base*>(std::declval<Class*>()); } ) {
|
||||
return +[](void* from) -> void* { return static_cast<Base*>(static_cast<Class*>(from)); };
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}()},
|
||||
});
|
||||
|
||||
new_base_data.deep_upcasts.emplace(base_class, std::move(self_to_base_list));
|
||||
};
|
||||
(add_base_class.template operator()<type_list_at_t<Is, meta_base_info>>(), ...);
|
||||
if constexpr ( std::is_same_v<Class, Derived> ) {
|
||||
new_base_data.base_classes.push_back(base_class);
|
||||
}
|
||||
|
||||
base_classes.swap(new_base_data.base_classes);
|
||||
base_upcasts.swap(new_base_data.base_upcasts);
|
||||
deep_upcasts.swap(new_base_data.deep_upcasts);
|
||||
}(std::make_index_sequence<type_list_arity_v<meta_base_info>>());
|
||||
}
|
||||
recur.template operator()<Base>(recur);
|
||||
};
|
||||
|
||||
const auto add_new_bases = [&add_new_base]<class_kind Derived>(auto&& recur) {
|
||||
if constexpr ( check_base_info_enabled<Derived> ) {
|
||||
using meta_base_info = typename Derived::meta_base_info;
|
||||
meta_base_info::for_each([&add_new_base, &recur]<class_kind Base>() {
|
||||
add_new_base.template operator()<Base, Derived>(recur);
|
||||
});
|
||||
} else {
|
||||
(void)recur;
|
||||
}
|
||||
};
|
||||
|
||||
add_new_bases.template operator()<Class>(add_new_bases);
|
||||
|
||||
base_classes.swap(new_base_data.base_classes);
|
||||
deep_upcasts.swap(new_base_data.deep_upcasts);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename Derived, typename Base >
|
||||
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>)
|
||||
: upcast{[](void* from) -> void* { return static_cast<Base*>(static_cast<Derived*>(from)); }}
|
||||
, target{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 {
|
||||
return upcast(ptr);
|
||||
}
|
||||
@@ -8421,52 +8363,6 @@ namespace meta_hpp::detail
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
inline class_type_data::upcast_func_list_t::upcast_func_list_t(const upcast_func_t& in_upcast)
|
||||
: upcasts{in_upcast} {
|
||||
for ( const upcast_func_t& upcast : upcasts ) {
|
||||
if ( upcast.is_virtual ) {
|
||||
vbases.emplace(upcast.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcasts_t in_upcasts, vbases_t in_vbases)
|
||||
: upcasts{std::move(in_upcasts)}
|
||||
, vbases{std::move(in_vbases)} {}
|
||||
|
||||
inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept {
|
||||
for ( const upcast_func_t& upcast : upcasts ) {
|
||||
ptr = upcast.apply(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<void*>(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
|
||||
) {
|
||||
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());
|
||||
|
||||
class_type_data::upcast_func_list_t::vbases_t new_vbases;
|
||||
new_vbases.insert(l.vbases.begin(), l.vbases.end());
|
||||
new_vbases.insert(r.vbases.begin(), r.vbases.end());
|
||||
|
||||
class_type_data::upcast_func_list_t result{std::move(new_upcasts), std::move(new_vbases)};
|
||||
result.is_ambiguous = l.is_ambiguous || r.is_ambiguous;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
inline class_bitflags class_type::get_flags() const noexcept {
|
||||
@@ -8576,7 +8472,17 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
inline bool class_type::is_base_of(const class_type& derived) const noexcept {
|
||||
return is_valid() && derived.is_valid() && derived.data_->deep_upcasts.contains(*this);
|
||||
if ( !is_valid() || !derived.is_valid() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( const auto& upcast : derived.data_->deep_upcasts ) {
|
||||
if ( upcast.target == *this ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template < detail::class_kind Derived >
|
||||
@@ -8585,24 +8491,14 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
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 Derived >
|
||||
bool class_type::is_virtual_base_of() const noexcept {
|
||||
return is_virtual_base_of(resolve_type<Derived>());
|
||||
}
|
||||
|
||||
inline bool class_type::is_virtual_base_of(const class_type& derived) const noexcept {
|
||||
if ( !is_valid() || !derived.is_valid() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
using deep_upcasts_t = detail::class_type_data::deep_upcasts_t;
|
||||
const deep_upcasts_t& deep_upcasts = derived.data_->deep_upcasts;
|
||||
|
||||
if ( auto iter{deep_upcasts.find(*this)}; iter != deep_upcasts.end() ) {
|
||||
return !iter->second.is_ambiguous && !iter->second.vbases.empty();
|
||||
for ( const class_type& base_class : derived.data_->base_classes ) {
|
||||
if ( base_class == *this ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -8626,15 +8522,6 @@ namespace meta_hpp
|
||||
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<Base>());
|
||||
}
|
||||
|
||||
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, bool recursively) const noexcept {
|
||||
for ( const function& function : data_->functions ) {
|
||||
if ( function.get_name() == name ) {
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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>
|
||||
|
||||
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<A, A>);
|
||||
static_assert(is_virtual_base_of_v<A, B>);
|
||||
static_assert(is_virtual_base_of_v<A, C>);
|
||||
|
||||
static_assert(is_virtual_base_of_v<A, D>);
|
||||
static_assert(!is_virtual_base_of_v<B, D>);
|
||||
static_assert(!is_virtual_base_of_v<C, D>);
|
||||
|
||||
static_assert(!is_virtual_base_of_v<A, E>);
|
||||
static_assert(!is_virtual_base_of_v<E, A>);
|
||||
|
||||
static_assert(!is_virtual_base_of_v<E, D>);
|
||||
static_assert(!is_virtual_base_of_v<D, E>);
|
||||
}
|
||||
|
||||
{
|
||||
static_assert(!is_virtual_base_of_v<I, I>);
|
||||
static_assert(is_virtual_base_of_v<I, J>);
|
||||
static_assert(is_virtual_base_of_v<I, K>);
|
||||
|
||||
static_assert(!is_virtual_base_of_v<J, I>);
|
||||
static_assert(!is_virtual_base_of_v<J, J>);
|
||||
static_assert(!is_virtual_base_of_v<J, K>);
|
||||
|
||||
static_assert(!is_virtual_base_of_v<K, I>);
|
||||
static_assert(!is_virtual_base_of_v<K, J>);
|
||||
static_assert(!is_virtual_base_of_v<K, K>);
|
||||
}
|
||||
|
||||
{
|
||||
static_assert(is_virtual_base_of_v<I, J>);
|
||||
|
||||
static_assert(is_virtual_base_of_v<const I, J>);
|
||||
static_assert(is_virtual_base_of_v<volatile I, J>);
|
||||
static_assert(is_virtual_base_of_v<const volatile I, J>);
|
||||
|
||||
static_assert(is_virtual_base_of_v<const I, const J>);
|
||||
static_assert(is_virtual_base_of_v<volatile I, const J>);
|
||||
static_assert(is_virtual_base_of_v<const volatile I, const J>);
|
||||
|
||||
static_assert(is_virtual_base_of_v<const I, volatile J>);
|
||||
static_assert(is_virtual_base_of_v<volatile I, volatile J>);
|
||||
static_assert(is_virtual_base_of_v<const volatile I, volatile J>);
|
||||
|
||||
static_assert(is_virtual_base_of_v<const I, const volatile J>);
|
||||
static_assert(is_virtual_base_of_v<volatile I, const volatile J>);
|
||||
static_assert(is_virtual_base_of_v<const volatile I, const volatile J>);
|
||||
}
|
||||
}
|
||||
@@ -42,13 +42,6 @@ TEST_CASE("meta/meta_features/ambiguous") {
|
||||
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<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<B1>().is_virtual_base_of<D1>());
|
||||
CHECK_FALSE(meta::resolve_type<C1>().is_virtual_base_of<D1>());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -65,13 +58,6 @@ TEST_CASE("meta/meta_features/ambiguous") {
|
||||
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<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_FALSE(meta::resolve_type<B2>().is_virtual_base_of<D2>());
|
||||
CHECK_FALSE(meta::resolve_type<C2>().is_virtual_base_of<D2>());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -88,12 +74,5 @@ TEST_CASE("meta/meta_features/ambiguous") {
|
||||
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(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<B3>().is_virtual_base_of<D3>());
|
||||
CHECK_FALSE(meta::resolve_type<C3>().is_virtual_base_of<D3>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,8 +51,6 @@ TEST_CASE("meta/meta_issues/random/1") {
|
||||
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<A1>().is_virtual_base_of<D1>());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -65,8 +63,6 @@ TEST_CASE("meta/meta_issues/random/1") {
|
||||
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<A2>().is_virtual_base_of<E2>());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -79,7 +75,5 @@ TEST_CASE("meta/meta_issues/random/1") {
|
||||
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<A3>().is_virtual_base_of<D3>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#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"
|
||||
#include "meta_base/noncopyable.hpp"
|
||||
#include "meta_base/nonesuch.hpp"
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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<const volatile To*>(std::declval<const volatile From*>())) = 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<bool,
|
||||
std::is_base_of_v<Base, Derived> &&
|
||||
impl::is_virtual_base_of_impl<Derived, Base>(0) &&
|
||||
!impl::is_virtual_base_of_impl<Base, Derived>(0)> {};
|
||||
|
||||
// clang-format on
|
||||
|
||||
template < typename Base, typename Derived >
|
||||
inline constexpr bool is_virtual_base_of_v = is_virtual_base_of<Base, Derived>::value;
|
||||
}
|
||||
@@ -11,7 +11,13 @@
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename... Types >
|
||||
struct type_list {};
|
||||
struct type_list {
|
||||
template < typename F >
|
||||
// NOLINTNEXTLINE(*-missing-std-forward)
|
||||
static void for_each(F&& f) {
|
||||
(f.template operator()<Types>(), ...);
|
||||
}
|
||||
};
|
||||
|
||||
template < std::size_t I >
|
||||
using size_constant = std::integral_constant<std::size_t, I>;
|
||||
|
||||
@@ -109,8 +109,10 @@ 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 ( auto iter{deep_upcasts.find(base)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) {
|
||||
return true;
|
||||
for ( const auto& upcast : deep_upcasts ) {
|
||||
if ( upcast.target == base_class ) {
|
||||
return upcast.upcast != nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,8 +134,10 @@ 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{deep_upcasts.find(to)}; iter != deep_upcasts.end() && !iter->second.is_ambiguous ) {
|
||||
return iter->second.apply(ptr);
|
||||
for ( const auto& upcast : deep_upcasts ) {
|
||||
if ( upcast.target == to ) {
|
||||
return upcast.upcast != nullptr ? upcast.apply(ptr) : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
@@ -126,6 +126,10 @@ namespace meta_hpp
|
||||
return id_type{data_};
|
||||
}
|
||||
|
||||
[[nodiscard]] explicit operator id_type() const noexcept {
|
||||
return get_id();
|
||||
}
|
||||
|
||||
[[nodiscard]] type_kind get_kind() const noexcept {
|
||||
return data_->kind;
|
||||
}
|
||||
@@ -236,10 +240,6 @@ 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;
|
||||
@@ -248,10 +248,6 @@ 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, bool recursively = true) const noexcept;
|
||||
[[nodiscard]] member get_member(std::string_view name, bool recursively = true) const noexcept;
|
||||
[[nodiscard]] method get_method(std::string_view name, bool recursively = true) const noexcept;
|
||||
@@ -514,39 +510,14 @@ namespace meta_hpp::detail
|
||||
struct upcast_func_t final {
|
||||
using upcast_t = void* (*)(void*);
|
||||
|
||||
type_id target{};
|
||||
upcast_t upcast{};
|
||||
class_type target{};
|
||||
bool is_virtual{};
|
||||
|
||||
template < typename Derived, typename Base >
|
||||
requires std::is_base_of_v<Base, Derived>
|
||||
upcast_func_t(std::in_place_type_t<Derived>, std::in_place_type_t<Base>);
|
||||
|
||||
[[nodiscard]] void* apply(void* ptr) const noexcept;
|
||||
[[nodiscard]] const void* apply(const void* ptr) const noexcept;
|
||||
};
|
||||
|
||||
struct upcast_func_list_t final {
|
||||
using upcasts_t = std::vector<upcast_func_t>;
|
||||
using vbases_t = std::set<class_type, std::less<>>;
|
||||
|
||||
upcasts_t upcasts{};
|
||||
vbases_t vbases{};
|
||||
bool is_ambiguous{};
|
||||
|
||||
explicit upcast_func_list_t(const upcast_func_t& in_upcast);
|
||||
upcast_func_list_t(upcasts_t in_upcasts, vbases_t in_vbases);
|
||||
|
||||
[[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);
|
||||
};
|
||||
|
||||
using base_upcasts_t = std::map<class_type, upcast_func_t, std::less<>>;
|
||||
using deep_upcasts_t = std::map<class_type, upcast_func_list_t, std::less<>>;
|
||||
|
||||
base_upcasts_t base_upcasts;
|
||||
using deep_upcasts_t = std::vector<upcast_func_t>;
|
||||
deep_upcasts_t deep_upcasts;
|
||||
|
||||
template < class_kind Class >
|
||||
|
||||
@@ -27,59 +27,52 @@ namespace meta_hpp::detail
|
||||
, size{class_traits<Class>::size}
|
||||
, align{class_traits<Class>::align}
|
||||
, argument_types{resolve_types(typename class_traits<Class>::argument_types{})} {
|
||||
if constexpr ( check_base_info_enabled<Class> ) {
|
||||
using meta_base_info = typename Class::meta_base_info;
|
||||
struct {
|
||||
class_list base_classes;
|
||||
deep_upcasts_t deep_upcasts;
|
||||
} new_base_data;
|
||||
|
||||
[this]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
struct {
|
||||
class_list base_classes;
|
||||
base_upcasts_t base_upcasts;
|
||||
deep_upcasts_t deep_upcasts;
|
||||
} new_base_data;
|
||||
const auto add_new_base = [&new_base_data]<class_kind Base, class_kind Derived>(auto&& recur) {
|
||||
const class_type& base_class = resolve_type<Base>();
|
||||
|
||||
[[maybe_unused]] const auto add_base_class = [&new_base_data]<class_kind Base>() {
|
||||
const class_type& base_class = resolve_type<Base>();
|
||||
const class_type_data& base_data = *type_access(base_class);
|
||||
|
||||
upcast_func_t self_to_base{std::in_place_type<Class>, std::in_place_type<Base>};
|
||||
upcast_func_list_t self_to_base_list{self_to_base};
|
||||
|
||||
new_base_data.base_classes.emplace_back(base_class);
|
||||
new_base_data.base_upcasts.emplace(base_class, self_to_base);
|
||||
|
||||
for ( const auto& [deep_class, base_to_deep] : base_data.deep_upcasts ) {
|
||||
upcast_func_list_t self_to_deep = self_to_base_list + base_to_deep;
|
||||
|
||||
const auto& [position, emplaced] = new_base_data.deep_upcasts.try_emplace(
|
||||
deep_class, std::move(self_to_deep)
|
||||
);
|
||||
|
||||
if ( !emplaced ) {
|
||||
position->second.is_ambiguous = is_disjoint(position->second.vbases, self_to_deep.vbases);
|
||||
}
|
||||
new_base_data.deep_upcasts.push_back(upcast_func_t{
|
||||
.target{base_class},
|
||||
.upcast{[]() {
|
||||
if constexpr ( requires { static_cast<Base*>(std::declval<Class*>()); } ) {
|
||||
return +[](void* from) -> void* { return static_cast<Base*>(static_cast<Class*>(from)); };
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}()},
|
||||
});
|
||||
|
||||
new_base_data.deep_upcasts.emplace(base_class, std::move(self_to_base_list));
|
||||
};
|
||||
(add_base_class.template operator()<type_list_at_t<Is, meta_base_info>>(), ...);
|
||||
if constexpr ( std::is_same_v<Class, Derived> ) {
|
||||
new_base_data.base_classes.push_back(base_class);
|
||||
}
|
||||
|
||||
base_classes.swap(new_base_data.base_classes);
|
||||
base_upcasts.swap(new_base_data.base_upcasts);
|
||||
deep_upcasts.swap(new_base_data.deep_upcasts);
|
||||
}(std::make_index_sequence<type_list_arity_v<meta_base_info>>());
|
||||
}
|
||||
recur.template operator()<Base>(recur);
|
||||
};
|
||||
|
||||
const auto add_new_bases = [&add_new_base]<class_kind Derived>(auto&& recur) {
|
||||
if constexpr ( check_base_info_enabled<Derived> ) {
|
||||
using meta_base_info = typename Derived::meta_base_info;
|
||||
meta_base_info::for_each([&add_new_base, &recur]<class_kind Base>() {
|
||||
add_new_base.template operator()<Base, Derived>(recur);
|
||||
});
|
||||
} else {
|
||||
(void)recur;
|
||||
}
|
||||
};
|
||||
|
||||
add_new_bases.template operator()<Class>(add_new_bases);
|
||||
|
||||
base_classes.swap(new_base_data.base_classes);
|
||||
deep_upcasts.swap(new_base_data.deep_upcasts);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
template < typename Derived, typename Base >
|
||||
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>)
|
||||
: upcast{[](void* from) -> void* { return static_cast<Base*>(static_cast<Derived*>(from)); }}
|
||||
, target{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 {
|
||||
return upcast(ptr);
|
||||
}
|
||||
@@ -90,52 +83,6 @@ namespace meta_hpp::detail
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
inline class_type_data::upcast_func_list_t::upcast_func_list_t(const upcast_func_t& in_upcast)
|
||||
: upcasts{in_upcast} {
|
||||
for ( const upcast_func_t& upcast : upcasts ) {
|
||||
if ( upcast.is_virtual ) {
|
||||
vbases.emplace(upcast.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline class_type_data::upcast_func_list_t::upcast_func_list_t(upcasts_t in_upcasts, vbases_t in_vbases)
|
||||
: upcasts{std::move(in_upcasts)}
|
||||
, vbases{std::move(in_vbases)} {}
|
||||
|
||||
inline void* class_type_data::upcast_func_list_t::apply(void* ptr) const noexcept {
|
||||
for ( const upcast_func_t& upcast : upcasts ) {
|
||||
ptr = upcast.apply(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<void*>(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
|
||||
) {
|
||||
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());
|
||||
|
||||
class_type_data::upcast_func_list_t::vbases_t new_vbases;
|
||||
new_vbases.insert(l.vbases.begin(), l.vbases.end());
|
||||
new_vbases.insert(r.vbases.begin(), r.vbases.end());
|
||||
|
||||
class_type_data::upcast_func_list_t result{std::move(new_upcasts), std::move(new_vbases)};
|
||||
result.is_ambiguous = l.is_ambiguous || r.is_ambiguous;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
inline class_bitflags class_type::get_flags() const noexcept {
|
||||
@@ -245,7 +192,17 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
inline bool class_type::is_base_of(const class_type& derived) const noexcept {
|
||||
return is_valid() && derived.is_valid() && derived.data_->deep_upcasts.contains(*this);
|
||||
if ( !is_valid() || !derived.is_valid() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( const auto& upcast : derived.data_->deep_upcasts ) {
|
||||
if ( upcast.target == *this ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template < detail::class_kind Derived >
|
||||
@@ -254,24 +211,14 @@ namespace meta_hpp
|
||||
}
|
||||
|
||||
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 Derived >
|
||||
bool class_type::is_virtual_base_of() const noexcept {
|
||||
return is_virtual_base_of(resolve_type<Derived>());
|
||||
}
|
||||
|
||||
inline bool class_type::is_virtual_base_of(const class_type& derived) const noexcept {
|
||||
if ( !is_valid() || !derived.is_valid() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
using deep_upcasts_t = detail::class_type_data::deep_upcasts_t;
|
||||
const deep_upcasts_t& deep_upcasts = derived.data_->deep_upcasts;
|
||||
|
||||
if ( auto iter{deep_upcasts.find(*this)}; iter != deep_upcasts.end() ) {
|
||||
return !iter->second.is_ambiguous && !iter->second.vbases.empty();
|
||||
for ( const class_type& base_class : derived.data_->base_classes ) {
|
||||
if ( base_class == *this ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -295,15 +242,6 @@ namespace meta_hpp
|
||||
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<Base>());
|
||||
}
|
||||
|
||||
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, bool recursively) const noexcept {
|
||||
for ( const function& function : data_->functions ) {
|
||||
if ( function.get_name() == name ) {
|
||||
|
||||
Reference in New Issue
Block a user