meta:
* meta_any: convert -> allow_cast * support for const references * as_cref_t policy
This commit is contained in:
6
TODO
6
TODO
@@ -15,10 +15,12 @@
|
||||
- spatial query
|
||||
- runtime types pool
|
||||
- off-line/off-memory/remote
|
||||
- poly
|
||||
- ...
|
||||
|
||||
WIP:
|
||||
* HP: any/meta_any/poly: ::REF -> ::CREF?
|
||||
* HP: meta, support for custom deref function other than operator*
|
||||
* HP: meta, as_cref_t other than as_ref_t
|
||||
* HP: headless (sparse set only) view
|
||||
* HP: pass the registry to pools, basic poly storage should have only component member
|
||||
* HP: make view pack work also with groups, make packs input iterator only, add view adapter for external sources
|
||||
@@ -27,6 +29,8 @@ WIP:
|
||||
* HP: any/poly: configurable sbo size, compile-time policies like sbo-required.
|
||||
* HP: registry: use a poly object for pools, no more pool_data type.
|
||||
* HP: make runtime views use opaque storage and therefore return also elements.
|
||||
* HP: meta_sequence_container & Co can be replaced by a poly object.
|
||||
* HP: poly: support for data members
|
||||
* suppress warnings in meta.hpp (uninitialized members)
|
||||
* add exclude-only views to combine with packs
|
||||
* deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
|
||||
|
||||
@@ -215,9 +215,9 @@ const bool equal = (any == other);
|
||||
Also, `meta_any` adds support for containers and pointer-like types (see the
|
||||
following sections for more details).<br/>
|
||||
Similar to `any`, this class can also be used to create _aliases_ for unmanaged
|
||||
objects either upon construction using `std::ref` or from an existing instance
|
||||
by means of the `as_ref` function. However, unlike `any`,` meta_any` treats an
|
||||
empty instance and one initialized with `void` differently:
|
||||
objects either upon construction using `std::ref` and `std::cref` or from an
|
||||
existing instance by means of the `as_ref` function. However, unlike `any`,
|
||||
`meta_any` treats an empty instance and one initialized with `void` differently:
|
||||
|
||||
```cpp
|
||||
entt::meta_any empty{};
|
||||
@@ -228,9 +228,10 @@ While `any` treats both objects as empty, `meta_any` treats objects initialized
|
||||
with `void` as if they were _valid_ ones. This allows to differentiate between
|
||||
failed function calls and function calls that are successful but return
|
||||
nothing.<br/>
|
||||
Finally, the member functions `try_cast`, `cast` and `convert` are used to know
|
||||
if the underlying object has a given type as a base or if it can be converted
|
||||
implicitly to it. There is in fact no `any_cast` equivalent for `meta_any`.
|
||||
Finally, the member functions `try_cast`, `cast` and `allow_cast` are used to
|
||||
cast the underlying object to a given type (either a reference or a value type)
|
||||
or to _convert_ a `meta_any` in such a way that a cast becomes viable for the
|
||||
resulting object. There is in fact no `any_cast` equivalent for `meta_any`.
|
||||
|
||||
## Enjoy the runtime
|
||||
|
||||
@@ -684,13 +685,14 @@ There are a few alternatives available at the moment:
|
||||
entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
|
||||
```
|
||||
|
||||
* The _as-ref_ policy, associated with the type `entt::as_ref_t`.<br/>
|
||||
It allows to build wrappers that act as references to unmanaged objects.
|
||||
Modifying the object contained in the wrapper for which the _reference_ was
|
||||
requested will make it possible to directly modify the instance used to
|
||||
* The _as-ref_ and _as-cref_ policies, associated with the types
|
||||
`entt::as_ref_t` and `entt::as_cref_t`.<br/>
|
||||
They allow to build wrappers that act as references to unmanaged objects.
|
||||
Accessing the object contained in the wrapper for which the _reference_ was
|
||||
requested will make it possible to directly access the instance used to
|
||||
initialize the wrapper itself.<br/>
|
||||
This policy works with constructors (for example, when objects are taken from
|
||||
an external container rather than created on demand), data members and
|
||||
These policies work with constructors (for example, when objects are taken
|
||||
from an external container rather than created on demand), data members and
|
||||
functions in general (as long as their return types are lvalue references).
|
||||
|
||||
As an example of use:
|
||||
|
||||
@@ -273,12 +273,12 @@ struct fixed_sequence_container {
|
||||
template<typename Type, typename... Args>
|
||||
struct meta_sequence_container_traits<std::vector<Type, Args...>>
|
||||
: container_traits<
|
||||
std::vector<Type, Args...>,
|
||||
basic_container,
|
||||
basic_dynamic_container,
|
||||
basic_sequence_container,
|
||||
dynamic_sequence_container
|
||||
>
|
||||
std::vector<Type, Args...>,
|
||||
basic_container,
|
||||
basic_dynamic_container,
|
||||
basic_sequence_container,
|
||||
dynamic_sequence_container
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
@@ -290,11 +290,11 @@ struct meta_sequence_container_traits<std::vector<Type, Args...>>
|
||||
template<typename Type, auto N>
|
||||
struct meta_sequence_container_traits<std::array<Type, N>>
|
||||
: container_traits<
|
||||
std::array<Type, N>,
|
||||
basic_container,
|
||||
basic_sequence_container,
|
||||
fixed_sequence_container
|
||||
>
|
||||
std::array<Type, N>,
|
||||
basic_container,
|
||||
basic_sequence_container,
|
||||
fixed_sequence_container
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
@@ -307,13 +307,13 @@ struct meta_sequence_container_traits<std::array<Type, N>>
|
||||
template<typename Key, typename Value, typename... Args>
|
||||
struct meta_associative_container_traits<std::map<Key, Value, Args...>>
|
||||
: container_traits<
|
||||
std::map<Key, Value, Args...>,
|
||||
basic_container,
|
||||
basic_associative_container,
|
||||
basic_dynamic_container,
|
||||
basic_dynamic_associative_container,
|
||||
dynamic_associative_key_value_container
|
||||
>
|
||||
std::map<Key, Value, Args...>,
|
||||
basic_container,
|
||||
basic_associative_container,
|
||||
basic_dynamic_container,
|
||||
basic_dynamic_associative_container,
|
||||
dynamic_associative_key_value_container
|
||||
>
|
||||
{
|
||||
/*! @brief Mapped type of the sequence container. */
|
||||
using mapped_type = typename std::map<Key, Value, Args...>::mapped_type;
|
||||
@@ -330,13 +330,13 @@ struct meta_associative_container_traits<std::map<Key, Value, Args...>>
|
||||
template<typename Key, typename Value, typename... Args>
|
||||
struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>>
|
||||
: container_traits<
|
||||
std::unordered_map<Key, Value, Args...>,
|
||||
basic_container,
|
||||
basic_associative_container,
|
||||
basic_dynamic_container,
|
||||
basic_dynamic_associative_container,
|
||||
dynamic_associative_key_value_container
|
||||
>
|
||||
std::unordered_map<Key, Value, Args...>,
|
||||
basic_container,
|
||||
basic_associative_container,
|
||||
basic_dynamic_container,
|
||||
basic_dynamic_associative_container,
|
||||
dynamic_associative_key_value_container
|
||||
>
|
||||
{
|
||||
/*! @brief Mapped type of the sequence container. */
|
||||
using mapped_type = typename std::unordered_map<Key, Value, Args...>::mapped_type;
|
||||
@@ -351,13 +351,13 @@ struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>
|
||||
template<typename Key, typename... Args>
|
||||
struct meta_associative_container_traits<std::set<Key, Args...>>
|
||||
: container_traits<
|
||||
std::set<Key, Args...>,
|
||||
basic_container,
|
||||
basic_associative_container,
|
||||
basic_dynamic_container,
|
||||
basic_dynamic_associative_container,
|
||||
dynamic_associative_key_only_container
|
||||
>
|
||||
std::set<Key, Args...>,
|
||||
basic_container,
|
||||
basic_associative_container,
|
||||
basic_dynamic_container,
|
||||
basic_dynamic_associative_container,
|
||||
dynamic_associative_key_only_container
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
@@ -370,13 +370,13 @@ struct meta_associative_container_traits<std::set<Key, Args...>>
|
||||
template<typename Key, typename... Args>
|
||||
struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
|
||||
: container_traits<
|
||||
std::unordered_set<Key, Args...>,
|
||||
basic_container,
|
||||
basic_associative_container,
|
||||
basic_dynamic_container,
|
||||
basic_dynamic_associative_container,
|
||||
dynamic_associative_key_only_container
|
||||
>
|
||||
std::unordered_set<Key, Args...>,
|
||||
basic_container,
|
||||
basic_associative_container,
|
||||
basic_dynamic_container,
|
||||
basic_dynamic_associative_container,
|
||||
dynamic_associative_key_only_container
|
||||
>
|
||||
{};
|
||||
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ struct meta_function_helper;
|
||||
|
||||
template<typename Ret, typename... Args, bool Const, bool Static>
|
||||
struct meta_function_helper<Ret(Args...), Const, Static> {
|
||||
using return_type = std::remove_cv_t<std::remove_reference_t<Ret>>;
|
||||
using args_type = std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>;
|
||||
using return_type = Ret;
|
||||
using args_type = type_list<Args...>;
|
||||
|
||||
static constexpr auto is_static = Static;
|
||||
static constexpr auto is_const = Const;
|
||||
@@ -48,12 +48,12 @@ struct meta_function_helper<Ret(Args...), Const, Static> {
|
||||
|
||||
|
||||
template<typename Type, typename Ret, typename... Args, typename Class>
|
||||
constexpr meta_function_helper<std::conditional_t<std::is_same_v<Type, Class>, Ret(Args...), Ret(std::add_lvalue_reference_t<Class>, Args...)>, true, !std::is_same_v<Type, Class>>
|
||||
constexpr meta_function_helper<std::conditional_t<std::is_same_v<Type, Class>, Ret(Args...), Ret(Class &, Args...)>, true, !std::is_same_v<Type, Class>>
|
||||
to_meta_function_helper(Ret(Class:: *)(Args...) const);
|
||||
|
||||
|
||||
template<typename Type, typename Ret, typename... Args, typename Class>
|
||||
constexpr meta_function_helper<std::conditional_t<std::is_same_v<Type, Class>, Ret(Args...), Ret(std::add_lvalue_reference_t<Class>, Args...)>, false, !std::is_same_v<Type, Class>>
|
||||
constexpr meta_function_helper<std::conditional_t<std::is_same_v<Type, Class>, Ret(Args...), Ret(Class &, Args...)>, false, !std::is_same_v<Type, Class>>
|
||||
to_meta_function_helper(Ret(Class:: *)(Args...));
|
||||
|
||||
|
||||
@@ -70,12 +70,13 @@ template<typename Type, typename Candidate>
|
||||
using meta_function_helper_t = decltype(to_meta_function_helper<Type>(std::declval<Candidate>()));
|
||||
|
||||
|
||||
template<typename Type, typename... Args, std::size_t... Indexes>
|
||||
[[nodiscard]] meta_any construct(meta_any * const args, std::index_sequence<Indexes...>) {
|
||||
[[maybe_unused]] auto direct = std::make_tuple((args+Indexes)->try_cast<Args>()...);
|
||||
return ((std::get<Indexes>(direct) || (args+Indexes)->convert<Args>()) && ...)
|
||||
? Type{(std::get<Indexes>(direct) ? *std::get<Indexes>(direct) : (args+Indexes)->cast<Args>())...}
|
||||
: meta_any{};
|
||||
template<typename Type, typename... Args, std::size_t... Index>
|
||||
[[nodiscard]] meta_any construct(meta_any * const args, std::index_sequence<Index...>) {
|
||||
if(((args+Index)->allow_cast<Args>() && ...)) {
|
||||
return Type{(args+Index)->cast<Args>()...};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -85,11 +86,11 @@ template<typename Type, auto Data>
|
||||
|
||||
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
|
||||
using helper_type = meta_function_helper_t<Type, decltype(Data)>;
|
||||
using data_type = std::tuple_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename helper_type::args_type>;
|
||||
using data_type = type_list_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename helper_type::args_type>;
|
||||
|
||||
if(auto * const clazz = instance->try_cast<Type>(); clazz) {
|
||||
if(auto * const direct = value.try_cast<data_type>(); direct || value.convert<data_type>()) {
|
||||
std::invoke(Data, *clazz, direct ? *direct : value.cast<data_type>());
|
||||
if(value.allow_cast<data_type>()) {
|
||||
std::invoke(Data, *clazz, value.cast<data_type>());
|
||||
accepted = true;
|
||||
}
|
||||
}
|
||||
@@ -98,8 +99,8 @@ template<typename Type, auto Data>
|
||||
|
||||
if constexpr(!std::is_array_v<data_type>) {
|
||||
if(auto * const clazz = instance->try_cast<Type>(); clazz) {
|
||||
if(auto * const direct = value.try_cast<data_type>(); direct || value.convert<data_type>()) {
|
||||
std::invoke(Data, clazz) = (direct ? *direct : value.cast<data_type>());
|
||||
if(value.allow_cast<data_type>()) {
|
||||
std::invoke(Data, clazz) = value.cast<data_type>();
|
||||
accepted = true;
|
||||
}
|
||||
}
|
||||
@@ -108,8 +109,8 @@ template<typename Type, auto Data>
|
||||
using data_type = std::remove_cv_t<std::remove_reference_t<decltype(*Data)>>;
|
||||
|
||||
if constexpr(!std::is_array_v<data_type>) {
|
||||
if(auto * const direct = value.try_cast<data_type>(); direct || value.convert<data_type>()) {
|
||||
*Data = (direct ? *direct : value.cast<data_type>());
|
||||
if(value.allow_cast<data_type>()) {
|
||||
*Data = value.cast<data_type>();
|
||||
accepted = true;
|
||||
}
|
||||
}
|
||||
@@ -126,6 +127,8 @@ template<typename Type, auto Data, typename Policy>
|
||||
return meta_any{std::in_place_type<void>, std::forward<decltype(value)>(value)};
|
||||
} else if constexpr(std::is_same_v<Policy, as_ref_t>) {
|
||||
return meta_any{std::ref(std::forward<decltype(value)>(value))};
|
||||
} else if constexpr(std::is_same_v<Policy, as_cref_t>) {
|
||||
return meta_any{std::cref(std::forward<decltype(value)>(value))};
|
||||
} else {
|
||||
static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
|
||||
return meta_any{std::forward<decltype(value)>(value)};
|
||||
@@ -133,13 +136,13 @@ template<typename Type, auto Data, typename Policy>
|
||||
};
|
||||
|
||||
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
|
||||
auto * const clazz = instance->try_cast<Type>();
|
||||
auto * const clazz = instance->try_cast<std::conditional_t<std::is_invocable_v<decltype(Data), const Type *>, const Type, Type>>();
|
||||
return clazz ? dispatch(std::invoke(Data, *clazz)) : 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)>>>) {
|
||||
return meta_any{};
|
||||
} else {
|
||||
auto * const clazz = instance->try_cast<Type>();
|
||||
auto * const clazz = instance->try_cast<std::conditional_t<std::is_same_v<Policy, as_ref_t>, Type, const Type>>();
|
||||
return clazz ? dispatch(std::invoke(Data, clazz)) : meta_any{};
|
||||
}
|
||||
} else if constexpr(std::is_pointer_v<std::decay_t<decltype(Data)>>) {
|
||||
@@ -154,38 +157,39 @@ template<typename Type, auto Data, typename Policy>
|
||||
}
|
||||
|
||||
|
||||
template<typename Type, auto Candidate, typename Policy, std::size_t... Indexes>
|
||||
[[nodiscard]] meta_any invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence<Indexes...>) {
|
||||
template<typename Type, auto Candidate, typename Policy, std::size_t... Index>
|
||||
[[nodiscard]] meta_any invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence<Index...>) {
|
||||
using helper_type = meta_function_helper_t<Type, decltype(Candidate)>;
|
||||
|
||||
auto dispatch = [](auto *... params) {
|
||||
if constexpr(std::is_void_v<typename helper_type::return_type> || std::is_same_v<Policy, as_void_t>) {
|
||||
std::invoke(Candidate, *params...);
|
||||
auto dispatch = [](auto &&... params) {
|
||||
if constexpr(std::is_void_v<std::remove_cv_t<typename helper_type::return_type>> || std::is_same_v<Policy, as_void_t>) {
|
||||
std::invoke(Candidate, std::forward<decltype(params)>(params)...);
|
||||
return meta_any{std::in_place_type<void>};
|
||||
} else if constexpr(std::is_same_v<Policy, as_ref_t>) {
|
||||
return meta_any{std::ref(std::invoke(Candidate, *params...))};
|
||||
return meta_any{std::ref(std::invoke(Candidate, std::forward<decltype(params)>(params)...))};
|
||||
} else if constexpr(std::is_same_v<Policy, as_cref_t>) {
|
||||
return meta_any{std::cref(std::invoke(Candidate, std::forward<decltype(params)>(params)...))};
|
||||
} else {
|
||||
static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
|
||||
return meta_any{std::invoke(Candidate, *params...)};
|
||||
return meta_any{std::invoke(Candidate, std::forward<decltype(params)>(params)...)};
|
||||
}
|
||||
};
|
||||
|
||||
[[maybe_unused]] const auto direct = std::make_tuple([](meta_any *any, auto *value) {
|
||||
using arg_type = std::remove_reference_t<decltype(*value)>;
|
||||
|
||||
if(!value && any->convert<arg_type>()) {
|
||||
value = any->try_cast<arg_type>();
|
||||
if constexpr(std::is_invocable_v<decltype(Candidate), const Type &, type_list_element_t<Index, typename helper_type::args_type>...>) {
|
||||
if(const auto * const clazz = instance->try_cast<const Type>(); clazz && ((args+Index)->allow_cast<type_list_element_t<Index, typename helper_type::args_type>>() && ...)) {
|
||||
return dispatch(*clazz, (args+Index)->cast<type_list_element_t<Index, typename helper_type::args_type>>()...);
|
||||
}
|
||||
} else if constexpr(std::is_invocable_v<decltype(Candidate), Type &, type_list_element_t<Index, typename helper_type::args_type>...>) {
|
||||
if(auto * const clazz = instance->try_cast<Type>(); clazz && ((args+Index)->allow_cast<type_list_element_t<Index, typename helper_type::args_type>>() && ...)) {
|
||||
return dispatch(*clazz, (args+Index)->cast<type_list_element_t<Index, typename helper_type::args_type>>()...);
|
||||
}
|
||||
|
||||
return value;
|
||||
}(args+Indexes, (args+Indexes)->try_cast<std::tuple_element_t<Indexes, typename helper_type::args_type>>())...);
|
||||
|
||||
if constexpr(std::is_invocable_v<decltype(Candidate), std::add_lvalue_reference_t<Type>, std::tuple_element_t<Indexes, typename helper_type::args_type>...>) {
|
||||
auto * const clazz = instance->try_cast<Type>();
|
||||
return (clazz && (std::get<Indexes>(direct) && ...)) ? dispatch(clazz, std::get<Indexes>(direct)...) : meta_any{};
|
||||
} else {
|
||||
return (std::get<Indexes>(direct) && ...) ? dispatch(std::get<Indexes>(direct)...) : meta_any{};
|
||||
if(((args+Index)->allow_cast<type_list_element_t<Index, typename helper_type::args_type>>() && ...)) {
|
||||
return dispatch((args+Index)->cast<type_list_element_t<Index, typename helper_type::args_type>>()...);
|
||||
}
|
||||
}
|
||||
|
||||
return meta_any{};
|
||||
}
|
||||
|
||||
|
||||
@@ -469,17 +473,17 @@ public:
|
||||
template<auto Candidate, typename Policy = as_is_t>
|
||||
auto ctor() ENTT_NOEXCEPT {
|
||||
using helper_type = internal::meta_function_helper_t<Type, decltype(Candidate)>;
|
||||
static_assert(std::is_same_v<typename helper_type::return_type, Type>, "The function doesn't return an object of the required type");
|
||||
static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<typename helper_type::return_type>>, Type>, "The function doesn't return an object of the required type");
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
|
||||
static internal::meta_ctor_node node{
|
||||
type,
|
||||
nullptr,
|
||||
nullptr,
|
||||
std::tuple_size_v<typename helper_type::args_type>,
|
||||
helper_type::args_type::size,
|
||||
&helper_type::arg,
|
||||
[](meta_any * const any) {
|
||||
return internal::invoke<Type, Candidate, Policy>({}, any, std::make_index_sequence<std::tuple_size_v<typename helper_type::args_type>>{});
|
||||
return internal::invoke<Type, Candidate, Policy>({}, any, std::make_index_sequence<helper_type::args_type::size>{});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -509,10 +513,10 @@ public:
|
||||
type,
|
||||
nullptr,
|
||||
nullptr,
|
||||
std::tuple_size_v<typename helper_type::args_type>,
|
||||
helper_type::args_type::size,
|
||||
&helper_type::arg,
|
||||
[](meta_any * const any) {
|
||||
return internal::construct<Type, std::remove_cv_t<std::remove_reference_t<Args>>...>(any, std::make_index_sequence<std::tuple_size_v<typename helper_type::args_type>>{});
|
||||
return internal::construct<Type, Args...>(any, std::make_index_sequence<helper_type::args_type::size>{});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -583,7 +587,7 @@ public:
|
||||
nullptr,
|
||||
true,
|
||||
&internal::meta_info<data_type>::resolve,
|
||||
[]() -> std::remove_const_t<decltype(internal::meta_data_node::set)> {
|
||||
[]() -> std::remove_cv_t<decltype(internal::meta_data_node::set)> {
|
||||
if constexpr(std::is_same_v<Type, data_type> || std::is_const_v<data_type>) {
|
||||
return nullptr;
|
||||
} else {
|
||||
@@ -635,7 +639,7 @@ public:
|
||||
nullptr,
|
||||
false,
|
||||
&internal::meta_info<underlying_type>::resolve,
|
||||
[]() -> std::remove_const_t<decltype(internal::meta_data_node::set)> {
|
||||
[]() -> std::remove_cv_t<decltype(internal::meta_data_node::set)> {
|
||||
if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t> || (std::is_member_object_pointer_v<decltype(Setter)> && std::is_const_v<underlying_type>)) {
|
||||
return nullptr;
|
||||
} else {
|
||||
@@ -677,13 +681,13 @@ public:
|
||||
type,
|
||||
nullptr,
|
||||
nullptr,
|
||||
std::tuple_size_v<typename helper_type::args_type>,
|
||||
helper_type::args_type::size,
|
||||
helper_type::is_const,
|
||||
helper_type::is_static,
|
||||
&internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, typename helper_type::return_type>>::resolve,
|
||||
&helper_type::arg,
|
||||
[](meta_handle instance, meta_any *args) {
|
||||
return internal::invoke<Type, Candidate, Policy>(std::move(instance), args, std::make_index_sequence<std::tuple_size_v<typename helper_type::args_type>>{});
|
||||
return internal::invoke<Type, Candidate, Policy>(std::move(instance), args, std::make_index_sequence<helper_type::args_type::size>{});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ public:
|
||||
[[nodiscard]] const Type * try_cast() const {
|
||||
if(node) {
|
||||
if(const auto info = internal::meta_info<Type>::resolve()->info; node->info == info) {
|
||||
return static_cast<const Type *>(storage.data());
|
||||
return any_cast<Type>(&storage);
|
||||
} else if(const auto *base = internal::find_if<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
|
||||
return static_cast<const Type *>(base->cast(storage.data()));
|
||||
}
|
||||
@@ -344,12 +344,12 @@ public:
|
||||
[[nodiscard]] Type * try_cast() {
|
||||
if(node) {
|
||||
if(const auto info = internal::meta_info<Type>::resolve()->info; node->info == info) {
|
||||
return static_cast<Type *>(storage.data());
|
||||
return any_cast<Type>(&storage);
|
||||
} else if(const auto *base = internal::find_if<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
|
||||
return static_cast<Type *>(const_cast<void *>(base->cast(storage.data())));
|
||||
return static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(base->cast(static_cast<constness_as_t<any, Type> &>(storage).data())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ public:
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] Type cast() const {
|
||||
auto * const actual = try_cast<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
auto * const actual = try_cast<std::remove_reference_t<Type>>();
|
||||
ENTT_ASSERT(actual);
|
||||
return static_cast<Type>(*actual);
|
||||
}
|
||||
@@ -375,30 +375,26 @@ public:
|
||||
/*! @copydoc cast */
|
||||
template<typename Type>
|
||||
[[nodiscard]] Type cast() {
|
||||
if constexpr(!std::is_reference_v<Type> || std::is_const_v<std::remove_reference_t<Type>>) {
|
||||
// last attempt to make wrappers for const references return their values
|
||||
auto * const actual = std::as_const(*this).try_cast<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
ENTT_ASSERT(actual);
|
||||
return static_cast<Type>(*actual);
|
||||
} else {
|
||||
auto * const actual = try_cast<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
ENTT_ASSERT(actual);
|
||||
return static_cast<Type>(*actual);
|
||||
}
|
||||
// forces const on non-reference types to make them work also with wrappers for const references
|
||||
auto * const actual = try_cast<std::conditional_t<std::is_reference_v<Type>, std::remove_reference_t<Type>, const Type>>();
|
||||
ENTT_ASSERT(actual);
|
||||
return static_cast<Type>(*actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to convert an instance to a given type and returns it.
|
||||
* @tparam Type Type to which to convert the instance.
|
||||
* @return A valid meta any object if the conversion is possible, an invalid
|
||||
* one otherwise.
|
||||
* @brief Tries to make an instance castable to a certain type.
|
||||
* @tparam Type Type to which the cast is requested.
|
||||
* @return A valid meta any object if there exists a a viable conversion
|
||||
* that makes the cast possible, an invalid object otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] meta_any convert() const {
|
||||
if(node) {
|
||||
if(const auto info = internal::meta_info<Type>::resolve()->info; node->info == info) {
|
||||
return *this;
|
||||
} else if(const auto * const conv = internal::find_if<&internal::meta_type_node::conv>([info](const auto *curr) { return curr->type()->info == info; }, node); conv) {
|
||||
[[nodiscard]] meta_any allow_cast() const {
|
||||
if(try_cast<std::remove_reference_t<Type>>() != nullptr) {
|
||||
return as_ref(*this);
|
||||
} else if(node) {
|
||||
if(const auto * const conv = internal::find_if<&internal::meta_type_node::conv>([info = internal::meta_info<Type>::resolve()->info](const auto *curr) {
|
||||
return curr->type()->info == info;
|
||||
}, node); conv) {
|
||||
return conv->conv(storage.data());
|
||||
}
|
||||
}
|
||||
@@ -407,22 +403,25 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to convert an instance to a given type.
|
||||
* @tparam Type Type to which to convert the instance.
|
||||
* @return True if the conversion is possible, false otherwise.
|
||||
* @brief Tries to make an instance castable to a certain type.
|
||||
* @tparam Type Type to which the cast is requested.
|
||||
* @return True if there exists a a viable conversion that makes the cast
|
||||
* possible, false otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
bool convert() {
|
||||
bool valid = (node && node->info == internal::meta_info<Type>::resolve()->info);
|
||||
|
||||
if(!valid) {
|
||||
if(auto any = std::as_const(*this).convert<Type>(); any) {
|
||||
swap(any, *this);
|
||||
valid = true;
|
||||
bool allow_cast() {
|
||||
if(try_cast<std::conditional_t<std::is_reference_v<Type>, std::remove_reference_t<Type>, const Type>>() != nullptr) {
|
||||
return true;
|
||||
} else if(node) {
|
||||
if(const auto * const conv = internal::find_if<&internal::meta_type_node::conv>([info = internal::meta_info<Type>::resolve()->info](const auto *curr) {
|
||||
return curr->type()->info == info;
|
||||
}, node); conv) {
|
||||
swap(conv->conv(std::as_const(storage).data()), *this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -570,6 +569,11 @@ struct meta_handle {
|
||||
return &any;
|
||||
}
|
||||
|
||||
/*! @brief operator-> */
|
||||
[[nodiscard]] const meta_any * operator->() const {
|
||||
return &any;
|
||||
}
|
||||
|
||||
private:
|
||||
meta_any any;
|
||||
};
|
||||
@@ -1767,8 +1771,8 @@ struct meta_sequence_container::meta_sequence_container_proxy {
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::pair<iterator, bool> insert(void *container, iterator it, meta_any value) {
|
||||
if(const auto *v_ptr = value.try_cast<typename traits_type::value_type>(); v_ptr || value.convert<typename traits_type::value_type>()) {
|
||||
auto ret = traits_type::insert(*static_cast<Type *>(container), it.handle.cast<const typename traits_type::iterator &>(), v_ptr ? *v_ptr : value.cast<const typename traits_type::value_type &>());
|
||||
if(value.allow_cast<const typename traits_type::value_type &>()) {
|
||||
auto ret = traits_type::insert(*static_cast<Type *>(container), it.handle.cast<const typename traits_type::iterator &>(), value.cast<const typename traits_type::value_type &>());
|
||||
return { iterator{std::move(ret.first)}, ret.second };
|
||||
}
|
||||
|
||||
@@ -2034,12 +2038,12 @@ struct meta_associative_container::meta_associative_container_proxy {
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool insert(void *container, meta_any key, meta_any value) {
|
||||
if(const auto *k_ptr = key.try_cast<typename traits_type::key_type>(); k_ptr || key.convert<typename traits_type::key_type>()) {
|
||||
if(key.allow_cast<const typename traits_type::key_type &>()) {
|
||||
if constexpr(is_key_only_meta_associative_container_v<Type>) {
|
||||
return traits_type::insert(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<const typename traits_type::key_type &>());
|
||||
return traits_type::insert(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>());
|
||||
} else {
|
||||
if(const auto *m_ptr = value.try_cast<typename traits_type::mapped_type>(); m_ptr || value.convert<typename traits_type::mapped_type>()) {
|
||||
return traits_type::insert(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<const typename traits_type::key_type &>(), m_ptr ? *m_ptr : value.cast<const typename traits_type::mapped_type &>());
|
||||
if(value.allow_cast<const typename traits_type::mapped_type &>()) {
|
||||
return traits_type::insert(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>(), value.cast<const typename traits_type::mapped_type &>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2048,16 +2052,16 @@ struct meta_associative_container::meta_associative_container_proxy {
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool erase(void *container, meta_any key) {
|
||||
if(const auto *k_ptr = key.try_cast<typename traits_type::key_type>(); k_ptr || key.convert<typename traits_type::key_type>()) {
|
||||
return traits_type::erase(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<const typename traits_type::key_type &>());
|
||||
if(key.allow_cast<const typename traits_type::key_type &>()) {
|
||||
return traits_type::erase(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator find(void *container, meta_any key) {
|
||||
if(const auto *k_ptr = key.try_cast<typename traits_type::key_type>(); k_ptr || key.convert<typename traits_type::key_type>()) {
|
||||
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::find(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<const typename traits_type::key_type &>())};
|
||||
if(key.allow_cast<const typename traits_type::key_type &>()) {
|
||||
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::find(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>())};
|
||||
}
|
||||
|
||||
return {};
|
||||
|
||||
@@ -9,6 +9,10 @@ namespace entt {
|
||||
struct as_ref_t {};
|
||||
|
||||
|
||||
/*! @brief Empty class type used to request the _as cref_ policy. */
|
||||
struct as_cref_t {};
|
||||
|
||||
|
||||
/*! @brief Empty class type used to request the _as-is_ policy. */
|
||||
struct as_is_t {};
|
||||
|
||||
|
||||
@@ -596,11 +596,11 @@ TEST_F(MetaAny, Convert) {
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<double>());
|
||||
ASSERT_TRUE(any.convert<double>());
|
||||
ASSERT_FALSE(any.convert<char>());
|
||||
ASSERT_TRUE(any.allow_cast<double>());
|
||||
ASSERT_FALSE(any.allow_cast<char>());
|
||||
ASSERT_EQ(any.type(), entt::resolve<double>());
|
||||
ASSERT_EQ(any.cast<double>(), 42.);
|
||||
ASSERT_TRUE(any.convert<int>());
|
||||
ASSERT_TRUE(any.allow_cast<int>());
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 42);
|
||||
}
|
||||
@@ -610,12 +610,12 @@ TEST_F(MetaAny, ConstConvert) {
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<double>());
|
||||
ASSERT_TRUE(any.convert<double>());
|
||||
ASSERT_FALSE(any.convert<char>());
|
||||
ASSERT_TRUE(any.allow_cast<double>());
|
||||
ASSERT_FALSE(any.allow_cast<char>());
|
||||
ASSERT_EQ(any.type(), entt::resolve<double>());
|
||||
ASSERT_EQ(any.cast<double>(), 42.);
|
||||
|
||||
auto other = any.convert<int>();
|
||||
auto other = any.allow_cast<int>();
|
||||
|
||||
ASSERT_EQ(any.type(), entt::resolve<double>());
|
||||
ASSERT_EQ(any.cast<double>(), 42.);
|
||||
@@ -638,11 +638,11 @@ TEST_F(MetaAny, UnmanageableType) {
|
||||
ASSERT_EQ(any.try_cast<int>(), nullptr);
|
||||
ASSERT_NE(any.try_cast<unmanageable_t>(), nullptr);
|
||||
|
||||
ASSERT_TRUE(any.convert<unmanageable_t>());
|
||||
ASSERT_FALSE(any.convert<int>());
|
||||
ASSERT_TRUE(any.allow_cast<unmanageable_t>());
|
||||
ASSERT_FALSE(any.allow_cast<int>());
|
||||
|
||||
ASSERT_TRUE(std::as_const(any).convert<unmanageable_t>());
|
||||
ASSERT_FALSE(std::as_const(any).convert<int>());
|
||||
ASSERT_TRUE(std::as_const(any).allow_cast<unmanageable_t>());
|
||||
ASSERT_FALSE(std::as_const(any).allow_cast<int>());
|
||||
}
|
||||
|
||||
TEST_F(MetaAny, Invoke) {
|
||||
|
||||
@@ -583,8 +583,8 @@ TEST_F(MetaType, ResetAndReRegistrationAfterReset) {
|
||||
entt::meta_any any{42.};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(any.convert<int>());
|
||||
ASSERT_TRUE(any.convert<float>());
|
||||
ASSERT_FALSE(any.allow_cast<int>());
|
||||
ASSERT_TRUE(any.allow_cast<float>());
|
||||
|
||||
ASSERT_FALSE(entt::resolve("derived"_hs));
|
||||
ASSERT_TRUE(entt::resolve("double"_hs));
|
||||
|
||||
@@ -35,7 +35,7 @@ TEST(Lib, Meta) {
|
||||
ASSERT_EQ(pos.type().data("y"_hs).get(pos).cast<int>(), 3);
|
||||
|
||||
ASSERT_EQ(vel.type().data("dx"_hs).type(), entt::resolve<double>());
|
||||
ASSERT_TRUE(vel.type().data("dy"_hs).get(vel).convert<double>());
|
||||
ASSERT_TRUE(vel.type().data("dy"_hs).get(vel).allow_cast<double>());
|
||||
ASSERT_EQ(vel.type().data("dx"_hs).get(vel).cast<double>(), 0.);
|
||||
ASSERT_EQ(vel.type().data("dy"_hs).get(vel).cast<double>(), 0.);
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ TEST(Lib, Meta) {
|
||||
ASSERT_EQ(pos.type().data("y"_hs).get(pos).cast<int>(), 3);
|
||||
|
||||
ASSERT_EQ(vel.type().data("dx"_hs).type(), entt::resolve<double>());
|
||||
ASSERT_TRUE(vel.type().data("dy"_hs).get(vel).convert<double>());
|
||||
ASSERT_TRUE(vel.type().data("dy"_hs).get(vel).allow_cast<double>());
|
||||
ASSERT_EQ(vel.type().data("dx"_hs).get(vel).cast<double>(), 0.);
|
||||
ASSERT_EQ(vel.type().data("dy"_hs).get(vel).cast<double>(), 0.);
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ TEST(Lib, Meta) {
|
||||
ASSERT_EQ(pos.type().data("y"_hs).get(pos).cast<int>(), 3);
|
||||
|
||||
ASSERT_EQ(vel.type().data("dx"_hs).type(), entt::resolve<double>());
|
||||
ASSERT_TRUE(vel.type().data("dy"_hs).get(vel).convert<double>());
|
||||
ASSERT_TRUE(vel.type().data("dy"_hs).get(vel).allow_cast<double>());
|
||||
ASSERT_EQ(vel.type().data("dx"_hs).get(vel).cast<double>(), 0.);
|
||||
ASSERT_EQ(vel.type().data("dy"_hs).get(vel).cast<double>(), 0.);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user