mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-16 14:09: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 std::string& name() const noexcept;
|
||||||
const member_type& type() 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:
|
public:
|
||||||
template < typename F >
|
template < typename F >
|
||||||
void visit(F&& f) const;
|
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
|
namespace meta_hpp
|
||||||
{
|
{
|
||||||
struct member_info::state final {
|
struct member_info::state final {
|
||||||
std::string name;
|
std::string name;
|
||||||
member_type type;
|
member_type type;
|
||||||
data_info_map datas;
|
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 {
|
inline const member_type& member_info::type() const noexcept {
|
||||||
return state_->type;
|
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
|
namespace meta_hpp
|
||||||
@@ -91,12 +166,12 @@ namespace meta_hpp
|
|||||||
namespace meta_hpp
|
namespace meta_hpp
|
||||||
{
|
{
|
||||||
template < typename Member >
|
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{
|
: state_{std::make_shared<state>(state{
|
||||||
std::move(name),
|
std::move(name),
|
||||||
type_db::get<Member>().template as<member_type>(),
|
type_db::get<Member>().template as<member_type>(),
|
||||||
{}
|
{},
|
||||||
})} {
|
detail::make_member_getter<Member>(member),
|
||||||
(void)instance;
|
detail::make_member_setter<Member>(member),
|
||||||
}
|
})} {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,156 @@
|
|||||||
|
|
||||||
namespace
|
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") {
|
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