add is_gettable_with, is_settable_with for member and variable

This commit is contained in:
BlackMATov
2022-01-08 07:10:41 +07:00
parent de77303c7a
commit a2708acbc7
8 changed files with 277 additions and 35 deletions

View File

@@ -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<value(const inst&)>;
using setter_impl = std::function<void(const inst&, const arg&)>;
using is_gettable_with_impl = std::function<bool(const inst_base&)>;
using is_settable_with_impl = std::function<bool(const inst_base&, const arg_base&)>;
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<value()>;
using setter_impl = std::function<void(const arg&)>;
using is_settable_with_impl = std::function<bool(const arg_base&)>;
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);

View File

@@ -34,15 +34,6 @@ namespace meta_hpp::detail
}, std::make_index_sequence<ct::arity>());
}
template < class_kind Class, typename... Args >
ctor_state::invoke_impl make_ctor_invoke() {
using namespace std::placeholders;
return std::bind(&raw_ctor_invoke<Class, Args...>, _1);
}
}
namespace meta_hpp::detail
{
template < class_kind Class, typename... Args >
bool raw_ctor_is_invocable_with(std::span<arg_base> args) {
using ct = ctor_traits<Class, Args...>;
@@ -57,6 +48,15 @@ namespace meta_hpp::detail
return (... && (args.data() + Is)->can_cast_to<type_list_at_t<Is, argument_types>>());
}, std::make_index_sequence<ct::arity>());
}
}
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<Class, Args...>, _1);
}
template < class_kind Class, typename... Args >
ctor_state::is_invocable_with_impl make_ctor_is_invocable_with() {

View File

@@ -43,15 +43,6 @@ namespace meta_hpp::detail
}, std::make_index_sequence<ft::arity>());
}
template < function_kind Function >
function_state::invoke_impl make_function_invoke(Function function) {
using namespace std::placeholders;
return std::bind(&raw_function_invoke<Function>, function, _1);
}
}
namespace meta_hpp::detail
{
template < function_kind Function >
bool raw_function_is_invocable_with(std::span<arg_base> args) {
using ft = function_traits<Function>;
@@ -66,6 +57,15 @@ namespace meta_hpp::detail
return (... && (args.data() + Is)->can_cast_to<type_list_at_t<Is, argument_types>>());
}, std::make_index_sequence<ft::arity>());
}
}
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>, function, _1);
}
template < function_kind Function >
function_state::is_invocable_with_impl make_function_is_invocable_with() {

View File

@@ -37,7 +37,9 @@ namespace meta_hpp::detail
using qualified_type = class_type;
if constexpr ( !std::is_const_v<value_type> ) {
if constexpr ( std::is_const_v<value_type> ) {
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<qualified_type>()) = arg.cast<value_type>();
} 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<Member>;
using class_type = typename mt::class_type;
using qualified_type = const class_type;
return inst.can_cast_to<qualified_type>();
}
template < member_kind Member >
bool raw_member_is_settable_with(const inst_base& inst, const arg_base& arg) {
using mt = member_traits<Member>;
using class_type = typename mt::class_type;
using value_type = typename mt::value_type;
using qualified_type = class_type;
return !std::is_const_v<value_type>
&& !inst.is_const()
&& inst.can_cast_to<qualified_type>()
&& arg.can_cast_to<value_type>();
}
}
namespace meta_hpp::detail
@@ -70,6 +94,18 @@ namespace meta_hpp::detail
using namespace std::placeholders;
return std::bind(&raw_member_setter<Member>, 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<Member>, _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<Member>, _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<Member>()}
, is_settable_with{make_member_is_settable_with<Member>()} {}
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>(instance), std::forward<Value>(value));
}
template < typename Instance >
[[nodiscard]] bool member::is_gettable_with() const noexcept {
using namespace detail;
return state_->is_gettable_with(inst_base{type_list<Instance>{}});
}
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>(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<Instance>{}}, arg_base{type_list<Value>{}});
}
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>(instance)}, arg{std::forward<Value>(value)});
}
}

View File

@@ -50,15 +50,6 @@ namespace meta_hpp::detail
}, std::make_index_sequence<mt::arity>());
}
template < method_kind Method >
method_state::invoke_impl make_method_invoke(Method method) {
using namespace std::placeholders;
return std::bind(&raw_method_invoke<Method>, method, _1, _2);
}
}
namespace meta_hpp::detail
{
template < method_kind Method >
bool raw_method_is_invocable_with(const inst_base& inst, std::span<arg_base> args) {
using mt = method_traits<Method>;
@@ -78,6 +69,15 @@ namespace meta_hpp::detail
return (... && (args.data() + Is)->can_cast_to<type_list_at_t<Is, argument_types>>());
}, std::make_index_sequence<mt::arity>());
}
}
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>, method, _1, _2);
}
template < method_kind Method >
method_state::is_invocable_with_impl make_method_is_invocable_with() {

View File

@@ -27,16 +27,25 @@ namespace meta_hpp::detail
using pt = pointer_traits<Pointer>;
using data_type = typename pt::data_type;
if constexpr ( !std::is_const_v<data_type> ) {
if constexpr ( std::is_const_v<data_type> ) {
throw std::logic_error("an attempt to set a constant variable");
} else {
if ( !arg.can_cast_to<data_type>() ) {
throw std::logic_error("an attempt to set a variable with an incorrect argument type");
}
*pointer = arg.cast<data_type>();
} 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<Pointer>;
using data_type = typename pt::data_type;
return !std::is_const_v<data_type>
&& arg.can_cast_to<data_type>();;
}
}
namespace meta_hpp::detail
@@ -52,6 +61,12 @@ namespace meta_hpp::detail
using namespace std::placeholders;
return std::bind(&raw_variable_setter<Pointer>, 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<Pointer>, _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<Pointer>()} {}
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>(value));
}
template < typename Value >
bool variable::is_settable_with() const noexcept {
using namespace detail;
return state_->is_settable_with(arg_base{type_list<Value>{}});
}
template < typename Value >
bool variable::is_settable_with(Value&& value) const noexcept {
using namespace detail;
return state_->is_settable_with(arg{std::forward<Value>(value)});
}
}

View File

@@ -51,6 +51,23 @@ TEST_CASE("meta/meta_states/member") {
clazz_1 v;
clazz_2 v2;
{
CHECK(vm.is_gettable_with<clazz_1>());
CHECK(vm.is_gettable_with<clazz_1&>());
CHECK(vm.is_gettable_with<clazz_1&&>());
CHECK(vm.is_gettable_with<const clazz_1>());
CHECK(vm.is_gettable_with<const clazz_1&>());
CHECK(vm.is_gettable_with<const clazz_1&&>());
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<clazz_2>());
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<clazz_1, int>());
CHECK(vm.is_settable_with<clazz_1&, int>());
CHECK(vm.is_settable_with<clazz_1&&, int>());
CHECK(vm.is_settable_with<clazz_1, int&&>());
CHECK(vm.is_settable_with<clazz_1&, int&&>());
CHECK(vm.is_settable_with<clazz_1&&, int&&>());
CHECK(vm.is_settable_with(v, 10));
CHECK(vm.is_settable_with(std::move(v), 12));
CHECK_FALSE(vm.is_settable_with<clazz_1, float>());
CHECK_FALSE(vm.is_settable_with<clazz_1&, float>());
CHECK_FALSE(vm.is_settable_with<clazz_1&&, float>());
CHECK_FALSE(vm.is_settable_with<const clazz_1, int>());
CHECK_FALSE(vm.is_settable_with<const clazz_1&, int>());
CHECK_FALSE(vm.is_settable_with<const clazz_1&&, int>());
CHECK_FALSE(vm.is_settable_with<clazz_2&, int>());
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<clazz_1>());
CHECK(vm.is_gettable_with<clazz_1&>());
CHECK(vm.is_gettable_with<clazz_1&&>());
CHECK(vm.is_gettable_with<const clazz_1>());
CHECK(vm.is_gettable_with<const clazz_1&>());
CHECK(vm.is_gettable_with<const clazz_1&&>());
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<clazz_2>());
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<clazz_1, int>());
CHECK_FALSE(vm.is_settable_with<clazz_1&, int>());
CHECK_FALSE(vm.is_settable_with<clazz_1&&, int>());
CHECK_FALSE(vm.is_settable_with<clazz_1, int&&>());
CHECK_FALSE(vm.is_settable_with<clazz_1&, int&&>());
CHECK_FALSE(vm.is_settable_with<clazz_1&&, int&&>());
CHECK_FALSE(vm.is_settable_with<clazz_1, float>());
CHECK_FALSE(vm.is_settable_with<clazz_1&, float>());
CHECK_FALSE(vm.is_settable_with<clazz_1&&, float>());
CHECK_FALSE(vm.is_settable_with<const clazz_1, int>());
CHECK_FALSE(vm.is_settable_with<const clazz_1&, int>());
CHECK_FALSE(vm.is_settable_with<const clazz_1&&, int>());
CHECK_FALSE(vm.is_settable_with(v, 10));
CHECK_FALSE(vm.is_settable_with(std::move(v), 12));
CHECK_FALSE(vm.is_settable_with<clazz_2&, int>());
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);

View File

@@ -60,6 +60,16 @@ TEST_CASE("meta/meta_states/variable") {
CHECK(vm.get() == 1);
CHECK(vm() == 1);
CHECK(vm.is_settable_with<int>());
CHECK(vm.is_settable_with<int&&>());
CHECK(vm.is_settable_with<const int&>());
CHECK(vm.is_settable_with(1));
CHECK_FALSE(vm.is_settable_with<float>());
CHECK_FALSE(vm.is_settable_with<float&&>());
CHECK_FALSE(vm.is_settable_with<const float&>());
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<int>());
CHECK_FALSE(vm.is_settable_with<int&&>());
CHECK_FALSE(vm.is_settable_with<const int&>());
CHECK_FALSE(vm.is_settable_with(1));
CHECK_FALSE(vm.is_settable_with<float>());
CHECK_FALSE(vm.is_settable_with<float&&>());
CHECK_FALSE(vm.is_settable_with<const float&>());
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<int>());
CHECK(vm.is_settable_with<int&&>());
CHECK(vm.is_settable_with<const int&>());
CHECK(vm.is_settable_with(1));
CHECK_FALSE(vm.is_settable_with<float>());
CHECK_FALSE(vm.is_settable_with<float&&>());
CHECK_FALSE(vm.is_settable_with<const float&>());
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<int>());
CHECK_FALSE(vm.is_settable_with<int&&>());
CHECK_FALSE(vm.is_settable_with<const int&>());
CHECK_FALSE(vm.is_settable_with(1));
CHECK_FALSE(vm.is_settable_with<float>());
CHECK_FALSE(vm.is_settable_with<float&&>());
CHECK_FALSE(vm.is_settable_with<const float&>());
CHECK_FALSE(vm.is_settable_with(1.0));
CHECK_THROWS(vm.set(10)); CHECK(vm.get() == 2);
CHECK_THROWS(vm(11)); CHECK(vm() == 2);
}