mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-16 22:17:02 +07:00
set and get member with static arguments
This commit is contained in:
@@ -21,6 +21,12 @@ namespace meta_hpp
|
||||
|
||||
const std::string& name() const noexcept;
|
||||
const member_type& type() const noexcept;
|
||||
|
||||
template < typename Instance >
|
||||
value get(Instance&& instance) const;
|
||||
|
||||
template < typename Instance, typename Value >
|
||||
void set(Instance&& instance, Value&& value) const;
|
||||
public:
|
||||
template < typename F >
|
||||
void visit(F&& f) const;
|
||||
@@ -40,12 +46,71 @@ namespace meta_hpp
|
||||
};
|
||||
}
|
||||
|
||||
namespace meta_hpp::detail
|
||||
{
|
||||
using member_getter = std::function<value(const inst&)>;
|
||||
using member_setter = std::function<void(const inst&, const arg&)>;
|
||||
|
||||
template < typename Member >
|
||||
value raw_member_getter(Member member, const inst& inst) {
|
||||
using mt = member_pointer_traits<Member>;
|
||||
using class_type = typename mt::class_type;
|
||||
using value_type = typename mt::value_type;
|
||||
|
||||
using qualified_type = const class_type;
|
||||
|
||||
if ( !inst.can_cast_to<qualified_type>() ) {
|
||||
throw std::logic_error("an attempt to get a member with an incorrect instance type");
|
||||
}
|
||||
|
||||
value_type return_value{std::invoke(member, inst.cast<qualified_type>())};
|
||||
return value{std::forward<value_type>(return_value)};
|
||||
}
|
||||
|
||||
template < typename Member >
|
||||
void raw_member_setter(Member member, const inst& inst, const arg& arg) {
|
||||
using mt = member_pointer_traits<Member>;
|
||||
using class_type = typename mt::class_type;
|
||||
using value_type = typename mt::value_type;
|
||||
|
||||
using qualified_type = class_type;
|
||||
|
||||
if constexpr ( !std::is_const_v<value_type> ) {
|
||||
if ( !inst.can_cast_to<qualified_type>() ) {
|
||||
throw std::logic_error("an attempt to set a member with an incorrect instance type");
|
||||
}
|
||||
|
||||
if ( !arg.can_cast_to<value_type>() ) {
|
||||
throw std::logic_error("an attempt to set a member with an incorrect argument type");
|
||||
}
|
||||
|
||||
std::invoke(member, inst.cast<qualified_type>()) = arg.cast<value_type>();
|
||||
} else {
|
||||
throw std::logic_error("an attempt to set a constant member");
|
||||
}
|
||||
}
|
||||
|
||||
template < typename Member >
|
||||
member_getter make_member_getter(Member member) {
|
||||
using namespace std::placeholders;
|
||||
return std::bind(&raw_member_getter<Member>, member, _1);
|
||||
}
|
||||
|
||||
template < typename Member >
|
||||
member_setter make_member_setter(Member member) {
|
||||
using namespace std::placeholders;
|
||||
return std::bind(&raw_member_setter<Member>, member, _1, _2);
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
{
|
||||
struct member_info::state final {
|
||||
std::string name;
|
||||
member_type type;
|
||||
data_info_map datas;
|
||||
detail::member_getter getter;
|
||||
detail::member_setter setter;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -67,6 +132,16 @@ namespace meta_hpp
|
||||
inline const member_type& member_info::type() const noexcept {
|
||||
return state_->type;
|
||||
}
|
||||
|
||||
template < typename Instance >
|
||||
value member_info::get(Instance&& instance) const {
|
||||
return state_->getter(inst{std::forward<Instance>(instance)});
|
||||
}
|
||||
|
||||
template < typename Instance, typename Value >
|
||||
void member_info::set(Instance&& instance, Value&& value) const {
|
||||
state_->setter(inst{std::forward<Instance>(instance)}, arg{std::forward<Value>(value)});
|
||||
}
|
||||
}
|
||||
|
||||
namespace meta_hpp
|
||||
@@ -91,12 +166,12 @@ namespace meta_hpp
|
||||
namespace meta_hpp
|
||||
{
|
||||
template < typename Member >
|
||||
member_info::member_info(std::string name, Member instance)
|
||||
member_info::member_info(std::string name, Member member)
|
||||
: state_{std::make_shared<state>(state{
|
||||
std::move(name),
|
||||
type_db::get<Member>().template as<member_type>(),
|
||||
{}
|
||||
})} {
|
||||
(void)instance;
|
||||
}
|
||||
{},
|
||||
detail::make_member_getter<Member>(member),
|
||||
detail::make_member_setter<Member>(member),
|
||||
})} {}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,156 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace meta_hpp;
|
||||
using namespace std::string_literals;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct ivec2 {
|
||||
int x{};
|
||||
int y{};
|
||||
|
||||
[[maybe_unused]] ivec2() = default;
|
||||
[[maybe_unused]] explicit ivec2(int v): x{v}, y{v} {}
|
||||
[[maybe_unused]] ivec2(int x, int y): x{x}, y{y} {}
|
||||
};
|
||||
|
||||
struct ipnt2 {
|
||||
const int x{};
|
||||
const int y{};
|
||||
|
||||
[[maybe_unused]] ipnt2() = default;
|
||||
[[maybe_unused]] explicit ipnt2(int v): x{v}, y{v} {}
|
||||
[[maybe_unused]] ipnt2(int x, int y): x{x}, y{y} {}
|
||||
};
|
||||
|
||||
bool operator==(const ivec2& l, const ivec2& r) noexcept {
|
||||
return l.x == r.x && l.y == r.y;
|
||||
}
|
||||
|
||||
bool operator==(const ipnt2& l, const ipnt2& r) noexcept {
|
||||
return l.x == r.x && l.y == r.y;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("features/infos/member") {
|
||||
registry db;
|
||||
|
||||
db(
|
||||
namespace_{"vmath"}(
|
||||
class_<ivec2>{"ivec2"}(
|
||||
member_{"x", &ivec2::x},
|
||||
member_{"y", &ivec2::y}
|
||||
),
|
||||
class_<ipnt2>{"ipnt2"}(
|
||||
member_{"x", &ipnt2::x},
|
||||
member_{"y", &ipnt2::y}
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
SUBCASE("non_const") {
|
||||
const member_info x_mi = db.get_member_by_path("vmath::ivec2::x");
|
||||
const member_info y_mi = db.get_member_by_path("vmath::ivec2::y");
|
||||
REQUIRE(x_mi);
|
||||
REQUIRE(y_mi);
|
||||
|
||||
{
|
||||
CHECK(x_mi.name() == "x");
|
||||
CHECK(x_mi.type().class_type() == type_db::get<ivec2>());
|
||||
CHECK(x_mi.type().value_type() == type_db::get<int>());
|
||||
|
||||
CHECK(y_mi.name() == "y");
|
||||
CHECK(y_mi.type().class_type() == type_db::get<ivec2>());
|
||||
CHECK(y_mi.type().value_type() == type_db::get<int>());
|
||||
}
|
||||
|
||||
{
|
||||
ivec2 v{1,2};
|
||||
|
||||
CHECK(x_mi.get(v).equals(1));
|
||||
CHECK(x_mi.get(std::as_const(v)).equals(1));
|
||||
CHECK(x_mi.get(std::move(v)).equals(1));
|
||||
CHECK(x_mi.get(std::move(std::as_const(v))).equals(1));
|
||||
|
||||
CHECK(y_mi.get(v).equals(2));
|
||||
CHECK(y_mi.get(std::as_const(v)).equals(2));
|
||||
CHECK(y_mi.get(std::move(v)).equals(2));
|
||||
CHECK(y_mi.get(std::move(std::as_const(v))).equals(2));
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&ivec2::x), ivec2&>);
|
||||
static_assert(std::is_invocable_v<decltype(&ivec2::x), const ivec2&>);
|
||||
static_assert(std::is_invocable_v<decltype(&ivec2::x), ivec2&&>);
|
||||
static_assert(std::is_invocable_v<decltype(&ivec2::x), const ivec2&&>);
|
||||
}
|
||||
|
||||
{
|
||||
ivec2 v{1,2};
|
||||
|
||||
CHECK_NOTHROW(x_mi.set(v, 10)); CHECK(v.x == 10);
|
||||
CHECK_THROWS(x_mi.set(std::as_const(v), 11)); CHECK(v.x == 10);
|
||||
CHECK_NOTHROW(x_mi.set(std::move(v), 12)); CHECK(v.x == 12);
|
||||
CHECK_THROWS(x_mi.set(std::move(std::as_const(v)), 13)); CHECK(v.x == 12);
|
||||
|
||||
CHECK_NOTHROW(y_mi.set(v, 20)); CHECK(v.y == 20);
|
||||
CHECK_THROWS(y_mi.set(std::as_const(v), 21)); CHECK(v.y == 20);
|
||||
CHECK_NOTHROW(y_mi.set(std::move(v), 22)); CHECK(v.y == 22);
|
||||
CHECK_THROWS(y_mi.set(std::move(std::as_const(v)), 23)); CHECK(v.y == 22);
|
||||
|
||||
CHECK(v == ivec2{12,22});
|
||||
}
|
||||
}
|
||||
|
||||
SUBCASE("const") {
|
||||
const member_info x_mi = db.get_member_by_path("vmath::ipnt2::x");
|
||||
const member_info y_mi = db.get_member_by_path("vmath::ipnt2::y");
|
||||
REQUIRE(x_mi);
|
||||
REQUIRE(y_mi);
|
||||
|
||||
{
|
||||
CHECK(x_mi.name() == "x");
|
||||
CHECK(x_mi.type().class_type() == type_db::get<ipnt2>());
|
||||
CHECK(x_mi.type().value_type() == type_db::get<const int>());
|
||||
|
||||
CHECK(y_mi.name() == "y");
|
||||
CHECK(y_mi.type().class_type() == type_db::get<ipnt2>());
|
||||
CHECK(y_mi.type().value_type() == type_db::get<const int>());
|
||||
}
|
||||
|
||||
{
|
||||
ipnt2 v{1,2};
|
||||
|
||||
CHECK(x_mi.get(v).equals(1));
|
||||
CHECK(x_mi.get(std::as_const(v)).equals(1));
|
||||
CHECK(x_mi.get(std::move(v)).equals(1));
|
||||
CHECK(x_mi.get(std::move(std::as_const(v))).equals(1));
|
||||
|
||||
CHECK(y_mi.get(v).equals(2));
|
||||
CHECK(y_mi.get(std::as_const(v)).equals(2));
|
||||
CHECK(y_mi.get(std::move(v)).equals(2));
|
||||
CHECK(y_mi.get(std::move(std::as_const(v))).equals(2));
|
||||
|
||||
static_assert(std::is_invocable_v<decltype(&ipnt2::x), ipnt2&>);
|
||||
static_assert(std::is_invocable_v<decltype(&ipnt2::x), const ipnt2&>);
|
||||
static_assert(std::is_invocable_v<decltype(&ipnt2::x), ipnt2&&>);
|
||||
static_assert(std::is_invocable_v<decltype(&ipnt2::x), const ipnt2&&>);
|
||||
}
|
||||
|
||||
{
|
||||
ipnt2 v{1,2};
|
||||
|
||||
CHECK_THROWS(x_mi.set(v, 10)); CHECK(v.x == 1);
|
||||
CHECK_THROWS(x_mi.set(std::as_const(v), 11)); CHECK(v.x == 1);
|
||||
CHECK_THROWS(x_mi.set(std::move(v), 12)); CHECK(v.x == 1);
|
||||
CHECK_THROWS(x_mi.set(std::move(std::as_const(v)), 13)); CHECK(v.x == 1);
|
||||
|
||||
CHECK_THROWS(y_mi.set(v, 20)); CHECK(v.y == 2);
|
||||
CHECK_THROWS(y_mi.set(std::as_const(v), 21)); CHECK(v.y == 2);
|
||||
CHECK_THROWS(y_mi.set(std::move(v), 22)); CHECK(v.y == 2);
|
||||
CHECK_THROWS(y_mi.set(std::move(std::as_const(v)), 23)); CHECK(v.y == 2);
|
||||
|
||||
CHECK(v == ipnt2{1,2});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user