From a2708acbc7375cb925916af9e306b7a9112b743c Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Sat, 8 Jan 2022 07:10:41 +0700 Subject: [PATCH] add is_gettable_with, is_settable_with for member and variable --- headers/meta.hpp/meta_states.hpp | 25 +++++++ headers/meta.hpp/meta_states/ctor.hpp | 18 ++--- headers/meta.hpp/meta_states/function.hpp | 18 ++--- headers/meta.hpp/meta_states/member.hpp | 70 ++++++++++++++++-- headers/meta.hpp/meta_states/method.hpp | 18 ++--- headers/meta.hpp/meta_states/variable.hpp | 36 ++++++++-- untests/meta_states/member_tests.cpp | 87 +++++++++++++++++++++++ untests/meta_states/variable_tests.cpp | 40 +++++++++++ 8 files changed, 277 insertions(+), 35 deletions(-) diff --git a/headers/meta.hpp/meta_states.hpp b/headers/meta.hpp/meta_states.hpp index d6484cc..ff4daea 100644 --- a/headers/meta.hpp/meta_states.hpp +++ b/headers/meta.hpp/meta_states.hpp @@ -153,6 +153,18 @@ namespace meta_hpp template < typename Instance, typename Value > void operator()(Instance&& instance, Value&& value) const; + + template < typename Instance > + [[nodiscard]] bool is_gettable_with() const noexcept; + + template < typename Instance > + [[nodiscard]] bool is_gettable_with(Instance&& instance) const noexcept; + + template < typename Instance, typename Value > + [[nodiscard]] bool is_settable_with() const noexcept; + + template < typename Instance, typename Value > + [[nodiscard]] bool is_settable_with(Instance&& instance, Value&& value) const noexcept; private: detail::member_state_ptr state_; }; @@ -234,6 +246,12 @@ namespace meta_hpp template < typename Value > void operator()(Value&& value) const; + + template < typename Value > + [[nodiscard]] bool is_settable_with() const noexcept; + + template < typename Value > + [[nodiscard]] bool is_settable_with(Value&& value) const noexcept; private: detail::variable_state_ptr state_; }; @@ -287,9 +305,14 @@ namespace meta_hpp::detail using getter_impl = std::function; using setter_impl = std::function; + using is_gettable_with_impl = std::function; + using is_settable_with_impl = std::function; + const member_index index; const getter_impl getter; const setter_impl setter; + const is_gettable_with_impl is_gettable_with; + const is_settable_with_impl is_settable_with; template < member_kind Member > explicit member_state(member_index index, Member member); @@ -330,10 +353,12 @@ namespace meta_hpp::detail struct variable_state final { using getter_impl = std::function; using setter_impl = std::function; + using is_settable_with_impl = std::function; const variable_index index; const getter_impl getter; const setter_impl setter; + const is_settable_with_impl is_settable_with; template < pointer_kind Pointer > explicit variable_state(variable_index index, Pointer pointer); diff --git a/headers/meta.hpp/meta_states/ctor.hpp b/headers/meta.hpp/meta_states/ctor.hpp index 2175fe0..e501499 100644 --- a/headers/meta.hpp/meta_states/ctor.hpp +++ b/headers/meta.hpp/meta_states/ctor.hpp @@ -34,15 +34,6 @@ namespace meta_hpp::detail }, std::make_index_sequence()); } - template < class_kind Class, typename... Args > - ctor_state::invoke_impl make_ctor_invoke() { - using namespace std::placeholders; - return std::bind(&raw_ctor_invoke, _1); - } -} - -namespace meta_hpp::detail -{ template < class_kind Class, typename... Args > bool raw_ctor_is_invocable_with(std::span args) { using ct = ctor_traits; @@ -57,6 +48,15 @@ namespace meta_hpp::detail return (... && (args.data() + Is)->can_cast_to>()); }, std::make_index_sequence()); } +} + +namespace meta_hpp::detail +{ + template < class_kind Class, typename... Args > + ctor_state::invoke_impl make_ctor_invoke() { + using namespace std::placeholders; + return std::bind(&raw_ctor_invoke, _1); + } template < class_kind Class, typename... Args > ctor_state::is_invocable_with_impl make_ctor_is_invocable_with() { diff --git a/headers/meta.hpp/meta_states/function.hpp b/headers/meta.hpp/meta_states/function.hpp index f40c6f0..f1efd24 100644 --- a/headers/meta.hpp/meta_states/function.hpp +++ b/headers/meta.hpp/meta_states/function.hpp @@ -43,15 +43,6 @@ namespace meta_hpp::detail }, std::make_index_sequence()); } - template < function_kind Function > - function_state::invoke_impl make_function_invoke(Function function) { - using namespace std::placeholders; - return std::bind(&raw_function_invoke, function, _1); - } -} - -namespace meta_hpp::detail -{ template < function_kind Function > bool raw_function_is_invocable_with(std::span args) { using ft = function_traits; @@ -66,6 +57,15 @@ namespace meta_hpp::detail return (... && (args.data() + Is)->can_cast_to>()); }, std::make_index_sequence()); } +} + +namespace meta_hpp::detail +{ + template < function_kind Function > + function_state::invoke_impl make_function_invoke(Function function) { + using namespace std::placeholders; + return std::bind(&raw_function_invoke, function, _1); + } template < function_kind Function > function_state::is_invocable_with_impl make_function_is_invocable_with() { diff --git a/headers/meta.hpp/meta_states/member.hpp b/headers/meta.hpp/meta_states/member.hpp index b09824b..6a66ec1 100644 --- a/headers/meta.hpp/meta_states/member.hpp +++ b/headers/meta.hpp/meta_states/member.hpp @@ -37,7 +37,9 @@ namespace meta_hpp::detail using qualified_type = class_type; - if constexpr ( !std::is_const_v ) { + if constexpr ( std::is_const_v ) { + throw std::logic_error("an attempt to set a constant member"); + } else { if ( inst.is_const() ) { throw std::logic_error("an attempt to set a member with an const instance type"); } @@ -51,10 +53,32 @@ namespace meta_hpp::detail } std::invoke(member, inst.cast()) = arg.cast(); - } else { - throw std::logic_error("an attempt to set a constant member"); } } + + template < member_kind Member > + bool raw_member_is_gettable_with(const inst_base& inst) { + using mt = member_traits; + using class_type = typename mt::class_type; + + using qualified_type = const class_type; + + return inst.can_cast_to(); + } + + template < member_kind Member > + bool raw_member_is_settable_with(const inst_base& inst, const arg_base& arg) { + using mt = member_traits; + using class_type = typename mt::class_type; + using value_type = typename mt::value_type; + + using qualified_type = class_type; + + return !std::is_const_v + && !inst.is_const() + && inst.can_cast_to() + && arg.can_cast_to(); + } } namespace meta_hpp::detail @@ -70,6 +94,18 @@ namespace meta_hpp::detail using namespace std::placeholders; return std::bind(&raw_member_setter, member, _1, _2); } + + template < member_kind Member > + member_state::is_gettable_with_impl make_member_is_gettable_with() { + using namespace std::placeholders; + return std::bind(&raw_member_is_gettable_with, _1); + } + + template < member_kind Member > + member_state::is_settable_with_impl make_member_is_settable_with() { + using namespace std::placeholders; + return std::bind(&raw_member_is_settable_with, _1, _2); + } } namespace meta_hpp::detail @@ -78,7 +114,9 @@ namespace meta_hpp::detail member_state::member_state(member_index index, Member member) : index{std::move(index)} , getter{make_member_getter(member)} - , setter{make_member_setter(member)} {} + , setter{make_member_setter(member)} + , is_gettable_with{make_member_is_gettable_with()} + , is_settable_with{make_member_is_settable_with()} {} template < member_kind Member > member_state_ptr member_state::make(std::string name, Member member) { @@ -133,4 +171,28 @@ namespace meta_hpp void member::operator()(Instance&& instance, Value&& value) const { set(std::forward(instance), std::forward(value)); } + + template < typename Instance > + [[nodiscard]] bool member::is_gettable_with() const noexcept { + using namespace detail; + return state_->is_gettable_with(inst_base{type_list{}}); + } + + template < typename Instance > + [[nodiscard]] bool member::is_gettable_with(Instance&& instance) const noexcept { + using namespace detail; + return state_->is_gettable_with(inst{std::forward(instance)}); + } + + template < typename Instance, typename Value > + [[nodiscard]] bool member::is_settable_with() const noexcept { + using namespace detail; + return state_->is_settable_with(inst_base{type_list{}}, arg_base{type_list{}}); + } + + template < typename Instance, typename Value > + [[nodiscard]] bool member::is_settable_with(Instance&& instance, Value&& value) const noexcept { + using namespace detail; + return state_->is_settable_with(inst{std::forward(instance)}, arg{std::forward(value)}); + } } diff --git a/headers/meta.hpp/meta_states/method.hpp b/headers/meta.hpp/meta_states/method.hpp index 2d303bb..3719dfd 100644 --- a/headers/meta.hpp/meta_states/method.hpp +++ b/headers/meta.hpp/meta_states/method.hpp @@ -50,15 +50,6 @@ namespace meta_hpp::detail }, std::make_index_sequence()); } - template < method_kind Method > - method_state::invoke_impl make_method_invoke(Method method) { - using namespace std::placeholders; - return std::bind(&raw_method_invoke, method, _1, _2); - } -} - -namespace meta_hpp::detail -{ template < method_kind Method > bool raw_method_is_invocable_with(const inst_base& inst, std::span args) { using mt = method_traits; @@ -78,6 +69,15 @@ namespace meta_hpp::detail return (... && (args.data() + Is)->can_cast_to>()); }, std::make_index_sequence()); } +} + +namespace meta_hpp::detail +{ + template < method_kind Method > + method_state::invoke_impl make_method_invoke(Method method) { + using namespace std::placeholders; + return std::bind(&raw_method_invoke, method, _1, _2); + } template < method_kind Method > method_state::is_invocable_with_impl make_method_is_invocable_with() { diff --git a/headers/meta.hpp/meta_states/variable.hpp b/headers/meta.hpp/meta_states/variable.hpp index 2b01ba7..5db678e 100644 --- a/headers/meta.hpp/meta_states/variable.hpp +++ b/headers/meta.hpp/meta_states/variable.hpp @@ -27,16 +27,25 @@ namespace meta_hpp::detail using pt = pointer_traits; using data_type = typename pt::data_type; - if constexpr ( !std::is_const_v ) { + if constexpr ( std::is_const_v ) { + throw std::logic_error("an attempt to set a constant variable"); + } else { if ( !arg.can_cast_to() ) { throw std::logic_error("an attempt to set a variable with an incorrect argument type"); } *pointer = arg.cast(); - } else { - throw std::logic_error("an attempt to set a constant variable"); } } + + template < pointer_kind Pointer > + bool raw_variable_is_settable_with(const arg_base& arg) { + using pt = pointer_traits; + using data_type = typename pt::data_type; + + return !std::is_const_v + && arg.can_cast_to();; + } } namespace meta_hpp::detail @@ -52,6 +61,12 @@ namespace meta_hpp::detail using namespace std::placeholders; return std::bind(&raw_variable_setter, pointer, _1); } + + template < pointer_kind Pointer > + variable_state::is_settable_with_impl make_variable_is_settable_with() { + using namespace std::placeholders; + return std::bind(&raw_variable_is_settable_with, _1); + } } namespace meta_hpp::detail @@ -60,7 +75,8 @@ namespace meta_hpp::detail variable_state::variable_state(variable_index index, Pointer pointer) : index{std::move(index)} , getter{make_variable_getter(pointer)} - , setter{make_variable_setter(pointer)} {} + , setter{make_variable_setter(pointer)} + , is_settable_with{make_variable_is_settable_with()} {} template < pointer_kind Pointer > variable_state_ptr variable_state::make(std::string name, Pointer pointer) { @@ -112,4 +128,16 @@ namespace meta_hpp void variable::operator()(Value&& value) const { set(std::forward(value)); } + + template < typename Value > + bool variable::is_settable_with() const noexcept { + using namespace detail; + return state_->is_settable_with(arg_base{type_list{}}); + } + + template < typename Value > + bool variable::is_settable_with(Value&& value) const noexcept { + using namespace detail; + return state_->is_settable_with(arg{std::forward(value)}); + } } diff --git a/untests/meta_states/member_tests.cpp b/untests/meta_states/member_tests.cpp index 9fa978d..25c1362 100644 --- a/untests/meta_states/member_tests.cpp +++ b/untests/meta_states/member_tests.cpp @@ -51,6 +51,23 @@ TEST_CASE("meta/meta_states/member") { clazz_1 v; clazz_2 v2; + { + CHECK(vm.is_gettable_with()); + CHECK(vm.is_gettable_with()); + CHECK(vm.is_gettable_with()); + CHECK(vm.is_gettable_with()); + CHECK(vm.is_gettable_with()); + CHECK(vm.is_gettable_with()); + + CHECK(vm.is_gettable_with(v)); + CHECK(vm.is_gettable_with(std::as_const(v))); + CHECK(vm.is_gettable_with(std::move(v))); + CHECK(vm.is_gettable_with(std::move(std::as_const(v)))); + + CHECK_FALSE(vm.is_gettable_with()); + CHECK_FALSE(vm.is_gettable_with(v2)); + } + { CHECK(vm.get(v) == 1); CHECK(vm.get(std::as_const(v)) == 1); @@ -66,6 +83,34 @@ TEST_CASE("meta/meta_states/member") { CHECK_THROWS(std::ignore = vm(v2)); } + { + CHECK(vm.is_settable_with()); + CHECK(vm.is_settable_with()); + CHECK(vm.is_settable_with()); + + CHECK(vm.is_settable_with()); + CHECK(vm.is_settable_with()); + CHECK(vm.is_settable_with()); + + CHECK(vm.is_settable_with(v, 10)); + CHECK(vm.is_settable_with(std::move(v), 12)); + + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + + CHECK_FALSE(vm.is_settable_with()); + + CHECK_FALSE(vm.is_settable_with(v2, 10)); + CHECK_FALSE(vm.is_settable_with(std::move(v2), 10)); + CHECK_FALSE(vm.is_settable_with(v, 10.0)); + CHECK_FALSE(vm.is_settable_with(std::move(v), 12.0)); + } + { CHECK_NOTHROW(vm.set(v, 10)); CHECK(vm.get(v) == 10); CHECK_THROWS(vm.set(std::as_const(v), 11)); CHECK(vm.get(v) == 10); @@ -93,6 +138,23 @@ TEST_CASE("meta/meta_states/member") { clazz_1 v; clazz_2 v2; + { + CHECK(vm.is_gettable_with()); + CHECK(vm.is_gettable_with()); + CHECK(vm.is_gettable_with()); + CHECK(vm.is_gettable_with()); + CHECK(vm.is_gettable_with()); + CHECK(vm.is_gettable_with()); + + CHECK(vm.is_gettable_with(v)); + CHECK(vm.is_gettable_with(std::as_const(v))); + CHECK(vm.is_gettable_with(std::move(v))); + CHECK(vm.is_gettable_with(std::move(std::as_const(v)))); + + CHECK_FALSE(vm.is_gettable_with()); + CHECK_FALSE(vm.is_gettable_with(v2)); + } + { CHECK(vm.get(v) == 2); CHECK(vm.get(std::as_const(v)) == 2); @@ -108,6 +170,31 @@ TEST_CASE("meta/meta_states/member") { CHECK_THROWS(std::ignore = vm(v2)); } + { + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + + CHECK_FALSE(vm.is_settable_with(v, 10)); + CHECK_FALSE(vm.is_settable_with(std::move(v), 12)); + + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with(v2, 10)); + CHECK_FALSE(vm.is_settable_with(std::move(v2), 12)); + } + { CHECK_THROWS(vm.set(v, 10)); CHECK(vm.get(v) == 2); CHECK_THROWS(vm.set(std::as_const(v), 11)); CHECK(vm.get(v) == 2); diff --git a/untests/meta_states/variable_tests.cpp b/untests/meta_states/variable_tests.cpp index e38d85c..17077b9 100644 --- a/untests/meta_states/variable_tests.cpp +++ b/untests/meta_states/variable_tests.cpp @@ -60,6 +60,16 @@ TEST_CASE("meta/meta_states/variable") { CHECK(vm.get() == 1); CHECK(vm() == 1); + CHECK(vm.is_settable_with()); + CHECK(vm.is_settable_with()); + CHECK(vm.is_settable_with()); + CHECK(vm.is_settable_with(1)); + + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with(1.0)); + CHECK_NOTHROW(vm.set(10)); CHECK(vm.get() == 10); CHECK_NOTHROW(vm(11)); CHECK(vm() == 11); } @@ -74,6 +84,16 @@ TEST_CASE("meta/meta_states/variable") { CHECK(vm.get() == 2); CHECK(vm() == 2); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with(1)); + + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with(1.0)); + CHECK_THROWS(vm.set(10)); CHECK(vm.get() == 2); CHECK_THROWS(vm(10)); CHECK(vm() == 2); } @@ -88,6 +108,16 @@ TEST_CASE("meta/meta_states/variable") { CHECK(vm.get() == 11); CHECK(vm() == 11); + CHECK(vm.is_settable_with()); + CHECK(vm.is_settable_with()); + CHECK(vm.is_settable_with()); + CHECK(vm.is_settable_with(1)); + + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with(1.0)); + CHECK_NOTHROW(vm.set(20)); CHECK(vm.get() == 20); CHECK_NOTHROW(vm(21)); CHECK(vm() == 21); } @@ -102,6 +132,16 @@ TEST_CASE("meta/meta_states/variable") { CHECK(vm.get() == 2); CHECK(vm() == 2); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with(1)); + + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with()); + CHECK_FALSE(vm.is_settable_with(1.0)); + CHECK_THROWS(vm.set(10)); CHECK(vm.get() == 2); CHECK_THROWS(vm(11)); CHECK(vm() == 2); }