meta:
* dtor support to member functions * review to introduce strict checks on policies
This commit is contained in:
@@ -110,9 +110,10 @@ decorated version of it. This object can be used to add the following:
|
||||
entt::meta<my_type>().ctor<int, char>().ctor<&factory>();
|
||||
```
|
||||
|
||||
* _Destructors_. Free functions can be set as destructors of reflected types.
|
||||
The purpose is to give users the ability to free up resources that require
|
||||
special treatment before an object is actually destroyed.<br/>
|
||||
* _Destructors_. Free functions and member functions can be used as destructors
|
||||
of reflected types. The purpose is to give users the ability to free up
|
||||
resources that require special treatment before an object is actually
|
||||
destroyed.<br/>
|
||||
Use the `dtor` member function for this purpose:
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -192,7 +193,7 @@ class meta_factory<Type> {
|
||||
(std::is_member_object_pointer_v<decltype(value_list_element_v<Index, Setter>)> && ... && std::is_const_v<data_type>) ? internal::meta_traits::is_const : internal::meta_traits::is_none,
|
||||
internal::meta_node<std::remove_const_t<std::remove_reference_t<data_type>>>::resolve(),
|
||||
&meta_arg<type_list<type_list_element_t<type_list_element_t<Index, args_type>::size != 1u, type_list_element_t<Index, args_type>>...>>,
|
||||
[](meta_handle instance, meta_any value) -> bool { return (meta_setter<Type, value_list_element_v<Index, Setter>>(*instance.operator->(), value) || ...); },
|
||||
[](meta_handle instance, meta_any value) -> bool { return (meta_setter<Type, value_list_element_v<Index, Setter>>(*instance.operator->(), value.as_ref()) || ...); },
|
||||
&meta_getter<Type, Getter, Policy>
|
||||
// tricks clang-format
|
||||
};
|
||||
@@ -269,26 +270,16 @@ public:
|
||||
auto conv() ENTT_NOEXCEPT {
|
||||
using conv_type = std::remove_const_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>;
|
||||
|
||||
if constexpr(std::is_member_function_pointer_v<decltype(Candidate)>) {
|
||||
static internal::meta_conv_node node{
|
||||
nullptr,
|
||||
internal::meta_node<conv_type>::resolve(),
|
||||
[](const meta_any &instance) -> meta_any { return forward_as_meta((static_cast<const Type *>(instance.data())->*Candidate)()); }
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
link_conv_if_required(node);
|
||||
} else {
|
||||
static internal::meta_conv_node node{
|
||||
nullptr,
|
||||
internal::meta_node<conv_type>::resolve(),
|
||||
[](const meta_any &instance) -> meta_any { return forward_as_meta(Candidate(*static_cast<const Type *>(instance.data()))); }
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
link_conv_if_required(node);
|
||||
}
|
||||
static internal::meta_conv_node node{
|
||||
nullptr,
|
||||
internal::meta_node<conv_type>::resolve(),
|
||||
[](const meta_any &instance) -> meta_any {
|
||||
return forward_as_meta(std::invoke(Candidate, *static_cast<const Type *>(instance.data())));
|
||||
}
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
link_conv_if_required(node);
|
||||
return meta_factory<Type>{};
|
||||
}
|
||||
|
||||
@@ -375,13 +366,15 @@ public:
|
||||
/**
|
||||
* @brief Assigns a meta destructor to a meta type.
|
||||
*
|
||||
* Free functions can be assigned to meta types in the role of destructors.
|
||||
* The signature of the function should identical to the following:
|
||||
* Both free functions and member functions can be assigned to meta types in
|
||||
* the role of destructors.<br/>
|
||||
* The signature of a free function should be identical to the following:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(Type &);
|
||||
* @endcode
|
||||
*
|
||||
* Member functions should not take arguments instead.<br/>
|
||||
* The purpose is to give users the ability to free up resources that
|
||||
* require special treatment before an object is actually destroyed.
|
||||
*
|
||||
@@ -391,7 +384,7 @@ public:
|
||||
template<auto Func>
|
||||
auto dtor() ENTT_NOEXCEPT {
|
||||
static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
|
||||
owner->dtor = [](void *instance) { Func(*static_cast<Type *>(instance)); };
|
||||
owner->dtor = [](void *instance) { std::invoke(Func, *static_cast<Type *>(instance)); };
|
||||
return meta_factory<Type>{};
|
||||
}
|
||||
|
||||
@@ -411,7 +404,24 @@ public:
|
||||
template<auto Data, typename Policy = as_is_t>
|
||||
auto data(const id_type id) ENTT_NOEXCEPT {
|
||||
if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
return data<Data, Data, Policy>(id);
|
||||
using data_type = std::remove_reference_t<std::invoke_result_t<decltype(Data), Type &>>;
|
||||
|
||||
static internal::meta_data_node node{
|
||||
{},
|
||||
nullptr,
|
||||
nullptr,
|
||||
1u,
|
||||
/* this is never static */
|
||||
std::is_const_v<data_type> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
|
||||
internal::meta_node<std::remove_const_t<data_type>>::resolve(),
|
||||
&meta_arg<type_list<std::remove_const_t<data_type>>>,
|
||||
&meta_setter<Type, Data>,
|
||||
&meta_getter<Type, Data, Policy>
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
link_data_if_required(id, node);
|
||||
return meta_factory<Type, std::integral_constant<decltype(Data), Data>, std::integral_constant<decltype(Data), Data>>{&node.prop};
|
||||
} else {
|
||||
using data_type = std::remove_pointer_t<decltype(Data)>;
|
||||
|
||||
@@ -422,7 +432,7 @@ public:
|
||||
1u,
|
||||
((std::is_same_v<Type, data_type> || std::is_const_v<data_type>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
|
||||
internal::meta_node<std::remove_const_t<std::remove_reference_t<data_type>>>::resolve(),
|
||||
&meta_arg<type_list<data_type>>,
|
||||
&meta_arg<type_list<std::remove_const_t<std::remove_reference_t<data_type>>>>,
|
||||
&meta_setter<Type, Data>,
|
||||
&meta_getter<Type, Data, Policy>
|
||||
// tricks clang-format
|
||||
@@ -482,8 +492,8 @@ public:
|
||||
nullptr,
|
||||
nullptr,
|
||||
1u,
|
||||
/* this is never static */
|
||||
(std::is_member_object_pointer_v<decltype(Setter)> && std::is_const_v<data_type>) ? internal::meta_traits::is_const : internal::meta_traits::is_none,
|
||||
/* this is never static nor const */
|
||||
internal::meta_traits::is_none,
|
||||
internal::meta_node<std::remove_const_t<std::remove_reference_t<data_type>>>::resolve(),
|
||||
&meta_arg<type_list<type_list_element_t<args_type::size != 1u, args_type>>>,
|
||||
&meta_setter<Type, Setter>,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define ENTT_META_UTILITY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
@@ -65,14 +66,14 @@ struct meta_function_descriptor<Type, Ret (Class::*)(Args...)> {
|
||||
template<typename Type, typename Ret, typename Class>
|
||||
struct meta_function_descriptor<Type, Ret Class::*> {
|
||||
/*! @brief Meta data return type. */
|
||||
using return_type = Ret;
|
||||
using return_type = Ret &;
|
||||
/*! @brief Meta data arguments. */
|
||||
using args_type = std::conditional_t<std::is_base_of_v<Class, Type>, type_list<Ret>, type_list<Class &, Ret>>;
|
||||
using args_type = std::conditional_t<std::is_base_of_v<Class, Type>, type_list<>, type_list<Class &>>;
|
||||
|
||||
/*! @brief True if the meta data is const, false otherwise. */
|
||||
static constexpr auto is_const = false;
|
||||
/*! @brief True if the meta data is static, false otherwise. */
|
||||
static constexpr auto is_static = false;
|
||||
static constexpr auto is_static = !std::is_base_of_v<Class, Type>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -195,27 +196,20 @@ template<typename Type>
|
||||
template<typename Type, auto Data>
|
||||
[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) {
|
||||
if constexpr(!std::is_same_v<decltype(Data), Type> && !std::is_same_v<decltype(Data), std::nullptr_t>) {
|
||||
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
|
||||
if constexpr(std::is_member_function_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
|
||||
using descriptor = meta_function_helper_t<Type, decltype(Data)>;
|
||||
using data_type = type_list_element_t<descriptor::is_static, typename descriptor::args_type>;
|
||||
|
||||
if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
|
||||
Data(*clazz, value.cast<data_type>());
|
||||
return true;
|
||||
}
|
||||
} else if constexpr(std::is_member_function_pointer_v<decltype(Data)>) {
|
||||
using data_type = type_list_element_t<0u, typename meta_function_helper_t<Type, decltype(Data)>::args_type>;
|
||||
|
||||
if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
|
||||
(clazz->*Data)(value.cast<data_type>());
|
||||
std::invoke(Data, *clazz, value.cast<data_type>());
|
||||
return true;
|
||||
}
|
||||
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
using data_type = std::remove_reference_t<decltype(std::declval<Type>().*Data)>;
|
||||
using data_type = std::remove_reference_t<typename meta_function_helper_t<Type, decltype(Data)>::return_type>;
|
||||
|
||||
if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
|
||||
if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
|
||||
clazz->*Data = value.cast<data_type>();
|
||||
std::invoke(Data, *clazz) = value.cast<data_type>();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -244,18 +238,18 @@ template<typename Type, auto Data>
|
||||
*/
|
||||
template<typename Type, auto Data, typename Policy = as_is_t>
|
||||
[[nodiscard]] meta_any meta_getter([[maybe_unused]] meta_handle instance) {
|
||||
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
|
||||
auto *const clazz = instance->try_cast<std::conditional_t<std::is_invocable_v<decltype(Data), const Type &>, const Type, Type>>();
|
||||
return clazz ? meta_dispatch<Policy>(Data(*clazz)) : meta_any{};
|
||||
} else if constexpr(std::is_member_function_pointer_v<decltype(Data)>) {
|
||||
auto *const clazz = instance->try_cast<std::conditional_t<std::is_invocable_v<decltype(Data), const Type &>, const Type, Type>>();
|
||||
return clazz ? meta_dispatch<Policy>((clazz->*Data)()) : meta_any{};
|
||||
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
if constexpr(!std::is_array_v<std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>>) {
|
||||
if(auto *clazz = instance->try_cast<Type>(); clazz) {
|
||||
return meta_dispatch<Policy>(clazz->*Data);
|
||||
} else if(auto *fallback = instance->try_cast<const Type>(); fallback) {
|
||||
return meta_dispatch<Policy>(fallback->*Data);
|
||||
if constexpr(std::is_member_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
|
||||
if constexpr(!std::is_array_v<std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Data), Type &>>>>) {
|
||||
if constexpr(std::is_invocable_v<decltype(Data), Type &>) {
|
||||
if(auto *clazz = instance->try_cast<Type>(); clazz) {
|
||||
return meta_dispatch<Policy>(std::invoke(Data, *clazz));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr(std::is_invocable_v<decltype(Data), const Type &>) {
|
||||
if(auto *fallback = instance->try_cast<const Type>(); fallback) {
|
||||
return meta_dispatch<Policy>(std::invoke(Data, *fallback));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,22 +272,13 @@ template<typename Type, auto Data, typename Policy = as_is_t>
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Type, typename Policy, typename Candidate, typename First, typename... Other>
|
||||
[[nodiscard]] meta_any meta_invoke_with_args(Candidate &&candidate, First &&maybe_clazz, Other &&...other) {
|
||||
using descriptor = meta_function_helper_t<Type, std::remove_reference_t<Candidate>>;
|
||||
|
||||
if constexpr(std::is_member_function_pointer_v<std::remove_reference_t<Candidate>>) {
|
||||
if constexpr(std::is_void_v<typename descriptor::return_type>) {
|
||||
(std::forward<First>(maybe_clazz).*std::forward<Candidate>(candidate))(std::forward<Other>(other)...);
|
||||
return meta_any{std::in_place_type<void>};
|
||||
} else {
|
||||
return meta_dispatch<Policy>((std::forward<First>(maybe_clazz).*std::forward<Candidate>(candidate))(std::forward<Other>(other)...));
|
||||
}
|
||||
} else if constexpr(std::is_void_v<typename descriptor::return_type>) {
|
||||
std::forward<Candidate>(candidate)(std::forward<First>(maybe_clazz), std::forward<Other>(other)...);
|
||||
template<typename Type, typename Policy, typename Candidate, typename... Args>
|
||||
[[nodiscard]] meta_any meta_invoke_with_args(Candidate &&candidate, Args &&...args) {
|
||||
if constexpr(std::is_same_v<std::invoke_result_t<decltype(candidate), Args...>, void>) {
|
||||
std::invoke(candidate, args...);
|
||||
return meta_any{std::in_place_type<void>};
|
||||
} else {
|
||||
return meta_dispatch<Policy>(std::forward<Candidate>(candidate)(std::forward<First>(maybe_clazz), std::forward<Other>(other)...));
|
||||
return meta_dispatch<Policy>(std::invoke(candidate, args...));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,26 +290,17 @@ template<typename Type, typename Policy, typename Candidate, std::size_t... Inde
|
||||
if(const auto *const clazz = instance->try_cast<const Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return meta_invoke_with_args<Type, Policy>(std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
}
|
||||
|
||||
return meta_any{};
|
||||
} else if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
|
||||
if(auto *const clazz = instance->try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return meta_invoke_with_args<Type, Policy>(std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
}
|
||||
|
||||
return meta_any{};
|
||||
} else if constexpr(sizeof...(Index) != 0u) {
|
||||
} else {
|
||||
if(((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return meta_invoke_with_args<Type, Policy>(std::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
}
|
||||
|
||||
return meta_any{};
|
||||
} else if constexpr(std::is_void_v<decltype(std::forward<Candidate>(candidate)())>) {
|
||||
std::forward<Candidate>(candidate)();
|
||||
return meta_any{std::in_place_type<void>};
|
||||
} else {
|
||||
return meta_dispatch<Policy>(std::forward<Candidate>(candidate)());
|
||||
}
|
||||
|
||||
return meta_any{};
|
||||
}
|
||||
|
||||
template<typename Type, typename... Args, std::size_t... Index>
|
||||
@@ -412,11 +388,7 @@ template<typename Type, typename Policy = as_is_t, typename Candidate>
|
||||
*/
|
||||
template<typename Type, auto Candidate, typename Policy = as_is_t>
|
||||
[[nodiscard]] meta_any meta_construct(meta_any *const args) {
|
||||
if constexpr(meta_function_helper_t<Type, decltype(Candidate)>::is_static) {
|
||||
return internal::meta_invoke<Type, Policy>({}, Candidate, args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
|
||||
} else {
|
||||
return internal::meta_invoke<Type, Policy>(*args, Candidate, args + 1u, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
|
||||
}
|
||||
return meta_construct<Type, Policy>(Candidate, args);
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -14,7 +14,7 @@ struct clazz_t {
|
||||
--counter;
|
||||
}
|
||||
|
||||
static void destroy_incr(clazz_t &) {
|
||||
void destroy_incr() const {
|
||||
++counter;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ TEST_F(MetaDtor, ReRegistration) {
|
||||
|
||||
ASSERT_NE(node->dtor, nullptr);
|
||||
|
||||
entt::meta<clazz_t>().dtor<clazz_t::destroy_incr>();
|
||||
entt::meta<clazz_t>().dtor<&clazz_t::destroy_incr>();
|
||||
entt::resolve<clazz_t>().construct().reset();
|
||||
|
||||
ASSERT_EQ(clazz_t::counter, 2);
|
||||
|
||||
Reference in New Issue
Block a user