mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-14 11:40:35 +07:00
first version of ucast
This commit is contained in:
@@ -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"
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
45
headers/meta.hpp/meta_ucast.hpp
Normal file
45
headers/meta.hpp/meta_ucast.hpp
Normal 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);
|
||||
}
|
||||
93
headers/meta.hpp/meta_ucast/ucast.hpp
Normal file
93
headers/meta.hpp/meta_ucast/ucast.hpp
Normal 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:
|
||||
Reference in New Issue
Block a user