cleanup uarg casts

This commit is contained in:
BlackMATov
2023-02-13 02:25:50 +07:00
parent d6922fa622
commit 0f92a0c763
2 changed files with 354 additions and 302 deletions

View File

@@ -5311,6 +5311,11 @@ namespace meta_hpp::detail
}
template < typename To >
requires(std::is_pointer_v<To>)
[[nodiscard]] bool can_cast_to() const noexcept;
template < typename To >
requires(!std::is_pointer_v<To>)
[[nodiscard]] bool can_cast_to() const noexcept;
private:
@@ -5346,6 +5351,11 @@ namespace meta_hpp::detail
, data_{const_cast<std::remove_cvref_t<T>*>(std::addressof(v))} {}
template < typename To >
requires(std::is_pointer_v<To>)
[[nodiscard]] To cast() const;
template < typename To >
requires(!std::is_pointer_v<To>)
[[nodiscard]] To cast() const;
private:
@@ -5356,16 +5366,11 @@ namespace meta_hpp::detail
namespace meta_hpp::detail
{
template < typename To >
// NOLINTNEXTLINE(*-cognitive-complexity)
bool uarg_base::can_cast_to() const noexcept {
requires(std::is_pointer_v<To>)
[[nodiscard]] bool uarg_base::can_cast_to() const noexcept {
using to_raw_type_cv = std::remove_reference_t<To>;
using to_raw_type = std::remove_cv_t<to_raw_type_cv>;
static_assert( //
!(std::is_reference_v<To> && std::is_pointer_v<to_raw_type>),
"references to pointers are not supported yet"
);
const any_type& from_type = get_raw_type();
const any_type& to_type = resolve_type<to_raw_type>();
@@ -5374,8 +5379,7 @@ namespace meta_hpp::detail
|| (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class()));
};
if constexpr ( std::is_pointer_v<To> ) {
if ( to_type.is_pointer() && from_type.is_nullptr() ) {
if ( from_type.is_nullptr() && to_type.is_pointer() ) {
return true;
}
@@ -5412,44 +5416,65 @@ namespace meta_hpp::detail
}
}
}
return false;
}
if constexpr ( std::is_reference_v<To> ) {
const auto is_convertible = [this]() {
template < typename To >
requires(!std::is_pointer_v<To>)
[[nodiscard]] bool uarg_base::can_cast_to() const noexcept {
using to_raw_type_cv = std::remove_reference_t<To>;
using to_raw_type = std::remove_cv_t<to_raw_type_cv>;
static_assert( //
!(std::is_reference_v<To> && std::is_pointer_v<to_raw_type>),
"references to pointers are not supported yet"
);
const any_type& from_type = get_raw_type();
const any_type& to_type = resolve_type<to_raw_type>();
const auto is_a = [](const any_type& base, const any_type& derived) {
return (base == derived) //
|| (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class()));
};
const auto is_convertible_to_ref = [this]<typename ToRef>(type_list<ToRef>) {
switch ( get_ref_type() ) {
case ref_types::lvalue:
return std::is_convertible_v<noncopyable&, copy_cvref_t<To, noncopyable>>;
return std::is_convertible_v<noncopyable&, copy_cvref_t<ToRef, noncopyable>>;
case ref_types::const_lvalue:
return std::is_convertible_v<const noncopyable&, copy_cvref_t<To, noncopyable>>;
return std::is_convertible_v<const noncopyable&, copy_cvref_t<ToRef, noncopyable>>;
case ref_types::rvalue:
return std::is_convertible_v<noncopyable&&, copy_cvref_t<To, noncopyable>>;
return std::is_convertible_v<noncopyable&&, copy_cvref_t<ToRef, noncopyable>>;
case ref_types::const_rvalue:
return std::is_convertible_v<const noncopyable&&, copy_cvref_t<To, noncopyable>>;
return std::is_convertible_v<const noncopyable&&, copy_cvref_t<ToRef, noncopyable>>;
}
return false;
};
if ( is_a(to_type, from_type) && is_convertible() ) {
const auto is_constructible_from_type = [this, &is_convertible_to_ref]<typename FromType>(type_list<FromType>) {
switch ( get_ref_type() ) {
case ref_types::lvalue:
return std::is_constructible_v<To, FromType&> && is_convertible_to_ref(type_list<FromType&>{});
case ref_types::const_lvalue:
return std::is_constructible_v<To, const FromType&> && is_convertible_to_ref(type_list<const FromType&>{});
case ref_types::rvalue:
return std::is_constructible_v<To, FromType&&> && is_convertible_to_ref(type_list<FromType&&>{});
case ref_types::const_rvalue:
return std::is_constructible_v<To, const FromType&&> && is_convertible_to_ref(type_list<const FromType&&>{});
}
return false;
};
if constexpr ( std::is_reference_v<To> ) {
if ( is_a(to_type, from_type) && is_convertible_to_ref(type_list<To>{}) ) {
return true;
}
}
if constexpr ( !std::is_pointer_v<To> && !std::is_reference_v<To> ) {
const auto is_constructible = [this]() {
switch ( get_ref_type() ) {
case ref_types::lvalue:
return std::is_constructible_v<To, to_raw_type&> && can_cast_to<to_raw_type&>();
case ref_types::const_lvalue:
return std::is_constructible_v<To, const to_raw_type&> && can_cast_to<const to_raw_type&>();
case ref_types::rvalue:
return std::is_constructible_v<To, to_raw_type&&> && can_cast_to<to_raw_type&&>();
case ref_types::const_rvalue:
return std::is_constructible_v<To, const to_raw_type&&> && can_cast_to<const to_raw_type&&>();
}
return false;
};
if ( is_a(to_type, from_type) && is_constructible() ) {
if ( is_a(to_type, from_type) && is_constructible_from_type(type_list<to_raw_type>{}) ) {
return true;
}
}
@@ -5461,8 +5486,8 @@ namespace meta_hpp::detail
namespace meta_hpp::detail
{
template < typename To >
// NOLINTNEXTLINE(*-cognitive-complexity)
To uarg::cast() const {
requires(std::is_pointer_v<To>)
[[nodiscard]] To uarg::cast() const {
META_HPP_ASSERT(can_cast_to<To>() && "bad argument cast");
using to_raw_type_cv = std::remove_reference_t<To>;
@@ -5471,7 +5496,6 @@ namespace meta_hpp::detail
const any_type& from_type = get_raw_type();
const any_type& to_type = resolve_type<to_raw_type>();
if constexpr ( std::is_pointer_v<To> ) {
if ( to_type.is_pointer() && from_type.is_nullptr() ) {
return static_cast<to_raw_type_cv>(nullptr);
}
@@ -5517,24 +5541,29 @@ namespace meta_hpp::detail
return static_cast<to_raw_type_cv>(to_ptr);
}
}
META_HPP_THROW("bad argument cast");
}
if constexpr ( std::is_reference_v<To> ) {
if ( to_type == from_type ) {
if constexpr ( std::is_lvalue_reference_v<To> ) {
return *static_cast<to_raw_type_cv*>(data_);
}
template < typename To >
requires(!std::is_pointer_v<To>)
[[nodiscard]] To uarg::cast() const {
META_HPP_ASSERT(can_cast_to<To>() && "bad argument cast");
if constexpr ( std::is_rvalue_reference_v<To> ) {
return std::move(*static_cast<to_raw_type_cv*>(data_));
}
}
using to_raw_type_cv = std::remove_reference_t<To>;
using to_raw_type = std::remove_cv_t<to_raw_type_cv>;
if ( to_type.is_class() && from_type.is_class() ) {
const class_type& to_class = to_type.as_class();
const class_type& from_class = from_type.as_class();
static_assert( //
!(std::is_reference_v<To> && std::is_pointer_v<to_raw_type>),
"references to pointers are not supported yet"
);
void* to_ptr = pointer_upcast(data_, from_class, to_class);
const any_type& from_type = get_raw_type();
const any_type& to_type = resolve_type<to_raw_type>();
void* to_ptr = to_type == from_type //
? data_
: pointer_upcast(data_, from_type.as_class(), to_type.as_class());
if constexpr ( std::is_lvalue_reference_v<To> ) {
return *static_cast<to_raw_type_cv*>(to_ptr);
@@ -5543,32 +5572,29 @@ namespace meta_hpp::detail
if constexpr ( std::is_rvalue_reference_v<To> ) {
return std::move(*static_cast<to_raw_type_cv*>(to_ptr));
}
}
}
if constexpr ( !std::is_pointer_v<To> && !std::is_reference_v<To> ) {
if constexpr ( !std::is_reference_v<To> ) {
switch ( get_ref_type() ) {
case ref_types::lvalue:
if constexpr ( std::is_constructible_v<To, to_raw_type&> ) {
if ( get_ref_type() == ref_types::lvalue ) {
return To{cast<to_raw_type&>()};
return To{*static_cast<to_raw_type*>(to_ptr)};
}
}
break;
case ref_types::const_lvalue:
if constexpr ( std::is_constructible_v<To, const to_raw_type&> ) {
if ( get_ref_type() == ref_types::const_lvalue ) {
return To{cast<const to_raw_type&>()};
return To{*static_cast<const to_raw_type*>(to_ptr)};
}
}
break;
case ref_types::rvalue:
if constexpr ( std::is_constructible_v<To, to_raw_type&&> ) {
if ( get_ref_type() == ref_types::rvalue ) {
return To{cast<to_raw_type&&>()};
return To{std::move(*static_cast<to_raw_type*>(to_ptr))};
}
}
break;
case ref_types::const_rvalue:
if constexpr ( std::is_constructible_v<To, const to_raw_type&&> ) {
if ( get_ref_type() == ref_types::const_rvalue ) {
return To{cast<const to_raw_type&&>()};
return To{std::move(*static_cast<const to_raw_type*>(to_ptr))};
}
break;
}
}

View File

@@ -82,6 +82,11 @@ namespace meta_hpp::detail
}
template < typename To >
requires(std::is_pointer_v<To>)
[[nodiscard]] bool can_cast_to() const noexcept;
template < typename To >
requires(!std::is_pointer_v<To>)
[[nodiscard]] bool can_cast_to() const noexcept;
private:
@@ -117,6 +122,11 @@ namespace meta_hpp::detail
, data_{const_cast<std::remove_cvref_t<T>*>(std::addressof(v))} {}
template < typename To >
requires(std::is_pointer_v<To>)
[[nodiscard]] To cast() const;
template < typename To >
requires(!std::is_pointer_v<To>)
[[nodiscard]] To cast() const;
private:
@@ -127,16 +137,11 @@ namespace meta_hpp::detail
namespace meta_hpp::detail
{
template < typename To >
// NOLINTNEXTLINE(*-cognitive-complexity)
bool uarg_base::can_cast_to() const noexcept {
requires(std::is_pointer_v<To>)
[[nodiscard]] bool uarg_base::can_cast_to() const noexcept {
using to_raw_type_cv = std::remove_reference_t<To>;
using to_raw_type = std::remove_cv_t<to_raw_type_cv>;
static_assert( //
!(std::is_reference_v<To> && std::is_pointer_v<to_raw_type>),
"references to pointers are not supported yet"
);
const any_type& from_type = get_raw_type();
const any_type& to_type = resolve_type<to_raw_type>();
@@ -145,8 +150,7 @@ namespace meta_hpp::detail
|| (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class()));
};
if constexpr ( std::is_pointer_v<To> ) {
if ( to_type.is_pointer() && from_type.is_nullptr() ) {
if ( from_type.is_nullptr() && to_type.is_pointer() ) {
return true;
}
@@ -183,44 +187,65 @@ namespace meta_hpp::detail
}
}
}
return false;
}
if constexpr ( std::is_reference_v<To> ) {
const auto is_convertible = [this]() {
template < typename To >
requires(!std::is_pointer_v<To>)
[[nodiscard]] bool uarg_base::can_cast_to() const noexcept {
using to_raw_type_cv = std::remove_reference_t<To>;
using to_raw_type = std::remove_cv_t<to_raw_type_cv>;
static_assert( //
!(std::is_reference_v<To> && std::is_pointer_v<to_raw_type>),
"references to pointers are not supported yet"
);
const any_type& from_type = get_raw_type();
const any_type& to_type = resolve_type<to_raw_type>();
const auto is_a = [](const any_type& base, const any_type& derived) {
return (base == derived) //
|| (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class()));
};
const auto is_convertible_to_ref = [this]<typename ToRef>(type_list<ToRef>) {
switch ( get_ref_type() ) {
case ref_types::lvalue:
return std::is_convertible_v<noncopyable&, copy_cvref_t<To, noncopyable>>;
return std::is_convertible_v<noncopyable&, copy_cvref_t<ToRef, noncopyable>>;
case ref_types::const_lvalue:
return std::is_convertible_v<const noncopyable&, copy_cvref_t<To, noncopyable>>;
return std::is_convertible_v<const noncopyable&, copy_cvref_t<ToRef, noncopyable>>;
case ref_types::rvalue:
return std::is_convertible_v<noncopyable&&, copy_cvref_t<To, noncopyable>>;
return std::is_convertible_v<noncopyable&&, copy_cvref_t<ToRef, noncopyable>>;
case ref_types::const_rvalue:
return std::is_convertible_v<const noncopyable&&, copy_cvref_t<To, noncopyable>>;
return std::is_convertible_v<const noncopyable&&, copy_cvref_t<ToRef, noncopyable>>;
}
return false;
};
if ( is_a(to_type, from_type) && is_convertible() ) {
const auto is_constructible_from_type = [this, &is_convertible_to_ref]<typename FromType>(type_list<FromType>) {
switch ( get_ref_type() ) {
case ref_types::lvalue:
return std::is_constructible_v<To, FromType&> && is_convertible_to_ref(type_list<FromType&>{});
case ref_types::const_lvalue:
return std::is_constructible_v<To, const FromType&> && is_convertible_to_ref(type_list<const FromType&>{});
case ref_types::rvalue:
return std::is_constructible_v<To, FromType&&> && is_convertible_to_ref(type_list<FromType&&>{});
case ref_types::const_rvalue:
return std::is_constructible_v<To, const FromType&&> && is_convertible_to_ref(type_list<const FromType&&>{});
}
return false;
};
if constexpr ( std::is_reference_v<To> ) {
if ( is_a(to_type, from_type) && is_convertible_to_ref(type_list<To>{}) ) {
return true;
}
}
if constexpr ( !std::is_pointer_v<To> && !std::is_reference_v<To> ) {
const auto is_constructible = [this]() {
switch ( get_ref_type() ) {
case ref_types::lvalue:
return std::is_constructible_v<To, to_raw_type&> && can_cast_to<to_raw_type&>();
case ref_types::const_lvalue:
return std::is_constructible_v<To, const to_raw_type&> && can_cast_to<const to_raw_type&>();
case ref_types::rvalue:
return std::is_constructible_v<To, to_raw_type&&> && can_cast_to<to_raw_type&&>();
case ref_types::const_rvalue:
return std::is_constructible_v<To, const to_raw_type&&> && can_cast_to<const to_raw_type&&>();
}
return false;
};
if ( is_a(to_type, from_type) && is_constructible() ) {
if ( is_a(to_type, from_type) && is_constructible_from_type(type_list<to_raw_type>{}) ) {
return true;
}
}
@@ -232,8 +257,8 @@ namespace meta_hpp::detail
namespace meta_hpp::detail
{
template < typename To >
// NOLINTNEXTLINE(*-cognitive-complexity)
To uarg::cast() const {
requires(std::is_pointer_v<To>)
[[nodiscard]] To uarg::cast() const {
META_HPP_ASSERT(can_cast_to<To>() && "bad argument cast");
using to_raw_type_cv = std::remove_reference_t<To>;
@@ -242,7 +267,6 @@ namespace meta_hpp::detail
const any_type& from_type = get_raw_type();
const any_type& to_type = resolve_type<to_raw_type>();
if constexpr ( std::is_pointer_v<To> ) {
if ( to_type.is_pointer() && from_type.is_nullptr() ) {
return static_cast<to_raw_type_cv>(nullptr);
}
@@ -288,24 +312,29 @@ namespace meta_hpp::detail
return static_cast<to_raw_type_cv>(to_ptr);
}
}
META_HPP_THROW("bad argument cast");
}
if constexpr ( std::is_reference_v<To> ) {
if ( to_type == from_type ) {
if constexpr ( std::is_lvalue_reference_v<To> ) {
return *static_cast<to_raw_type_cv*>(data_);
}
template < typename To >
requires(!std::is_pointer_v<To>)
[[nodiscard]] To uarg::cast() const {
META_HPP_ASSERT(can_cast_to<To>() && "bad argument cast");
if constexpr ( std::is_rvalue_reference_v<To> ) {
return std::move(*static_cast<to_raw_type_cv*>(data_));
}
}
using to_raw_type_cv = std::remove_reference_t<To>;
using to_raw_type = std::remove_cv_t<to_raw_type_cv>;
if ( to_type.is_class() && from_type.is_class() ) {
const class_type& to_class = to_type.as_class();
const class_type& from_class = from_type.as_class();
static_assert( //
!(std::is_reference_v<To> && std::is_pointer_v<to_raw_type>),
"references to pointers are not supported yet"
);
void* to_ptr = pointer_upcast(data_, from_class, to_class);
const any_type& from_type = get_raw_type();
const any_type& to_type = resolve_type<to_raw_type>();
void* to_ptr = to_type == from_type //
? data_
: pointer_upcast(data_, from_type.as_class(), to_type.as_class());
if constexpr ( std::is_lvalue_reference_v<To> ) {
return *static_cast<to_raw_type_cv*>(to_ptr);
@@ -314,32 +343,29 @@ namespace meta_hpp::detail
if constexpr ( std::is_rvalue_reference_v<To> ) {
return std::move(*static_cast<to_raw_type_cv*>(to_ptr));
}
}
}
if constexpr ( !std::is_pointer_v<To> && !std::is_reference_v<To> ) {
if constexpr ( !std::is_reference_v<To> ) {
switch ( get_ref_type() ) {
case ref_types::lvalue:
if constexpr ( std::is_constructible_v<To, to_raw_type&> ) {
if ( get_ref_type() == ref_types::lvalue ) {
return To{cast<to_raw_type&>()};
return To{*static_cast<to_raw_type*>(to_ptr)};
}
}
break;
case ref_types::const_lvalue:
if constexpr ( std::is_constructible_v<To, const to_raw_type&> ) {
if ( get_ref_type() == ref_types::const_lvalue ) {
return To{cast<const to_raw_type&>()};
return To{*static_cast<const to_raw_type*>(to_ptr)};
}
}
break;
case ref_types::rvalue:
if constexpr ( std::is_constructible_v<To, to_raw_type&&> ) {
if ( get_ref_type() == ref_types::rvalue ) {
return To{cast<to_raw_type&&>()};
return To{std::move(*static_cast<to_raw_type*>(to_ptr))};
}
}
break;
case ref_types::const_rvalue:
if constexpr ( std::is_constructible_v<To, const to_raw_type&&> ) {
if ( get_ref_type() == ref_types::const_rvalue ) {
return To{cast<const to_raw_type&&>()};
return To{std::move(*static_cast<const to_raw_type*>(to_ptr))};
}
break;
}
}