* meta_any: convert -> allow_cast
* support for const references
* as_cref_t policy
This commit is contained in:
Michele Caini
2020-12-16 15:29:28 +01:00
parent 3dac65a012
commit c52f16f5b8
11 changed files with 178 additions and 160 deletions

6
TODO
View File

@@ -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

View File

@@ -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:

View File

@@ -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
>
{};

View File

@@ -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>{});
}
};

View File

@@ -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 {};

View File

@@ -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 {};

View File

@@ -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) {

View File

@@ -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));

View File

@@ -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.);

View File

@@ -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.);

View File

@@ -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.);