mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-14 11:40:35 +07:00
cleanup uarg casts
This commit is contained in:
@@ -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,8 +5366,63 @@ 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>;
|
||||
|
||||
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()));
|
||||
};
|
||||
|
||||
if ( from_type.is_nullptr() && to_type.is_pointer() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_array() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const array_type& from_type_array = from_type.as_array();
|
||||
const bool from_type_array_readonly = is_ref_const();
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_array.get_data_type();
|
||||
|
||||
if ( to_type_ptr_readonly >= from_type_array_readonly ) {
|
||||
if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_pointer() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
const bool from_type_ptr_readonly = from_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
if ( to_type_ptr_readonly >= from_type_ptr_readonly ) {
|
||||
if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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>;
|
||||
|
||||
@@ -5374,82 +5439,42 @@ 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() ) {
|
||||
return true;
|
||||
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<ToRef, noncopyable>>;
|
||||
case ref_types::const_lvalue:
|
||||
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<ToRef, noncopyable>>;
|
||||
case ref_types::const_rvalue:
|
||||
return std::is_convertible_v<const noncopyable&&, copy_cvref_t<ToRef, noncopyable>>;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_array() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const array_type& from_type_array = from_type.as_array();
|
||||
const bool from_type_array_readonly = is_ref_const();
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_array.get_data_type();
|
||||
|
||||
if ( to_type_ptr_readonly >= from_type_array_readonly ) {
|
||||
if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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&&>{});
|
||||
}
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_pointer() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
const bool from_type_ptr_readonly = from_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
if ( to_type_ptr_readonly >= from_type_ptr_readonly ) {
|
||||
if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if constexpr ( std::is_reference_v<To> ) {
|
||||
const auto is_convertible = [this]() {
|
||||
switch ( get_ref_type() ) {
|
||||
case ref_types::lvalue:
|
||||
return std::is_convertible_v<noncopyable&, copy_cvref_t<To, noncopyable>>;
|
||||
case ref_types::const_lvalue:
|
||||
return std::is_convertible_v<const noncopyable&, copy_cvref_t<To, noncopyable>>;
|
||||
case ref_types::rvalue:
|
||||
return std::is_convertible_v<noncopyable&&, copy_cvref_t<To, noncopyable>>;
|
||||
case ref_types::const_rvalue:
|
||||
return std::is_convertible_v<const noncopyable&&, copy_cvref_t<To, noncopyable>>;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if ( is_a(to_type, from_type) && is_convertible() ) {
|
||||
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,104 +5496,105 @@ 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);
|
||||
if ( to_type.is_pointer() && from_type.is_nullptr() ) {
|
||||
return static_cast<to_raw_type_cv>(nullptr);
|
||||
}
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_array() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const array_type& from_type_array = from_type.as_array();
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_array.get_data_type();
|
||||
|
||||
if ( to_data_type.is_void() || to_data_type == from_data_type ) {
|
||||
return static_cast<to_raw_type_cv>(data_);
|
||||
}
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_array() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const array_type& from_type_array = from_type.as_array();
|
||||
if ( to_data_type.is_class() && from_data_type.is_class() ) {
|
||||
const class_type& to_data_class = to_data_type.as_class();
|
||||
const class_type& from_data_class = from_data_type.as_class();
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_array.get_data_type();
|
||||
|
||||
if ( to_data_type.is_void() || to_data_type == from_data_type ) {
|
||||
return static_cast<to_raw_type_cv>(data_);
|
||||
}
|
||||
|
||||
if ( to_data_type.is_class() && from_data_type.is_class() ) {
|
||||
const class_type& to_data_class = to_data_type.as_class();
|
||||
const class_type& from_data_class = from_data_type.as_class();
|
||||
|
||||
void* to_ptr = pointer_upcast(data_, from_data_class, to_data_class);
|
||||
return static_cast<to_raw_type_cv>(to_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_pointer() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
void** from_data_ptr = static_cast<void**>(data_);
|
||||
|
||||
if ( to_data_type.is_void() || to_data_type == from_data_type ) {
|
||||
return static_cast<to_raw_type_cv>(*from_data_ptr);
|
||||
}
|
||||
|
||||
if ( to_data_type.is_class() && from_data_type.is_class() ) {
|
||||
const class_type& to_data_class = to_data_type.as_class();
|
||||
const class_type& from_data_class = from_data_type.as_class();
|
||||
|
||||
void* to_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_data_class);
|
||||
return static_cast<to_raw_type_cv>(to_ptr);
|
||||
}
|
||||
void* to_ptr = pointer_upcast(data_, from_data_class, to_data_class);
|
||||
return static_cast<to_raw_type_cv>(to_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
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_);
|
||||
}
|
||||
if ( to_type.is_pointer() && from_type.is_pointer() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<To> ) {
|
||||
return std::move(*static_cast<to_raw_type_cv*>(data_));
|
||||
}
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
void** from_data_ptr = static_cast<void**>(data_);
|
||||
|
||||
if ( to_data_type.is_void() || to_data_type == from_data_type ) {
|
||||
return static_cast<to_raw_type_cv>(*from_data_ptr);
|
||||
}
|
||||
|
||||
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();
|
||||
if ( to_data_type.is_class() && from_data_type.is_class() ) {
|
||||
const class_type& to_data_class = to_data_type.as_class();
|
||||
const class_type& from_data_class = from_data_type.as_class();
|
||||
|
||||
void* to_ptr = pointer_upcast(data_, from_class, to_class);
|
||||
|
||||
if constexpr ( std::is_lvalue_reference_v<To> ) {
|
||||
return *static_cast<to_raw_type_cv*>(to_ptr);
|
||||
}
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<To> ) {
|
||||
return std::move(*static_cast<to_raw_type_cv*>(to_ptr));
|
||||
}
|
||||
void* to_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_data_class);
|
||||
return static_cast<to_raw_type_cv>(to_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr ( !std::is_pointer_v<To> && !std::is_reference_v<To> ) {
|
||||
if constexpr ( std::is_constructible_v<To, to_raw_type&> ) {
|
||||
if ( get_ref_type() == ref_types::lvalue ) {
|
||||
return To{cast<to_raw_type&>()};
|
||||
}
|
||||
}
|
||||
META_HPP_THROW("bad argument cast");
|
||||
}
|
||||
|
||||
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&>()};
|
||||
}
|
||||
}
|
||||
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_constructible_v<To, to_raw_type&&> ) {
|
||||
if ( get_ref_type() == ref_types::rvalue ) {
|
||||
return To{cast<to_raw_type&&>()};
|
||||
}
|
||||
}
|
||||
using to_raw_type_cv = std::remove_reference_t<To>;
|
||||
using to_raw_type = std::remove_cv_t<to_raw_type_cv>;
|
||||
|
||||
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&&>()};
|
||||
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>();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<To> ) {
|
||||
return std::move(*static_cast<to_raw_type_cv*>(to_ptr));
|
||||
}
|
||||
|
||||
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&> ) {
|
||||
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&> ) {
|
||||
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&&> ) {
|
||||
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&&> ) {
|
||||
return To{std::move(*static_cast<const to_raw_type*>(to_ptr))};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,8 +137,63 @@ 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>;
|
||||
|
||||
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()));
|
||||
};
|
||||
|
||||
if ( from_type.is_nullptr() && to_type.is_pointer() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_array() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const array_type& from_type_array = from_type.as_array();
|
||||
const bool from_type_array_readonly = is_ref_const();
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_array.get_data_type();
|
||||
|
||||
if ( to_type_ptr_readonly >= from_type_array_readonly ) {
|
||||
if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_pointer() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
const bool from_type_ptr_readonly = from_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
if ( to_type_ptr_readonly >= from_type_ptr_readonly ) {
|
||||
if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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>;
|
||||
|
||||
@@ -145,82 +210,42 @@ 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() ) {
|
||||
return true;
|
||||
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<ToRef, noncopyable>>;
|
||||
case ref_types::const_lvalue:
|
||||
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<ToRef, noncopyable>>;
|
||||
case ref_types::const_rvalue:
|
||||
return std::is_convertible_v<const noncopyable&&, copy_cvref_t<ToRef, noncopyable>>;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_array() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const array_type& from_type_array = from_type.as_array();
|
||||
const bool from_type_array_readonly = is_ref_const();
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_array.get_data_type();
|
||||
|
||||
if ( to_type_ptr_readonly >= from_type_array_readonly ) {
|
||||
if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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&&>{});
|
||||
}
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_pointer() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const bool to_type_ptr_readonly = to_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
const bool from_type_ptr_readonly = from_type_ptr.get_flags().has(pointer_flags::is_readonly);
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
if ( to_type_ptr_readonly >= from_type_ptr_readonly ) {
|
||||
if ( to_data_type.is_void() || is_a(to_data_type, from_data_type) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if constexpr ( std::is_reference_v<To> ) {
|
||||
const auto is_convertible = [this]() {
|
||||
switch ( get_ref_type() ) {
|
||||
case ref_types::lvalue:
|
||||
return std::is_convertible_v<noncopyable&, copy_cvref_t<To, noncopyable>>;
|
||||
case ref_types::const_lvalue:
|
||||
return std::is_convertible_v<const noncopyable&, copy_cvref_t<To, noncopyable>>;
|
||||
case ref_types::rvalue:
|
||||
return std::is_convertible_v<noncopyable&&, copy_cvref_t<To, noncopyable>>;
|
||||
case ref_types::const_rvalue:
|
||||
return std::is_convertible_v<const noncopyable&&, copy_cvref_t<To, noncopyable>>;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if ( is_a(to_type, from_type) && is_convertible() ) {
|
||||
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,104 +267,105 @@ 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);
|
||||
if ( to_type.is_pointer() && from_type.is_nullptr() ) {
|
||||
return static_cast<to_raw_type_cv>(nullptr);
|
||||
}
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_array() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const array_type& from_type_array = from_type.as_array();
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_array.get_data_type();
|
||||
|
||||
if ( to_data_type.is_void() || to_data_type == from_data_type ) {
|
||||
return static_cast<to_raw_type_cv>(data_);
|
||||
}
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_array() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const array_type& from_type_array = from_type.as_array();
|
||||
if ( to_data_type.is_class() && from_data_type.is_class() ) {
|
||||
const class_type& to_data_class = to_data_type.as_class();
|
||||
const class_type& from_data_class = from_data_type.as_class();
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_array.get_data_type();
|
||||
|
||||
if ( to_data_type.is_void() || to_data_type == from_data_type ) {
|
||||
return static_cast<to_raw_type_cv>(data_);
|
||||
}
|
||||
|
||||
if ( to_data_type.is_class() && from_data_type.is_class() ) {
|
||||
const class_type& to_data_class = to_data_type.as_class();
|
||||
const class_type& from_data_class = from_data_type.as_class();
|
||||
|
||||
void* to_ptr = pointer_upcast(data_, from_data_class, to_data_class);
|
||||
return static_cast<to_raw_type_cv>(to_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
if ( to_type.is_pointer() && from_type.is_pointer() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
void** from_data_ptr = static_cast<void**>(data_);
|
||||
|
||||
if ( to_data_type.is_void() || to_data_type == from_data_type ) {
|
||||
return static_cast<to_raw_type_cv>(*from_data_ptr);
|
||||
}
|
||||
|
||||
if ( to_data_type.is_class() && from_data_type.is_class() ) {
|
||||
const class_type& to_data_class = to_data_type.as_class();
|
||||
const class_type& from_data_class = from_data_type.as_class();
|
||||
|
||||
void* to_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_data_class);
|
||||
return static_cast<to_raw_type_cv>(to_ptr);
|
||||
}
|
||||
void* to_ptr = pointer_upcast(data_, from_data_class, to_data_class);
|
||||
return static_cast<to_raw_type_cv>(to_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
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_);
|
||||
}
|
||||
if ( to_type.is_pointer() && from_type.is_pointer() ) {
|
||||
const pointer_type& to_type_ptr = to_type.as_pointer();
|
||||
const pointer_type& from_type_ptr = from_type.as_pointer();
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<To> ) {
|
||||
return std::move(*static_cast<to_raw_type_cv*>(data_));
|
||||
}
|
||||
const any_type& to_data_type = to_type_ptr.get_data_type();
|
||||
const any_type& from_data_type = from_type_ptr.get_data_type();
|
||||
|
||||
void** from_data_ptr = static_cast<void**>(data_);
|
||||
|
||||
if ( to_data_type.is_void() || to_data_type == from_data_type ) {
|
||||
return static_cast<to_raw_type_cv>(*from_data_ptr);
|
||||
}
|
||||
|
||||
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();
|
||||
if ( to_data_type.is_class() && from_data_type.is_class() ) {
|
||||
const class_type& to_data_class = to_data_type.as_class();
|
||||
const class_type& from_data_class = from_data_type.as_class();
|
||||
|
||||
void* to_ptr = pointer_upcast(data_, from_class, to_class);
|
||||
|
||||
if constexpr ( std::is_lvalue_reference_v<To> ) {
|
||||
return *static_cast<to_raw_type_cv*>(to_ptr);
|
||||
}
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<To> ) {
|
||||
return std::move(*static_cast<to_raw_type_cv*>(to_ptr));
|
||||
}
|
||||
void* to_ptr = pointer_upcast(*from_data_ptr, from_data_class, to_data_class);
|
||||
return static_cast<to_raw_type_cv>(to_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr ( !std::is_pointer_v<To> && !std::is_reference_v<To> ) {
|
||||
if constexpr ( std::is_constructible_v<To, to_raw_type&> ) {
|
||||
if ( get_ref_type() == ref_types::lvalue ) {
|
||||
return To{cast<to_raw_type&>()};
|
||||
}
|
||||
}
|
||||
META_HPP_THROW("bad argument cast");
|
||||
}
|
||||
|
||||
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&>()};
|
||||
}
|
||||
}
|
||||
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_constructible_v<To, to_raw_type&&> ) {
|
||||
if ( get_ref_type() == ref_types::rvalue ) {
|
||||
return To{cast<to_raw_type&&>()};
|
||||
}
|
||||
}
|
||||
using to_raw_type_cv = std::remove_reference_t<To>;
|
||||
using to_raw_type = std::remove_cv_t<to_raw_type_cv>;
|
||||
|
||||
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&&>()};
|
||||
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>();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if constexpr ( std::is_rvalue_reference_v<To> ) {
|
||||
return std::move(*static_cast<to_raw_type_cv*>(to_ptr));
|
||||
}
|
||||
|
||||
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&> ) {
|
||||
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&> ) {
|
||||
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&&> ) {
|
||||
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&&> ) {
|
||||
return To{std::move(*static_cast<const to_raw_type*>(to_ptr))};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user