diff --git a/headers/meta.hpp/meta_all.hpp b/headers/meta.hpp/meta_all.hpp index 3befe92..432a9f8 100644 --- a/headers/meta.hpp/meta_all.hpp +++ b/headers/meta.hpp/meta_all.hpp @@ -17,6 +17,7 @@ #include "meta_states.hpp" #include "meta_states/ctor.hpp" +#include "meta_states/dtor.hpp" #include "meta_states/evalue.hpp" #include "meta_states/function.hpp" #include "meta_states/member.hpp" @@ -28,6 +29,7 @@ #include "meta_traits/array_traits.hpp" #include "meta_traits/class_traits.hpp" #include "meta_traits/ctor_traits.hpp" +#include "meta_traits/dtor_traits.hpp" #include "meta_traits/enum_traits.hpp" #include "meta_traits/function_traits.hpp" #include "meta_traits/member_traits.hpp" @@ -41,6 +43,7 @@ #include "meta_types/array_type.hpp" #include "meta_types/class_type.hpp" #include "meta_types/ctor_type.hpp" +#include "meta_types/dtor_type.hpp" #include "meta_types/enum_type.hpp" #include "meta_types/function_type.hpp" #include "meta_types/member_type.hpp" diff --git a/headers/meta.hpp/meta_base.hpp b/headers/meta.hpp/meta_base.hpp index 7068549..5f08db5 100644 --- a/headers/meta.hpp/meta_base.hpp +++ b/headers/meta.hpp/meta_base.hpp @@ -86,6 +86,7 @@ namespace meta_hpp namespace meta_hpp { class ctor; + class dtor; class evalue; class function; class member; @@ -96,6 +97,7 @@ namespace meta_hpp namespace detail { struct ctor_state; + struct dtor_state; struct evalue_state; struct function_state; struct member_state; @@ -104,6 +106,7 @@ namespace meta_hpp struct variable_state; using ctor_state_ptr = std::shared_ptr; + using dtor_state_ptr = std::shared_ptr; using evalue_state_ptr = std::shared_ptr; using function_state_ptr = std::shared_ptr; using member_state_ptr = std::shared_ptr; @@ -119,6 +122,7 @@ namespace meta_hpp class array_type; class class_type; class ctor_type; + class dtor_type; class enum_type; class function_type; class member_type; @@ -135,6 +139,7 @@ namespace meta_hpp struct array_type_data; struct class_type_data; struct ctor_type_data; + struct dtor_type_data; struct enum_type_data; struct function_type_data; struct member_type_data; @@ -149,6 +154,7 @@ namespace meta_hpp using array_type_data_ptr = std::shared_ptr; using class_type_data_ptr = std::shared_ptr; using ctor_type_data_ptr = std::shared_ptr; + using dtor_type_data_ptr = std::shared_ptr; using enum_type_data_ptr = std::shared_ptr; using function_type_data_ptr = std::shared_ptr; using member_type_data_ptr = std::shared_ptr; @@ -164,6 +170,7 @@ namespace meta_hpp namespace meta_hpp { struct ctor_index; + struct dtor_index; struct evalue_index; struct function_index; struct member_index; @@ -178,6 +185,7 @@ namespace meta_hpp using enum_map = std::map>; using ctor_map = std::map>; + using dtor_map = std::map>; using evalue_map = std::map>; using function_map = std::map>; using member_map = std::map>; diff --git a/headers/meta.hpp/meta_kinds.hpp b/headers/meta.hpp/meta_kinds.hpp index 9ff3d00..72691a6 100644 --- a/headers/meta.hpp/meta_kinds.hpp +++ b/headers/meta.hpp/meta_kinds.hpp @@ -14,6 +14,7 @@ namespace meta_hpp array_, class_, ctor_, + dtor_, enum_, function_, member_, @@ -100,6 +101,12 @@ namespace meta_hpp::detail using kind_type_data = ctor_type_data; }; + template <> + struct type_kind_traits { + using kind_type = dtor_type; + using kind_type_data = dtor_type_data; + }; + template <> struct type_kind_traits { using kind_type = enum_type; diff --git a/headers/meta.hpp/meta_registry.hpp b/headers/meta.hpp/meta_registry.hpp index 52b365a..958013b 100644 --- a/headers/meta.hpp/meta_registry.hpp +++ b/headers/meta.hpp/meta_registry.hpp @@ -18,6 +18,11 @@ namespace meta_hpp class_kind && requires(Args&&... args) { { Class{std::forward(args)...} }; }; + template < typename Class > + concept class_bind_dtor_kind = + class_kind && + requires(Class&& inst) { { inst.~Class() }; }; + template < typename Class, typename Base > concept class_bind_base_kind = class_kind && class_kind && @@ -45,6 +50,9 @@ namespace meta_hpp class_bind& ctor_(Policy = Policy{}) requires detail::class_bind_ctor_kind; + class_bind& dtor_() + requires detail::class_bind_dtor_kind; + template < detail::class_kind Base > class_bind& base_() requires detail::class_bind_base_kind; diff --git a/headers/meta.hpp/meta_registry/class_bind.hpp b/headers/meta.hpp/meta_registry/class_bind.hpp index 5f5b811..c2388f8 100644 --- a/headers/meta.hpp/meta_registry/class_bind.hpp +++ b/headers/meta.hpp/meta_registry/class_bind.hpp @@ -31,6 +31,15 @@ namespace meta_hpp return *this; } + template < detail::class_kind Class > + class_bind& class_bind::dtor_() + requires detail::class_bind_dtor_kind + { + auto dtor_state = detail::dtor_state::make(); + data_->dtors.emplace(dtor_state->index, std::move(dtor_state)); + return *this; + } + template < detail::class_kind Class > template < detail::class_kind Base > class_bind& class_bind::base_() diff --git a/headers/meta.hpp/meta_states.hpp b/headers/meta.hpp/meta_states.hpp index c8f5bc7..9115cd4 100644 --- a/headers/meta.hpp/meta_states.hpp +++ b/headers/meta.hpp/meta_states.hpp @@ -17,6 +17,7 @@ namespace meta_hpp template < typename T > concept state_family = std::is_same_v || + std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || @@ -153,6 +154,32 @@ namespace meta_hpp detail::ctor_state_ptr state_; }; + class dtor final { + public: + explicit dtor() = default; + explicit dtor(detail::dtor_state_ptr state); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] const dtor_index& get_index() const noexcept; + [[nodiscard]] const dtor_type& get_type() const noexcept; + + template < typename Arg > + void invoke(Arg&& ptr) const; + + template < typename Arg > + void operator()(Arg&& ptr) const; + + template < typename Arg > + [[nodiscard]] bool is_invocable_with() const noexcept; + + template < typename Arg > + [[nodiscard]] bool is_invocable_with(Arg&& ptr) const noexcept; + private: + detail::dtor_state_ptr state_; + }; + class evalue final { public: explicit evalue() = default; @@ -339,6 +366,18 @@ namespace meta_hpp::detail [[nodiscard]] static ctor_state_ptr make(); }; + struct dtor_state final { + using invoke_impl = std::function; + using is_invocable_with_impl = std::function; + + const dtor_index index; + const invoke_impl invoke; + const is_invocable_with_impl is_invocable_with; + + template < class_kind Class > + [[nodiscard]] static dtor_state_ptr make(); + }; + struct evalue_state final { const evalue_index index; const value enum_value; diff --git a/headers/meta.hpp/meta_states/dtor.hpp b/headers/meta.hpp/meta_states/dtor.hpp new file mode 100644 index 0000000..fdee5bd --- /dev/null +++ b/headers/meta.hpp/meta_states/dtor.hpp @@ -0,0 +1,114 @@ +/******************************************************************************* + * 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, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#pragma once + +#include "../meta_base.hpp" +#include "../meta_states.hpp" + +#include "../meta_types/dtor_type.hpp" + +namespace meta_hpp::detail +{ + template < class_kind Class > + void raw_dtor_invoke(const arg& ptr) { + using dt = dtor_traits; + using class_type = typename dt::class_type; + + if ( !ptr.can_cast_to() ) { + throw std::logic_error("an attempt to call a destructor with an incorrect argument type"); + } + + class_type* raw_ptr = ptr.cast(); + if ( raw_ptr ) { + raw_ptr->~Class(); + } + } + + template < class_kind Class > + bool raw_dtor_is_invocable_with(const arg_base& ptr) { + using dt = dtor_traits; + using class_type = typename dt::class_type; + + return ptr.can_cast_to(); + } +} + +namespace meta_hpp::detail +{ + template < class_kind Class > + dtor_state::invoke_impl make_dtor_invoke() { + using namespace std::placeholders; + return std::bind(&raw_dtor_invoke, _1); + } + + template < class_kind Class > + dtor_state::is_invocable_with_impl make_dtor_is_invocable_with() { + using namespace std::placeholders; + return std::bind(&raw_dtor_is_invocable_with, _1); + } +} + +namespace meta_hpp::detail +{ + template < class_kind Class > + dtor_state_ptr dtor_state::make() { + dtor_index index{dtor_type_data::get_static()}; + return std::make_shared(dtor_state{ + .index{std::move(index)}, + .invoke{make_dtor_invoke()}, + .is_invocable_with{make_dtor_is_invocable_with()}, + }); + } +} + +namespace meta_hpp +{ + inline dtor::dtor(detail::dtor_state_ptr state) + : state_{std::move(state)} {} + + inline bool dtor::is_valid() const noexcept { + return !!state_; + } + + inline dtor::operator bool() const noexcept { + return is_valid(); + } + + inline const dtor_index& dtor::get_index() const noexcept { + return state_->index; + } + + inline const dtor_type& dtor::get_type() const noexcept { + return state_->index.type; + } + + template < typename Arg > + void dtor::invoke(Arg&& ptr) const { + using namespace detail; + const arg varg{std::forward(ptr)}; + state_->invoke(varg); + } + + template < typename Arg > + void dtor::operator()(Arg&& ptr) const { + invoke(std::forward(ptr)); + } + + template < typename Arg > + bool dtor::is_invocable_with() const noexcept { + using namespace detail; + const arg_base varg{type_list{}}; + return state_->is_invocable_with(varg); + } + + template < typename Arg > + bool dtor::is_invocable_with(Arg&& ptr) const noexcept { + using namespace detail; + const arg_base varg{std::forward(ptr)}; + return state_->is_invocable_with(varg); + } +} diff --git a/headers/meta.hpp/meta_traits.hpp b/headers/meta.hpp/meta_traits.hpp index cde2cd0..5ce4006 100644 --- a/headers/meta.hpp/meta_traits.hpp +++ b/headers/meta.hpp/meta_traits.hpp @@ -20,6 +20,9 @@ namespace meta_hpp::detail template < class_kind Class, typename... Args > struct ctor_traits; + template < class_kind Class > + struct dtor_traits; + template < enum_kind Enum > struct enum_traits; @@ -61,6 +64,10 @@ namespace meta_hpp is_noexcept = 1 << 0, }; + enum class dtor_flags : std::uint32_t { + is_noexcept = 1 << 0, + }; + enum class enum_flags : std::uint32_t { is_scoped = 1 << 0, }; @@ -100,6 +107,7 @@ namespace meta_hpp ENUM_HPP_OPERATORS_DECL(array_flags) ENUM_HPP_OPERATORS_DECL(class_flags) ENUM_HPP_OPERATORS_DECL(ctor_flags) + ENUM_HPP_OPERATORS_DECL(dtor_flags) ENUM_HPP_OPERATORS_DECL(enum_flags) ENUM_HPP_OPERATORS_DECL(function_flags) ENUM_HPP_OPERATORS_DECL(member_flags) diff --git a/headers/meta.hpp/meta_traits/dtor_traits.hpp b/headers/meta.hpp/meta_traits/dtor_traits.hpp new file mode 100644 index 0000000..1838343 --- /dev/null +++ b/headers/meta.hpp/meta_traits/dtor_traits.hpp @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#pragma once + +#include "../meta_base.hpp" +#include "../meta_traits.hpp" + +namespace meta_hpp::detail +{ + template < class_kind Class > + struct dtor_traits { + using class_type = Class; + + [[nodiscard]] static constexpr bitflags make_flags() noexcept { + bitflags flags; + + if constexpr ( std::is_nothrow_destructible_v ) { + flags.set(dtor_flags::is_noexcept); + } + + return flags; + } + }; +} diff --git a/headers/meta.hpp/meta_types.hpp b/headers/meta.hpp/meta_types.hpp index ebf8a7e..d0a6d90 100644 --- a/headers/meta.hpp/meta_types.hpp +++ b/headers/meta.hpp/meta_types.hpp @@ -68,6 +68,7 @@ namespace meta_hpp std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || @@ -132,6 +133,7 @@ namespace meta_hpp any_type(const array_type& other) noexcept; any_type(const class_type& other) noexcept; any_type(const ctor_type& other) noexcept; + any_type(const dtor_type& other) noexcept; any_type(const enum_type& other) noexcept; any_type(const function_type& other) noexcept; any_type(const member_type& other) noexcept; @@ -145,6 +147,7 @@ namespace meta_hpp [[nodiscard]] bool is_array() const noexcept; [[nodiscard]] bool is_class() const noexcept; [[nodiscard]] bool is_ctor() const noexcept; + [[nodiscard]] bool is_dtor() const noexcept; [[nodiscard]] bool is_enum() const noexcept; [[nodiscard]] bool is_function() const noexcept; [[nodiscard]] bool is_member() const noexcept; @@ -158,6 +161,7 @@ namespace meta_hpp [[nodiscard]] array_type as_array() const noexcept; [[nodiscard]] class_type as_class() const noexcept; [[nodiscard]] ctor_type as_ctor() const noexcept; + [[nodiscard]] dtor_type as_dtor() const noexcept; [[nodiscard]] enum_type as_enum() const noexcept; [[nodiscard]] function_type as_function() const noexcept; [[nodiscard]] member_type as_member() const noexcept; @@ -208,6 +212,7 @@ namespace meta_hpp [[nodiscard]] const std::vector& get_argument_types() const noexcept; [[nodiscard]] const ctor_map& get_ctors() const noexcept; + [[nodiscard]] const dtor_map& get_dtors() const noexcept; [[nodiscard]] const class_set& get_bases() const noexcept; [[nodiscard]] const function_map& get_functions() const noexcept; [[nodiscard]] const member_map& get_members() const noexcept; @@ -220,6 +225,9 @@ namespace meta_hpp template < typename... Args > [[nodiscard]] std::optional operator()(Args&&... args) const; + template < typename Arg > + bool destroy(Arg&& ptr) const; + template < detail::class_kind Derived > [[nodiscard]] bool is_base_of() const noexcept; [[nodiscard]] bool is_base_of(const class_type& derived) const noexcept; @@ -272,6 +280,23 @@ namespace meta_hpp friend auto detail::data_access(const ctor_type&); }; + class dtor_type final { + public: + dtor_type() = default; + dtor_type(detail::dtor_type_data_ptr data); + + [[nodiscard]] bool is_valid() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] type_id get_id() const noexcept; + [[nodiscard]] bitflags get_flags() const noexcept; + + [[nodiscard]] any_type get_class_type() const noexcept; + private: + detail::dtor_type_data_ptr data_; + friend auto detail::data_access(const dtor_type&); + }; + class enum_type final { public: enum_type() = default; @@ -465,6 +490,7 @@ namespace meta_hpp::detail const std::vector argument_types; ctor_map ctors; + dtor_map dtors; class_set bases; function_map functions; member_map members; @@ -498,6 +524,17 @@ namespace meta_hpp::detail [[nodiscard]] static ctor_type_data_ptr get_static(); }; + struct dtor_type_data final : type_data_base { + const bitflags flags; + const any_type class_type; + + template < class_kind Class > + explicit dtor_type_data(type_list); + + template < class_kind Class > + [[nodiscard]] static dtor_type_data_ptr get_static(); + }; + struct enum_type_data final : type_data_base { const bitflags flags; const number_type underlying_type; @@ -615,6 +652,21 @@ namespace meta_hpp } }; + struct dtor_index final { + const dtor_type type; + + explicit dtor_index(dtor_type type) + : type{std::move(type)} {} + + [[nodiscard]] friend bool operator<(const dtor_index& l, const dtor_index& r) noexcept { + return l.type < r.type; + } + + [[nodiscard]] friend bool operator==(const dtor_index& l, const dtor_index& r) noexcept { + return l.type == r.type; + } + }; + struct evalue_index final { const enum_type type; const std::string name; diff --git a/headers/meta.hpp/meta_types/any_type.hpp b/headers/meta.hpp/meta_types/any_type.hpp index 2a4884c..a545ee5 100644 --- a/headers/meta.hpp/meta_types/any_type.hpp +++ b/headers/meta.hpp/meta_types/any_type.hpp @@ -39,6 +39,9 @@ namespace meta_hpp inline any_type::any_type(const ctor_type& other) noexcept : data_{detail::data_access(other)} {} + inline any_type::any_type(const dtor_type& other) noexcept + : data_{detail::data_access(other)} {} + inline any_type::any_type(const enum_type& other) noexcept : data_{detail::data_access(other)} {} @@ -78,6 +81,10 @@ namespace meta_hpp return data_ && data_->kind == type_kind::ctor_; } + inline bool any_type::is_dtor() const noexcept { + return data_ && data_->kind == type_kind::dtor_; + } + inline bool any_type::is_enum() const noexcept { return data_ && data_->kind == type_kind::enum_; } @@ -132,6 +139,12 @@ namespace meta_hpp : ctor_type{}; } + inline dtor_type any_type::as_dtor() const noexcept { + return is_dtor() + ? dtor_type{std::static_pointer_cast(data_)} + : dtor_type{}; + } + inline enum_type any_type::as_enum() const noexcept { return is_enum() ? enum_type{std::static_pointer_cast(data_)} diff --git a/headers/meta.hpp/meta_types/class_type.hpp b/headers/meta.hpp/meta_types/class_type.hpp index d2bb6bf..4925fda 100644 --- a/headers/meta.hpp/meta_types/class_type.hpp +++ b/headers/meta.hpp/meta_types/class_type.hpp @@ -78,6 +78,10 @@ namespace meta_hpp return data_->ctors; } + inline const dtor_map& class_type::get_dtors() const noexcept { + return data_->dtors; + } + inline const class_set& class_type::get_bases() const noexcept { return data_->bases; } @@ -113,6 +117,17 @@ namespace meta_hpp return create(std::forward(args)...); } + template < typename Arg > + bool class_type::destroy(Arg&& ptr) const { + for ( auto&& dtor : data_->dtors ) { + if ( dtor.second.is_invocable_with(std::forward(ptr)) ) { + dtor.second.invoke(std::forward(ptr)); + return true; + } + } + return false; + } + template < detail::class_kind Derived > bool class_type::is_base_of() const noexcept { return is_base_of(resolve_type()); diff --git a/headers/meta.hpp/meta_types/dtor_type.hpp b/headers/meta.hpp/meta_types/dtor_type.hpp new file mode 100644 index 0000000..5e2c3da --- /dev/null +++ b/headers/meta.hpp/meta_types/dtor_type.hpp @@ -0,0 +1,57 @@ +/******************************************************************************* + * 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, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#pragma once + +#include "../meta_base.hpp" +#include "../meta_types.hpp" + +#include "../meta_traits/dtor_traits.hpp" + +namespace meta_hpp::detail +{ + template < class_kind Class > + struct dtor_tag {}; + + template < class_kind Class > + // NOLINTNEXTLINE(readability-named-parameter) + dtor_type_data::dtor_type_data(type_list) + : type_data_base{type_id{type_list>{}}, type_kind::dtor_} + , flags{dtor_traits::make_flags()} + , class_type{resolve_type::class_type>()} {} + + template < class_kind Class > + dtor_type_data_ptr dtor_type_data::get_static() { + static dtor_type_data_ptr data = std::make_shared(type_list{}); + return data; + } +} + +namespace meta_hpp +{ + inline dtor_type::dtor_type(detail::dtor_type_data_ptr data) + : data_{std::move(data)} {} + + inline bool dtor_type::is_valid() const noexcept { + return !!data_; + } + + inline dtor_type::operator bool() const noexcept { + return is_valid(); + } + + inline type_id dtor_type::get_id() const noexcept { + return data_->id; + } + + inline bitflags dtor_type::get_flags() const noexcept { + return data_->flags; + } + + inline any_type dtor_type::get_class_type() const noexcept { + return data_->class_type; + } +} diff --git a/headers/meta.hpp/meta_utilities.hpp b/headers/meta.hpp/meta_utilities.hpp index 522233d..e97eb99 100644 --- a/headers/meta.hpp/meta_utilities.hpp +++ b/headers/meta.hpp/meta_utilities.hpp @@ -62,12 +62,13 @@ namespace meta_hpp::detail template < typename T > concept arg_lvalue_ref_kind = + (decay_non_uvalue_kind) && (std::is_lvalue_reference_v); template < typename T > concept arg_rvalue_ref_kind = - (!std::is_reference_v) || - (std::is_rvalue_reference_v); + (decay_non_uvalue_kind) && + (!std::is_reference_v || std::is_rvalue_reference_v); template < typename T > concept inst_class_ref_kind = @@ -76,12 +77,13 @@ namespace meta_hpp::detail template < typename T > concept inst_class_lvalue_ref_kind = + (decay_non_uvalue_kind) && (std::is_lvalue_reference_v && std::is_class_v>); template < typename T > concept inst_class_rvalue_ref_kind = - (std::is_class_v) || - (std::is_rvalue_reference_v && std::is_class_v>); + (decay_non_uvalue_kind) && + (std::is_class_v || (std::is_rvalue_reference_v && std::is_class_v>)); } namespace meta_hpp::detail @@ -194,11 +196,9 @@ namespace meta_hpp::detail explicit arg_base(T&& v); template < arg_lvalue_ref_kind T > - requires decay_non_uvalue_kind explicit arg_base(type_list); template < arg_rvalue_ref_kind T > - requires decay_non_uvalue_kind explicit arg_base(type_list); explicit arg_base(value& v); @@ -293,13 +293,13 @@ namespace meta_hpp::detail [[nodiscard]] bool is_rvalue() const noexcept; [[nodiscard]] ref_types get_ref_type() const noexcept; - [[nodiscard]] const class_type& get_raw_type() const noexcept; + [[nodiscard]] const any_type& get_raw_type() const noexcept; template < inst_class_ref_kind Q > [[nodiscard]] bool can_cast_to() const noexcept; private: ref_types ref_type_{}; - class_type raw_type_{}; + any_type raw_type_{}; }; } diff --git a/headers/meta.hpp/meta_utilities/arg.hpp b/headers/meta.hpp/meta_utilities/arg.hpp index c71de18..9181066 100644 --- a/headers/meta.hpp/meta_utilities/arg.hpp +++ b/headers/meta.hpp/meta_utilities/arg.hpp @@ -22,7 +22,6 @@ namespace meta_hpp::detail : arg_base{type_list{}} {} template < arg_lvalue_ref_kind T > - requires decay_non_uvalue_kind // NOLINTNEXTLINE(readability-named-parameter) arg_base::arg_base(type_list) : ref_type_{std::is_const_v> @@ -31,7 +30,6 @@ namespace meta_hpp::detail , raw_type_{resolve_type>()} {} template < arg_rvalue_ref_kind T > - requires decay_non_uvalue_kind // NOLINTNEXTLINE(readability-named-parameter) arg_base::arg_base(type_list) : ref_type_{std::is_const_v> diff --git a/headers/meta.hpp/meta_utilities/inst.hpp b/headers/meta.hpp/meta_utilities/inst.hpp index 9c34939..b49c9f5 100644 --- a/headers/meta.hpp/meta_utilities/inst.hpp +++ b/headers/meta.hpp/meta_utilities/inst.hpp @@ -90,35 +90,19 @@ namespace meta_hpp::detail inline inst_base::inst_base(value& v) : ref_type_{ref_types::lvalue} - , raw_type_{v.get_type().as_class()} { - if ( !v.get_type().is_class() ) { - throw std::logic_error("an attempt to create an instance with a non-class value type"); - } - } + , raw_type_{v.get_type()} {} inline inst_base::inst_base(const value& v) : ref_type_{ref_types::const_lvalue} - , raw_type_{v.get_type().as_class()} { - if ( !v.get_type().is_class() ) { - throw std::logic_error("an attempt to create an instance with a non-class value type"); - } - } + , raw_type_{v.get_type()} {} inline inst_base::inst_base(value&& v) : ref_type_{ref_types::rvalue} - , raw_type_{v.get_type().as_class()} { - if ( !v.get_type().is_class() ) { - throw std::logic_error("an attempt to create an instance with a non-class value type"); - } - } + , raw_type_{v.get_type()} {} inline inst_base::inst_base(const value&& v) : ref_type_{ref_types::const_rvalue} - , raw_type_{v.get_type().as_class()} { - if ( !v.get_type().is_class() ) { - throw std::logic_error("an attempt to create an instance with a non-class value type"); - } - } + , raw_type_{v.get_type()} {} inline bool inst_base::is_const() const noexcept { return ref_type_ == ref_types::const_lvalue @@ -139,7 +123,7 @@ namespace meta_hpp::detail return ref_type_; } - inline const class_type& inst_base::get_raw_type() const noexcept { + inline const any_type& inst_base::get_raw_type() const noexcept { return raw_type_; } @@ -148,11 +132,12 @@ namespace meta_hpp::detail using inst_class = typename inst_traits::class_type; using inst_method = typename inst_traits::method_type; - const class_type& from_type = get_raw_type(); - const class_type& to_type = resolve_type(); + const any_type& from_type = get_raw_type(); + const any_type& to_type = resolve_type(); - const auto is_a = [](const class_type& base, const class_type& derived){ - return base == derived || base.is_base_of(derived); + const auto is_a = [](const any_type& base, const any_type& derived){ + return (base == derived) + || (base.is_class() && derived.is_class() && base.as_class().is_base_of(derived.as_class())); }; const auto is_invocable = [this](){ @@ -197,21 +182,28 @@ namespace meta_hpp::detail using inst_class_cv = std::remove_reference_t; using inst_class = std::remove_cv_t; - const class_type& from_type = get_raw_type(); - const class_type& to_type = resolve_type(); + const any_type& from_type = get_raw_type(); + const any_type& to_type = resolve_type(); - void* to_ptr = detail::pointer_upcast(data_, from_type, to_type); + if ( from_type.is_class() && to_type.is_class() ) { + const class_type& from_class = from_type.as_class(); + const class_type& to_class = to_type.as_class(); - if constexpr ( !std::is_reference_v ) { - return *static_cast(to_ptr); + void* to_ptr = detail::pointer_upcast(data_, from_class, to_class); + + if constexpr ( !std::is_reference_v ) { + return *static_cast(to_ptr); + } + + if constexpr ( std::is_lvalue_reference_v ) { + return *static_cast(to_ptr); + } + + if constexpr ( std::is_rvalue_reference_v ) { + return std::move(*static_cast(to_ptr)); + } } - if constexpr ( std::is_lvalue_reference_v ) { - return *static_cast(to_ptr); - } - - if constexpr ( std::is_rvalue_reference_v ) { - return std::move(*static_cast(to_ptr)); - } + throw std::logic_error("bad instance cast"); } } diff --git a/untests/meta_states/ctor_tests.cpp b/untests/meta_states/ctor_tests.cpp index 3318d39..5b5b4f2 100644 --- a/untests/meta_states/ctor_tests.cpp +++ b/untests/meta_states/ctor_tests.cpp @@ -8,60 +8,137 @@ namespace { - struct clazz_1 { + template < std::size_t N > + struct clazz { int i{}; - clazz_1(int i) : i{i} {} + + clazz(int i) + : i{i} { + ++ctor_counter; + } + + clazz(clazz&& other) + : i{other.i} { + other.i = 0; + ++move_ctor_counter; + } + + clazz(const clazz& other) + : i{other.i} { + ++copy_ctor_counter; + } + + clazz& operator=(clazz&& other) = delete; + clazz& operator=(const clazz& other) = delete; + + ~clazz() { + ++dtor_counter; + } + public: + static int ctor_counter; + static int dtor_counter; + static int move_ctor_counter; + static int copy_ctor_counter; }; - struct clazz_2 { - int i{}; - clazz_2(int i) : i{i} {} - }; + template < std::size_t N > + int clazz::ctor_counter{0}; - struct clazz_3 { - int i{}; - clazz_3(int i) : i{i} {} - }; + template < std::size_t N > + int clazz::dtor_counter{0}; + + template < std::size_t N > + int clazz::move_ctor_counter{0}; + + template < std::size_t N > + int clazz::copy_ctor_counter{0}; } TEST_CASE("meta/meta_states/ctor") { namespace meta = meta_hpp; - meta::class_() - .ctor_(meta::ctor_policy::as_object{}); + meta::class_>() + .ctor_(meta::ctor_policy::as_object{}) + .dtor_(); - meta::class_() - .ctor_(meta::ctor_policy::as_raw_pointer{}); + meta::class_>() + .ctor_(meta::ctor_policy::as_raw_pointer{}) + .dtor_(); - meta::class_() - .ctor_(meta::ctor_policy::as_shared_pointer{}); + meta::class_>() + .ctor_(meta::ctor_policy::as_shared_pointer{}) + .dtor_(); - SUBCASE("clazz_1") { - const meta::class_type clazz_type = meta::resolve_type(); + clazz<1>::ctor_counter = 0; + clazz<1>::dtor_counter = 0; + clazz<1>::move_ctor_counter = 0; + clazz<1>::copy_ctor_counter = 0; + + clazz<2>::ctor_counter = 0; + clazz<2>::dtor_counter = 0; + clazz<2>::move_ctor_counter = 0; + clazz<2>::copy_ctor_counter = 0; + + clazz<3>::ctor_counter = 0; + clazz<3>::dtor_counter = 0; + clazz<3>::move_ctor_counter = 0; + clazz<3>::copy_ctor_counter = 0; + + SUBCASE("clazz<1>") { + const meta::class_type clazz_type = meta::resolve_type>(); REQUIRE(clazz_type); - const meta::value v = clazz_type.create(10).value(); - CHECK(v.get_type() == meta::resolve_type()); - CHECK(v.cast().i == 10); + { + const meta::value v = clazz_type.create(10).value(); + CHECK(v.get_type() == meta::resolve_type>()); + CHECK(v.cast>().i == 10); + + CHECK(clazz_type.destroy(nullptr)); + CHECK(clazz_type.destroy(meta::value{nullptr})); + } + + CHECK(clazz<1>::ctor_counter == 1); + CHECK(clazz<1>::dtor_counter == 4); + CHECK(clazz<1>::move_ctor_counter == 3); + CHECK(clazz<1>::copy_ctor_counter == 0); } - SUBCASE("clazz_2") { - const meta::class_type clazz_type = meta::resolve_type(); + SUBCASE("clazz<2>") { + const meta::class_type clazz_type = meta::resolve_type>(); REQUIRE(clazz_type); - const meta::value v = clazz_type.create(20).value(); - CHECK(v.get_type() == meta::resolve_type()); - CHECK(v.cast()->i == 20); + { + const meta::value v = clazz_type.create(20).value(); + CHECK(v.get_type() == meta::resolve_type*>()); + CHECK(v.cast*>()->i == 20); + CHECK(clazz_type.destroy(v)); - //TODO: dtor!!! + CHECK(clazz_type.destroy(nullptr)); + CHECK(clazz_type.destroy(meta::value{nullptr})); + } + + CHECK(clazz<2>::ctor_counter == 1); + CHECK(clazz<2>::dtor_counter == 1); + CHECK(clazz<2>::move_ctor_counter == 0); + CHECK(clazz<2>::copy_ctor_counter == 0); } - SUBCASE("clazz_3") { - const meta::class_type clazz_type = meta::resolve_type(); + SUBCASE("clazz<3>") { + const meta::class_type clazz_type = meta::resolve_type>(); REQUIRE(clazz_type); - const meta::value v = clazz_type.create(30).value(); - CHECK(v.get_type() == meta::resolve_type>()); - CHECK(v.cast>()->i == 30); + { + const meta::value v = clazz_type.create(30).value(); + CHECK(v.get_type() == meta::resolve_type>>()); + CHECK(v.cast>>()->i == 30); + + CHECK(clazz_type.destroy(nullptr)); + CHECK(clazz_type.destroy(meta::value{nullptr})); + } + + CHECK(clazz<3>::ctor_counter == 1); + CHECK(clazz<3>::dtor_counter == 1); + CHECK(clazz<3>::move_ctor_counter == 0); + CHECK(clazz<3>::copy_ctor_counter == 0); } }