mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-15 11:52:08 +07:00
uvalue upcasting support: wip
This commit is contained in:
@@ -135,6 +135,11 @@ namespace meta_hpp::detail
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline const void* pointer_upcast(const void* ptr, const class_type& from, const class_type& to) {
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
||||||
|
return pointer_upcast(const_cast<void*>(ptr), from, to);
|
||||||
|
}
|
||||||
|
|
||||||
template < class_kind To, class_kind From >
|
template < class_kind To, class_kind From >
|
||||||
[[nodiscard]] To* pointer_upcast(From* ptr) {
|
[[nodiscard]] To* pointer_upcast(From* ptr) {
|
||||||
return static_cast<To*>(pointer_upcast(ptr, resolve_type<From>(), resolve_type<To>()));
|
return static_cast<To*>(pointer_upcast(ptr, resolve_type<From>(), resolve_type<To>()));
|
||||||
@@ -142,7 +147,6 @@ namespace meta_hpp::detail
|
|||||||
|
|
||||||
template < class_kind To, class_kind From >
|
template < class_kind To, class_kind From >
|
||||||
[[nodiscard]] const To* pointer_upcast(const From* ptr) {
|
[[nodiscard]] const To* pointer_upcast(const From* ptr) {
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
return static_cast<const To*>(pointer_upcast(ptr, resolve_type<From>(), resolve_type<To>()));
|
||||||
return pointer_upcast<To>(const_cast<From*>(ptr));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#include "../meta_detail/value_traits/less_traits.hpp"
|
#include "../meta_detail/value_traits/less_traits.hpp"
|
||||||
#include "../meta_detail/value_traits/ostream_traits.hpp"
|
#include "../meta_detail/value_traits/ostream_traits.hpp"
|
||||||
|
|
||||||
|
#include "../meta_detail/value_utilities/utraits.hpp"
|
||||||
|
|
||||||
namespace meta_hpp
|
namespace meta_hpp
|
||||||
{
|
{
|
||||||
struct uvalue::vtable_t final {
|
struct uvalue::vtable_t final {
|
||||||
@@ -327,53 +329,83 @@ namespace meta_hpp
|
|||||||
template < typename T >
|
template < typename T >
|
||||||
std::decay_t<T>& uvalue::cast() & {
|
std::decay_t<T>& uvalue::cast() & {
|
||||||
using Tp = std::decay_t<T>;
|
using Tp = std::decay_t<T>;
|
||||||
|
|
||||||
if ( Tp* ptr = try_cast<Tp>() ) {
|
if ( Tp* ptr = try_cast<Tp>() ) {
|
||||||
return *ptr;
|
return *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::throw_exception_with("bad value cast");
|
detail::throw_exception_with("bad value cast");
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
std::decay_t<T>&& uvalue::cast() && {
|
std::decay_t<T>&& uvalue::cast() && {
|
||||||
using Tp = std::decay_t<T>;
|
using Tp = std::decay_t<T>;
|
||||||
|
|
||||||
if ( Tp* ptr = try_cast<Tp>() ) {
|
if ( Tp* ptr = try_cast<Tp>() ) {
|
||||||
return std::move(*ptr);
|
return std::move(*ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::throw_exception_with("bad value cast");
|
detail::throw_exception_with("bad value cast");
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
const std::decay_t<T>& uvalue::cast() const & {
|
const std::decay_t<T>& uvalue::cast() const & {
|
||||||
using Tp = std::decay_t<T>;
|
using Tp = std::decay_t<T>;
|
||||||
|
|
||||||
if ( const Tp* ptr = try_cast<const Tp>() ) {
|
if ( const Tp* ptr = try_cast<const Tp>() ) {
|
||||||
return *ptr;
|
return *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::throw_exception_with("bad value cast");
|
detail::throw_exception_with("bad value cast");
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
const std::decay_t<T>&& uvalue::cast() const && {
|
const std::decay_t<T>&& uvalue::cast() const && {
|
||||||
using Tp = std::decay_t<T>;
|
using Tp = std::decay_t<T>;
|
||||||
|
|
||||||
if ( const Tp* ptr = try_cast<const Tp>() ) {
|
if ( const Tp* ptr = try_cast<const Tp>() ) {
|
||||||
return std::move(*ptr);
|
return std::move(*ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::throw_exception_with("bad value cast");
|
detail::throw_exception_with("bad value cast");
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
std::decay_t<T>* uvalue::try_cast() noexcept {
|
std::decay_t<T>* uvalue::try_cast() noexcept {
|
||||||
using Tp = std::decay_t<T>;
|
using Tp = std::decay_t<T>;
|
||||||
return get_type() == resolve_type<Tp>()
|
|
||||||
? vtable_t::storage_cast<Tp>(storage_)
|
const any_type& from_type = get_type();
|
||||||
: nullptr;
|
const any_type& to_type = resolve_type<Tp>();
|
||||||
|
|
||||||
|
if ( from_type == to_type ) {
|
||||||
|
return static_cast<Tp*>(data());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( from_type.is_class() && to_type.is_class() ) {
|
||||||
|
void* to_ptr = detail::pointer_upcast(data(), from_type.as_class(), to_type.as_class());
|
||||||
|
return static_cast<Tp*>(to_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
const std::decay_t<T>* uvalue::try_cast() const noexcept {
|
const std::decay_t<T>* uvalue::try_cast() const noexcept {
|
||||||
using Tp = std::decay_t<T>;
|
using Tp = std::decay_t<T>;
|
||||||
return get_type() == resolve_type<Tp>()
|
|
||||||
? vtable_t::storage_cast<Tp>(storage_)
|
const any_type& from_type = get_type();
|
||||||
: nullptr;
|
const any_type& to_type = resolve_type<Tp>();
|
||||||
|
|
||||||
|
if ( from_type == to_type ) {
|
||||||
|
return static_cast<const Tp*>(data());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( from_type.is_class() && to_type.is_class() ) {
|
||||||
|
const void* to_ptr = detail::pointer_upcast(data(), from_type.as_class(), to_type.as_class());
|
||||||
|
return static_cast<const Tp*>(to_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
92
untests/meta_utilities/value3_tests.cpp
Normal file
92
untests/meta_utilities/value3_tests.cpp
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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-2022, by Matvey Cherevko (blackmatov@gmail.com)
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "../meta_untests.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct base0 {
|
||||||
|
int i{21};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct base1 : virtual base0 {
|
||||||
|
int j{42};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct base2 : virtual base0 {
|
||||||
|
int k{84};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct derived : base1, base2 {
|
||||||
|
int l{168};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("meta/meta_utilities/value3") {
|
||||||
|
namespace meta = meta_hpp;
|
||||||
|
|
||||||
|
meta::class_<base0>();
|
||||||
|
|
||||||
|
meta::class_<base1>()
|
||||||
|
.base_<base0>();
|
||||||
|
|
||||||
|
meta::class_<base2>()
|
||||||
|
.base_<base0>();
|
||||||
|
|
||||||
|
meta::class_<derived>()
|
||||||
|
.base_<base1>()
|
||||||
|
.base_<base2>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("meta/meta_utilities/value3/cast") {
|
||||||
|
namespace meta = meta_hpp;
|
||||||
|
|
||||||
|
SUBCASE("derived") {
|
||||||
|
{
|
||||||
|
meta::uvalue v{derived{}};
|
||||||
|
CHECK(v.get_type() == meta::resolve_type<derived>());
|
||||||
|
|
||||||
|
CHECK(v.cast<base0>().i == 21);
|
||||||
|
CHECK(v.cast<base1>().j == 42);
|
||||||
|
CHECK(v.cast<base2>().k == 84);
|
||||||
|
CHECK(v.cast<derived>().l == 168);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const meta::uvalue v{derived{}};
|
||||||
|
CHECK(v.get_type() == meta::resolve_type<derived>());
|
||||||
|
|
||||||
|
CHECK(v.cast<base0>().i == 21);
|
||||||
|
CHECK(v.cast<base1>().j == 42);
|
||||||
|
CHECK(v.cast<base2>().k == 84);
|
||||||
|
CHECK(v.cast<derived>().l == 168);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("meta/meta_utilities/value3/try_cast") {
|
||||||
|
namespace meta = meta_hpp;
|
||||||
|
|
||||||
|
SUBCASE("derived") {
|
||||||
|
{
|
||||||
|
meta::uvalue v{derived{}};
|
||||||
|
CHECK(v.get_type() == meta::resolve_type<derived>());
|
||||||
|
|
||||||
|
CHECK((v.try_cast<base0>() && v.try_cast<base0>()->i == 21));
|
||||||
|
CHECK((v.try_cast<base1>() && v.try_cast<base1>()->j == 42));
|
||||||
|
CHECK((v.try_cast<base2>() && v.try_cast<base2>()->k == 84));
|
||||||
|
CHECK((v.try_cast<derived>() && v.try_cast<derived>()->l == 168));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const meta::uvalue v{derived{}};
|
||||||
|
CHECK(v.get_type() == meta::resolve_type<derived>());
|
||||||
|
|
||||||
|
CHECK((v.try_cast<base0>() && v.try_cast<base0>()->i == 21));
|
||||||
|
CHECK((v.try_cast<base1>() && v.try_cast<base1>()->j == 42));
|
||||||
|
CHECK((v.try_cast<base2>() && v.try_cast<base2>()->k == 84));
|
||||||
|
CHECK((v.try_cast<derived>() && v.try_cast<derived>()->l == 168));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user