diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index a99d657..d339945 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -30,8 +30,6 @@ #include #include #include -#include -#include #include #include #include @@ -4152,76 +4150,6 @@ namespace meta_hpp::detail }; } -namespace meta_hpp::detail -{ - class state_registry final { - public: - class locker final { - public: - explicit locker() - : lock_{instance().mutex_} {} - - ~locker() = default; - - locker(locker&&) = default; - locker& operator=(locker&&) = default; - - locker(const locker&) = delete; - locker& operator=(const locker&) = delete; - - private: - std::unique_lock lock_; - }; - - [[nodiscard]] static state_registry& instance() { - static state_registry instance; - return instance; - } - - public: - template < typename F > - void for_each_scope(F&& f) const { - const locker lock; - - for ( auto&& [name, scope] : scopes_ ) { - std::invoke(f, scope); - } - } - - [[nodiscard]] scope get_scope_by_name(std::string_view name) const noexcept { - const locker lock; - - if ( auto iter{scopes_.find(name)}; iter != scopes_.end() ) { - return iter->second; - } - - return scope{}; - } - - [[nodiscard]] scope resolve_scope(std::string_view name) { - const locker lock; - - if ( auto iter{scopes_.find(name)}; iter != scopes_.end() ) { - return iter->second; - } - - auto&& [iter, _] = scopes_.emplace( // - std::string{name}, - scope_state::make(std::string{name}, metadata_map{}) - ); - - return iter->second; - } - - private: - state_registry() = default; - - private: - std::recursive_mutex mutex_; - std::map> scopes_; - }; -} - namespace meta_hpp::detail { class type_registry final { @@ -4268,18 +4196,6 @@ namespace meta_hpp::detail return any_type{}; } -#if !defined(META_HPP_NO_RTTI) - [[nodiscard]] any_type get_type_by_rtti(const std::type_index& index) const noexcept { - const locker lock; - - if ( auto iter{rtti_types_.find(index)}; iter != rtti_types_.end() ) { - return iter->second; - } - - return any_type{}; - } -#endif - public: template < array_kind Array > [[nodiscard]] array_type resolve_type() { @@ -4487,29 +4403,106 @@ namespace meta_hpp::detail template < typename Type, typename TypeData > void ensure_type(TypeData& type_data) { const locker lock; - - auto&& [position, emplaced] = types_.emplace(any_type{&type_data}); - if ( !emplaced ) { - return; - } - -#if !defined(META_HPP_NO_RTTI) - META_HPP_TRY { - rtti_types_.emplace(typeid(Type), any_type{&type_data}); - } - META_HPP_CATCH(...) { - types_.erase(position); - META_HPP_RETHROW(); - } -#endif + types_.emplace(any_type{&type_data}); } private: std::recursive_mutex mutex_; std::set> types_; -#if !defined(META_HPP_NO_RTTI) - std::map> rtti_types_; -#endif + }; +} + +namespace meta_hpp::detail +{ + struct poly_info final { + const void* ptr{}; + class_type type{}; + }; + + template < typename T > + concept check_poly_info_enabled // + = requires(type_registry& r, const T& v) { + { v.get_most_derived_poly_info(r) } -> std::convertible_to; + }; +} + +#define META_HPP_ENABLE_POLY_INFO() \ +public: \ + META_HPP_IGNORE_OVERRIDE_WARNINGS_PUSH() \ + virtual ::meta_hpp::detail::poly_info get_most_derived_poly_info(::meta_hpp::detail::type_registry& registry) const { \ + using self_type = std::remove_cvref_t; \ + return ::meta_hpp::detail::poly_info{.ptr = this, .type = registry.resolve_class_type()}; \ + } \ + META_HPP_IGNORE_OVERRIDE_WARNINGS_POP() \ +private: + +namespace meta_hpp::detail +{ + class state_registry final { + public: + class locker final { + public: + explicit locker() + : lock_{instance().mutex_} {} + + ~locker() = default; + + locker(locker&&) = default; + locker& operator=(locker&&) = default; + + locker(const locker&) = delete; + locker& operator=(const locker&) = delete; + + private: + std::unique_lock lock_; + }; + + [[nodiscard]] static state_registry& instance() { + static state_registry instance; + return instance; + } + + public: + template < typename F > + void for_each_scope(F&& f) const { + const locker lock; + + for ( auto&& [name, scope] : scopes_ ) { + std::invoke(f, scope); + } + } + + [[nodiscard]] scope get_scope_by_name(std::string_view name) const noexcept { + const locker lock; + + if ( auto iter{scopes_.find(name)}; iter != scopes_.end() ) { + return iter->second; + } + + return scope{}; + } + + [[nodiscard]] scope resolve_scope(std::string_view name) { + const locker lock; + + if ( auto iter{scopes_.find(name)}; iter != scopes_.end() ) { + return iter->second; + } + + auto&& [iter, _] = scopes_.emplace( // + std::string{name}, + scope_state::make(std::string{name}, metadata_map{}) + ); + + return iter->second; + } + + private: + state_registry() = default; + + private: + std::recursive_mutex mutex_; + std::map> scopes_; }; } @@ -4567,16 +4560,19 @@ namespace meta_hpp return registry.resolve_destructor_type(); } - template < typename T > - [[nodiscard]] any_type resolve_polymorphic_type(T&& v) noexcept { -#if !defined(META_HPP_NO_RTTI) + template < typename From > + requires std::is_class_v> + [[nodiscard]] class_type resolve_poly_type(From&& from) noexcept { + using from_data_type = std::remove_reference_t; + + static_assert( + detail::check_poly_info_enabled, + "The type doesn't support ucasts. Use the META_HPP_ENABLE_POLY_INFO macro to fix it." + ); + using namespace detail; type_registry& registry = type_registry::instance(); - return registry.get_type_by_rtti(typeid(v)); -#else - (void)v; - return any_type{}; -#endif + return from.get_most_derived_poly_info(registry).type; } } @@ -9133,20 +9129,6 @@ namespace meta_hpp 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; - }; -} - namespace meta_hpp { template < typename To, typename From > @@ -9156,8 +9138,8 @@ namespace meta_hpp using to_data_type = std::remove_pointer_t; static_assert( - detail::check_polymorphic_cast_support, - "The type doesn't support ucasts. Use the META_HPP_ENABLE_POLYMORPHIC_CAST macro to fix it." + detail::check_poly_info_enabled, + "The type doesn't support ucasts. Use the META_HPP_ENABLE_POLY_INFO macro to fix it." ); if ( from == nullptr ) { @@ -9168,12 +9150,12 @@ namespace meta_hpp return from; } else { detail::type_registry& registry{detail::type_registry::instance()}; - const detail::polymorphic_meta_info& meta_info{from->get_most_derived_polymorphic_meta_info(registry)}; + const detail::poly_info& meta_info{from->get_most_derived_poly_info(registry)}; // NOLINTNEXTLINE(*-const-cast) void* most_derived_object_ptr = const_cast(meta_info.ptr); - if constexpr ( std::is_void_v> ) { + if constexpr ( std::is_void_v ) { return most_derived_object_ptr; } else { const class_type& to_class_type = registry.resolve_class_type(); @@ -9189,8 +9171,8 @@ namespace meta_hpp using to_data_type = std::remove_reference_t; static_assert( - detail::check_polymorphic_cast_support, - "The type doesn't support ucasts. Use the META_HPP_ENABLE_POLYMORPHIC_CAST macro to fix it." + detail::check_poly_info_enabled, + "The type doesn't support ucasts. Use the META_HPP_ENABLE_POLY_INFO macro to fix it." ); if ( to_data_type* ptr = ucast(std::addressof(from)) ) { @@ -9201,18 +9183,6 @@ namespace meta_hpp } } -#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; \ - return ::meta_hpp::detail::polymorphic_meta_info{.ptr = this, .type = registry.resolve_class_type()}; \ - } \ - META_HPP_IGNORE_OVERRIDE_WARNINGS_POP() \ -private: - namespace meta_hpp::detail { template < typename T > diff --git a/develop/untests/meta_features/diamond_tests.cpp b/develop/untests/meta_features/diamond_tests.cpp index 11384af..9319eef 100644 --- a/develop/untests/meta_features/diamond_tests.cpp +++ b/develop/untests/meta_features/diamond_tests.cpp @@ -19,11 +19,12 @@ namespace A& operator=(const A&) = delete; virtual ~A() = default; + META_HPP_ENABLE_POLY_INFO() }; - struct B : virtual A {}; - struct C : virtual A {}; - struct D : B, C {}; + struct B : virtual A { META_HPP_ENABLE_POLY_INFO() }; + struct C : virtual A { META_HPP_ENABLE_POLY_INFO() }; + struct D : B, C { META_HPP_ENABLE_POLY_INFO() }; struct E {}; } @@ -322,24 +323,42 @@ TEST_CASE("meta/meta_features/diamond") { } } - SUBCASE("resolve_polymorphic_type") { - const D d; + SUBCASE("resolve_poly_type") { + D d; - const A& ad = d; - const B& bd = d; - const C& cd = d; - const D& dd = d; + A& ad = d; + B& bd = d; + C& cd = d; + D& dd = d; CHECK(meta::resolve_type(ad) == meta::resolve_type()); CHECK(meta::resolve_type(bd) == meta::resolve_type()); CHECK(meta::resolve_type(cd) == meta::resolve_type()); CHECK(meta::resolve_type(dd) == meta::resolve_type()); - #if !defined(META_HPP_NO_RTTI) - CHECK(meta::resolve_polymorphic_type(ad) == meta::resolve_type()); - CHECK(meta::resolve_polymorphic_type(bd) == meta::resolve_type()); - CHECK(meta::resolve_polymorphic_type(cd) == meta::resolve_type()); - CHECK(meta::resolve_polymorphic_type(dd) == meta::resolve_type()); - #endif + CHECK(meta::resolve_type(std::as_const(ad)) == meta::resolve_type()); + CHECK(meta::resolve_type(std::as_const(bd)) == meta::resolve_type()); + CHECK(meta::resolve_type(std::as_const(cd)) == meta::resolve_type()); + CHECK(meta::resolve_type(std::as_const(dd)) == meta::resolve_type()); + + CHECK(meta::resolve_poly_type(A{}) == meta::resolve_type()); + CHECK(meta::resolve_poly_type(B{}) == meta::resolve_type()); + CHECK(meta::resolve_poly_type(C{}) == meta::resolve_type()); + CHECK(meta::resolve_poly_type(D{}) == meta::resolve_type()); + + CHECK(meta::resolve_poly_type(ad) == meta::resolve_type()); + CHECK(meta::resolve_poly_type(bd) == meta::resolve_type()); + CHECK(meta::resolve_poly_type(cd) == meta::resolve_type()); + CHECK(meta::resolve_poly_type(dd) == meta::resolve_type()); + + CHECK(meta::resolve_poly_type(std::move(ad)) == meta::resolve_type()); + CHECK(meta::resolve_poly_type(std::move(bd)) == meta::resolve_type()); + CHECK(meta::resolve_poly_type(std::move(cd)) == meta::resolve_type()); + CHECK(meta::resolve_poly_type(std::move(dd)) == meta::resolve_type()); + + CHECK(meta::resolve_poly_type(std::as_const(ad)) == meta::resolve_type()); + CHECK(meta::resolve_poly_type(std::as_const(bd)) == meta::resolve_type()); + CHECK(meta::resolve_poly_type(std::as_const(cd)) == meta::resolve_type()); + CHECK(meta::resolve_poly_type(std::as_const(dd)) == meta::resolve_type()); } } diff --git a/develop/untests/meta_utilities/cast_tests.cpp b/develop/untests/meta_utilities/cast_tests.cpp index 2a92029..c975576 100644 --- a/develop/untests/meta_utilities/cast_tests.cpp +++ b/develop/untests/meta_utilities/cast_tests.cpp @@ -14,21 +14,21 @@ namespace A1(const A1&) = default; virtual ~A1() = default; char a{'a'}; - META_HPP_ENABLE_POLYMORPHIC_CAST() + META_HPP_ENABLE_POLY_INFO() }; struct B1 : A1 { B1() = default; B1(const B1&) = default; char b{'b'}; - META_HPP_ENABLE_POLYMORPHIC_CAST() + META_HPP_ENABLE_POLY_INFO() }; struct C1 : B1 { C1() = default; C1(const C1&) = default; char c{'c'}; - META_HPP_ENABLE_POLYMORPHIC_CAST() + META_HPP_ENABLE_POLY_INFO() }; // A1 <- B1 <- C1 @@ -38,21 +38,21 @@ namespace A2(const A2&) = default; virtual ~A2() = default; char a{'a'}; - META_HPP_ENABLE_POLYMORPHIC_CAST() + META_HPP_ENABLE_POLY_INFO() }; struct B2 : virtual A2 { B2() = default; B2(const B2&) = default; char b{'b'}; - META_HPP_ENABLE_POLYMORPHIC_CAST() + META_HPP_ENABLE_POLY_INFO() }; struct C2 : virtual A2 { C2() = default; C2(const C2&) = default; char c{'c'}; - META_HPP_ENABLE_POLYMORPHIC_CAST() + META_HPP_ENABLE_POLY_INFO() }; @@ -61,21 +61,21 @@ namespace D2(const D2&) = default; virtual ~D2() = default; char d{'d'}; - META_HPP_ENABLE_POLYMORPHIC_CAST() + META_HPP_ENABLE_POLY_INFO() }; struct E2 : D2 { E2() = default; E2(const E2&) = default; char e{'e'}; - META_HPP_ENABLE_POLYMORPHIC_CAST() + META_HPP_ENABLE_POLY_INFO() }; struct F2 : B2, C2, E2 { F2() = default; F2(const F2&) = default; char f{'f'}; - META_HPP_ENABLE_POLYMORPHIC_CAST() + META_HPP_ENABLE_POLY_INFO() }; diff --git a/headers/meta.hpp/meta_base/base.hpp b/headers/meta.hpp/meta_base/base.hpp index 48be7a1..13ac4ab 100644 --- a/headers/meta.hpp/meta_base/base.hpp +++ b/headers/meta.hpp/meta_base/base.hpp @@ -31,8 +31,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/headers/meta.hpp/meta_detail/poly_info.hpp b/headers/meta.hpp/meta_detail/poly_info.hpp new file mode 100644 index 0000000..c69d830 --- /dev/null +++ b/headers/meta.hpp/meta_detail/poly_info.hpp @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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_types.hpp" + +#include "type_registry.hpp" + +namespace meta_hpp::detail +{ + struct poly_info final { + const void* ptr{}; + class_type type{}; + }; + + template < typename T > + concept check_poly_info_enabled // + = requires(type_registry& r, const T& v) { + { v.get_most_derived_poly_info(r) } -> std::convertible_to; + }; +} + +#define META_HPP_ENABLE_POLY_INFO() \ +public: \ + META_HPP_IGNORE_OVERRIDE_WARNINGS_PUSH() \ + virtual ::meta_hpp::detail::poly_info get_most_derived_poly_info(::meta_hpp::detail::type_registry& registry) const { \ + using self_type = std::remove_cvref_t; \ + return ::meta_hpp::detail::poly_info{.ptr = this, .type = registry.resolve_class_type()}; \ + } \ + META_HPP_IGNORE_OVERRIDE_WARNINGS_POP() \ +private: diff --git a/headers/meta.hpp/meta_detail/type_registry.hpp b/headers/meta.hpp/meta_detail/type_registry.hpp index f86552f..05911ac 100644 --- a/headers/meta.hpp/meta_detail/type_registry.hpp +++ b/headers/meta.hpp/meta_detail/type_registry.hpp @@ -55,18 +55,6 @@ namespace meta_hpp::detail return any_type{}; } -#if !defined(META_HPP_NO_RTTI) - [[nodiscard]] any_type get_type_by_rtti(const std::type_index& index) const noexcept { - const locker lock; - - if ( auto iter{rtti_types_.find(index)}; iter != rtti_types_.end() ) { - return iter->second; - } - - return any_type{}; - } -#endif - public: template < array_kind Array > [[nodiscard]] array_type resolve_type() { @@ -274,28 +262,11 @@ namespace meta_hpp::detail template < typename Type, typename TypeData > void ensure_type(TypeData& type_data) { const locker lock; - - auto&& [position, emplaced] = types_.emplace(any_type{&type_data}); - if ( !emplaced ) { - return; - } - -#if !defined(META_HPP_NO_RTTI) - META_HPP_TRY { - rtti_types_.emplace(typeid(Type), any_type{&type_data}); - } - META_HPP_CATCH(...) { - types_.erase(position); - META_HPP_RETHROW(); - } -#endif + types_.emplace(any_type{&type_data}); } private: std::recursive_mutex mutex_; std::set> types_; -#if !defined(META_HPP_NO_RTTI) - std::map> rtti_types_; -#endif }; } diff --git a/headers/meta.hpp/meta_registry.hpp b/headers/meta.hpp/meta_registry.hpp index 2876ef0..ef89bdc 100644 --- a/headers/meta.hpp/meta_registry.hpp +++ b/headers/meta.hpp/meta_registry.hpp @@ -10,6 +10,7 @@ #include "meta_states.hpp" #include "meta_types.hpp" +#include "meta_detail/poly_info.hpp" #include "meta_detail/state_registry.hpp" #include "meta_detail/type_registry.hpp" @@ -67,16 +68,19 @@ namespace meta_hpp return registry.resolve_destructor_type(); } - template < typename T > - [[nodiscard]] any_type resolve_polymorphic_type(T&& v) noexcept { -#if !defined(META_HPP_NO_RTTI) + template < typename From > + requires std::is_class_v> + [[nodiscard]] class_type resolve_poly_type(From&& from) noexcept { + using from_data_type = std::remove_reference_t; + + static_assert( + detail::check_poly_info_enabled, + "The type doesn't support ucasts. Use the META_HPP_ENABLE_POLY_INFO macro to fix it." + ); + using namespace detail; type_registry& registry = type_registry::instance(); - return registry.get_type_by_rtti(typeid(v)); -#else - (void)v; - return any_type{}; -#endif + return from.get_most_derived_poly_info(registry).type; } } diff --git a/headers/meta.hpp/meta_ucast/ucast.hpp b/headers/meta.hpp/meta_ucast/ucast.hpp index b4fbd57..79fc77a 100644 --- a/headers/meta.hpp/meta_ucast/ucast.hpp +++ b/headers/meta.hpp/meta_ucast/ucast.hpp @@ -9,23 +9,10 @@ #include "../meta_base.hpp" #include "../meta_ucast.hpp" +#include "../meta_detail/poly_info.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; - }; -} - namespace meta_hpp { template < typename To, typename From > @@ -35,8 +22,8 @@ namespace meta_hpp using to_data_type = std::remove_pointer_t; static_assert( - detail::check_polymorphic_cast_support, - "The type doesn't support ucasts. Use the META_HPP_ENABLE_POLYMORPHIC_CAST macro to fix it." + detail::check_poly_info_enabled, + "The type doesn't support ucasts. Use the META_HPP_ENABLE_POLY_INFO macro to fix it." ); if ( from == nullptr ) { @@ -47,12 +34,12 @@ namespace meta_hpp return from; } else { detail::type_registry& registry{detail::type_registry::instance()}; - const detail::polymorphic_meta_info& meta_info{from->get_most_derived_polymorphic_meta_info(registry)}; + const detail::poly_info& meta_info{from->get_most_derived_poly_info(registry)}; // NOLINTNEXTLINE(*-const-cast) void* most_derived_object_ptr = const_cast(meta_info.ptr); - if constexpr ( std::is_void_v> ) { + if constexpr ( std::is_void_v ) { return most_derived_object_ptr; } else { const class_type& to_class_type = registry.resolve_class_type(); @@ -68,8 +55,8 @@ namespace meta_hpp using to_data_type = std::remove_reference_t; static_assert( - detail::check_polymorphic_cast_support, - "The type doesn't support ucasts. Use the META_HPP_ENABLE_POLYMORPHIC_CAST macro to fix it." + detail::check_poly_info_enabled, + "The type doesn't support ucasts. Use the META_HPP_ENABLE_POLY_INFO macro to fix it." ); if ( to_data_type* ptr = ucast(std::addressof(from)) ) { @@ -79,15 +66,3 @@ namespace meta_hpp 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; \ - return ::meta_hpp::detail::polymorphic_meta_info{.ptr = this, .type = registry.resolve_class_type()}; \ - } \ - META_HPP_IGNORE_OVERRIDE_WARNINGS_POP() \ -private: