meta: meta_type::from_void support

This commit is contained in:
Michele Caini
2022-07-06 11:30:21 +02:00
parent c0e20825ac
commit 274a08070f
4 changed files with 73 additions and 0 deletions

View File

@@ -15,6 +15,7 @@
* [Template information](#template-information)
* [Automatic conversions](#automatic-conversions)
* [Implicitly generated default constructor](#implicitly-generated-default-constructor)
* [From void to any](#from-void-to-any)
* [Policies: the more, the less](#policies-the-more-the-less)
* [Named constants and enums](#named-constants-and-enums)
* [Properties and meta objects](#properties-and-meta-objects)
@@ -783,6 +784,24 @@ useful for building keys without knowing or having to register the actual types.
In all cases, when users register default constructors, they are preferred both
during searches and when the `construct` member function is invoked.
## From void to any
Sometimes all a user has is an opaque pointer to an object of a known meta type.
It would be handy in this case to be able to construct a `meta_any` object from
them.<br/>
For this purpose, the `meta_type` class offers a `from_void` member function
designed to convert an opaque pointer into a `meta_any`:
```cpp
entt::meta_any any = entt::resolve(id).from_void(element);
```
It goes without saying that it's not possible to do a check on the actual type.
Therefore, this call can be considered as a _static cast_ with all the problems
and undefined behaviors of the case following errors.<br/>
On the other hand, the ability to construct a `meta_any` from an opaque pointer
opens the door to some pretty interesting uses that are worth exploring.
## Policies: the more, the less
Policies are a kind of compile-time directives that can be used when registering

View File

@@ -1231,6 +1231,20 @@ public:
return construct(arguments, sizeof...(Args));
}
/**
* @brief Wraps an opaque element of the underlying type.
* @param element A valid pointer to an element of the underlying type.
* @return A wrapper that references the given instance.
*/
meta_any from_void(void *element) {
return node->from_void ? node->from_void(element, nullptr) : meta_any{};
}
/*! @copydoc from_void */
meta_any from_void(const void *element) {
return node->from_void ? node->from_void(nullptr, element) : meta_any{};
}
/**
* @brief Invokes a function given an identifier, if possible.
*

View File

@@ -111,6 +111,7 @@ struct meta_type_node {
meta_type_node *(*const remove_pointer)() noexcept;
meta_any (*const default_constructor)();
double (*const conversion_helper)(void *, const void *);
meta_any (*const from_void)(void *, const void *);
const meta_template_node *const templ;
meta_ctor_node *ctor{nullptr};
meta_base_node *base{nullptr};
@@ -149,6 +150,16 @@ class ENTT_API meta_node {
}
}
[[nodiscard]] static auto *meta_from_void() noexcept {
if constexpr(std::is_same_v<Type, void> || std::is_array_v<Type> || std::is_function_v<Type>) {
return static_cast<std::decay_t<decltype(meta_type_node::from_void)>>(nullptr);
} else {
return +[](void *element, const void *as_const) {
return element ? meta_any{std::in_place_type<Type &>, *static_cast<Type *>(element)} : meta_any{std::in_place_type<const Type &>, *static_cast<const Type *>(as_const)};
};
}
}
[[nodiscard]] static meta_template_node *meta_template_info() noexcept {
if constexpr(is_complete_v<meta_template_traits<Type>>) {
static meta_template_node node{
@@ -184,6 +195,7 @@ public:
&meta_node<std::remove_cv_t<std::remove_pointer_t<Type>>>::resolve,
meta_default_constructor(),
meta_conversion_helper(),
meta_from_void(),
meta_template_info()
// tricks clang-format
};

View File

@@ -465,6 +465,34 @@ TEST_F(MetaType, ConstructArithmeticConversion) {
ASSERT_EQ(any.cast<clazz_t>().value, 1);
}
TEST_F(MetaType, FromVoid) {
using namespace entt::literals;
ASSERT_FALSE(entt::resolve<void>().from_void(static_cast<void *>(nullptr)));
ASSERT_FALSE(entt::resolve<void>().from_void(static_cast<const void *>(nullptr)));
auto type = entt::resolve<double>();
double value = 4.2;
auto as_void = type.from_void(static_cast<void *>(&value));
auto as_const_void = type.from_void(static_cast<const void *>(&value));
ASSERT_TRUE(as_void);
ASSERT_TRUE(as_const_void);
ASSERT_EQ(as_void.type(), entt::resolve<double>());
ASSERT_NE(as_void.try_cast<double>(), nullptr);
ASSERT_EQ(as_const_void.type(), entt::resolve<double>());
ASSERT_EQ(as_const_void.try_cast<double>(), nullptr);
ASSERT_NE(as_const_void.try_cast<const double>(), nullptr);
value = 1.2;
ASSERT_EQ(as_void.cast<double>(), as_const_void.cast<double>());
ASSERT_EQ(as_void.cast<double>(), 1.2);
}
TEST_F(MetaType, Reset) {
using namespace entt::literals;