From 36e76ccd93e451e27d2ba47344d20ea13505efa5 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 17 Feb 2023 22:29:21 +0700 Subject: [PATCH] use uerror in is_invokable_with functions --- develop/singles/headers/meta.hpp/meta_all.hpp | 636 +++++++++++------- develop/unbench/invoke_function_bench.cpp | 8 +- develop/untests/meta_states/dtor_tests.cpp | 7 + headers/meta.hpp/meta_base/exceptions.hpp | 9 +- .../meta_detail/value_utilities/uarg.hpp | 3 +- headers/meta.hpp/meta_invoke/invoke.hpp | 12 +- headers/meta.hpp/meta_states.hpp | 80 ++- headers/meta.hpp/meta_states/constructor.hpp | 23 +- headers/meta.hpp/meta_states/destructor.hpp | 48 +- headers/meta.hpp/meta_states/function.hpp | 23 +- headers/meta.hpp/meta_states/member.hpp | 54 +- headers/meta.hpp/meta_states/method.hpp | 46 +- headers/meta.hpp/meta_states/variable.hpp | 19 +- headers/meta.hpp/meta_types/class_type.hpp | 5 +- headers/meta.hpp/meta_uresult.hpp | 9 +- headers/meta.hpp/meta_uresult/uresult.hpp | 30 +- 16 files changed, 638 insertions(+), 374 deletions(-) diff --git a/develop/singles/headers/meta.hpp/meta_all.hpp b/develop/singles/headers/meta.hpp/meta_all.hpp index 5af4129..c5cddf2 100644 --- a/develop/singles/headers/meta.hpp/meta_all.hpp +++ b/develop/singles/headers/meta.hpp/meta_all.hpp @@ -319,6 +319,7 @@ namespace meta_hpp::detail enum class error_code { no_error, + bad_const_access, bad_uvalue_access, bad_uresult_access, @@ -328,13 +329,15 @@ namespace meta_hpp::detail arity_mismatch, instance_type_mismatch, - argument_types_mismatch, + argument_type_mismatch, }; inline const char* get_error_code_message(error_code error) noexcept { switch ( error ) { case error_code::no_error: return "no error"; + case error_code::bad_const_access: + return "bad const access"; case error_code::bad_uvalue_access: return "bad uvalue access"; case error_code::bad_uresult_access: @@ -349,8 +352,8 @@ namespace meta_hpp::detail return "arity mismatch"; case error_code::instance_type_mismatch: return "instance type mismatch"; - case error_code::argument_types_mismatch: - return "argument types mismatch"; + case error_code::argument_type_mismatch: + return "argument type mismatch"; } META_HPP_ASSERT(false); @@ -3020,6 +3023,150 @@ namespace meta_hpp } } +namespace meta_hpp +{ + class uerror final { + public: + uerror() = default; + ~uerror() = default; + + uerror(uerror&&) noexcept = default; + uerror(const uerror&) noexcept = default; + + uerror& operator=(uerror&&) noexcept = default; + uerror& operator=(const uerror&) noexcept = default; + + explicit uerror(error_code error) noexcept; + uerror& operator=(error_code error) noexcept; + + [[nodiscard]] bool has_error() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] error_code get_error() const noexcept; + + void reset() noexcept; + void swap(uerror& other) noexcept; + + [[nodiscard]] std::size_t get_hash() const noexcept; + [[nodiscard]] std::strong_ordering operator<=>(const uerror& other) const = default; + + private: + error_code error_{error_code::no_error}; + }; + + inline void swap(uerror& l, uerror& r) noexcept { + l.swap(r); + } + + inline uerror make_uerror(error_code error) { + return uerror{error}; + } +} + +namespace std +{ + template <> + struct hash { + size_t operator()(meta_hpp::uerror ue) const noexcept { + return ue.get_hash(); + } + }; +} + +namespace meta_hpp +{ + class uresult final { + public: + uresult() = default; + ~uresult() = default; + + uresult(uresult&&) noexcept = default; + uresult(const uresult&) = default; + + uresult& operator=(uresult&&) noexcept = default; + uresult& operator=(const uresult&) = default; + + explicit(false) uresult(uerror error) noexcept; + explicit(false) uresult(uvalue value) noexcept; + + uresult& operator=(uerror error) noexcept; + uresult& operator=(uvalue value) noexcept; + + template < // + typename T, // + typename Tp = std::decay_t, // + typename = std::enable_if_t< // + !std::is_same_v && // + !std::is_same_v && // + !std::is_same_v && // + !detail::is_in_place_type_v && // + std::is_copy_constructible_v>> // + uresult(T&& val); + + template < // + typename T, // + typename Tp = std::decay_t, // + typename = std::enable_if_t< // + !std::is_same_v && // + !std::is_same_v && // + !std::is_same_v && // + std::is_copy_constructible_v>> // + uresult& operator=(T&& val); + + template < typename T, typename... Args, typename Tp = std::decay_t > + requires std::is_copy_constructible_v // + && std::is_constructible_v // + explicit uresult(std::in_place_type_t, Args&&... args); + + template < typename T, typename U, typename... Args, typename Tp = std::decay_t > + requires std::is_copy_constructible_v // + && std::is_constructible_v&, Args...> // + explicit uresult(std::in_place_type_t, std::initializer_list ilist, Args&&... args); + + template < typename T, typename... Args, typename Tp = std::decay_t > + requires std::is_copy_constructible_v // + && std::is_constructible_v // + Tp& emplace(Args&&... args); + + template < typename T, typename U, typename... Args, typename Tp = std::decay_t > + requires std::is_copy_constructible_v // + && std::is_constructible_v&, Args...> // + Tp& emplace(std::initializer_list ilist, Args&&... args); + + [[nodiscard]] bool has_error() const noexcept; + [[nodiscard]] bool has_value() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + + [[nodiscard]] uvalue& get_value() &; + [[nodiscard]] uvalue&& get_value() &&; + [[nodiscard]] const uvalue& get_value() const&; + [[nodiscard]] const uvalue&& get_value() const&&; + + [[nodiscard]] error_code get_error() const noexcept; + + void reset() noexcept; + void swap(uresult& other) noexcept; + + private: + uvalue value_{}; + error_code error_{error_code::no_error}; + }; + + inline void swap(uresult& l, uresult& r) noexcept { + l.swap(r); + } + + template < typename T, typename... Args > + uresult make_uresult(Args&&... args) { + return uresult(std::in_place_type, std::forward(args)...); + } + + template < typename T, typename U, typename... Args > + uresult make_uresult(std::initializer_list ilist, Args&&... args) { + return uresult(std::in_place_type, ilist, std::forward(args)...); + } +} + namespace meta_hpp::detail { template < typename T > @@ -3168,34 +3315,34 @@ namespace meta_hpp } template < typename Policy > - concept constructor_policy_kind // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; // + concept constructor_policy_kind // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; template < typename Policy > - concept function_policy_kind // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; // + concept function_policy_kind // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; template < typename Policy > - concept member_policy_kind // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; // + concept member_policy_kind // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; template < typename Policy > - concept method_policy_kind // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; // + concept method_policy_kind // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; template < typename Policy > - concept variable_policy_kind // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; // + concept variable_policy_kind // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; } namespace meta_hpp @@ -3289,9 +3436,15 @@ namespace meta_hpp [[nodiscard]] destructor_type get_type() const noexcept; template < typename Arg > - bool destroy(Arg&& arg) const; + void destroy(Arg&& arg) const; void destroy_at(void* mem) const; + + template < typename Arg > + [[nodiscard]] bool is_invocable_with() const noexcept; + + template < typename Arg > + [[nodiscard]] bool is_invocable_with(Arg&& arg) const noexcept; }; class evalue final : public state_base { @@ -3400,6 +3553,9 @@ namespace meta_hpp template < typename Instance, typename... Args > std::optional safe_invoke(Instance&& instance, Args&&... args) const; + template < typename Instance, typename... Args > + uresult try_invoke(Instance&& instance, Args&&... args) const; + template < typename Instance, typename... Args > uvalue operator()(Instance&& instance, Args&&... args) const; @@ -3526,14 +3682,14 @@ namespace meta_hpp::detail struct constructor_state final : intrusive_ref_counter { using create_impl = fixed_function)>; using create_at_impl = fixed_function)>; - using is_invocable_with_impl = fixed_function)>; + using create_error_impl = fixed_function)>; constructor_index index; metadata_map metadata; create_impl create{}; create_at_impl create_at{}; - is_invocable_with_impl is_invocable_with{}; + create_error_impl create_error{}; argument_list arguments{}; template < constructor_policy_kind Policy, class_kind Class, typename... Args > @@ -3542,14 +3698,16 @@ namespace meta_hpp::detail }; struct destructor_state final : intrusive_ref_counter { - using destroy_impl = fixed_function; + using destroy_impl = fixed_function; using destroy_at_impl = fixed_function; + using destroy_error_impl = fixed_function; destructor_index index; metadata_map metadata; destroy_impl destroy{}; destroy_at_impl destroy_at{}; + destroy_error_impl destroy_error{}; template < class_kind Class > [[nodiscard]] static destructor_state_ptr make(metadata_map metadata); @@ -3570,13 +3728,13 @@ namespace meta_hpp::detail struct function_state final : intrusive_ref_counter { using invoke_impl = fixed_function)>; - using is_invocable_with_impl = fixed_function)>; + using invoke_error_impl = fixed_function)>; function_index index; metadata_map metadata; invoke_impl invoke{}; - is_invocable_with_impl is_invocable_with{}; + invoke_error_impl invoke_error{}; argument_list arguments{}; template < function_policy_kind Policy, function_pointer_kind Function > @@ -3588,16 +3746,16 @@ namespace meta_hpp::detail using getter_impl = fixed_function; using setter_impl = fixed_function; - using is_gettable_with_impl = fixed_function; - using is_settable_with_impl = fixed_function; + using getter_error_impl = fixed_function; + using setter_error_impl = fixed_function; member_index index; metadata_map metadata; getter_impl getter{}; setter_impl setter{}; - is_gettable_with_impl is_gettable_with{}; - is_settable_with_impl is_settable_with{}; + getter_error_impl getter_error{}; + setter_error_impl setter_error{}; template < member_policy_kind Policy, member_pointer_kind Member > [[nodiscard]] static member_state_ptr make(std::string name, Member member_ptr, metadata_map metadata); @@ -3606,13 +3764,13 @@ namespace meta_hpp::detail struct method_state final : intrusive_ref_counter { using invoke_impl = fixed_function)>; - using is_invocable_with_impl = fixed_function)>; + using invoke_error_impl = fixed_function)>; method_index index; metadata_map metadata; invoke_impl invoke{}; - is_invocable_with_impl is_invocable_with{}; + invoke_error_impl invoke_error{}; argument_list arguments{}; template < method_policy_kind Policy, method_pointer_kind Method > @@ -3635,14 +3793,14 @@ namespace meta_hpp::detail struct variable_state final : intrusive_ref_counter { using getter_impl = fixed_function; using setter_impl = fixed_function; - using is_settable_with_impl = fixed_function; + using setter_error_impl = fixed_function; variable_index index; metadata_map metadata; getter_impl getter{}; setter_impl setter{}; - is_settable_with_impl is_settable_with{}; + setter_error_impl setter_error{}; template < variable_policy_kind Policy, pointer_kind Pointer > [[nodiscard]] static variable_state_ptr make(std::string name, Pointer variable_ptr, metadata_map metadata); @@ -5703,9 +5861,8 @@ namespace meta_hpp::detail } break; } + throw_exception(error_code::bad_argument_cast); } - - throw_exception(error_code::bad_argument_cast); } } @@ -5826,12 +5983,19 @@ namespace meta_hpp::detail } template < function_pointer_kind Function > - bool raw_function_is_invocable_with(type_registry& registry, std::span args) { + uerror raw_function_invoke_error(type_registry& registry, std::span args) { using ft = function_traits; using argument_types = typename ft::argument_types; - return args.size() == ft::arity // - && can_cast_all_uargs(registry, args); + if ( args.size() != ft::arity ) { + return uerror{error_code::arity_mismatch}; + } + + if ( !can_cast_all_uargs(registry, args) ) { + return uerror{error_code::argument_type_mismatch}; + } + + return uerror{error_code::no_error}; } } @@ -5845,9 +6009,9 @@ namespace meta_hpp::detail } template < function_pointer_kind Function > - function_state::is_invocable_with_impl make_function_is_invocable_with(type_registry& registry) { + function_state::invoke_error_impl make_function_invoke_error(type_registry& registry) { return [®istry](std::span args) { // - return raw_function_is_invocable_with(registry, args); + return raw_function_invoke_error(registry, args); }; } @@ -5878,7 +6042,7 @@ namespace meta_hpp::detail type_registry& registry{type_registry::instance()}; function_state state{function_index{registry.resolve_type(), std::move(name)}, std::move(metadata)}; state.invoke = make_function_invoke(registry, function_ptr); - state.is_invocable_with = make_function_is_invocable_with(registry); + state.invoke_error = make_function_invoke_error(registry); state.arguments = make_function_arguments(); return make_intrusive(std::move(state)); } @@ -5920,7 +6084,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const std::array vargs{uarg_base{registry, type_list{}}...}; - return state_->is_invocable_with(vargs); + return !state_->invoke_error(vargs); } template < typename... Args > @@ -5928,7 +6092,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const std::array vargs{uarg_base{registry, std::forward(args)}...}; - return state_->is_invocable_with(vargs); + return !state_->invoke_error(vargs); } inline argument function::get_argument(std::size_t position) const noexcept { @@ -6248,11 +6412,21 @@ namespace meta_hpp::detail } template < member_pointer_kind Member > - bool raw_member_is_gettable_with(type_registry& registry, const uinst_base& inst) { + uerror raw_member_getter_error(type_registry& registry, const uinst_base& inst) { using mt = member_traits; using class_type = typename mt::class_type; - return inst.can_cast_to(registry); + if ( inst.is_inst_const() ) { + if ( !inst.can_cast_to(registry) ) { + return uerror{error_code::bad_instance_cast}; + } + } else { + if ( !inst.can_cast_to(registry) ) { + return uerror{error_code::bad_instance_cast}; + } + } + + return uerror{error_code::no_error}; } } @@ -6291,7 +6465,7 @@ namespace meta_hpp::detail } template < member_pointer_kind Member > - bool raw_member_is_settable_with(type_registry& registry, const uinst_base& inst, const uarg_base& arg) { + uerror raw_member_setter_error(type_registry& registry, const uinst_base& inst, const uarg_base& arg) { using mt = member_traits; using class_type = typename mt::class_type; using value_type = typename mt::value_type; @@ -6300,11 +6474,21 @@ namespace meta_hpp::detail (void)registry; (void)inst; (void)arg; - return false; + return uerror{error_code::bad_const_access}; } else { - return !inst.is_inst_const() // - && inst.can_cast_to(registry) // - && arg.can_cast_to(registry); // + if ( inst.is_inst_const() ) { + return uerror{error_code::bad_const_access}; + } + + if ( !inst.can_cast_to(registry) ) { + return uerror{error_code::instance_type_mismatch}; + } + + if ( !arg.can_cast_to(registry) ) { + return uerror{error_code::argument_type_mismatch}; + } + + return uerror{error_code::no_error}; } } } @@ -6319,9 +6503,9 @@ namespace meta_hpp::detail } template < member_pointer_kind Member > - member_state::is_gettable_with_impl make_member_is_gettable_with(type_registry& registry) { + member_state::getter_error_impl make_member_getter_error(type_registry& registry) { return [®istry](const uinst_base& inst) { // - return raw_member_is_gettable_with(registry, inst); + return raw_member_getter_error(registry, inst); }; } @@ -6333,9 +6517,9 @@ namespace meta_hpp::detail } template < member_pointer_kind Member > - member_state::is_settable_with_impl make_member_is_settable_with(type_registry& registry) { + member_state::setter_error_impl make_member_setter_error(type_registry& registry) { return [®istry](const uinst_base& inst, const uarg_base& arg) { // - return raw_member_is_settable_with(registry, inst, arg); + return raw_member_setter_error(registry, inst, arg); }; } } @@ -6352,8 +6536,8 @@ namespace meta_hpp::detail member_state state{member_index{registry.resolve_type(), std::move(name)}, std::move(metadata)}; state.getter = make_member_getter(registry, member_ptr); state.setter = make_member_setter(registry, member_ptr); - state.is_gettable_with = make_member_is_gettable_with(registry); - state.is_settable_with = make_member_is_settable_with(registry); + state.getter_error = make_member_getter_error(registry); + state.setter_error = make_member_setter_error(registry); return make_intrusive(std::move(state)); } } @@ -6427,7 +6611,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, type_list{}}; - return state_->is_gettable_with(vinst); + return !state_->getter_error(vinst); } template < typename Instance > @@ -6435,7 +6619,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, std::forward(instance)}; - return state_->is_gettable_with(vinst); + return !state_->getter_error(vinst); } template < typename Instance, typename Value > @@ -6444,7 +6628,7 @@ namespace meta_hpp type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, type_list{}}; const uarg_base vvalue{registry, type_list{}}; - return state_->is_settable_with(vinst, vvalue); + return !state_->setter_error(vinst, vvalue); } template < typename Instance, typename Value > @@ -6453,7 +6637,7 @@ namespace meta_hpp type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, std::forward(instance)}; const uarg_base vvalue{registry, std::forward(value)}; - return state_->is_settable_with(vinst, vvalue); + return !state_->setter_error(vinst, vvalue); } } @@ -6555,14 +6739,24 @@ namespace meta_hpp::detail } template < method_pointer_kind Method > - bool raw_method_is_invocable_with(type_registry& registry, const uinst_base& inst, std::span args) { + uerror raw_method_invoke_error(type_registry& registry, const uinst_base& inst, std::span args) { using mt = method_traits; using qualified_type = typename mt::qualified_type; using argument_types = typename mt::argument_types; - return args.size() == mt::arity // - && inst.can_cast_to(registry) // - && can_cast_all_uargs(registry, args); + if ( args.size() != mt::arity ) { + return uerror{error_code::arity_mismatch}; + } + + if ( !inst.can_cast_to(registry) ) { + return uerror{error_code::instance_type_mismatch}; + } + + if ( !can_cast_all_uargs(registry, args) ) { + return uerror{error_code::argument_type_mismatch}; + } + + return uerror{error_code::no_error}; } } @@ -6576,9 +6770,9 @@ namespace meta_hpp::detail } template < method_pointer_kind Method > - method_state::is_invocable_with_impl make_method_is_invocable_with(type_registry& registry) { + method_state::invoke_error_impl make_method_invoke_error(type_registry& registry) { return [®istry](const uinst_base& inst, std::span args) { - return raw_method_is_invocable_with(registry, inst, args); + return raw_method_invoke_error(registry, inst, args); }; } @@ -6609,7 +6803,7 @@ namespace meta_hpp::detail type_registry& registry{type_registry::instance()}; method_state state{method_index{registry.resolve_type(), std::move(name)}, std::move(metadata)}; state.invoke = make_method_invoke(registry, method_ptr); - state.is_invocable_with = make_method_is_invocable_with(registry); + state.invoke_error = make_method_invoke_error(registry); state.arguments = make_method_arguments(); return make_intrusive(std::move(state)); } @@ -6642,6 +6836,24 @@ namespace meta_hpp return std::nullopt; } + template < typename Instance, typename... Args > + uresult method::try_invoke(Instance&& instance, Args&&... args) const { + using namespace detail; + type_registry& registry{type_registry::instance()}; + + { + const uinst_base vinst{registry, type_list{}}; + const std::array vargs{uarg_base{registry, type_list{}}...}; + if ( const uerror err = state_->invoke_error(vinst, vargs) ) { + return err; + } + } + + const uinst vinst{registry, std::forward(instance)}; + const std::array vargs{uarg{registry, std::forward(args)}...}; + return state_->invoke(vinst, vargs); + } + template < typename Instance, typename... Args > uvalue method::operator()(Instance&& instance, Args&&... args) const { return invoke(std::forward(instance), std::forward(args)...); @@ -6653,7 +6865,7 @@ namespace meta_hpp type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, type_list{}}; const std::array vargs{uarg_base{registry, type_list{}}...}; - return state_->is_invocable_with(vinst, vargs); + return !state_->invoke_error(vinst, vargs); } template < typename Instance, typename... Args > @@ -6662,7 +6874,7 @@ namespace meta_hpp type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, std::forward(instance)}; const std::array vargs{uarg_base{registry, std::forward(args)}...}; - return state_->is_invocable_with(vinst, vargs); + return !state_->invoke_error(vinst, vargs); } inline argument method::get_argument(std::size_t position) const noexcept { @@ -6740,7 +6952,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const std::array vargs{uarg_base{registry, type_list{}}...}; - return raw_function_is_invocable_with(registry, vargs); + return !raw_function_invoke_error(registry, vargs); } template < detail::function_pointer_kind Function, typename... Args > @@ -6748,7 +6960,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const std::array vargs{uarg_base{registry, std::forward(args)}...}; - return raw_function_is_invocable_with(registry, vargs); + return !raw_function_invoke_error(registry, vargs); } } @@ -6769,7 +6981,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, type_list{}}; - return raw_member_is_gettable_with(registry, vinst); + return !raw_member_getter_error(registry, vinst); } template < detail::member_pointer_kind Member, typename Instance > @@ -6777,7 +6989,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, std::forward(instance)}; - return raw_member_is_gettable_with(registry, vinst); + return !raw_member_getter_error(registry, vinst); } } @@ -6799,7 +7011,7 @@ namespace meta_hpp type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, type_list{}}; const std::array vargs{uarg_base{registry, type_list{}}...}; - return raw_method_is_invocable_with(registry, vinst, vargs); + return !raw_method_invoke_error(registry, vinst, vargs); } template < detail::method_pointer_kind Method, typename Instance, typename... Args > @@ -6808,7 +7020,7 @@ namespace meta_hpp type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, std::forward(instance)}; const std::array vargs{uarg_base{registry, std::forward(args)}...}; - return raw_method_is_invocable_with(registry, vinst, vargs); + return !raw_method_invoke_error(registry, vinst, vargs); } } @@ -6944,12 +7156,19 @@ namespace meta_hpp::detail } template < class_kind Class, typename... Args > - bool raw_constructor_is_invocable_with(type_registry& registry, std::span args) { + uerror raw_constructor_create_error(type_registry& registry, std::span args) { using ct = constructor_traits; using argument_types = typename ct::argument_types; - return args.size() == ct::arity // - && can_cast_all_uargs(registry, args); + if ( args.size() != ct::arity ) { + return uerror{error_code::arity_mismatch}; + } + + if ( !can_cast_all_uargs(registry, args) ) { + return uerror{error_code::argument_type_mismatch}; + } + + return uerror{error_code::no_error}; } } @@ -6970,9 +7189,9 @@ namespace meta_hpp::detail } template < class_kind Class, typename... Args > - constructor_state::is_invocable_with_impl make_constructor_is_invocable_with(type_registry& registry) { + constructor_state::create_error_impl make_constructor_create_error(type_registry& registry) { return [®istry](std::span args) { // - return raw_constructor_is_invocable_with(registry, args); + return raw_constructor_create_error(registry, args); }; } @@ -7004,7 +7223,7 @@ namespace meta_hpp::detail constructor_state state{constructor_index{registry.resolve_constructor_type()}, std::move(metadata)}; state.create = make_constructor_create(registry); state.create_at = make_constructor_create_at(registry); - state.is_invocable_with = make_constructor_is_invocable_with(registry); + state.create_error = make_constructor_create_error(registry); state.arguments = make_constructor_arguments(); return make_intrusive(std::move(state)); } @@ -7053,7 +7272,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const std::array vargs{uarg_base{registry, type_list{}}...}; - return state_->is_invocable_with(vargs); + return !state_->create_error(vargs); } template < typename... Args > @@ -7061,7 +7280,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const std::array vargs{uarg_base{registry, std::forward(args)}...}; - return state_->is_invocable_with(vargs); + return !state_->create_error(vargs); } inline argument constructor::get_argument(std::size_t position) const noexcept { @@ -7099,16 +7318,16 @@ namespace meta_hpp namespace meta_hpp::detail { template < class_kind Class > - bool raw_destructor_destroy(type_registry& registry, const uarg& arg) { + void raw_destructor_destroy(type_registry& registry, const uarg& arg) { using dt = destructor_traits; using class_type = typename dt::class_type; - if ( !arg.can_cast_to(registry) ) { - return false; - } + META_HPP_ASSERT( // + arg.can_cast_to(registry) // + && "an attempt to call a destructor with an incorrect argument type" + ); std::unique_ptr{arg.cast(registry)}.reset(); - return true; } template < class_kind Class > @@ -7118,6 +7337,18 @@ namespace meta_hpp::detail std::destroy_at(static_cast(mem)); } + + template < class_kind Class > + uerror raw_destructor_destroy_error(type_registry& registry, const uarg_base& arg) { + using dt = destructor_traits; + using class_type = typename dt::class_type; + + if ( !arg.can_cast_to(registry) ) { + return uerror{error_code::argument_type_mismatch}; + } + + return uerror{error_code::no_error}; + } } namespace meta_hpp::detail @@ -7133,6 +7364,13 @@ namespace meta_hpp::detail destructor_state::destroy_at_impl make_destructor_destroy_at() { return &raw_destructor_destroy_at; } + + template < class_kind Class > + destructor_state::destroy_error_impl make_destructor_destroy_error(type_registry& registry) { + return [®istry](const uarg_base& arg) { // + return raw_destructor_destroy_error(registry, arg); + }; + } } namespace meta_hpp::detail @@ -7147,6 +7385,7 @@ namespace meta_hpp::detail destructor_state state{destructor_index{registry.resolve_destructor_type()}, std::move(metadata)}; state.destroy = make_destructor_destroy(registry); state.destroy_at = make_destructor_destroy_at(); + state.destroy_error = make_destructor_destroy_error(registry); return make_intrusive(std::move(state)); } } @@ -7158,7 +7397,7 @@ namespace meta_hpp } template < typename Arg > - bool destructor::destroy(Arg&& arg) const { + void destructor::destroy(Arg&& arg) const { using namespace detail; type_registry& registry{type_registry::instance()}; const uarg varg{registry, std::forward(arg)}; @@ -7168,6 +7407,22 @@ namespace meta_hpp inline void destructor::destroy_at(void* mem) const { state_->destroy_at(mem); } + + template < typename Arg > + bool destructor::is_invocable_with() const noexcept { + using namespace detail; + type_registry& registry{type_registry::instance()}; + const uarg_base varg{registry, type_list{}}; + return !state_->destroy_error(varg); + } + + template < typename Arg > + bool destructor::is_invocable_with(Arg&& arg) const noexcept { + using namespace detail; + type_registry& registry{type_registry::instance()}; + const uarg_base varg{registry, std::forward(arg)}; + return !state_->destroy_error(varg); + } } namespace meta_hpp::detail @@ -7372,16 +7627,19 @@ namespace meta_hpp::detail } template < pointer_kind Pointer > - bool raw_variable_is_settable_with(type_registry& registry, const uarg_base& arg) { + uerror raw_variable_setter_error(type_registry& registry, const uarg_base& arg) { using pt = pointer_traits; using data_type = typename pt::data_type; if constexpr ( std::is_const_v ) { (void)registry; (void)arg; - return false; + return uerror{error_code::bad_const_access}; } else { - return arg.can_cast_to(registry); + if ( !arg.can_cast_to(registry) ) { + return uerror{error_code::argument_type_mismatch}; + } + return uerror{error_code::no_error}; } } } @@ -7403,9 +7661,9 @@ namespace meta_hpp::detail } template < pointer_kind Pointer > - variable_state::is_settable_with_impl make_variable_is_settable_with(type_registry& registry) { + variable_state::setter_error_impl make_variable_setter_error(type_registry& registry) { return [®istry](const uarg_base& arg) { // - return raw_variable_is_settable_with(registry, arg); + return raw_variable_setter_error(registry, arg); }; } } @@ -7422,7 +7680,7 @@ namespace meta_hpp::detail variable_state state{variable_index{registry.resolve_type(), std::move(name)}, std::move(metadata)}; state.getter = make_variable_getter(registry, variable_ptr); state.setter = make_variable_setter(registry, variable_ptr); - state.is_settable_with = make_variable_is_settable_with(registry); + state.setter_error = make_variable_setter_error(registry); return make_intrusive(std::move(state)); } } @@ -7486,7 +7744,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const uarg_base vvalue{registry, type_list{}}; - return state_->is_settable_with(vvalue); + return !state_->setter_error(vvalue); } template < typename Value > @@ -7494,7 +7752,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const uarg_base vvalue{registry, std::forward(value)}; - return state_->is_settable_with(vvalue); + return !state_->setter_error(vvalue); } } @@ -7593,7 +7851,10 @@ namespace meta_hpp template < typename Arg > bool class_type::destroy(Arg&& arg) const { if ( const destructor& dtor = get_destructor() ) { - return dtor.destroy(std::forward(arg)); + if ( dtor.is_invocable_with(std::forward(arg)) ) { + dtor.destroy(std::forward(arg)); + return true; + } } return false; } @@ -8168,147 +8429,6 @@ namespace meta_hpp::detail : type_data_base{type_id{type_list>{}}, type_kind::void_} {} } -namespace meta_hpp -{ - class uerror final { - public: - uerror() = default; - ~uerror() = default; - - uerror(uerror&&) noexcept = default; - uerror(const uerror&) noexcept = default; - - uerror& operator=(uerror&&) noexcept = default; - uerror& operator=(const uerror&) noexcept = default; - - explicit uerror(error_code error) noexcept; - uerror& operator=(error_code error) noexcept; - - [[nodiscard]] error_code get_error() const noexcept; - - void reset() noexcept; - void swap(uerror& other) noexcept; - - [[nodiscard]] std::size_t get_hash() const noexcept; - [[nodiscard]] std::strong_ordering operator<=>(const uerror& other) const = default; - - private: - error_code error_{error_code::no_error}; - }; - - inline void swap(uerror& l, uerror& r) noexcept { - l.swap(r); - } - - inline uerror make_uerror(error_code error) { - return uerror{error}; - } -} - -namespace std -{ - template <> - struct hash { - size_t operator()(meta_hpp::uerror ue) const noexcept { - return ue.get_hash(); - } - }; -} - -namespace meta_hpp -{ - class uresult final { - public: - uresult() = default; - ~uresult() = default; - - uresult(uresult&&) noexcept = default; - uresult(const uresult&) = default; - - uresult& operator=(uresult&&) noexcept = default; - uresult& operator=(const uresult&) = default; - - explicit(false) uresult(uerror error) noexcept; - explicit(false) uresult(uvalue value) noexcept; - - uresult& operator=(uerror error) noexcept; - uresult& operator=(uvalue value) noexcept; - - template < // - typename T, // - typename Tp = std::decay_t, // - typename = std::enable_if_t< // - !std::is_same_v && // - !std::is_same_v && // - !std::is_same_v && // - !detail::is_in_place_type_v && // - std::is_copy_constructible_v>> // - uresult(T&& val); - - template < // - typename T, // - typename Tp = std::decay_t, // - typename = std::enable_if_t< // - !std::is_same_v && // - !std::is_same_v && // - !std::is_same_v && // - std::is_copy_constructible_v>> // - uresult& operator=(T&& val); - - template < typename T, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v // - explicit uresult(std::in_place_type_t, Args&&... args); - - template < typename T, typename U, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // - explicit uresult(std::in_place_type_t, std::initializer_list ilist, Args&&... args); - - template < typename T, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v // - Tp& emplace(Args&&... args); - - template < typename T, typename U, typename... Args, typename Tp = std::decay_t > - requires std::is_copy_constructible_v // - && std::is_constructible_v&, Args...> // - Tp& emplace(std::initializer_list ilist, Args&&... args); - - [[nodiscard]] bool has_error() const noexcept; - [[nodiscard]] bool has_value() const noexcept; - [[nodiscard]] explicit operator bool() const noexcept; - - void reset() noexcept; - void swap(uresult& other) noexcept; - - [[nodiscard]] uvalue& get_value() &; - [[nodiscard]] uvalue&& get_value() &&; - [[nodiscard]] const uvalue& get_value() const&; - [[nodiscard]] const uvalue&& get_value() const&&; - - [[nodiscard]] error_code get_error() const noexcept; - - private: - uvalue value_{}; - error_code error_{error_code::no_error}; - }; - - inline void swap(uresult& l, uresult& r) noexcept { - l.swap(r); - } - - template < typename T, typename... Args > - uresult make_uresult(Args&&... args) { - return uresult(std::in_place_type, std::forward(args)...); - } - - template < typename T, typename U, typename... Args > - uresult make_uresult(std::initializer_list ilist, Args&&... args) { - return uresult(std::in_place_type, ilist, std::forward(args)...); - } -} - namespace meta_hpp::detail { template < typename T > @@ -9147,6 +9267,14 @@ namespace meta_hpp return *this; } + inline bool uerror::has_error() const noexcept { + return error_ != error_code::no_error; + } + + inline uerror::operator bool() const noexcept { + return has_error(); + } + inline error_code uerror::get_error() const noexcept { return error_; } @@ -9238,17 +9366,6 @@ namespace meta_hpp return has_value(); } - inline void uresult::reset() noexcept { - value_ = uvalue{}; - error_ = error_code::no_error; - } - - inline void uresult::swap(uresult& other) noexcept { - using std::swap; - swap(value_, other.value_); - swap(error_, other.error_); - } - inline uvalue& uresult::get_value() & { return value_; } @@ -9269,4 +9386,15 @@ namespace meta_hpp inline error_code uresult::get_error() const noexcept { return error_; } + + inline void uresult::reset() noexcept { + value_ = uvalue{}; + error_ = error_code::no_error; + } + + inline void uresult::swap(uresult& other) noexcept { + using std::swap; + swap(value_, other.value_); + swap(error_, other.error_); + } } diff --git a/develop/unbench/invoke_function_bench.cpp b/develop/unbench/invoke_function_bench.cpp index 2d58ef2..470c094 100644 --- a/develop/unbench/invoke_function_bench.cpp +++ b/develop/unbench/invoke_function_bench.cpp @@ -128,7 +128,7 @@ namespace [[maybe_unused]] void meta_invoke_function_1(benchmark::State &state) { meta::function f = meta_bench_scope.get_function("static_function_1"); - META_HPP_ASSERT(f.is_valid()); + META_HPP_ASSERT(!f.is_empty()); for ( auto _ : state ) { f(static_angle); @@ -138,7 +138,7 @@ namespace [[maybe_unused]] void meta_invoke_function_2(benchmark::State &state) { meta::function f = meta_bench_scope.get_function("static_function_2"); - META_HPP_ASSERT(f.is_valid()); + META_HPP_ASSERT(!f.is_empty()); for ( auto _ : state ) { f(static_angle, vmath::unit3_x); @@ -148,7 +148,7 @@ namespace [[maybe_unused]] void meta_invoke_function_3(benchmark::State &state) { meta::function f = meta_bench_scope.get_function("static_function_3"); - META_HPP_ASSERT(f.is_valid()); + META_HPP_ASSERT(!f.is_empty()); for ( auto _ : state ) { f(static_angle, vmath::unit3_x, 2.f); @@ -158,7 +158,7 @@ namespace [[maybe_unused]] void meta_invoke_function_4(benchmark::State &state) { meta::function f = meta_bench_scope.get_function("static_function_4"); - META_HPP_ASSERT(f.is_valid()); + META_HPP_ASSERT(!f.is_empty()); for ( auto _ : state ) { f(static_angle, vmath::unit3_x, 2.f, vmath::midentity3); diff --git a/develop/untests/meta_states/dtor_tests.cpp b/develop/untests/meta_states/dtor_tests.cpp index 89376a8..e7c1fbb 100644 --- a/develop/untests/meta_states/dtor_tests.cpp +++ b/develop/untests/meta_states/dtor_tests.cpp @@ -59,6 +59,13 @@ TEST_CASE("meta/meta_states/dtor") { CHECK(dtor.get_type().get_owner_type() == meta::resolve_type()); CHECK(dtor.get_type().get_flags() == meta::destructor_flags::is_noexcept); + + CHECK(dtor.is_invocable_with()); + CHECK(dtor.is_invocable_with(meta::make_uvalue(nullptr))); + + CHECK_FALSE(dtor.is_invocable_with()); + CHECK_FALSE(dtor.is_invocable_with()); + CHECK_FALSE(dtor.is_invocable_with()); } SUBCASE("virtual_dtor") { diff --git a/headers/meta.hpp/meta_base/exceptions.hpp b/headers/meta.hpp/meta_base/exceptions.hpp index 04f9458..0e3f1aa 100644 --- a/headers/meta.hpp/meta_base/exceptions.hpp +++ b/headers/meta.hpp/meta_base/exceptions.hpp @@ -23,6 +23,7 @@ namespace meta_hpp::detail enum class error_code { no_error, + bad_const_access, bad_uvalue_access, bad_uresult_access, @@ -32,13 +33,15 @@ namespace meta_hpp::detail arity_mismatch, instance_type_mismatch, - argument_types_mismatch, + argument_type_mismatch, }; inline const char* get_error_code_message(error_code error) noexcept { switch ( error ) { case error_code::no_error: return "no error"; + case error_code::bad_const_access: + return "bad const access"; case error_code::bad_uvalue_access: return "bad uvalue access"; case error_code::bad_uresult_access: @@ -53,8 +56,8 @@ namespace meta_hpp::detail return "arity mismatch"; case error_code::instance_type_mismatch: return "instance type mismatch"; - case error_code::argument_types_mismatch: - return "argument types mismatch"; + case error_code::argument_type_mismatch: + return "argument type mismatch"; } META_HPP_ASSERT(false); diff --git a/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp b/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp index 1d9445e..83f12a6 100644 --- a/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp +++ b/headers/meta.hpp/meta_detail/value_utilities/uarg.hpp @@ -362,9 +362,8 @@ namespace meta_hpp::detail } break; } + throw_exception(error_code::bad_argument_cast); } - - throw_exception(error_code::bad_argument_cast); } } diff --git a/headers/meta.hpp/meta_invoke/invoke.hpp b/headers/meta.hpp/meta_invoke/invoke.hpp index aee4008..ba1e3e7 100644 --- a/headers/meta.hpp/meta_invoke/invoke.hpp +++ b/headers/meta.hpp/meta_invoke/invoke.hpp @@ -83,7 +83,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const std::array vargs{uarg_base{registry, type_list{}}...}; - return raw_function_is_invocable_with(registry, vargs); + return !raw_function_invoke_error(registry, vargs); } template < detail::function_pointer_kind Function, typename... Args > @@ -91,7 +91,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const std::array vargs{uarg_base{registry, std::forward(args)}...}; - return raw_function_is_invocable_with(registry, vargs); + return !raw_function_invoke_error(registry, vargs); } } @@ -112,7 +112,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, type_list{}}; - return raw_member_is_gettable_with(registry, vinst); + return !raw_member_getter_error(registry, vinst); } template < detail::member_pointer_kind Member, typename Instance > @@ -120,7 +120,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, std::forward(instance)}; - return raw_member_is_gettable_with(registry, vinst); + return !raw_member_getter_error(registry, vinst); } } @@ -142,7 +142,7 @@ namespace meta_hpp type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, type_list{}}; const std::array vargs{uarg_base{registry, type_list{}}...}; - return raw_method_is_invocable_with(registry, vinst, vargs); + return !raw_method_invoke_error(registry, vinst, vargs); } template < detail::method_pointer_kind Method, typename Instance, typename... Args > @@ -151,6 +151,6 @@ namespace meta_hpp type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, std::forward(instance)}; const std::array vargs{uarg_base{registry, std::forward(args)}...}; - return raw_method_is_invocable_with(registry, vinst, vargs); + return !raw_method_invoke_error(registry, vinst, vargs); } } diff --git a/headers/meta.hpp/meta_states.hpp b/headers/meta.hpp/meta_states.hpp index 2000cdf..8ead6a2 100644 --- a/headers/meta.hpp/meta_states.hpp +++ b/headers/meta.hpp/meta_states.hpp @@ -9,6 +9,7 @@ #include "meta_base.hpp" #include "meta_indices.hpp" #include "meta_types.hpp" +#include "meta_uresult.hpp" #include "meta_uvalue.hpp" #include "meta_detail/state_family.hpp" @@ -81,34 +82,34 @@ namespace meta_hpp } template < typename Policy > - concept constructor_policy_kind // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; // + concept constructor_policy_kind // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; template < typename Policy > - concept function_policy_kind // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; // + concept function_policy_kind // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; template < typename Policy > - concept member_policy_kind // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; // + concept member_policy_kind // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; template < typename Policy > - concept method_policy_kind // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; // + concept method_policy_kind // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; template < typename Policy > - concept variable_policy_kind // - = std::is_same_v // - || std::is_same_v // - || std::is_same_v; // + concept variable_policy_kind // + = std::is_same_v // + || std::is_same_v // + || std::is_same_v; } namespace meta_hpp @@ -202,9 +203,15 @@ namespace meta_hpp [[nodiscard]] destructor_type get_type() const noexcept; template < typename Arg > - bool destroy(Arg&& arg) const; + void destroy(Arg&& arg) const; void destroy_at(void* mem) const; + + template < typename Arg > + [[nodiscard]] bool is_invocable_with() const noexcept; + + template < typename Arg > + [[nodiscard]] bool is_invocable_with(Arg&& arg) const noexcept; }; class evalue final : public state_base { @@ -313,6 +320,9 @@ namespace meta_hpp template < typename Instance, typename... Args > std::optional safe_invoke(Instance&& instance, Args&&... args) const; + template < typename Instance, typename... Args > + uresult try_invoke(Instance&& instance, Args&&... args) const; + template < typename Instance, typename... Args > uvalue operator()(Instance&& instance, Args&&... args) const; @@ -439,14 +449,14 @@ namespace meta_hpp::detail struct constructor_state final : intrusive_ref_counter { using create_impl = fixed_function)>; using create_at_impl = fixed_function)>; - using is_invocable_with_impl = fixed_function)>; + using create_error_impl = fixed_function)>; constructor_index index; metadata_map metadata; create_impl create{}; create_at_impl create_at{}; - is_invocable_with_impl is_invocable_with{}; + create_error_impl create_error{}; argument_list arguments{}; template < constructor_policy_kind Policy, class_kind Class, typename... Args > @@ -455,14 +465,16 @@ namespace meta_hpp::detail }; struct destructor_state final : intrusive_ref_counter { - using destroy_impl = fixed_function; + using destroy_impl = fixed_function; using destroy_at_impl = fixed_function; + using destroy_error_impl = fixed_function; destructor_index index; metadata_map metadata; destroy_impl destroy{}; destroy_at_impl destroy_at{}; + destroy_error_impl destroy_error{}; template < class_kind Class > [[nodiscard]] static destructor_state_ptr make(metadata_map metadata); @@ -483,13 +495,13 @@ namespace meta_hpp::detail struct function_state final : intrusive_ref_counter { using invoke_impl = fixed_function)>; - using is_invocable_with_impl = fixed_function)>; + using invoke_error_impl = fixed_function)>; function_index index; metadata_map metadata; invoke_impl invoke{}; - is_invocable_with_impl is_invocable_with{}; + invoke_error_impl invoke_error{}; argument_list arguments{}; template < function_policy_kind Policy, function_pointer_kind Function > @@ -501,16 +513,16 @@ namespace meta_hpp::detail using getter_impl = fixed_function; using setter_impl = fixed_function; - using is_gettable_with_impl = fixed_function; - using is_settable_with_impl = fixed_function; + using getter_error_impl = fixed_function; + using setter_error_impl = fixed_function; member_index index; metadata_map metadata; getter_impl getter{}; setter_impl setter{}; - is_gettable_with_impl is_gettable_with{}; - is_settable_with_impl is_settable_with{}; + getter_error_impl getter_error{}; + setter_error_impl setter_error{}; template < member_policy_kind Policy, member_pointer_kind Member > [[nodiscard]] static member_state_ptr make(std::string name, Member member_ptr, metadata_map metadata); @@ -519,13 +531,13 @@ namespace meta_hpp::detail struct method_state final : intrusive_ref_counter { using invoke_impl = fixed_function)>; - using is_invocable_with_impl = fixed_function)>; + using invoke_error_impl = fixed_function)>; method_index index; metadata_map metadata; invoke_impl invoke{}; - is_invocable_with_impl is_invocable_with{}; + invoke_error_impl invoke_error{}; argument_list arguments{}; template < method_policy_kind Policy, method_pointer_kind Method > @@ -548,14 +560,14 @@ namespace meta_hpp::detail struct variable_state final : intrusive_ref_counter { using getter_impl = fixed_function; using setter_impl = fixed_function; - using is_settable_with_impl = fixed_function; + using setter_error_impl = fixed_function; variable_index index; metadata_map metadata; getter_impl getter{}; setter_impl setter{}; - is_settable_with_impl is_settable_with{}; + setter_error_impl setter_error{}; template < variable_policy_kind Policy, pointer_kind Pointer > [[nodiscard]] static variable_state_ptr make(std::string name, Pointer variable_ptr, metadata_map metadata); diff --git a/headers/meta.hpp/meta_states/constructor.hpp b/headers/meta.hpp/meta_states/constructor.hpp index 855271b..8dd7560 100644 --- a/headers/meta.hpp/meta_states/constructor.hpp +++ b/headers/meta.hpp/meta_states/constructor.hpp @@ -80,12 +80,19 @@ namespace meta_hpp::detail } template < class_kind Class, typename... Args > - bool raw_constructor_is_invocable_with(type_registry& registry, std::span args) { + uerror raw_constructor_create_error(type_registry& registry, std::span args) { using ct = constructor_traits; using argument_types = typename ct::argument_types; - return args.size() == ct::arity // - && can_cast_all_uargs(registry, args); + if ( args.size() != ct::arity ) { + return uerror{error_code::arity_mismatch}; + } + + if ( !can_cast_all_uargs(registry, args) ) { + return uerror{error_code::argument_type_mismatch}; + } + + return uerror{error_code::no_error}; } } @@ -106,9 +113,9 @@ namespace meta_hpp::detail } template < class_kind Class, typename... Args > - constructor_state::is_invocable_with_impl make_constructor_is_invocable_with(type_registry& registry) { + constructor_state::create_error_impl make_constructor_create_error(type_registry& registry) { return [®istry](std::span args) { // - return raw_constructor_is_invocable_with(registry, args); + return raw_constructor_create_error(registry, args); }; } @@ -140,7 +147,7 @@ namespace meta_hpp::detail constructor_state state{constructor_index{registry.resolve_constructor_type()}, std::move(metadata)}; state.create = make_constructor_create(registry); state.create_at = make_constructor_create_at(registry); - state.is_invocable_with = make_constructor_is_invocable_with(registry); + state.create_error = make_constructor_create_error(registry); state.arguments = make_constructor_arguments(); return make_intrusive(std::move(state)); } @@ -189,7 +196,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const std::array vargs{uarg_base{registry, type_list{}}...}; - return state_->is_invocable_with(vargs); + return !state_->create_error(vargs); } template < typename... Args > @@ -197,7 +204,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const std::array vargs{uarg_base{registry, std::forward(args)}...}; - return state_->is_invocable_with(vargs); + return !state_->create_error(vargs); } inline argument constructor::get_argument(std::size_t position) const noexcept { diff --git a/headers/meta.hpp/meta_states/destructor.hpp b/headers/meta.hpp/meta_states/destructor.hpp index e17e2a6..fdfe725 100644 --- a/headers/meta.hpp/meta_states/destructor.hpp +++ b/headers/meta.hpp/meta_states/destructor.hpp @@ -16,16 +16,16 @@ namespace meta_hpp::detail { template < class_kind Class > - bool raw_destructor_destroy(type_registry& registry, const uarg& arg) { + void raw_destructor_destroy(type_registry& registry, const uarg& arg) { using dt = destructor_traits; using class_type = typename dt::class_type; - if ( !arg.can_cast_to(registry) ) { - return false; - } + META_HPP_ASSERT( // + arg.can_cast_to(registry) // + && "an attempt to call a destructor with an incorrect argument type" + ); std::unique_ptr{arg.cast(registry)}.reset(); - return true; } template < class_kind Class > @@ -35,6 +35,18 @@ namespace meta_hpp::detail std::destroy_at(static_cast(mem)); } + + template < class_kind Class > + uerror raw_destructor_destroy_error(type_registry& registry, const uarg_base& arg) { + using dt = destructor_traits; + using class_type = typename dt::class_type; + + if ( !arg.can_cast_to(registry) ) { + return uerror{error_code::argument_type_mismatch}; + } + + return uerror{error_code::no_error}; + } } namespace meta_hpp::detail @@ -50,6 +62,13 @@ namespace meta_hpp::detail destructor_state::destroy_at_impl make_destructor_destroy_at() { return &raw_destructor_destroy_at; } + + template < class_kind Class > + destructor_state::destroy_error_impl make_destructor_destroy_error(type_registry& registry) { + return [®istry](const uarg_base& arg) { // + return raw_destructor_destroy_error(registry, arg); + }; + } } namespace meta_hpp::detail @@ -64,6 +83,7 @@ namespace meta_hpp::detail destructor_state state{destructor_index{registry.resolve_destructor_type()}, std::move(metadata)}; state.destroy = make_destructor_destroy(registry); state.destroy_at = make_destructor_destroy_at(); + state.destroy_error = make_destructor_destroy_error(registry); return make_intrusive(std::move(state)); } } @@ -75,7 +95,7 @@ namespace meta_hpp } template < typename Arg > - bool destructor::destroy(Arg&& arg) const { + void destructor::destroy(Arg&& arg) const { using namespace detail; type_registry& registry{type_registry::instance()}; const uarg varg{registry, std::forward(arg)}; @@ -85,4 +105,20 @@ namespace meta_hpp inline void destructor::destroy_at(void* mem) const { state_->destroy_at(mem); } + + template < typename Arg > + bool destructor::is_invocable_with() const noexcept { + using namespace detail; + type_registry& registry{type_registry::instance()}; + const uarg_base varg{registry, type_list{}}; + return !state_->destroy_error(varg); + } + + template < typename Arg > + bool destructor::is_invocable_with(Arg&& arg) const noexcept { + using namespace detail; + type_registry& registry{type_registry::instance()}; + const uarg_base varg{registry, std::forward(arg)}; + return !state_->destroy_error(varg); + } } diff --git a/headers/meta.hpp/meta_states/function.hpp b/headers/meta.hpp/meta_states/function.hpp index bbcebb0..1f1a297 100644 --- a/headers/meta.hpp/meta_states/function.hpp +++ b/headers/meta.hpp/meta_states/function.hpp @@ -64,12 +64,19 @@ namespace meta_hpp::detail } template < function_pointer_kind Function > - bool raw_function_is_invocable_with(type_registry& registry, std::span args) { + uerror raw_function_invoke_error(type_registry& registry, std::span args) { using ft = function_traits; using argument_types = typename ft::argument_types; - return args.size() == ft::arity // - && can_cast_all_uargs(registry, args); + if ( args.size() != ft::arity ) { + return uerror{error_code::arity_mismatch}; + } + + if ( !can_cast_all_uargs(registry, args) ) { + return uerror{error_code::argument_type_mismatch}; + } + + return uerror{error_code::no_error}; } } @@ -83,9 +90,9 @@ namespace meta_hpp::detail } template < function_pointer_kind Function > - function_state::is_invocable_with_impl make_function_is_invocable_with(type_registry& registry) { + function_state::invoke_error_impl make_function_invoke_error(type_registry& registry) { return [®istry](std::span args) { // - return raw_function_is_invocable_with(registry, args); + return raw_function_invoke_error(registry, args); }; } @@ -116,7 +123,7 @@ namespace meta_hpp::detail type_registry& registry{type_registry::instance()}; function_state state{function_index{registry.resolve_type(), std::move(name)}, std::move(metadata)}; state.invoke = make_function_invoke(registry, function_ptr); - state.is_invocable_with = make_function_is_invocable_with(registry); + state.invoke_error = make_function_invoke_error(registry); state.arguments = make_function_arguments(); return make_intrusive(std::move(state)); } @@ -158,7 +165,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const std::array vargs{uarg_base{registry, type_list{}}...}; - return state_->is_invocable_with(vargs); + return !state_->invoke_error(vargs); } template < typename... Args > @@ -166,7 +173,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const std::array vargs{uarg_base{registry, std::forward(args)}...}; - return state_->is_invocable_with(vargs); + return !state_->invoke_error(vargs); } inline argument function::get_argument(std::size_t position) const noexcept { diff --git a/headers/meta.hpp/meta_states/member.hpp b/headers/meta.hpp/meta_states/member.hpp index 202dba2..4865936 100644 --- a/headers/meta.hpp/meta_states/member.hpp +++ b/headers/meta.hpp/meta_states/member.hpp @@ -76,11 +76,21 @@ namespace meta_hpp::detail } template < member_pointer_kind Member > - bool raw_member_is_gettable_with(type_registry& registry, const uinst_base& inst) { + uerror raw_member_getter_error(type_registry& registry, const uinst_base& inst) { using mt = member_traits; using class_type = typename mt::class_type; - return inst.can_cast_to(registry); + if ( inst.is_inst_const() ) { + if ( !inst.can_cast_to(registry) ) { + return uerror{error_code::bad_instance_cast}; + } + } else { + if ( !inst.can_cast_to(registry) ) { + return uerror{error_code::bad_instance_cast}; + } + } + + return uerror{error_code::no_error}; } } @@ -119,7 +129,7 @@ namespace meta_hpp::detail } template < member_pointer_kind Member > - bool raw_member_is_settable_with(type_registry& registry, const uinst_base& inst, const uarg_base& arg) { + uerror raw_member_setter_error(type_registry& registry, const uinst_base& inst, const uarg_base& arg) { using mt = member_traits; using class_type = typename mt::class_type; using value_type = typename mt::value_type; @@ -128,11 +138,21 @@ namespace meta_hpp::detail (void)registry; (void)inst; (void)arg; - return false; + return uerror{error_code::bad_const_access}; } else { - return !inst.is_inst_const() // - && inst.can_cast_to(registry) // - && arg.can_cast_to(registry); // + if ( inst.is_inst_const() ) { + return uerror{error_code::bad_const_access}; + } + + if ( !inst.can_cast_to(registry) ) { + return uerror{error_code::instance_type_mismatch}; + } + + if ( !arg.can_cast_to(registry) ) { + return uerror{error_code::argument_type_mismatch}; + } + + return uerror{error_code::no_error}; } } } @@ -147,9 +167,9 @@ namespace meta_hpp::detail } template < member_pointer_kind Member > - member_state::is_gettable_with_impl make_member_is_gettable_with(type_registry& registry) { + member_state::getter_error_impl make_member_getter_error(type_registry& registry) { return [®istry](const uinst_base& inst) { // - return raw_member_is_gettable_with(registry, inst); + return raw_member_getter_error(registry, inst); }; } @@ -161,9 +181,9 @@ namespace meta_hpp::detail } template < member_pointer_kind Member > - member_state::is_settable_with_impl make_member_is_settable_with(type_registry& registry) { + member_state::setter_error_impl make_member_setter_error(type_registry& registry) { return [®istry](const uinst_base& inst, const uarg_base& arg) { // - return raw_member_is_settable_with(registry, inst, arg); + return raw_member_setter_error(registry, inst, arg); }; } } @@ -180,8 +200,8 @@ namespace meta_hpp::detail member_state state{member_index{registry.resolve_type(), std::move(name)}, std::move(metadata)}; state.getter = make_member_getter(registry, member_ptr); state.setter = make_member_setter(registry, member_ptr); - state.is_gettable_with = make_member_is_gettable_with(registry); - state.is_settable_with = make_member_is_settable_with(registry); + state.getter_error = make_member_getter_error(registry); + state.setter_error = make_member_setter_error(registry); return make_intrusive(std::move(state)); } } @@ -255,7 +275,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, type_list{}}; - return state_->is_gettable_with(vinst); + return !state_->getter_error(vinst); } template < typename Instance > @@ -263,7 +283,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, std::forward(instance)}; - return state_->is_gettable_with(vinst); + return !state_->getter_error(vinst); } template < typename Instance, typename Value > @@ -272,7 +292,7 @@ namespace meta_hpp type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, type_list{}}; const uarg_base vvalue{registry, type_list{}}; - return state_->is_settable_with(vinst, vvalue); + return !state_->setter_error(vinst, vvalue); } template < typename Instance, typename Value > @@ -281,6 +301,6 @@ namespace meta_hpp type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, std::forward(instance)}; const uarg_base vvalue{registry, std::forward(value)}; - return state_->is_settable_with(vinst, vvalue); + return !state_->setter_error(vinst, vvalue); } } diff --git a/headers/meta.hpp/meta_states/method.hpp b/headers/meta.hpp/meta_states/method.hpp index 1a6000a..8e22566 100644 --- a/headers/meta.hpp/meta_states/method.hpp +++ b/headers/meta.hpp/meta_states/method.hpp @@ -71,14 +71,24 @@ namespace meta_hpp::detail } template < method_pointer_kind Method > - bool raw_method_is_invocable_with(type_registry& registry, const uinst_base& inst, std::span args) { + uerror raw_method_invoke_error(type_registry& registry, const uinst_base& inst, std::span args) { using mt = method_traits; using qualified_type = typename mt::qualified_type; using argument_types = typename mt::argument_types; - return args.size() == mt::arity // - && inst.can_cast_to(registry) // - && can_cast_all_uargs(registry, args); + if ( args.size() != mt::arity ) { + return uerror{error_code::arity_mismatch}; + } + + if ( !inst.can_cast_to(registry) ) { + return uerror{error_code::instance_type_mismatch}; + } + + if ( !can_cast_all_uargs(registry, args) ) { + return uerror{error_code::argument_type_mismatch}; + } + + return uerror{error_code::no_error}; } } @@ -92,9 +102,9 @@ namespace meta_hpp::detail } template < method_pointer_kind Method > - method_state::is_invocable_with_impl make_method_is_invocable_with(type_registry& registry) { + method_state::invoke_error_impl make_method_invoke_error(type_registry& registry) { return [®istry](const uinst_base& inst, std::span args) { - return raw_method_is_invocable_with(registry, inst, args); + return raw_method_invoke_error(registry, inst, args); }; } @@ -125,7 +135,7 @@ namespace meta_hpp::detail type_registry& registry{type_registry::instance()}; method_state state{method_index{registry.resolve_type(), std::move(name)}, std::move(metadata)}; state.invoke = make_method_invoke(registry, method_ptr); - state.is_invocable_with = make_method_is_invocable_with(registry); + state.invoke_error = make_method_invoke_error(registry); state.arguments = make_method_arguments(); return make_intrusive(std::move(state)); } @@ -158,6 +168,24 @@ namespace meta_hpp return std::nullopt; } + template < typename Instance, typename... Args > + uresult method::try_invoke(Instance&& instance, Args&&... args) const { + using namespace detail; + type_registry& registry{type_registry::instance()}; + + { + const uinst_base vinst{registry, type_list{}}; + const std::array vargs{uarg_base{registry, type_list{}}...}; + if ( const uerror err = state_->invoke_error(vinst, vargs) ) { + return err; + } + } + + const uinst vinst{registry, std::forward(instance)}; + const std::array vargs{uarg{registry, std::forward(args)}...}; + return state_->invoke(vinst, vargs); + } + template < typename Instance, typename... Args > uvalue method::operator()(Instance&& instance, Args&&... args) const { return invoke(std::forward(instance), std::forward(args)...); @@ -169,7 +197,7 @@ namespace meta_hpp type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, type_list{}}; const std::array vargs{uarg_base{registry, type_list{}}...}; - return state_->is_invocable_with(vinst, vargs); + return !state_->invoke_error(vinst, vargs); } template < typename Instance, typename... Args > @@ -178,7 +206,7 @@ namespace meta_hpp type_registry& registry{type_registry::instance()}; const uinst_base vinst{registry, std::forward(instance)}; const std::array vargs{uarg_base{registry, std::forward(args)}...}; - return state_->is_invocable_with(vinst, vargs); + return !state_->invoke_error(vinst, vargs); } inline argument method::get_argument(std::size_t position) const noexcept { diff --git a/headers/meta.hpp/meta_states/variable.hpp b/headers/meta.hpp/meta_states/variable.hpp index 7601559..93a789a 100644 --- a/headers/meta.hpp/meta_states/variable.hpp +++ b/headers/meta.hpp/meta_states/variable.hpp @@ -68,16 +68,19 @@ namespace meta_hpp::detail } template < pointer_kind Pointer > - bool raw_variable_is_settable_with(type_registry& registry, const uarg_base& arg) { + uerror raw_variable_setter_error(type_registry& registry, const uarg_base& arg) { using pt = pointer_traits; using data_type = typename pt::data_type; if constexpr ( std::is_const_v ) { (void)registry; (void)arg; - return false; + return uerror{error_code::bad_const_access}; } else { - return arg.can_cast_to(registry); + if ( !arg.can_cast_to(registry) ) { + return uerror{error_code::argument_type_mismatch}; + } + return uerror{error_code::no_error}; } } } @@ -99,9 +102,9 @@ namespace meta_hpp::detail } template < pointer_kind Pointer > - variable_state::is_settable_with_impl make_variable_is_settable_with(type_registry& registry) { + variable_state::setter_error_impl make_variable_setter_error(type_registry& registry) { return [®istry](const uarg_base& arg) { // - return raw_variable_is_settable_with(registry, arg); + return raw_variable_setter_error(registry, arg); }; } } @@ -118,7 +121,7 @@ namespace meta_hpp::detail variable_state state{variable_index{registry.resolve_type(), std::move(name)}, std::move(metadata)}; state.getter = make_variable_getter(registry, variable_ptr); state.setter = make_variable_setter(registry, variable_ptr); - state.is_settable_with = make_variable_is_settable_with(registry); + state.setter_error = make_variable_setter_error(registry); return make_intrusive(std::move(state)); } } @@ -182,7 +185,7 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const uarg_base vvalue{registry, type_list{}}; - return state_->is_settable_with(vvalue); + return !state_->setter_error(vvalue); } template < typename Value > @@ -190,6 +193,6 @@ namespace meta_hpp using namespace detail; type_registry& registry{type_registry::instance()}; const uarg_base vvalue{registry, std::forward(value)}; - return state_->is_settable_with(vvalue); + return !state_->setter_error(vvalue); } } diff --git a/headers/meta.hpp/meta_types/class_type.hpp b/headers/meta.hpp/meta_types/class_type.hpp index 43a1055..67a7c83 100644 --- a/headers/meta.hpp/meta_types/class_type.hpp +++ b/headers/meta.hpp/meta_types/class_type.hpp @@ -113,7 +113,10 @@ namespace meta_hpp template < typename Arg > bool class_type::destroy(Arg&& arg) const { if ( const destructor& dtor = get_destructor() ) { - return dtor.destroy(std::forward(arg)); + if ( dtor.is_invocable_with(std::forward(arg)) ) { + dtor.destroy(std::forward(arg)); + return true; + } } return false; } diff --git a/headers/meta.hpp/meta_uresult.hpp b/headers/meta.hpp/meta_uresult.hpp index 2246cbc..8f36640 100644 --- a/headers/meta.hpp/meta_uresult.hpp +++ b/headers/meta.hpp/meta_uresult.hpp @@ -25,6 +25,9 @@ namespace meta_hpp explicit uerror(error_code error) noexcept; uerror& operator=(error_code error) noexcept; + [[nodiscard]] bool has_error() const noexcept; + [[nodiscard]] explicit operator bool() const noexcept; + [[nodiscard]] error_code get_error() const noexcept; void reset() noexcept; @@ -120,9 +123,6 @@ namespace meta_hpp [[nodiscard]] bool has_value() const noexcept; [[nodiscard]] explicit operator bool() const noexcept; - void reset() noexcept; - void swap(uresult& other) noexcept; - [[nodiscard]] uvalue& get_value() &; [[nodiscard]] uvalue&& get_value() &&; [[nodiscard]] const uvalue& get_value() const&; @@ -130,6 +130,9 @@ namespace meta_hpp [[nodiscard]] error_code get_error() const noexcept; + void reset() noexcept; + void swap(uresult& other) noexcept; + private: uvalue value_{}; error_code error_{error_code::no_error}; diff --git a/headers/meta.hpp/meta_uresult/uresult.hpp b/headers/meta.hpp/meta_uresult/uresult.hpp index 57d06a4..820f6dd 100644 --- a/headers/meta.hpp/meta_uresult/uresult.hpp +++ b/headers/meta.hpp/meta_uresult/uresult.hpp @@ -21,6 +21,14 @@ namespace meta_hpp return *this; } + inline bool uerror::has_error() const noexcept { + return error_ != error_code::no_error; + } + + inline uerror::operator bool() const noexcept { + return has_error(); + } + inline error_code uerror::get_error() const noexcept { return error_; } @@ -112,17 +120,6 @@ namespace meta_hpp return has_value(); } - inline void uresult::reset() noexcept { - value_ = uvalue{}; - error_ = error_code::no_error; - } - - inline void uresult::swap(uresult& other) noexcept { - using std::swap; - swap(value_, other.value_); - swap(error_, other.error_); - } - inline uvalue& uresult::get_value() & { return value_; } @@ -143,4 +140,15 @@ namespace meta_hpp inline error_code uresult::get_error() const noexcept { return error_; } + + inline void uresult::reset() noexcept { + value_ = uvalue{}; + error_ = error_code::no_error; + } + + inline void uresult::swap(uresult& other) noexcept { + using std::swap; + swap(value_, other.value_); + swap(error_, other.error_); + } }