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

@@ -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: