Implemented shortcuts for meta-functions and meta-data

The shortcut for meta-functions allows invoking them directly from an instance
of meta_type or meta_any. If the meta-function was not found or the arguments
don't match its signature an invalid meta_any object is returned.

The shortcut for meta-data allows getting and setting meta-data directly from an
instance of meta_type of meta_any. If the meta_data was not found or
getting/setting it failed and invalid meta_any object is returned.

Signed-off-by: Innokentiy Alaytsev <alaitsev@gmail.com>
This commit is contained in:
Innokentiy Alaytsev
2020-09-07 19:28:38 +00:00
committed by Michele Caini
parent c9f47ed89a
commit 5995adf8b6
3 changed files with 182 additions and 0 deletions

View File

@@ -296,6 +296,48 @@ public:
return storage.data();
}
/**
* @copybrief invoke
*
* @sa invoke
*
* @param id identifier of function to invoke.
* @tparam Args Types of arguments to use to invoke the function.
* @param instance An opaque instance of the underlying type.
* @param args Parameters to use to invoke the function.
* @return A meta any containing the new instance, if any.
*/
template<typename... Args>
meta_any invoke(const id_type id, Args &&... args) const;
/**
* @brief Sets the value of a given variable.
*
* It must be possible to cast the instance to the parent type of the meta
* data. Otherwise, invoking the setter results in an undefined
* behavior.<br/>
* The type of the value must be such that a cast or conversion to the type
* of the variable is possible. Otherwise, invoking the setter does nothing.
*
* @tparam Type Type of value to assign.
* @param id identifier of the variable to set.
* @param value Parameter to use to set the underlying variable.
* @return True in case of success, false otherwise.
*/
template<typename Type>
bool set(const id_type id, Type &&value) const;
/**
* @brief Gets the value of a given variable.
*
* It must be possible to cast the instance to the parent type of the meta
* data. Otherwise, invoking the getter results in an undefined behavior.
*
* @param id identifier of the variable to get.
* @return A meta any containing the value of the underlying variable.
*/
[[nodiscard]] meta_any get(const id_type id) const;
/**
* @brief Tries to cast an instance to a given type.
* @tparam Type Type to which to cast the instance.
@@ -1305,6 +1347,80 @@ public:
return construct(arguments.data(), sizeof...(Args));
}
/**
* @brief Invokes the function with the given identifier, if possible.
*
* To invoke a meta function, the parameters must be such that a cast or
* conversion to the required types is possible. Otherwise, an empty and
* thus invalid wrapper is returned.<br/>
* It must be possible to cast the instance to the parent type of the meta
* function. Otherwise, invoking the underlying function results in an
* undefined behavior.
*
* @param id identifier of function to invoke.
* @param instance An opaque instance of the underlying type.
* @param args Parameters to use to invoke the function.
* @param sz Number of parameters to use to invoke the function.
* @return A meta any containing the returned value, if any.
*/
[[nodiscard]] meta_any invoke(const id_type id, meta_handle instance, meta_any * const args, const std::size_t sz) const {
auto const f = func(id);
return f ? f.invoke(instance, args, sz) : meta_any{};
}
/**
* @copybrief invoke
*
* @sa invoke
*
* @param id identifier of function to invoke.
* @tparam Args Types of arguments to use to invoke the function.
* @param instance An opaque instance of the underlying type.
* @param args Parameters to use to invoke the function.
* @return A meta any containing the new instance, if any.
*/
template<typename... Args>
meta_any invoke(const id_type id, meta_handle instance, Args &&... args) const {
std::array<meta_any, sizeof...(Args)> arguments{std::forward<Args>(args)...};
return invoke(id, instance, arguments.data(), sizeof...(Args));
}
/**
* @brief Sets the value of a given variable.
*
* It must be possible to cast the instance to the parent type of the meta
* data. Otherwise, invoking the setter results in an undefined
* behavior.<br/>
* The type of the value must be such that a cast or conversion to the type
* of the variable is possible. Otherwise, invoking the setter does nothing.
*
* @tparam Type Type of value to assign.
* @param id identifier of the variable to set.
* @param instance An opaque instance of the underlying type.
* @param value Parameter to use to set the underlying variable.
* @return True in case of success, false otherwise.
*/
template<typename Type>
bool set(const id_type id, meta_handle instance, Type &&value) const {
auto const d = data(id);
return d ? d.set(std::move(instance), std::forward<Type>(value)) : false;
}
/**
* @brief Gets the value of a given variable.
*
* It must be possible to cast the instance to the parent type of the meta
* data. Otherwise, invoking the getter results in an undefined behavior.
*
* @param id identifier of the variable to get.
* @param instance An opaque instance of the underlying type.
* @return A meta any containing the value of the underlying variable.
*/
[[nodiscard]] meta_any get(const id_type id, meta_handle instance) const {
auto const d = data(id);
return d ? d.get(std::move(instance)) : meta_any{};
}
/**
* @brief Returns a range to use to visit top-level meta properties.
* @return An iterable range to use to visit top-level meta properties.
@@ -1409,6 +1525,23 @@ private:
}
template<typename... Args>
meta_any meta_any::invoke(const id_type id, Args &&... args) const {
return type().invoke(id, *this, std::forward<Args>(args)...);
}
template<typename Type>
bool meta_any::set(const id_type id, Type &&value) const {
return type().set(id, *this, std::forward<Type>(value));
}
[[nodiscard]] inline meta_any meta_any::get(const id_type id) const {
return type().get(id, *this);
}
[[nodiscard]] inline meta_type meta_base::parent() const ENTT_NOEXCEPT {
return node->parent;
}

View File

@@ -5,6 +5,17 @@
#include <entt/meta/meta.hpp>
#include <entt/meta/resolve.hpp>
struct clazz_t {
clazz_t() = default;
void member(int i) { value = i; }
static void func() { c = 'd'; }
static inline char c = 'c';
int value = 0;
};
struct empty_t {
virtual ~empty_t() = default;
static void destroy(empty_t &) {
@@ -46,6 +57,12 @@ struct MetaAny: ::testing::Test {
entt::meta<double>().conv<int>();
entt::meta<empty_t>().dtor<&empty_t::destroy>();
entt::meta<fat_t>().base<empty_t>().dtor<&fat_t::destroy>();
entt::meta<clazz_t>()
.type("clazz"_hs)
.data<&clazz_t::value>("value"_hs)
.func<&clazz_t::member>("member"_hs)
.func<&clazz_t::func>("func"_hs);
}
void SetUp() override {
@@ -622,3 +639,32 @@ TEST_F(MetaAny, UnmanageableType) {
ASSERT_TRUE(std::as_const(any).convert<unmanageable_t>());
ASSERT_FALSE(std::as_const(any).convert<int>());
}
TEST_F(MetaAny, FuncInvokeShortcut) {
clazz_t instance;
entt::meta_any any{std::ref(instance)};
ASSERT_TRUE(any.invoke("func"_hs));
ASSERT_TRUE(any.invoke("member"_hs, 42));
ASSERT_FALSE(any.invoke("non_existent"_hs, 42));
ASSERT_EQ(clazz_t::c, 'd');
ASSERT_EQ(instance.value, 42);
}
TEST_F(MetaAny, DataAccessShortcut) {
clazz_t instance;
entt::meta_any any{std::ref(instance)};
ASSERT_TRUE(any.set("value"_hs, 42));
auto const value_any = any.get("value"_hs);
ASSERT_EQ(instance.value, 42);
ASSERT_TRUE(value_any);
ASSERT_TRUE(value_any.try_cast<int>());
ASSERT_EQ(value_any.cast<int>(), 42);
ASSERT_FALSE(any.set("non_existent"_hs, 42));
ASSERT_FALSE(any.get("non_existent"_hs));
}

View File

@@ -270,6 +270,9 @@ TEST_F(MetaType, Func) {
ASSERT_TRUE(type.func("func"_hs));
ASSERT_TRUE(type.func("member"_hs).invoke(instance));
ASSERT_TRUE(type.func("func"_hs).invoke({}));
ASSERT_TRUE(type.invoke("member"_hs, instance));
ASSERT_TRUE(type.invoke("func"_hs, {}));
}
TEST_F(MetaType, Construct) {