first version of ucast

This commit is contained in:
BlackMATov
2023-03-10 06:26:42 +07:00
parent ae0d402fa2
commit d05de90e36
8 changed files with 975 additions and 13 deletions

View File

@@ -63,6 +63,60 @@
# define META_HPP_PP_CAT_I(x, y) x##y
#endif
#if defined(_MSC_VER)
# define META_HPP_MSVC
#elif defined(__clang__)
# define META_HPP_CLANG
#elif defined(__GNUC__)
# define META_HPP_GCC
#endif
#if defined(META_HPP_MSVC)
# define META_HPP_MSVC_IGNORE_WARNING(w) __pragma(warning(disable : w))
# define META_HPP_MSVC_IGNORE_WARNINGS_PUSH() __pragma(warning(push))
# define META_HPP_MSVC_IGNORE_WARNINGS_POP() __pragma(warning(pop))
#else
# define META_HPP_MSVC_IGNORE_WARNING(w)
# define META_HPP_MSVC_IGNORE_WARNINGS_PUSH()
# define META_HPP_MSVC_IGNORE_WARNINGS_POP()
#endif
#if defined(META_HPP_CLANG)
# define META_HPP_CLANG_PRAGMA_TO_STR(x) _Pragma(#x)
# define META_HPP_CLANG_IGNORE_WARNING(w) META_HPP_CLANG_PRAGMA_TO_STR(clang diagnostic ignored w)
# define META_HPP_CLANG_IGNORE_WARNINGS_PUSH() _Pragma("clang diagnostic push")
# define META_HPP_CLANG_IGNORE_WARNINGS_POP() _Pragma("clang diagnostic pop")
#else
# define META_HPP_CLANG_PRAGMA_TO_STR(x)
# define META_HPP_CLANG_IGNORE_WARNING(w)
# define META_HPP_CLANG_IGNORE_WARNINGS_PUSH()
# define META_HPP_CLANG_IGNORE_WARNINGS_POP()
#endif
#if defined(META_HPP_GCC)
# define META_HPP_GCC_PRAGMA_TO_STR(x) _Pragma(#x)
# define META_HPP_GCC_IGNORE_WARNING(w) META_HPP_GCC_PRAGMA_TO_STR(GCC diagnostic ignored w)
# define META_HPP_GCC_IGNORE_WARNINGS_PUSH() _Pragma("GCC diagnostic push")
# define META_HPP_GCC_IGNORE_WARNINGS_POP() _Pragma("GCC diagnostic pop")
#else
# define META_HPP_GCC_PRAGMA_TO_STR(x)
# define META_HPP_GCC_IGNORE_WARNING(w)
# define META_HPP_GCC_IGNORE_WARNINGS_PUSH()
# define META_HPP_GCC_IGNORE_WARNINGS_POP()
#endif
#define META_HPP_IGNORE_OVERRIDE_WARNINGS_PUSH() \
META_HPP_MSVC_IGNORE_WARNINGS_PUSH() \
META_HPP_CLANG_IGNORE_WARNINGS_PUSH() \
META_HPP_GCC_IGNORE_WARNINGS_PUSH() \
META_HPP_CLANG_IGNORE_WARNING("-Winconsistent-missing-override") \
META_HPP_CLANG_IGNORE_WARNING("-Wsuggest-override")
#define META_HPP_IGNORE_OVERRIDE_WARNINGS_POP() \
META_HPP_GCC_IGNORE_WARNINGS_POP() \
META_HPP_CLANG_IGNORE_WARNINGS_POP() \
META_HPP_MSVC_IGNORE_WARNINGS_POP()\
namespace meta_hpp::detail
{
template < typename Enum >
@@ -458,6 +512,8 @@ namespace meta_hpp::detail
enum class error_code {
no_error,
bad_cast,
bad_const_access,
bad_uvalue_access,
@@ -473,6 +529,8 @@ namespace meta_hpp::detail
switch ( error ) {
case error_code::no_error:
return "no error";
case error_code::bad_cast:
return "bad cast";
case error_code::bad_const_access:
return "bad const access";
case error_code::bad_uvalue_access:
@@ -4285,67 +4343,67 @@ namespace meta_hpp::detail
public:
template < array_kind Array >
[[nodiscard]] array_type resolve_array_type() {
return array_type{resolve_array_type_data<Array>()};
return array_type{resolve_array_type_data<std::remove_cv_t<Array>>()};
}
template < class_kind Class >
[[nodiscard]] class_type resolve_class_type() {
return class_type{resolve_class_type_data<Class>()};
return class_type{resolve_class_type_data<std::remove_cv_t<Class>>()};
}
template < class_kind Class, typename... Args >
[[nodiscard]] constructor_type resolve_constructor_type() {
return constructor_type{resolve_constructor_type_data<Class, Args...>()};
return constructor_type{resolve_constructor_type_data<std::remove_cv_t<Class>, Args...>()};
}
template < class_kind Class >
[[nodiscard]] destructor_type resolve_destructor_type() {
return destructor_type{resolve_destructor_type_data<Class>()};
return destructor_type{resolve_destructor_type_data<std::remove_cv_t<Class>>()};
}
template < enum_kind Enum >
[[nodiscard]] enum_type resolve_enum_type() {
return enum_type{resolve_enum_type_data<Enum>()};
return enum_type{resolve_enum_type_data<std::remove_cv_t<Enum>>()};
}
template < function_pointer_kind Function >
[[nodiscard]] function_type resolve_function_type() {
return function_type{resolve_function_type_data<Function>()};
return function_type{resolve_function_type_data<std::remove_cv_t<Function>>()};
}
template < member_pointer_kind Member >
[[nodiscard]] member_type resolve_member_type() {
return member_type{resolve_member_type_data<Member>()};
return member_type{resolve_member_type_data<std::remove_cv_t<Member>>()};
}
template < method_pointer_kind Method >
[[nodiscard]] method_type resolve_method_type() {
return method_type{resolve_method_type_data<Method>()};
return method_type{resolve_method_type_data<std::remove_cv_t<Method>>()};
}
template < nullptr_kind Nullptr >
[[nodiscard]] nullptr_type resolve_nullptr_type() {
return nullptr_type{resolve_nullptr_type_data<Nullptr>()};
return nullptr_type{resolve_nullptr_type_data<std::remove_cv_t<Nullptr>>()};
}
template < number_kind Number >
[[nodiscard]] number_type resolve_number_type() {
return number_type{resolve_number_type_data<Number>()};
return number_type{resolve_number_type_data<std::remove_cv_t<Number>>()};
}
template < pointer_kind Pointer >
[[nodiscard]] pointer_type resolve_pointer_type() {
return pointer_type{resolve_pointer_type_data<Pointer>()};
return pointer_type{resolve_pointer_type_data<std::remove_cv_t<Pointer>>()};
}
template < reference_kind Reference >
[[nodiscard]] reference_type resolve_reference_type() {
return reference_type{resolve_reference_type_data<Reference>()};
return reference_type{resolve_reference_type_data<std::remove_cv_t<Reference>>()};
}
template < void_kind Void >
[[nodiscard]] void_type resolve_void_type() {
return void_type{resolve_void_type_data<Void>()};
return void_type{resolve_void_type_data<std::remove_cv_t<Void>>()};
}
private:
@@ -9043,6 +9101,122 @@ namespace meta_hpp::detail
: type_data_base{type_id{type_list<void_tag<Void>>{}}, type_kind::void_} {}
}
namespace meta_hpp::detail
{
template <
typename To,
typename From,
typename ToDT = std::remove_pointer_t<To>,
typename FromDT = std::remove_pointer_t<From> >
concept pointer_ucast_kind //
= (std::is_pointer_v<From> && std::is_class_v<FromDT>) //
&& (std::is_pointer_v<To> && (std::is_class_v<ToDT> || std::is_void_v<ToDT>)) //
&& (!std::is_const_v<FromDT> || std::is_const_v<ToDT>) //
&& (!std::is_volatile_v<FromDT> || std::is_volatile_v<ToDT>); //
template <
typename To,
typename From,
typename ToDT = std::remove_reference_t<To>,
typename FromDT = std::remove_reference_t<From> >
concept reference_ucast_kind //
= (std::is_reference_v<From> && std::is_class_v<FromDT>) //
&& (std::is_reference_v<To> && std::is_class_v<ToDT>) //
&& (!std::is_const_v<FromDT> || std::is_const_v<ToDT>) //
&& (!std::is_volatile_v<FromDT> || std::is_volatile_v<ToDT>); //
}
namespace meta_hpp
{
template < typename To, typename From >
requires detail::pointer_ucast_kind<To, From>
To ucast(From from);
template < typename To, typename From >
requires detail::reference_ucast_kind<To, From>
To ucast(From&& from);
}
namespace meta_hpp::detail
{
struct polymorphic_meta_info {
const void* ptr{};
class_type type{};
};
template < typename T >
concept check_polymorphic_cast_support //
= requires(type_registry& r, const T& v) {
{ v.get_most_derived_polymorphic_meta_info(r) } -> std::convertible_to<polymorphic_meta_info>;
};
}
namespace meta_hpp
{
template < typename To, typename From >
requires detail::pointer_ucast_kind<To, From>
To ucast(From from) {
using from_data_type = std::remove_pointer_t<From>;
using to_data_type = std::remove_pointer_t<To>;
static_assert(
detail::check_polymorphic_cast_support<from_data_type>,
"The type doesn't support ucasts. Use the META_HPP_ENABLE_POLYMORPHIC_CAST macro to fix it."
);
if ( from == nullptr ) {
return nullptr;
}
if constexpr ( std::is_same_v<std::remove_cv_t<from_data_type>, std::remove_cv_t<to_data_type>> ) {
return from;
}
detail::type_registry& registry{detail::type_registry::instance()};
const detail::polymorphic_meta_info& meta_info{from->get_most_derived_polymorphic_meta_info(registry)};
// NOLINTNEXTLINE(*-const-cast)
void* most_derived_object_ptr = const_cast<void*>(meta_info.ptr);
if constexpr ( std::is_void_v<std::remove_cv_t<to_data_type>> ) {
return most_derived_object_ptr;
} else {
const class_type& to_class_type = registry.resolve_class_type<to_data_type>();
return static_cast<To>(detail::pointer_upcast(most_derived_object_ptr, meta_info.type, to_class_type));
}
}
template < typename To, typename From >
requires detail::reference_ucast_kind<To, From>
To ucast(From&& from) {
using from_data_type = std::remove_reference_t<From>;
using to_data_type = std::remove_reference_t<To>;
static_assert(
detail::check_polymorphic_cast_support<from_data_type>,
"The type doesn't support ucasts. Use the META_HPP_ENABLE_POLYMORPHIC_CAST macro to fix it."
);
if ( to_data_type* ptr = ucast<to_data_type*>(std::addressof(from)) ) {
return *ptr;
}
throw_exception(error_code::bad_cast);
}
}
#define META_HPP_ENABLE_POLYMORPHIC_CAST() \
public: \
META_HPP_IGNORE_OVERRIDE_WARNINGS_PUSH() \
virtual ::meta_hpp::detail::polymorphic_meta_info get_most_derived_polymorphic_meta_info( \
::meta_hpp::detail::type_registry& registry \
) const { \
using self_type = std::remove_cvref_t<decltype(*this)>; \
return ::meta_hpp::detail::polymorphic_meta_info{.ptr = this, .type = registry.resolve_class_type<self_type>()}; \
} \
META_HPP_IGNORE_OVERRIDE_WARNINGS_POP() \
private:
namespace meta_hpp::detail
{
template < typename T >

View File

@@ -0,0 +1,219 @@
/*******************************************************************************
* 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 <vmath.hpp/vmath_all.hpp>
#include <rttr/type>
#include <rttr/registration>
#include <benchmark/benchmark.h>
namespace
{
namespace meta = meta_hpp;
namespace vmath = vmath_hpp;
struct base1 {
unsigned b1{1};
base1() = default;
virtual ~base1() = default;
base1(const base1&) = default;
base1& operator=(const base1&) = default;
RTTR_ENABLE()
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
struct base2 : base1 {
unsigned b2{2};
RTTR_ENABLE(base1)
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
struct base3 : base2 {
unsigned b3{3};
RTTR_ENABLE(base2)
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
struct base4 : base3 {
unsigned b4{4};
RTTR_ENABLE(base3)
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
base4* dynamic_cast_1(base1* b1) {
return dynamic_cast<base4*>(b1);
}
base4* dynamic_cast_2(base2* b2) {
return dynamic_cast<base4*>(b2);
}
base4* dynamic_cast_3(base3* b3) {
return dynamic_cast<base4*>(b3);
}
base4* dynamic_cast_4(base4* b4) {
return dynamic_cast<base4*>(b4);
}
const bool registered = [](){
meta::class_<base1>();
meta::class_<base2>().base_<base1>();
meta::class_<base3>().base_<base2>();
meta::class_<base4>().base_<base3>();
return true;
}();
}
//
// native
//
namespace
{
[[maybe_unused]]
void dynamic_cast_1(benchmark::State &state) {
base4 b4;
for ( auto _ : state ) {
base4* r = dynamic_cast_1(&b4);
benchmark::DoNotOptimize(r);
}
}
[[maybe_unused]]
void dynamic_cast_2(benchmark::State &state) {
base4 b4;
for ( auto _ : state ) {
base4* r = dynamic_cast_2(&b4);
benchmark::DoNotOptimize(r);
}
}
[[maybe_unused]]
void dynamic_cast_3(benchmark::State &state) {
base4 b4;
for ( auto _ : state ) {
base4* r = dynamic_cast_3(&b4);
benchmark::DoNotOptimize(r);
}
}
[[maybe_unused]]
void dynamic_cast_4(benchmark::State &state) {
base4 b4;
for ( auto _ : state ) {
base4* r = dynamic_cast_4(&b4);
benchmark::DoNotOptimize(r);
}
}
}
//
// meta
//
namespace
{
[[maybe_unused]]
void meta_dynamic_cast_1(benchmark::State &state) {
base4 b4;
for ( auto _ : state ) {
base4* r = meta::ucast<base4*>(static_cast<base1*>(&b4));
benchmark::DoNotOptimize(r);
}
}
[[maybe_unused]]
void meta_dynamic_cast_2(benchmark::State &state) {
base4 b4;
for ( auto _ : state ) {
base4* r = meta::ucast<base4*>(static_cast<base2*>(&b4));
benchmark::DoNotOptimize(r);
}
}
[[maybe_unused]]
void meta_dynamic_cast_3(benchmark::State &state) {
base4 b4;
for ( auto _ : state ) {
base4* r = meta::ucast<base4*>(static_cast<base3*>(&b4));
benchmark::DoNotOptimize(r);
}
}
[[maybe_unused]]
void meta_dynamic_cast_4(benchmark::State &state) {
base4 b4;
for ( auto _ : state ) {
base4* r = meta::ucast<base4*>(static_cast<base4*>(&b4));
benchmark::DoNotOptimize(r);
}
}
}
//
// rttr
//
namespace
{
[[maybe_unused]]
void rttr_dynamic_cast_1(benchmark::State &state) {
base4 b4;
for ( auto _ : state ) {
base4* r = rttr::rttr_cast<base4*>(static_cast<base1*>(&b4));
benchmark::DoNotOptimize(r);
}
}
[[maybe_unused]]
void rttr_dynamic_cast_2(benchmark::State &state) {
base4 b4;
for ( auto _ : state ) {
base4* r = rttr::rttr_cast<base4*>(static_cast<base2*>(&b4));
benchmark::DoNotOptimize(r);
}
}
[[maybe_unused]]
void rttr_dynamic_cast_3(benchmark::State &state) {
base4 b4;
for ( auto _ : state ) {
base4* r = rttr::rttr_cast<base4*>(static_cast<base3*>(&b4));
benchmark::DoNotOptimize(r);
}
}
[[maybe_unused]]
void rttr_dynamic_cast_4(benchmark::State &state) {
base4 b4;
for ( auto _ : state ) {
base4* r = rttr::rttr_cast<base4*>(static_cast<base4*>(&b4));
benchmark::DoNotOptimize(r);
}
}
}
BENCHMARK(dynamic_cast_1);
BENCHMARK(meta_dynamic_cast_1);
BENCHMARK(rttr_dynamic_cast_1);
BENCHMARK(dynamic_cast_2);
BENCHMARK(meta_dynamic_cast_2);
BENCHMARK(rttr_dynamic_cast_2);
BENCHMARK(dynamic_cast_3);
BENCHMARK(meta_dynamic_cast_3);
BENCHMARK(rttr_dynamic_cast_3);
BENCHMARK(dynamic_cast_4);
BENCHMARK(meta_dynamic_cast_4);
BENCHMARK(rttr_dynamic_cast_4);

View File

@@ -0,0 +1,370 @@
/*******************************************************************************
* 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 A1 {
A1() = default;
A1(const A1&) = default;
virtual ~A1() = default;
char a{'a'};
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
struct B1 : A1 {
B1() = default;
B1(const B1&) = default;
char b{'b'};
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
struct C1 : B1 {
C1() = default;
C1(const C1&) = default;
char c{'c'};
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
// A1 <- B1 <- C1
struct A2 {
A2() = default;
A2(const A2&) = default;
virtual ~A2() = default;
char a{'a'};
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
struct B2 : virtual A2 {
B2() = default;
B2(const B2&) = default;
char b{'b'};
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
struct C2 : virtual A2 {
C2() = default;
C2(const C2&) = default;
char c{'c'};
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
struct D2 {
D2() = default;
D2(const D2&) = default;
virtual ~D2() = default;
char d{'d'};
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
struct E2 : D2 {
E2() = default;
E2(const E2&) = default;
char e{'e'};
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
struct F2 : B2, C2, E2 {
F2() = default;
F2(const F2&) = default;
char f{'f'};
META_HPP_ENABLE_POLYMORPHIC_CAST()
};
// A2 <= B2
// <-
// A2 <= C2 F2
// <-
// D2 <- E2
namespace meta = meta_hpp;
template < meta::detail::class_kind From, meta::detail::class_kind To, typename Value >
void check_casts_impl(Value& value) {
using from_void_cv = meta::detail::add_cv_t<From, void>;
from_void_cv* from_void_ptr = dynamic_cast<from_void_cv*>(std::addressof(value));
REQUIRE(from_void_ptr == meta::ucast<from_void_cv*>(std::addressof(value)));
From* from_ptr = dynamic_cast<From*>(std::addressof(value));
REQUIRE(from_ptr == meta::ucast<From*>(std::addressof(value)));
using to_void_cv = meta::detail::add_cv_t<To, void>;
to_void_cv* to_void_ptr = dynamic_cast<to_void_cv*>(from_ptr);
REQUIRE(to_void_ptr == meta::ucast<to_void_cv*>(from_ptr));
To* to_ptr = dynamic_cast<To*>(from_ptr);
REQUIRE(to_ptr == meta::ucast<To*>(from_ptr));
if ( from_ptr ) {
if ( to_ptr ) {
REQUIRE(to_ptr == std::addressof(meta::ucast<To&>(*from_ptr)));
} else {
REQUIRE_THROWS(meta::ucast<To&>(*from_ptr));
}
}
}
template < meta::detail::class_kind From, meta::detail::class_kind To, typename Value >
void check_casts(Value& value) {
check_casts_impl<From, To>(value);
check_casts_impl<const From, const To>(std::as_const(value));
}
}
TEST_CASE("meta/meta_utilities/ucast/_") {
namespace meta = meta_hpp;
meta::class_<A1>();
meta::class_<B1>().base_<A1>();
meta::class_<C1>().base_<B1>();
meta::class_<A2>();
meta::class_<B2>().base_<A2>();
meta::class_<C2>().base_<A2>();
meta::class_<D2>();
meta::class_<E2>().base_<D2>();
meta::class_<F2>().base_<B2, C2, E2>();
}
TEST_CASE("meta/meta_utilities/ucast") {
namespace meta = meta_hpp;
SUBCASE("1") {
{
C1 c;
check_casts<A1, A1>(c);
check_casts<A1, B1>(c);
check_casts<A1, C1>(c);
check_casts<B1, A1>(c);
check_casts<B1, B1>(c);
check_casts<B1, C1>(c);
check_casts<C1, A1>(c);
check_casts<C1, B1>(c);
check_casts<C1, C1>(c);
}
{
B1 b;
check_casts<A1, A1>(b);
check_casts<A1, B1>(b);
check_casts<A1, C1>(b);
check_casts<B1, A1>(b);
check_casts<B1, B1>(b);
check_casts<B1, C1>(b);
check_casts<C1, A1>(b);
check_casts<C1, B1>(b);
check_casts<C1, C1>(b);
}
{
A1 a;
check_casts<A1, A1>(a);
check_casts<A1, B1>(a);
check_casts<A1, C1>(a);
check_casts<B1, A1>(a);
check_casts<B1, B1>(a);
check_casts<B1, C1>(a);
check_casts<C1, A1>(a);
check_casts<C1, B1>(a);
check_casts<C1, C1>(a);
}
}
SUBCASE("2") {
{
F2 f;
check_casts<A2, A2>(f);
check_casts<A2, B2>(f);
check_casts<A2, C2>(f);
check_casts<A2, D2>(f);
check_casts<A2, E2>(f);
check_casts<A2, F2>(f);
check_casts<B2, A2>(f);
check_casts<B2, B2>(f);
check_casts<B2, C2>(f);
check_casts<B2, D2>(f);
check_casts<B2, E2>(f);
check_casts<B2, F2>(f);
check_casts<C2, A2>(f);
check_casts<C2, B2>(f);
check_casts<C2, C2>(f);
check_casts<C2, D2>(f);
check_casts<C2, E2>(f);
check_casts<C2, F2>(f);
check_casts<D2, A2>(f);
check_casts<D2, B2>(f);
check_casts<D2, C2>(f);
check_casts<D2, D2>(f);
check_casts<D2, E2>(f);
check_casts<D2, F2>(f);
check_casts<E2, A2>(f);
check_casts<E2, B2>(f);
check_casts<E2, C2>(f);
check_casts<E2, D2>(f);
check_casts<E2, E2>(f);
check_casts<E2, F2>(f);
check_casts<F2, A2>(f);
check_casts<F2, B2>(f);
check_casts<F2, C2>(f);
check_casts<F2, D2>(f);
check_casts<F2, E2>(f);
check_casts<F2, F2>(f);
}
{
B2 b;
check_casts<A2, A2>(b);
check_casts<A2, B2>(b);
check_casts<A2, C2>(b);
check_casts<A2, D2>(b);
check_casts<A2, E2>(b);
check_casts<A2, F2>(b);
check_casts<B2, A2>(b);
check_casts<B2, B2>(b);
check_casts<B2, C2>(b);
check_casts<B2, D2>(b);
check_casts<B2, E2>(b);
check_casts<B2, F2>(b);
check_casts<C2, A2>(b);
check_casts<C2, B2>(b);
check_casts<C2, C2>(b);
check_casts<C2, D2>(b);
check_casts<C2, E2>(b);
check_casts<C2, F2>(b);
check_casts<D2, A2>(b);
check_casts<D2, B2>(b);
check_casts<D2, C2>(b);
check_casts<D2, D2>(b);
check_casts<D2, E2>(b);
check_casts<D2, F2>(b);
check_casts<E2, A2>(b);
check_casts<E2, B2>(b);
check_casts<E2, C2>(b);
check_casts<E2, D2>(b);
check_casts<E2, E2>(b);
check_casts<E2, F2>(b);
check_casts<F2, A2>(b);
check_casts<F2, B2>(b);
check_casts<F2, C2>(b);
check_casts<F2, D2>(b);
check_casts<F2, E2>(b);
check_casts<F2, F2>(b);
}
{
E2 e;
check_casts<A2, A2>(e);
check_casts<A2, B2>(e);
check_casts<A2, C2>(e);
check_casts<A2, D2>(e);
check_casts<A2, E2>(e);
check_casts<A2, F2>(e);
check_casts<B2, A2>(e);
check_casts<B2, B2>(e);
check_casts<B2, C2>(e);
check_casts<B2, D2>(e);
check_casts<B2, E2>(e);
check_casts<B2, F2>(e);
check_casts<C2, A2>(e);
check_casts<C2, B2>(e);
check_casts<C2, C2>(e);
check_casts<C2, D2>(e);
check_casts<C2, E2>(e);
check_casts<C2, F2>(e);
check_casts<D2, A2>(e);
check_casts<D2, B2>(e);
check_casts<D2, C2>(e);
check_casts<D2, D2>(e);
check_casts<D2, E2>(e);
check_casts<D2, F2>(e);
check_casts<E2, A2>(e);
check_casts<E2, B2>(e);
check_casts<E2, C2>(e);
check_casts<E2, D2>(e);
check_casts<E2, E2>(e);
check_casts<E2, F2>(e);
check_casts<F2, A2>(e);
check_casts<F2, B2>(e);
check_casts<F2, C2>(e);
check_casts<F2, D2>(e);
check_casts<F2, E2>(e);
check_casts<F2, F2>(e);
}
{
D2 d;
check_casts<A2, A2>(d);
check_casts<A2, B2>(d);
check_casts<A2, C2>(d);
check_casts<A2, D2>(d);
check_casts<A2, E2>(d);
check_casts<A2, F2>(d);
check_casts<B2, A2>(d);
check_casts<B2, B2>(d);
check_casts<B2, C2>(d);
check_casts<B2, D2>(d);
check_casts<B2, E2>(d);
check_casts<B2, F2>(d);
check_casts<C2, A2>(d);
check_casts<C2, B2>(d);
check_casts<C2, C2>(d);
check_casts<C2, D2>(d);
check_casts<C2, E2>(d);
check_casts<C2, F2>(d);
check_casts<D2, A2>(d);
check_casts<D2, B2>(d);
check_casts<D2, C2>(d);
check_casts<D2, D2>(d);
check_casts<D2, E2>(d);
check_casts<D2, F2>(d);
check_casts<E2, A2>(d);
check_casts<E2, B2>(d);
check_casts<E2, C2>(d);
check_casts<E2, D2>(d);
check_casts<E2, E2>(d);
check_casts<E2, F2>(d);
check_casts<F2, A2>(d);
check_casts<F2, B2>(d);
check_casts<F2, C2>(d);
check_casts<F2, D2>(d);
check_casts<F2, E2>(d);
check_casts<F2, F2>(d);
}
}
}

View File

@@ -65,6 +65,9 @@
#include "meta_types/reference_type.hpp"
#include "meta_types/void_type.hpp"
#include "meta_ucast.hpp"
#include "meta_ucast/ucast.hpp"
#include "meta_uresult.hpp"
#include "meta_uresult/uresult.hpp"

View File

@@ -63,3 +63,57 @@
# define META_HPP_PP_CAT(x, y) META_HPP_PP_CAT_I(x, y)
# define META_HPP_PP_CAT_I(x, y) x##y
#endif
#if defined(_MSC_VER)
# define META_HPP_MSVC
#elif defined(__clang__)
# define META_HPP_CLANG
#elif defined(__GNUC__)
# define META_HPP_GCC
#endif
#if defined(META_HPP_MSVC)
# define META_HPP_MSVC_IGNORE_WARNING(w) __pragma(warning(disable : w))
# define META_HPP_MSVC_IGNORE_WARNINGS_PUSH() __pragma(warning(push))
# define META_HPP_MSVC_IGNORE_WARNINGS_POP() __pragma(warning(pop))
#else
# define META_HPP_MSVC_IGNORE_WARNING(w)
# define META_HPP_MSVC_IGNORE_WARNINGS_PUSH()
# define META_HPP_MSVC_IGNORE_WARNINGS_POP()
#endif
#if defined(META_HPP_CLANG)
# define META_HPP_CLANG_PRAGMA_TO_STR(x) _Pragma(#x)
# define META_HPP_CLANG_IGNORE_WARNING(w) META_HPP_CLANG_PRAGMA_TO_STR(clang diagnostic ignored w)
# define META_HPP_CLANG_IGNORE_WARNINGS_PUSH() _Pragma("clang diagnostic push")
# define META_HPP_CLANG_IGNORE_WARNINGS_POP() _Pragma("clang diagnostic pop")
#else
# define META_HPP_CLANG_PRAGMA_TO_STR(x)
# define META_HPP_CLANG_IGNORE_WARNING(w)
# define META_HPP_CLANG_IGNORE_WARNINGS_PUSH()
# define META_HPP_CLANG_IGNORE_WARNINGS_POP()
#endif
#if defined(META_HPP_GCC)
# define META_HPP_GCC_PRAGMA_TO_STR(x) _Pragma(#x)
# define META_HPP_GCC_IGNORE_WARNING(w) META_HPP_GCC_PRAGMA_TO_STR(GCC diagnostic ignored w)
# define META_HPP_GCC_IGNORE_WARNINGS_PUSH() _Pragma("GCC diagnostic push")
# define META_HPP_GCC_IGNORE_WARNINGS_POP() _Pragma("GCC diagnostic pop")
#else
# define META_HPP_GCC_PRAGMA_TO_STR(x)
# define META_HPP_GCC_IGNORE_WARNING(w)
# define META_HPP_GCC_IGNORE_WARNINGS_PUSH()
# define META_HPP_GCC_IGNORE_WARNINGS_POP()
#endif
#define META_HPP_IGNORE_OVERRIDE_WARNINGS_PUSH() \
META_HPP_MSVC_IGNORE_WARNINGS_PUSH() \
META_HPP_CLANG_IGNORE_WARNINGS_PUSH() \
META_HPP_GCC_IGNORE_WARNINGS_PUSH() \
META_HPP_CLANG_IGNORE_WARNING("-Winconsistent-missing-override") \
META_HPP_CLANG_IGNORE_WARNING("-Wsuggest-override")
#define META_HPP_IGNORE_OVERRIDE_WARNINGS_POP() \
META_HPP_GCC_IGNORE_WARNINGS_POP() \
META_HPP_CLANG_IGNORE_WARNINGS_POP() \
META_HPP_MSVC_IGNORE_WARNINGS_POP()

View File

@@ -23,6 +23,8 @@ namespace meta_hpp::detail
enum class error_code {
no_error,
bad_cast,
bad_const_access,
bad_uvalue_access,
@@ -38,6 +40,8 @@ namespace meta_hpp::detail
switch ( error ) {
case error_code::no_error:
return "no error";
case error_code::bad_cast:
return "bad cast";
case error_code::bad_const_access:
return "bad const access";
case error_code::bad_uvalue_access:

View File

@@ -0,0 +1,45 @@
/*******************************************************************************
* 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 "meta_base.hpp"
namespace meta_hpp::detail
{
template <
typename To,
typename From,
typename ToDT = std::remove_pointer_t<To>,
typename FromDT = std::remove_pointer_t<From> >
concept pointer_ucast_kind //
= (std::is_pointer_v<From> && std::is_class_v<FromDT>) //
&& (std::is_pointer_v<To> && (std::is_class_v<ToDT> || std::is_void_v<ToDT>)) //
&& (!std::is_const_v<FromDT> || std::is_const_v<ToDT>) //
&& (!std::is_volatile_v<FromDT> || std::is_volatile_v<ToDT>); //
template <
typename To,
typename From,
typename ToDT = std::remove_reference_t<To>,
typename FromDT = std::remove_reference_t<From> >
concept reference_ucast_kind //
= (std::is_reference_v<From> && std::is_class_v<FromDT>) //
&& (std::is_reference_v<To> && std::is_class_v<ToDT>) //
&& (!std::is_const_v<FromDT> || std::is_const_v<ToDT>) //
&& (!std::is_volatile_v<FromDT> || std::is_volatile_v<ToDT>); //
}
namespace meta_hpp
{
template < typename To, typename From >
requires detail::pointer_ucast_kind<To, From>
To ucast(From from);
template < typename To, typename From >
requires detail::reference_ucast_kind<To, From>
To ucast(From&& from);
}

View File

@@ -0,0 +1,93 @@
/*******************************************************************************
* 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 "../meta_base.hpp"
#include "../meta_ucast.hpp"
#include "../meta_detail/type_registry.hpp"
#include "../meta_detail/value_utilities/utraits.hpp"
namespace meta_hpp::detail
{
struct polymorphic_meta_info {
const void* ptr{};
class_type type{};
};
template < typename T >
concept check_polymorphic_cast_support //
= requires(type_registry& r, const T& v) {
{ v.get_most_derived_polymorphic_meta_info(r) } -> std::convertible_to<polymorphic_meta_info>;
};
}
namespace meta_hpp
{
template < typename To, typename From >
requires detail::pointer_ucast_kind<To, From>
To ucast(From from) {
using from_data_type = std::remove_pointer_t<From>;
using to_data_type = std::remove_pointer_t<To>;
static_assert(
detail::check_polymorphic_cast_support<from_data_type>,
"The type doesn't support ucasts. Use the META_HPP_ENABLE_POLYMORPHIC_CAST macro to fix it."
);
if ( from == nullptr ) {
return nullptr;
}
if constexpr ( std::is_same_v<std::remove_cv_t<from_data_type>, std::remove_cv_t<to_data_type>> ) {
return from;
}
detail::type_registry& registry{detail::type_registry::instance()};
const detail::polymorphic_meta_info& meta_info{from->get_most_derived_polymorphic_meta_info(registry)};
// NOLINTNEXTLINE(*-const-cast)
void* most_derived_object_ptr = const_cast<void*>(meta_info.ptr);
if constexpr ( std::is_void_v<std::remove_cv_t<to_data_type>> ) {
return most_derived_object_ptr;
} else {
const class_type& to_class_type = registry.resolve_class_type<to_data_type>();
return static_cast<To>(detail::pointer_upcast(most_derived_object_ptr, meta_info.type, to_class_type));
}
}
template < typename To, typename From >
requires detail::reference_ucast_kind<To, From>
To ucast(From&& from) {
using from_data_type = std::remove_reference_t<From>;
using to_data_type = std::remove_reference_t<To>;
static_assert(
detail::check_polymorphic_cast_support<from_data_type>,
"The type doesn't support ucasts. Use the META_HPP_ENABLE_POLYMORPHIC_CAST macro to fix it."
);
if ( to_data_type* ptr = ucast<to_data_type*>(std::addressof(from)) ) {
return *ptr;
}
throw_exception(error_code::bad_cast);
}
}
#define META_HPP_ENABLE_POLYMORPHIC_CAST() \
public: \
META_HPP_IGNORE_OVERRIDE_WARNINGS_PUSH() \
virtual ::meta_hpp::detail::polymorphic_meta_info get_most_derived_polymorphic_meta_info( \
::meta_hpp::detail::type_registry& registry \
) const { \
using self_type = std::remove_cvref_t<decltype(*this)>; \
return ::meta_hpp::detail::polymorphic_meta_info{.ptr = this, .type = registry.resolve_class_type<self_type>()}; \
} \
META_HPP_IGNORE_OVERRIDE_WARNINGS_POP() \
private: