/************************************************************************************ * * * Copyright (c) 2014 - 2018 Axel Menzel * * * * This file is part of RTTR (Run Time Type Reflection) * * License: MIT License * * * * Permission is hereby granted, free of charge, to any person obtaining * * a copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * * SOFTWARE. * * * *************************************************************************************/ #ifndef RTTR_BIND_IMPL_H_ #define RTTR_BIND_IMPL_H_ #include "rttr/detail/base/core_prerequisites.h" #include "rttr/detail/misc/argument_extractor.h" #include "rttr/detail/constructor/constructor_wrapper.h" #include "rttr/detail/destructor/destructor_wrapper.h" #include "rttr/detail/enumeration/enumeration_wrapper.h" #include "rttr/detail/enumeration/enum_data.h" #include "rttr/detail/metadata/metadata.h" #include "rttr/detail/method/method_wrapper.h" #include "rttr/detail/parameter_info/parameter_infos.h" #include "rttr/detail/property/property_wrapper.h" #include "rttr/detail/type/accessor_type.h" #include "rttr/detail/misc/misc_type_traits.h" #include "rttr/detail/misc/utility.h" #include "rttr/detail/type/type_register.h" #include "rttr/detail/default_arguments/default_arguments.h" #include "rttr/detail/registration/register_base_class_from_accessor.h" #include "rttr/policy.h" #include "rttr/type.h" #include "rttr/detail/registration/registration_manager.h" #include "rttr/detail/visitor/visitor_registration.h" #include #include #include namespace rttr { namespace detail { ///////////////////////////////////////////////////////////////////////////////////////// template static RTTR_INLINE auto get_metadata(Args&&... arg) -> decltype(forward_to_array(std::forward(arg)...)) { return forward_to_array(std::forward(arg)...); } ///////////////////////////////////////////////////////////////////////////////////////// template static RTTR_INLINE auto get_enum_values(Args&&... arg) -> decltype(forward_to_array>(std::forward(arg)...)) { return forward_to_array>(std::forward(arg)...); } ///////////////////////////////////////////////////////////////////////////////////////// template using map_access_level_to_enum = conditional_t< std::is_same::value, std::integral_constant, conditional_t< std::is_same::value, std::integral_constant, std::integral_constant > >; ///////////////////////////////////////////////////////////////////////////////////////// } // end namespace detail ///////////////////////////////////////////////////////////////////////////////////////// template class registration::bind : public registration::class_ { private: // this 'as_std_shared_ptr' policy has been selected, because: // * it has automatic memory management; should not leak anything // * we can copy the object inside the variant, without invoking the copy constructor (could be disabled by user) // REMARK: For the default constructor registration will always be code instantiated, when copying is disabled, we get a compile error using default_create_policy = detail::as_std_shared_ptr; // this additional wrapper function is needed, because of not triggered static_assert in func: 'operator()(Args&&... args)' // when we create the object directly inside the operator function, seems to be a bug in MSVC template static RTTR_INLINE std::unique_ptr create_constructor_wrapper(std::array metadata_list, detail::default_args def_args, detail::parameter_infos param_infos) { using namespace detail; return detail::make_unique::value, Policy, Metadata_Count, default_args, parameter_infos, Visitor_List, Ctor_Args...>>(std::move(metadata_list), std::move(def_args), std::move(param_infos)); } template static RTTR_INLINE std::unique_ptr create_constructor_wrapper(std::array metadata_list, detail::default_args<> def_args, detail::parameter_infos param_infos) { using namespace detail; return detail::make_unique::value, Policy, Metadata_Count, default_args<>, parameter_infos, Visitor_List, Ctor_Args...>>(std::move(metadata_list), std::move(param_infos)); } public: bind(const std::shared_ptr& reg_exec) : registration::class_(reg_exec), m_reg_exec(reg_exec) { m_reg_exec->add_registration_func(this); } ~bind() { using namespace detail; using param_info_t = decltype(create_param_infos, constructor_type>()); if (!m_ctor.get()) m_ctor = detail::make_unique::value, default_create_policy, 0, detail::default_args<>, param_info_t, Visitor_List, Ctor_Args...>>(std::array(), param_info_t()); auto wrapper = detail::make_rref(std::move(m_ctor)); auto reg_func = [wrapper]() { store_item(std::move(wrapper.m_value)); store_item(detail::make_unique>()); }; m_reg_exec->add_registration_func(this, std::move(reg_func)); } template registration::class_ operator()(Args&&... args) { using namespace detail; using policy_types_found = typename find_types...>>::type; static_assert(!has_double_types::value, "There are multiple policies of the same type forwarded, that is not allowed!"); using has_valid_default_types = has_default_types, type_list, constructor_type>; static_assert( (has_default_args::value && has_valid_default_types::value) || !has_default_args::value, "The provided default arguments, cannot be used with the given constructor. Please check the provided argument types." "The given arguments must match the signature from the starting position to the right most argument."); static_assert((count_default_args::value <= 1), "Only one set of 'default_arguments' can be provided during registration of a constructor!"); static_assert((count_param_names::value <= 1), "Only one set of 'parameter_names' can be provided during registration of a constructor!"); static_assert(((!has_param_names::value) || (param_names_count::value == sizeof...(Ctor_Args))), "The provided amount of names in 'parameter_names' does not match argument count of the constructor signature."); // when no policy was added, we need a default policy using policy_list = conditional_t< type_list_size::value == 0, default_create_policy, policy_types_found>; // at the moment we only supported one policy using first_prop_policy = typename std::tuple_element<0, as_std_tuple_t>::type; m_ctor = create_constructor_wrapper(std::move(get_metadata(std::forward(args)...)), std::move(get_default_args, constructor_type>(std::forward(args)...)), std::move(create_param_infos, constructor_type>(std::forward(args)...))); return registration::class_(m_reg_exec); } private: std::shared_ptr m_reg_exec; std::unique_ptr m_ctor; }; ///////////////////////////////////////////////////////////////////////////////////////// template class registration::bind : public registration::class_ { private: template static RTTR_INLINE std::unique_ptr create_constructor_wrapper(F func, std::array metadata_list, detail::default_args def_args, detail::parameter_infos param_infos) { using namespace detail; return detail::make_unique::value, default_invoke, Metadata_Count, default_args, parameter_infos, Visitor_List, F>>(func, std::move(metadata_list), std::move(def_args), std::move(param_infos)); } template static RTTR_INLINE std::unique_ptr create_constructor_wrapper(F func, std::array metadata_list, detail::default_args<> def_args, detail::parameter_infos param_infos) { using namespace detail; return detail::make_unique::value, default_invoke, Metadata_Count, default_args<>, parameter_infos, Visitor_List, F>>(func, std::move(metadata_list), std::move(param_infos)); } // this indirection is necessary to delay the instantiation of the created constructor wrapper // so we can make use of static_assert and check whether the given accessor is correct or not // REMARK: this seems to be a MSVC problem... template static RTTR_INLINE std::unique_ptr create_default_constructor(Acc_Func func) { using namespace detail; using param_info_t = decltype(create_param_infos, function_type>()); return detail::make_unique::value, default_invoke, 0, detail::default_args<>, param_info_t, Visitor_List, F>>(func, std::array(), param_info_t()); } template static RTTR_INLINE std::unique_ptr create_custom_constructor(Acc_Func func, Args&&...args) { using namespace detail; using has_valid_default_types = has_default_types, type_list, function_type>; static_assert( (has_default_args::value && has_valid_default_types::value) || !has_default_args::value, "The provided default arguments, cannot be used with the given constructor. Please check the provided argument types." "The given arguments must match the signature from the starting position to the right most argument."); static_assert((count_default_args::value <= 1), "Only one set of 'default_arguments' can be provided during registration of a constructor!"); static_assert((count_param_names::value <= 1), "Only one set of 'parameter_names' can be provided during registration of a constructor!"); static_assert(((!has_param_names::value) || (param_names_count::value == function_traits::arg_count)), "The provided amount of names in 'parameter_names' does not match argument count of the function signature."); return create_constructor_wrapper(func, get_metadata(std::forward(args)...), get_default_args, function_type>(std::forward(args)...), create_param_infos, function_type>(std::forward(args)...)); } public: bind(const std::shared_ptr& reg_exec, F func) : registration::class_(reg_exec), m_reg_exec(reg_exec), m_func(func) { m_reg_exec->add_registration_func(this); } ~bind() { using namespace detail; if (!m_ctor.get()) m_ctor = create_default_constructor(m_func); auto wrapper = detail::make_rref(std::move(m_ctor)); auto reg_func = [wrapper]() { store_item(std::move(wrapper.m_value)); store_item(detail::make_unique>()); }; m_reg_exec->add_registration_func(this, reg_func); } template registration::class_ operator()(Args&&... args) { m_ctor = create_custom_constructor(m_func, std::forward(args)...); return registration::class_(m_reg_exec); } private: std::shared_ptr m_reg_exec; F m_func; std::unique_ptr m_ctor; }; ///////////////////////////////////////////////////////////////////////////////////////// template using registration_derived_t = detail::conditional_t< std::is_same::value, registration, registration::class_ >; ///////////////////////////////////////////////////////////////////////////////////////// template class registration::bind : public registration_derived_t { private: using default_getter_policy = detail::return_as_copy; using default_setter_policy = detail::set_value; template static RTTR_INLINE std::unique_ptr create_default_property(string_view name, Acc acc) { using namespace detail; using acc_type = typename property_type::type; return detail::make_unique::value, default_getter_policy, default_setter_policy, 0, Visitor_List> >(name, acc, std::array()); } template static RTTR_INLINE std::unique_ptr create_custom_property(string_view name, Acc acc, std::array metadata_list, Args&&...args) { using namespace detail; using policy_types_found = typename find_types...>>::type; static_assert(!has_double_types::value, "There are multiple policies of the same type forwarded, that is not allowed!"); // when no policy was added, we need a default policy using policy_list = conditional_t< type_list_size::value == 0, default_getter_policy, policy_types_found>; // at the moment we only supported one policy using first_prop_policy = typename std::tuple_element<0, as_std_tuple_t>::type; using getter_policy = typename get_getter_policy::type; using setter_policy = typename get_setter_policy::type; using acc_type = typename property_type::type; return detail::make_unique::value, getter_policy, setter_policy, Metadata_Count, Visitor_List>>(name, acc, std::move(metadata_list)); } public: bind(const std::shared_ptr& reg_exec, string_view name, A acc) : registration_derived_t(reg_exec), m_reg_exec(reg_exec), m_name(name), m_acc(acc) { detail::register_accessor_class_type_when_needed(); m_reg_exec->add_registration_func(this); } ~bind() { using namespace detail; if (!m_prop.get()) m_prop = create_default_property(m_name, m_acc); auto wrapper = detail::make_rref(std::move(m_prop)); auto reg_func = [wrapper]() { store_item(std::move(wrapper.m_value)); }; m_reg_exec->add_registration_func(this, std::move(reg_func)); } template registration_derived_t operator()(Args&&... args) { m_prop = create_custom_property(m_name, m_acc, std::move(get_metadata(std::forward(args)...)), std::forward(args)...); return registration_derived_t(m_reg_exec); } private: std::shared_ptr m_reg_exec; string_view m_name; A m_acc; std::unique_ptr m_prop; }; ///////////////////////////////////////////////////////////////////////////////////////// template class registration::bind : public registration_derived_t { private: using default_getter_policy = detail::return_as_copy; using default_setter_policy = detail::set_value; template static RTTR_INLINE std::unique_ptr create_default_property(string_view name, Acc1 getter, Acc2 setter) { using namespace detail; using acc_type = typename property_type::type; return detail::make_unique::value, default_getter_policy, default_setter_policy, 0, Visitor_List > >(name, getter, setter, std::array()); } template static RTTR_INLINE std::unique_ptr create_custom_property(string_view name, Acc1 getter, Acc2 setter, std::array metadata_list, Args&&...args) { using namespace detail; using policy_types_found = typename find_types...>>::type; static_assert(!has_double_types::value, "There are multiple policies of the same type forwarded, that is not allowed!"); // when no policy was added, we need a default policy using policy_list = conditional_t< type_list_size::value == 0, default_getter_policy, policy_types_found>; // at the moment we only supported one policy using first_prop_policy = typename std::tuple_element<0, as_std_tuple_t>::type; using getter_policy = typename get_getter_policy::type; using setter_policy = typename get_setter_policy::type; using acc_type = typename property_type::type; return detail::make_unique::value, getter_policy, setter_policy, Metadata_Count, Visitor_List > >(name, getter, setter, std::move(metadata_list)); } public: bind(const std::shared_ptr& reg_exec, string_view name, A1 getter, A2 setter) : registration_derived_t(reg_exec), m_reg_exec(reg_exec), m_name(name), m_getter(getter), m_setter(setter) { detail::register_accessor_class_type_when_needed(); detail::register_accessor_class_type_when_needed(); m_reg_exec->add_registration_func(this); } ~bind() { using namespace detail; if (!m_prop.get()) m_prop = create_default_property(m_name, m_getter, m_setter); auto wrapper = detail::make_rref(std::move(m_prop)); auto reg_func = [wrapper]() { store_item(std::move(wrapper.m_value)); }; m_reg_exec->add_registration_func(this, std::move(reg_func)); } template registration_derived_t operator()(Args&&... args) { m_prop = create_custom_property(m_name, m_getter, m_setter, std::move(get_metadata(std::forward(args)...)), std::forward(args)...); return registration_derived_t(m_reg_exec); } private: std::shared_ptr m_reg_exec; string_view m_name; A1 m_getter; A2 m_setter; std::unique_ptr m_prop; }; ///////////////////////////////////////////////////////////////////////////////////////// template class registration::bind : public registration_derived_t { private: using default_getter_policy = detail::return_as_copy; using default_setter_policy = detail::read_only; template static RTTR_INLINE std::unique_ptr create_default_property(string_view name, Acc acc) { using namespace detail; using acc_type = typename property_type::type; return detail::make_unique::value, default_getter_policy, default_setter_policy, 0, Visitor_List > >(name, acc, std::array()); } template static RTTR_INLINE std::unique_ptr create_custom_property(string_view name, Acc acc, std::array metadata_list, Args&&...args) { using namespace detail; using policy_types_found = typename find_types...>>::type; static_assert(!has_double_types::value, "There are multiple policies of the same type forwarded, that is not allowed!"); // when no policy was added, we need a default policy using policy_list = conditional_t< type_list_size::value == 0, default_getter_policy, policy_types_found>; // at the moment we only supported one policy using first_prop_policy = typename std::tuple_element<0, as_std_tuple_t>::type; using getter_policy = typename get_getter_policy::type; using acc_type = typename property_type::type; return detail::make_unique::value, getter_policy, default_setter_policy, Metadata_Count, Visitor_List > >(name, acc, std::move(metadata_list)); } public: bind(const std::shared_ptr& reg_exec, string_view name, A acc) : registration_derived_t(reg_exec), m_reg_exec(reg_exec), m_name(name), m_acc(acc) { detail::register_accessor_class_type_when_needed(); m_reg_exec->add_registration_func(this); } ~bind() { using namespace detail; if (!m_prop.get()) m_prop = create_default_property(m_name, m_acc); auto wrapper = detail::make_rref(std::move(m_prop)); auto reg_func = [wrapper]() { store_item(std::move(wrapper.m_value)); }; m_reg_exec->add_registration_func(this, std::move(reg_func)); } template registration_derived_t operator()(Args&&... args) { m_prop = create_custom_property(m_name, m_acc, std::move(get_metadata(std::forward(args)...)), std::forward(args)...); return registration_derived_t(m_reg_exec); } private: std::shared_ptr m_reg_exec; string_view m_name; A m_acc; std::unique_ptr m_prop; }; ///////////////////////////////////////////////////////////////////////////////////////// template class registration::bind : public registration_derived_t { private: template static RTTR_INLINE std::unique_ptr create_default_method(string_view name, Acc_Func func) { using namespace detail; using param_info_t = decltype(create_param_infos, function_type>()); return detail::make_unique::value, default_invoke, default_args<>, param_info_t, 0, Visitor_List>>(name, func, std::array(), param_info_t()); } template static RTTR_INLINE std::unique_ptr create_custom_method(string_view name, Acc_Func func, Args&&...args) { using namespace detail; using policy_types_found = typename find_types...>>::type; static_assert(!has_double_types::value, "There are multiple policies of the same type forwarded, that is not allowed!"); using has_valid_default_types = has_default_types, type_list, function_type>; static_assert( (has_default_args::value && has_valid_default_types::value) || !has_default_args::value, "The provided default arguments, cannot be used with the given method. Please check the provided argument types." "The given arguments must match the signature from the starting position to the right most argument."); static_assert((count_default_args::value <= 1), "Only one set of 'default_arguments' can be provided during registration of a method!"); static_assert((count_param_names::value <= 1), "Only one set of 'parameter_names' can be provided during registration of a method!"); static_assert(((!has_param_names::value) || (param_names_count::value == function_traits::arg_count)), "The provided amount of names in 'parameter_names' does not match argument count of the function signature."); // when no policy was added, we need a default policy using policy_list = conditional_t< type_list_size::value == 0, default_invoke, policy_types_found>; using policy = typename std::tuple_element<0, as_std_tuple_t>::type; using metadata_count = count_type<::rttr::detail::metadata, type_list>; return create_method_wrapper(name, func, get_metadata(std::forward(args)...), get_default_args, function_type>(std::forward(args)...), create_param_infos, function_type>(std::forward(args)...) ); } template static RTTR_INLINE std::unique_ptr create_method_wrapper(string_view name, F func, std::array metadata_list, detail::default_args def_args, detail::parameter_infos param_infos) { return detail::make_unique::value, Policy, detail::default_args, detail::parameter_infos, Metadata_Count, Visitor_List>>(name, func, std::move(metadata_list), std::move(def_args), std::move(param_infos)); } template static RTTR_INLINE std::unique_ptr create_method_wrapper(string_view name, F func, std::array metadata_list, detail::default_args<> def_args, detail::parameter_infos param_infos) { return detail::make_unique::value, Policy, detail::default_args<>, detail::parameter_infos, Metadata_Count, Visitor_List>>(name, func, std::move(metadata_list), std::move(param_infos)); } public: bind(const std::shared_ptr& reg_exec, string_view name, F f) : registration_derived_t(reg_exec), m_reg_exec(reg_exec), m_name(name), m_func(f) { detail::register_accessor_class_type_when_needed(); m_reg_exec->add_registration_func(this); } ~bind() { using namespace detail; if (!m_meth.get()) m_meth = create_default_method(m_name, m_func); auto wrapper = detail::make_rref(std::move(m_meth)); auto reg_func = [wrapper]() { store_item(std::move(wrapper.m_value)); }; m_reg_exec->add_registration_func(this, std::move(reg_func)); } public: template registration_derived_t operator()(Args&&... args) { m_meth = create_custom_method(m_name, m_func, std::forward(args)...); return registration_derived_t(m_reg_exec); } private: std::shared_ptr m_reg_exec; string_view m_name; F m_func; std::unique_ptr m_meth; }; ///////////////////////////////////////////////////////////////////////////////////////// template class registration::bind : public registration_derived_t { private: template static RTTR_INLINE std::unique_ptr create_default_enum() { using namespace detail; return detail::make_unique>(get_enum_values(), std::array()); } template static RTTR_INLINE std::unique_ptr create_custom_enum(Args&&...args) { using namespace detail; static RTTR_CONSTEXPR_OR_CONST std::size_t enum_count = count_type, type_list...>>::value; static RTTR_CONSTEXPR_OR_CONST std::size_t global_enum_count = count_if...>::value; static_assert(enum_count == global_enum_count, "Invalid 'value' pair for enumeration type provided, please specify values only for enums of type 'Enum_Type'."); using metadata_count = count_type<::rttr::detail::metadata, type_list>; return detail::make_unique>(get_enum_values(std::forward(args)...), get_metadata(std::forward(args)...)); } public: bind(const std::shared_ptr& reg_exec, string_view name) : registration_derived_t(reg_exec), m_reg_exec(reg_exec), m_declared_type(type::template get()) { using namespace detail; m_reg_exec->add_registration_func(this); auto t = type::template get(); type_register::custom_name(t, name); } ~bind() { using namespace detail; if (!m_enum.get()) m_enum = create_default_enum(); m_enum->set_declaring_type(m_declared_type); // register the underlying type with the following call: m_enum->get_type(); auto wrapper = detail::make_rref(std::move(m_enum)); auto reg_func = [wrapper]() { store_item(std::move(wrapper.m_value)); }; m_reg_exec->add_registration_func(this, std::move(reg_func)); } template registration_derived_t operator()(Args&&... arg) { m_enum = create_custom_enum(std::forward(arg)...); return registration_derived_t(m_reg_exec); } private: std::shared_ptr m_reg_exec; type m_declared_type; std::unique_ptr m_enum; }; } // end namespace rttr #endif // RTTR_BIND_REFLECTION_IMPL_H_