meta system:
* perf improvements * meta_any::try_cast * meta_any is void-friendly * meta_any support for unmanaged objects * general cleanup
This commit is contained in:
2
TODO
2
TODO
@@ -21,7 +21,7 @@
|
||||
* multi component registry::remove and some others?
|
||||
* can I use opaque connection also for the emitter?
|
||||
* built-in support for dual (or N-) buffering
|
||||
* meta: opaque references and pointers
|
||||
|
||||
TODO
|
||||
* custom (decoupled) pools ==> double buffering, shared components, multi-model
|
||||
* use direct access (pool-like) also for context variables
|
||||
|
||||
@@ -195,13 +195,21 @@ entt::meta_any any{0};
|
||||
entt::meta_any empty{};
|
||||
```
|
||||
|
||||
It can be constructed or assigned by copy and move and it takes the burden of
|
||||
destroying the contained object when required.<br/>
|
||||
It takes the burden of destroying the contained instance when required.<br/>
|
||||
Moreover, it can be used as an opaque container for unmanaged objects if needed:
|
||||
|
||||
```cpp
|
||||
int value;
|
||||
entt::meta_any any{std::in_place, value};
|
||||
```
|
||||
|
||||
In this case, the contained instance is never destroyed and users must ensure
|
||||
that the lifetime of the object exceeds that of the container.
|
||||
|
||||
A meta any object has a `type` member function that returns the meta type of the
|
||||
contained value, if any. The member functions `can_cast` and `can_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. Similarly, `cast` and `convert` do what they promise
|
||||
and return the expected value.
|
||||
contained value, if any. 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.
|
||||
|
||||
## Enjoy the runtime
|
||||
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
#define ENTT_META_FACTORY_HPP
|
||||
|
||||
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "meta.hpp"
|
||||
@@ -12,16 +15,220 @@
|
||||
namespace entt {
|
||||
|
||||
|
||||
template<typename>
|
||||
class meta_factory;
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
template<typename Type, typename... Property>
|
||||
meta_factory<Type> reflect(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT;
|
||||
namespace internal {
|
||||
|
||||
|
||||
template<typename Type>
|
||||
bool unregister() ENTT_NOEXCEPT;
|
||||
template<typename...>
|
||||
struct meta_function_helper;
|
||||
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
struct meta_function_helper<Ret(Args...)> {
|
||||
using return_type = Ret;
|
||||
using args_type = std::tuple<Args...>;
|
||||
|
||||
template<std::size_t Index>
|
||||
using arg_type = std::decay_t<std::tuple_element_t<Index, args_type>>;
|
||||
|
||||
static constexpr auto size = sizeof...(Args);
|
||||
|
||||
static auto arg(typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT {
|
||||
return std::array<meta_type_node *, sizeof...(Args)>{{meta_info<Args>::resolve()...}}[index];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Class, typename Ret, typename... Args, bool Const, bool Static>
|
||||
struct meta_function_helper<Class, Ret(Args...), std::bool_constant<Const>, std::bool_constant<Static>>: meta_function_helper<Ret(Args...)> {
|
||||
using class_type = Class;
|
||||
static constexpr auto is_const = Const;
|
||||
static constexpr auto is_static = Static;
|
||||
};
|
||||
|
||||
|
||||
template<typename Ret, typename... Args, typename Class>
|
||||
constexpr meta_function_helper<Class, Ret(Args...), std::bool_constant<false>, std::bool_constant<false>>
|
||||
to_meta_function_helper(Ret(Class:: *)(Args...));
|
||||
|
||||
|
||||
template<typename Ret, typename... Args, typename Class>
|
||||
constexpr meta_function_helper<Class, Ret(Args...), std::bool_constant<true>, std::bool_constant<false>>
|
||||
to_meta_function_helper(Ret(Class:: *)(Args...) const);
|
||||
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
constexpr meta_function_helper<void, Ret(Args...), std::bool_constant<false>, std::bool_constant<true>>
|
||||
to_meta_function_helper(Ret(*)(Args...));
|
||||
|
||||
|
||||
template<auto Func>
|
||||
struct meta_function_helper<std::integral_constant<decltype(Func), Func>>: decltype(to_meta_function_helper(Func)) {};
|
||||
|
||||
|
||||
template<typename Type, typename... Args, std::size_t... Indexes>
|
||||
meta_any construct(meta_any * const args, std::index_sequence<Indexes...>) {
|
||||
[[maybe_unused]] auto direct = std::make_tuple((args+Indexes)->try_cast<std::remove_cv_t<std::remove_reference_t<Args>>>()...);
|
||||
meta_any any{};
|
||||
|
||||
if(((std::get<Indexes>(direct) || (args+Indexes)->convert<std::remove_cv_t<std::remove_reference_t<Args>>>()) && ...)) {
|
||||
any = Type{(std::get<Indexes>(direct) ? *std::get<Indexes>(direct) : (args+Indexes)->cast<std::remove_cv_t<std::remove_reference_t<Args>>>())...};
|
||||
}
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
template<bool Const, typename Type, auto Data>
|
||||
bool setter([[maybe_unused]] meta_handle handle, [[maybe_unused]] meta_any index, [[maybe_unused]] meta_any value) {
|
||||
bool accepted = false;
|
||||
|
||||
if constexpr(!Const) {
|
||||
if constexpr(std::is_function_v<std::remove_pointer_t<decltype(Data)>> || std::is_member_function_pointer_v<decltype(Data)>) {
|
||||
using helper_type = meta_function_helper<std::integral_constant<decltype(Data), Data>>;
|
||||
using data_type = std::decay_t<std::tuple_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename helper_type::args_type>>;
|
||||
static_assert(std::is_invocable_v<decltype(Data), Type &, data_type>);
|
||||
auto *direct = value.try_cast<data_type>();
|
||||
auto *clazz = handle.data<Type>();
|
||||
|
||||
if(clazz && (direct || value.convert<data_type>())) {
|
||||
std::invoke(Data, *clazz, direct ? *direct : value.cast<data_type>());
|
||||
accepted = true;
|
||||
}
|
||||
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
using data_type = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>;
|
||||
static_assert(std::is_invocable_v<decltype(Data), Type>);
|
||||
auto *clazz = handle.data<Type>();
|
||||
|
||||
if constexpr(std::is_array_v<data_type>) {
|
||||
using underlying_type = std::remove_extent_t<data_type>;
|
||||
auto *direct = value.try_cast<underlying_type>();
|
||||
auto *idx = index.try_cast<std::size_t>();
|
||||
|
||||
if(clazz && idx && (direct || value.convert<underlying_type>())) {
|
||||
std::invoke(Data, clazz)[*idx] = direct ? *direct : value.cast<underlying_type>();
|
||||
accepted = true;
|
||||
}
|
||||
} else {
|
||||
auto *direct = value.try_cast<data_type>();
|
||||
|
||||
if(clazz && (direct || value.convert<data_type>())) {
|
||||
std::invoke(Data, clazz) = (direct ? *direct : value.cast<data_type>());
|
||||
accepted = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
static_assert(std::is_pointer_v<decltype(Data)>);
|
||||
using data_type = std::remove_cv_t<std::remove_reference_t<decltype(*Data)>>;
|
||||
|
||||
if constexpr(std::is_array_v<data_type>) {
|
||||
using underlying_type = std::remove_extent_t<data_type>;
|
||||
auto *direct = value.try_cast<underlying_type>();
|
||||
auto *idx = index.try_cast<std::size_t>();
|
||||
|
||||
if(idx && (direct || value.convert<underlying_type>())) {
|
||||
(*Data)[*idx] = (direct ? *direct : value.cast<underlying_type>());
|
||||
accepted = true;
|
||||
}
|
||||
} else {
|
||||
auto *direct = value.try_cast<data_type>();
|
||||
|
||||
if(direct || value.convert<data_type>()) {
|
||||
*Data = (direct ? *direct : value.cast<data_type>());
|
||||
accepted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return accepted;
|
||||
}
|
||||
|
||||
|
||||
template<typename Type, auto Data>
|
||||
meta_any getter([[maybe_unused]] meta_handle handle, [[maybe_unused]] meta_any index) {
|
||||
if constexpr(std::is_function_v<std::remove_pointer_t<decltype(Data)>> || std::is_member_function_pointer_v<decltype(Data)>) {
|
||||
static_assert(std::is_invocable_v<decltype(Data), Type &>);
|
||||
auto *clazz = handle.data<Type>();
|
||||
return clazz ? std::invoke(Data, *clazz) : meta_any{};
|
||||
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
using data_type = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>;
|
||||
static_assert(std::is_invocable_v<decltype(Data), Type *>);
|
||||
auto *clazz = handle.data<Type>();
|
||||
|
||||
if constexpr(std::is_array_v<data_type>) {
|
||||
auto *idx = index.try_cast<std::size_t>();
|
||||
return (clazz && idx) ? std::invoke(Data, clazz)[*idx] : meta_any{};
|
||||
} else {
|
||||
return clazz ? std::invoke(Data, clazz) : meta_any{};
|
||||
}
|
||||
} else {
|
||||
static_assert(std::is_pointer_v<decltype(Data)>);
|
||||
|
||||
if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
|
||||
auto *idx = index.try_cast<std::size_t>();
|
||||
return idx ? (*Data)[*idx] : meta_any{};
|
||||
} else {
|
||||
return *Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename Type, auto Func, std::size_t... Indexes>
|
||||
std::enable_if_t<std::is_function_v<std::remove_pointer_t<decltype(Func)>>, meta_any>
|
||||
invoke(meta_handle, meta_any *args, std::index_sequence<Indexes...>) {
|
||||
using helper_type = meta_function_helper<std::integral_constant<decltype(Func), Func>>;
|
||||
[[maybe_unused]] auto direct = std::make_tuple((args+Indexes)->try_cast<typename helper_type::template arg_type<Indexes>>()...);
|
||||
meta_any any{};
|
||||
|
||||
if(((std::get<Indexes>(direct) || (args+Indexes)->convert<typename helper_type::template arg_type<Indexes>>()) && ...)) {
|
||||
if constexpr(std::is_void_v<typename helper_type::return_type>) {
|
||||
std::invoke(Func, (std::get<Indexes>(direct) ? *std::get<Indexes>(direct) : (args+Indexes)->cast<typename helper_type::template arg_type<Indexes>>())...);
|
||||
any.emplace<void>();
|
||||
} else {
|
||||
any = std::invoke(Func, (std::get<Indexes>(direct) ? *std::get<Indexes>(direct) : (args+Indexes)->cast<typename helper_type::template arg_type<Indexes>>())...);
|
||||
}
|
||||
}
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
template<typename Type, auto Member, std::size_t... Indexes>
|
||||
std::enable_if_t<std::is_member_function_pointer_v<decltype(Member)>, meta_any>
|
||||
invoke(meta_handle handle, meta_any *args, std::index_sequence<Indexes...>) {
|
||||
using helper_type = meta_function_helper<std::integral_constant<decltype(Member), Member>>;
|
||||
static_assert(std::is_base_of_v<typename helper_type::class_type, Type>);
|
||||
[[maybe_unused]] auto direct = std::make_tuple((args+Indexes)->try_cast<typename helper_type::template arg_type<Indexes>>()...);
|
||||
auto *clazz = handle.data<Type>();
|
||||
meta_any any{};
|
||||
|
||||
if(clazz && ((std::get<Indexes>(direct) || (args+Indexes)->convert<typename helper_type::template arg_type<Indexes>>()) && ...)) {
|
||||
if constexpr(std::is_void_v<typename helper_type::return_type>) {
|
||||
std::invoke(Member, clazz, (std::get<Indexes>(direct) ? *std::get<Indexes>(direct) : (args+Indexes)->cast<typename helper_type::template arg_type<Indexes>>())...);
|
||||
any.emplace<void>();
|
||||
} else {
|
||||
any = std::invoke(Member, clazz, (std::get<Indexes>(direct) ? *std::get<Indexes>(direct) : (args+Indexes)->cast<typename helper_type::template arg_type<Indexes>>())...);
|
||||
}
|
||||
}
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond TURN_OFF_DOXYGEN
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
@@ -75,44 +282,6 @@ class meta_factory {
|
||||
return &node;
|
||||
}
|
||||
|
||||
template<typename... Property>
|
||||
meta_factory type(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT {
|
||||
static internal::meta_type_node node{
|
||||
{},
|
||||
nullptr,
|
||||
nullptr,
|
||||
std::is_void_v<Type>,
|
||||
std::is_integral_v<Type>,
|
||||
std::is_floating_point_v<Type>,
|
||||
std::is_array_v<Type>,
|
||||
std::is_enum_v<Type>,
|
||||
std::is_union_v<Type>,
|
||||
std::is_class_v<Type>,
|
||||
std::is_pointer_v<Type>,
|
||||
std::is_function_v<Type>,
|
||||
std::is_member_object_pointer_v<Type>,
|
||||
std::is_member_function_pointer_v<Type>,
|
||||
std::extent_v<Type>,
|
||||
[]() ENTT_NOEXCEPT -> meta_type {
|
||||
return internal::meta_info<std::remove_pointer_t<Type>>::resolve();
|
||||
},
|
||||
&internal::destroy<Type>,
|
||||
[]() ENTT_NOEXCEPT -> meta_type {
|
||||
return &node;
|
||||
}
|
||||
};
|
||||
|
||||
node.identifier = identifier;
|
||||
node.next = internal::meta_info<>::type;
|
||||
node.prop = properties<Type>(std::forward<Property>(property)...);
|
||||
ENTT_ASSERT(!duplicate(identifier, node.next));
|
||||
ENTT_ASSERT(!internal::meta_info<Type>::type);
|
||||
internal::meta_info<Type>::type = &node;
|
||||
internal::meta_info<>::type = &node;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void unregister_prop(internal::meta_prop_node **prop) {
|
||||
while(*prop) {
|
||||
auto *node = *prop;
|
||||
@@ -150,46 +319,29 @@ class meta_factory {
|
||||
}
|
||||
}
|
||||
|
||||
bool unregister() ENTT_NOEXCEPT {
|
||||
const auto registered = internal::meta_info<Type>::type;
|
||||
|
||||
if(registered) {
|
||||
if(auto *curr = internal::meta_info<>::type; curr == internal::meta_info<Type>::type) {
|
||||
internal::meta_info<>::type = internal::meta_info<Type>::type->next;
|
||||
} else {
|
||||
while(curr && curr->next != internal::meta_info<Type>::type) {
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
if(curr) {
|
||||
curr->next = internal::meta_info<Type>::type->next;
|
||||
}
|
||||
}
|
||||
|
||||
unregister_prop(&internal::meta_info<Type>::type->prop);
|
||||
unregister_all<&internal::meta_type_node::base>(0);
|
||||
unregister_all<&internal::meta_type_node::conv>(0);
|
||||
unregister_all<&internal::meta_type_node::ctor>(0);
|
||||
unregister_all<&internal::meta_type_node::data>(0);
|
||||
unregister_all<&internal::meta_type_node::func>(0);
|
||||
unregister_dtor();
|
||||
|
||||
internal::meta_info<Type>::type->identifier = {};
|
||||
internal::meta_info<Type>::type->next = nullptr;
|
||||
internal::meta_info<Type>::type = nullptr;
|
||||
}
|
||||
|
||||
return registered;
|
||||
}
|
||||
|
||||
meta_factory() ENTT_NOEXCEPT = default;
|
||||
|
||||
public:
|
||||
template<typename Other, typename... Property>
|
||||
friend meta_factory<Other> reflect(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT;
|
||||
/**
|
||||
* @brief Extends a meta type by assigning it an identifier and properties.
|
||||
* @tparam Property Types of properties to assign to the meta type.
|
||||
* @param identifier Unique identifier.
|
||||
* @param property Properties to assign to the meta type.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<typename... Property>
|
||||
meta_factory type(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT {
|
||||
ENTT_ASSERT(!internal::meta_info<Type>::type);
|
||||
auto *node = internal::meta_info<Type>::resolve();
|
||||
node->identifier = identifier;
|
||||
node->next = internal::meta_info<>::type;
|
||||
node->prop = properties<Type>(std::forward<Property>(property)...);
|
||||
ENTT_ASSERT(!duplicate(identifier, node->next));
|
||||
internal::meta_info<Type>::type = node;
|
||||
internal::meta_info<>::type = node;
|
||||
|
||||
template<typename Other>
|
||||
friend bool unregister() ENTT_NOEXCEPT;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a meta base to a meta type.
|
||||
@@ -326,7 +478,7 @@ public:
|
||||
helper_type::size,
|
||||
&helper_type::arg,
|
||||
[](meta_any * const any) {
|
||||
return internal::invoke<Type, Func>(nullptr, any, std::make_index_sequence<helper_type::size>{});
|
||||
return internal::invoke<Type, Func>({}, any, std::make_index_sequence<helper_type::size>{});
|
||||
},
|
||||
[]() ENTT_NOEXCEPT -> meta_ctor {
|
||||
return &node;
|
||||
@@ -409,7 +561,7 @@ public:
|
||||
type,
|
||||
[](meta_handle handle) {
|
||||
return handle.type() == internal::meta_info<Type>::resolve()->meta()
|
||||
? ((*Func)(static_cast<Type *>(handle.data())), true)
|
||||
? ((*Func)(handle.data<Type>()), true)
|
||||
: false;
|
||||
},
|
||||
[]() ENTT_NOEXCEPT -> meta_dtor {
|
||||
@@ -622,11 +774,54 @@ public:
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unregisters a meta type and all its parts.
|
||||
*
|
||||
* This function unregisters a meta type and all its data members, member
|
||||
* functions and properties, as well as its constructors, destructors and
|
||||
* conversion functions if any.<br/>
|
||||
* Base classes aren't unregistered but the link between the two types is
|
||||
* removed.
|
||||
*
|
||||
* @return True if the meta type exists, false otherwise.
|
||||
*/
|
||||
bool unregister() ENTT_NOEXCEPT {
|
||||
const auto registered = internal::meta_info<Type>::type;
|
||||
|
||||
if(registered) {
|
||||
if(auto *curr = internal::meta_info<>::type; curr == internal::meta_info<Type>::type) {
|
||||
internal::meta_info<>::type = internal::meta_info<Type>::type->next;
|
||||
} else {
|
||||
while(curr && curr->next != internal::meta_info<Type>::type) {
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
if(curr) {
|
||||
curr->next = internal::meta_info<Type>::type->next;
|
||||
}
|
||||
}
|
||||
|
||||
unregister_prop(&internal::meta_info<Type>::type->prop);
|
||||
unregister_all<&internal::meta_type_node::base>(0);
|
||||
unregister_all<&internal::meta_type_node::conv>(0);
|
||||
unregister_all<&internal::meta_type_node::ctor>(0);
|
||||
unregister_all<&internal::meta_type_node::data>(0);
|
||||
unregister_all<&internal::meta_type_node::func>(0);
|
||||
unregister_dtor();
|
||||
|
||||
internal::meta_info<Type>::type->identifier = {};
|
||||
internal::meta_info<Type>::type->next = nullptr;
|
||||
internal::meta_info<Type>::type = nullptr;
|
||||
}
|
||||
|
||||
return registered;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic function to use for reflection.
|
||||
* @brief Utility function to use for reflection.
|
||||
*
|
||||
* This is the point from which everything starts.<br/>
|
||||
* By invoking this function with a type that is not yet reflected, a meta type
|
||||
@@ -646,7 +841,7 @@ inline meta_factory<Type> reflect(const ENTT_ID_TYPE identifier, Property &&...
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic function to use for reflection.
|
||||
* @brief Utility function to use for reflection.
|
||||
*
|
||||
* This is the point from which everything starts.<br/>
|
||||
* By invoking this function with a type that is not yet reflected, a meta type
|
||||
@@ -663,7 +858,7 @@ inline meta_factory<Type> reflect() ENTT_NOEXCEPT {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic function to unregister a type.
|
||||
* @brief Utility function to unregister a type.
|
||||
*
|
||||
* This function unregisters a type and all its data members, member functions
|
||||
* and properties, as well as its constructors, destructors and conversion
|
||||
@@ -676,7 +871,7 @@ inline meta_factory<Type> reflect() ENTT_NOEXCEPT {
|
||||
*/
|
||||
template<typename Type>
|
||||
inline bool unregister() ENTT_NOEXCEPT {
|
||||
return meta_factory<Type>().unregister();
|
||||
return meta_factory<Type>{}.unregister();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
#define ENTT_META_META_HPP
|
||||
|
||||
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
|
||||
@@ -17,7 +15,7 @@ namespace entt {
|
||||
|
||||
|
||||
class meta_any;
|
||||
class meta_handle;
|
||||
struct meta_handle;
|
||||
class meta_prop;
|
||||
class meta_base;
|
||||
class meta_conv;
|
||||
@@ -300,74 +298,41 @@ inline auto ctor(std::index_sequence<Indexes...>, const meta_type_node *node) EN
|
||||
*/
|
||||
class meta_any {
|
||||
/*! @brief A meta handle is allowed to _inherit_ from a meta any. */
|
||||
friend class meta_handle;
|
||||
friend struct meta_handle;
|
||||
|
||||
using storage_type = std::aligned_storage_t<sizeof(void *), alignof(void *)>;
|
||||
using compare_fn_type = bool(const void *, const void *);
|
||||
using copy_fn_type = void *(storage_type &, const void *);
|
||||
using destroy_fn_type = void(storage_type &);
|
||||
using steal_fn_type = void *(storage_type &, storage_type &, destroy_fn_type *, void *) ENTT_NOEXCEPT;
|
||||
using steal_fn_type = void *(storage_type &, storage_type &, destroy_fn_type *) ENTT_NOEXCEPT;
|
||||
|
||||
template<typename Type, typename = std::void_t<>>
|
||||
struct type_traits {
|
||||
using chunk_type = std::aligned_storage_t<sizeof(Type), alignof(Type)>;
|
||||
|
||||
template<typename... Args>
|
||||
static void * instance(storage_type &storage, Args &&... args) {
|
||||
auto chunk = std::make_unique<chunk_type>();
|
||||
auto *instance = new (chunk.get()) Type{std::forward<Args>(args)...};
|
||||
new (&storage) chunk_type *{chunk.get()};
|
||||
chunk.release();
|
||||
return instance;
|
||||
auto instance = std::make_unique<Type>(std::forward<Args>(args)...);
|
||||
new (&storage) Type *{instance.get()};
|
||||
return instance.release();
|
||||
}
|
||||
|
||||
static void destroy(storage_type &storage) {
|
||||
auto *node = internal::meta_info<Type>::resolve();
|
||||
auto *chunk = *reinterpret_cast<chunk_type **>(&storage);
|
||||
auto *instance = reinterpret_cast<Type *>(chunk);
|
||||
auto *instance = *reinterpret_cast<Type **>(&storage);
|
||||
node->dtor ? node->dtor->invoke(*instance) : node->destroy(*instance);
|
||||
delete chunk;
|
||||
delete instance;
|
||||
}
|
||||
|
||||
static void * copy(storage_type &storage, const void *instance) {
|
||||
auto chunk = std::make_unique<chunk_type>();
|
||||
new (&storage) chunk_type *{chunk.get()};
|
||||
auto *other = new (chunk.get()) Type{*static_cast<const Type *>(instance)};
|
||||
chunk.release();
|
||||
return other;
|
||||
static void * copy(storage_type &storage, const void *other) {
|
||||
auto instance = std::make_unique<Type>(*static_cast<const Type *>(other));
|
||||
new (&storage) Type *{instance.get()};
|
||||
return instance.release();
|
||||
}
|
||||
|
||||
static void * steal(storage_type &to, storage_type &from, destroy_fn_type *, void *instance) ENTT_NOEXCEPT {
|
||||
auto *chunk = *reinterpret_cast<chunk_type **>(&from);
|
||||
new (&to) chunk_type *{chunk};
|
||||
chunk->~chunk_type();
|
||||
static void * steal(storage_type &to, storage_type &from, destroy_fn_type *) ENTT_NOEXCEPT {
|
||||
auto *instance = *reinterpret_cast<Type **>(&from);
|
||||
new (&to) Type *{instance};
|
||||
return instance;
|
||||
}
|
||||
|
||||
static bool compare(const void *lhs, const void *rhs) {
|
||||
return meta_any::compare(0, *static_cast<const Type *>(lhs), *static_cast<const Type *>(rhs));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct type_traits<Type, std::enable_if_t<std::is_void_v<Type>>> {
|
||||
static void * instance(storage_type &) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void destroy(storage_type &) {}
|
||||
|
||||
static void * copy(storage_type &, const void *) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void * steal(storage_type &, storage_type &, destroy_fn_type *, void *) ENTT_NOEXCEPT {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool compare(const void *, const void *) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
@@ -381,25 +346,23 @@ class meta_any {
|
||||
auto *node = internal::meta_info<Type>::resolve();
|
||||
auto *instance = reinterpret_cast<Type *>(&storage);
|
||||
node->dtor ? node->dtor->invoke(*instance) : node->destroy(*instance);
|
||||
instance->~Type();
|
||||
}
|
||||
|
||||
static void * copy(storage_type &storage, const void *instance) {
|
||||
return new (&storage) Type{*static_cast<const Type *>(instance)};
|
||||
}
|
||||
|
||||
static void * steal(storage_type &to, storage_type &from, destroy_fn_type *destroy_fn, void *) ENTT_NOEXCEPT {
|
||||
static void * steal(storage_type &to, storage_type &from, destroy_fn_type *destroy_fn) ENTT_NOEXCEPT {
|
||||
void *instance = new (&to) Type{std::move(*reinterpret_cast<Type *>(&from))};
|
||||
destroy_fn(from);
|
||||
return instance;
|
||||
}
|
||||
|
||||
static bool compare(const void *lhs, const void *rhs) {
|
||||
return meta_any::compare(0, *static_cast<const Type *>(lhs), *static_cast<const Type *>(rhs));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
static auto compare(int, const Type &lhs, const Type &rhs) -> decltype(lhs == rhs, bool{}) {
|
||||
static auto compare(int, const Type &lhs, const Type &rhs)
|
||||
-> decltype(lhs == rhs, bool{}) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
@@ -422,41 +385,48 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Constructs a meta any by directly initializing the new object.
|
||||
*
|
||||
* This class uses a technique called small buffer optimization (SBO) to
|
||||
* completely eliminate the need to allocate memory, where possible.<br/>
|
||||
* From the user's point of view, nothing will change, but the elimination
|
||||
* of allocations will reduce the jumps in memory and therefore will avoid
|
||||
* chasing of pointers. This will greatly improve the use of the cache, thus
|
||||
* increasing the overall performance.
|
||||
*
|
||||
* @tparam Type Type of object to use to initialize the container.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
meta_any(std::in_place_type_t<Type>, Args &&... args) {
|
||||
using actual_type = std::remove_cv_t<std::remove_reference_t<Type>>;
|
||||
using traits_type = type_traits<actual_type>;
|
||||
|
||||
explicit meta_any(std::in_place_type_t<Type>, [[maybe_unused]] Args &&... args)
|
||||
: meta_any{}
|
||||
{
|
||||
node = internal::meta_info<Type>::resolve();
|
||||
instance = traits_type::instance(storage, std::forward<Args>(args)...);
|
||||
destroy_fn = &traits_type::destroy;
|
||||
copy_fn = &traits_type::copy;
|
||||
steal_fn = &traits_type::steal;
|
||||
compare_fn = &traits_type::compare;
|
||||
|
||||
if constexpr(!std::is_void_v<Type>) {
|
||||
using traits_type = type_traits<std::remove_cv_t<std::remove_reference_t<Type>>>;
|
||||
instance = traits_type::instance(storage, std::forward<Args>(args)...);
|
||||
destroy_fn = &traits_type::destroy;
|
||||
copy_fn = &traits_type::copy;
|
||||
steal_fn = &traits_type::steal;
|
||||
|
||||
compare_fn = [](const void *lhs, const void *rhs) {
|
||||
return compare(0, *static_cast<const Type *>(lhs), *static_cast<const Type *>(rhs));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a meta any that holds an unmanaged object.
|
||||
* @tparam Type Type of object to use to initialize the container.
|
||||
* @param type An instance of an object to use to initialize the container.
|
||||
*/
|
||||
template<typename Type>
|
||||
explicit meta_any(std::in_place_t, Type &type)
|
||||
: meta_any{}
|
||||
{
|
||||
node = internal::meta_info<Type>::resolve();
|
||||
instance = &type;
|
||||
|
||||
compare_fn = [](const void *lhs, const void *rhs) {
|
||||
return compare(0, *static_cast<const Type *>(lhs), *static_cast<const Type *>(rhs));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a meta any from a given value.
|
||||
*
|
||||
* This class uses a technique called small buffer optimization (SBO) to
|
||||
* completely eliminate the need to allocate memory, where possible.<br/>
|
||||
* From the user's point of view, nothing will change, but the elimination
|
||||
* of allocations will reduce the jumps in memory and therefore will avoid
|
||||
* chasing of pointers. This will greatly improve the use of the cache, thus
|
||||
* increasing the overall performance.
|
||||
*
|
||||
* @tparam Type Type of object to use to initialize the container.
|
||||
* @param type An instance of an object to use to initialize the container.
|
||||
*/
|
||||
@@ -472,14 +442,12 @@ public:
|
||||
meta_any(const meta_any &other)
|
||||
: meta_any{}
|
||||
{
|
||||
if(other) {
|
||||
instance = other.copy_fn(storage, other.instance);
|
||||
node = other.node;
|
||||
destroy_fn = other.destroy_fn;
|
||||
compare_fn = other.compare_fn;
|
||||
copy_fn = other.copy_fn;
|
||||
steal_fn = other.steal_fn;
|
||||
}
|
||||
node = other.node;
|
||||
instance = other.copy_fn ? other.copy_fn(storage, other.instance) : other.instance;
|
||||
destroy_fn = other.destroy_fn;
|
||||
compare_fn = other.compare_fn;
|
||||
copy_fn = other.copy_fn;
|
||||
steal_fn = other.steal_fn;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -506,11 +474,32 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Assignment operator.
|
||||
* @tparam Type Type of object to use to initialize the container.
|
||||
* @param type An instance of an object to use to initialize the container.
|
||||
* @return This meta any object.
|
||||
*/
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, meta_any>>>
|
||||
meta_any & operator=(Type &&type) {
|
||||
return (*this = meta_any{std::forward<Type>(type)});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The instance to assign.
|
||||
* @return This meta any object.
|
||||
*/
|
||||
meta_any & operator=(meta_any other) {
|
||||
swap(other, *this);
|
||||
meta_any & operator=(const meta_any &other) {
|
||||
return (*this = meta_any{other});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The instance to assign.
|
||||
* @return This meta any object.
|
||||
*/
|
||||
meta_any & operator=(meta_any &&other) ENTT_NOEXCEPT {
|
||||
meta_any any{std::move(other)};
|
||||
swap(any, *this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -534,14 +523,19 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if it's possible to cast an instance to a given type.
|
||||
* @brief Tries to cast an instance to a given type.
|
||||
* @tparam Type Type to which to cast the instance.
|
||||
* @return True if the cast is viable, false otherwise.
|
||||
* @return A (possibly null) pointer to the contained instance.
|
||||
*/
|
||||
template<typename Type>
|
||||
bool can_cast() const ENTT_NOEXCEPT {
|
||||
const auto *type = internal::meta_info<Type>::resolve();
|
||||
return internal::can_cast_or_convert<&internal::meta_type_node::base>(node, type);
|
||||
const Type * try_cast() const ENTT_NOEXCEPT {
|
||||
return internal::try_cast<Type>(node, instance);
|
||||
}
|
||||
|
||||
/*! @copydoc try_cast */
|
||||
template<typename Type>
|
||||
Type * try_cast() ENTT_NOEXCEPT {
|
||||
return const_cast<Type *>(std::as_const(*this).try_cast<Type>());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -560,8 +554,8 @@ public:
|
||||
*/
|
||||
template<typename Type>
|
||||
const Type & cast() const ENTT_NOEXCEPT {
|
||||
ENTT_ASSERT(can_cast<Type>());
|
||||
return *internal::try_cast<Type>(node, instance);
|
||||
ENTT_ASSERT(try_cast<Type>());
|
||||
return *try_cast<Type>();
|
||||
}
|
||||
|
||||
/*! @copydoc cast */
|
||||
@@ -570,17 +564,6 @@ public:
|
||||
return const_cast<Type &>(std::as_const(*this).cast<Type>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if it's possible to convert an instance to a given type.
|
||||
* @tparam Type Type to which to convert the instance.
|
||||
* @return True if the conversion is viable, false otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
bool can_convert() const ENTT_NOEXCEPT {
|
||||
const auto *type = internal::meta_info<Type>::resolve();
|
||||
return internal::can_cast_or_convert<&internal::meta_type_node::conv>(node, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to convert an instance to a given type and returns it.
|
||||
* @tparam Type Type to which to convert the instance.
|
||||
@@ -642,7 +625,7 @@ public:
|
||||
* @return False if the container is empty, true otherwise.
|
||||
*/
|
||||
explicit operator bool() const ENTT_NOEXCEPT {
|
||||
return destroy_fn;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -652,7 +635,7 @@ public:
|
||||
* otherwise.
|
||||
*/
|
||||
bool operator==(const meta_any &other) const ENTT_NOEXCEPT {
|
||||
return (!compare_fn && !other.compare_fn) || (compare_fn && other.compare_fn && node == other.node && compare_fn(instance, other.instance));
|
||||
return node == other.node && ((!compare_fn && !other.compare_fn) || compare_fn(instance, other.instance));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -661,17 +644,19 @@ public:
|
||||
* @param rhs A valid meta any object.
|
||||
*/
|
||||
friend void swap(meta_any &lhs, meta_any &rhs) ENTT_NOEXCEPT {
|
||||
if(lhs && rhs) {
|
||||
if(lhs.steal_fn && rhs.steal_fn) {
|
||||
storage_type buffer;
|
||||
void *instance = lhs.steal_fn(buffer, lhs.storage, lhs.destroy_fn, lhs.instance);
|
||||
lhs.instance = rhs.steal_fn(lhs.storage, rhs.storage, rhs.destroy_fn, rhs.instance);
|
||||
rhs.instance = lhs.steal_fn(rhs.storage, buffer, lhs.destroy_fn, instance);
|
||||
} else if(lhs) {
|
||||
rhs.instance = lhs.steal_fn(rhs.storage, lhs.storage, lhs.destroy_fn, lhs.instance);
|
||||
lhs.instance = nullptr;
|
||||
} else if(rhs) {
|
||||
lhs.instance = rhs.steal_fn(lhs.storage, rhs.storage, rhs.destroy_fn, rhs.instance);
|
||||
rhs.instance = nullptr;
|
||||
lhs.steal_fn(buffer, lhs.storage, lhs.destroy_fn);
|
||||
lhs.instance = rhs.steal_fn(lhs.storage, rhs.storage, rhs.destroy_fn);
|
||||
rhs.instance = lhs.steal_fn(rhs.storage, buffer, lhs.destroy_fn);
|
||||
} else if(lhs.steal_fn) {
|
||||
lhs.instance = rhs.instance;
|
||||
rhs.instance = lhs.steal_fn(rhs.storage, lhs.storage, lhs.destroy_fn);
|
||||
} else if(rhs.steal_fn) {
|
||||
rhs.instance = lhs.instance;
|
||||
lhs.instance = rhs.steal_fn(lhs.storage, rhs.storage, rhs.destroy_fn);
|
||||
} else {
|
||||
std::swap(lhs.instance, rhs.instance);
|
||||
}
|
||||
|
||||
std::swap(lhs.node, rhs.node);
|
||||
@@ -702,33 +687,31 @@ private:
|
||||
* responsible for ensuring that the target object remains alive for the entire
|
||||
* interval of use of the handle.
|
||||
*/
|
||||
class meta_handle {
|
||||
meta_handle(int, meta_any &any) ENTT_NOEXCEPT
|
||||
: node{any.node},
|
||||
instance{any.instance}
|
||||
{}
|
||||
|
||||
template<typename Type>
|
||||
meta_handle(char, Type &&obj) ENTT_NOEXCEPT
|
||||
: node{internal::meta_info<Type>::resolve()},
|
||||
instance{&obj}
|
||||
{}
|
||||
|
||||
public:
|
||||
struct meta_handle {
|
||||
/*! @brief Default constructor. */
|
||||
meta_handle() ENTT_NOEXCEPT
|
||||
: node{nullptr},
|
||||
instance{nullptr}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Constructs a meta handle from a meta any object.
|
||||
* @param any A reference to an object to use to initialize the handle.
|
||||
*/
|
||||
meta_handle(meta_any &any) ENTT_NOEXCEPT
|
||||
: node{any.node},
|
||||
instance{any.instance}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Constructs a meta handle from a given instance.
|
||||
* @tparam Type Type of object to use to initialize the handle.
|
||||
* @param obj A reference to an object to use to initialize the handle.
|
||||
*/
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, meta_handle>>>
|
||||
meta_handle(Type &&obj) ENTT_NOEXCEPT
|
||||
: meta_handle{0, std::forward<Type>(obj)}
|
||||
meta_handle(Type &obj) ENTT_NOEXCEPT
|
||||
: node{internal::meta_info<Type>::resolve()},
|
||||
instance{&obj}
|
||||
{}
|
||||
|
||||
/**
|
||||
@@ -737,31 +720,6 @@ public:
|
||||
*/
|
||||
inline meta_type type() const ENTT_NOEXCEPT;
|
||||
|
||||
/**
|
||||
* @brief Tries to cast an instance to a given type.
|
||||
*
|
||||
* The type of the instance must be such that the conversion is possible.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to perform a conversion that isn't viable results in undefined
|
||||
* behavior.<br/>
|
||||
* An assertion will abort the execution at runtime in debug mode in case
|
||||
* the conversion is not feasible.
|
||||
*
|
||||
* @tparam Type Type to which to cast the instance.
|
||||
* @return A pointer to the contained instance.
|
||||
*/
|
||||
template<typename Type>
|
||||
const Type * try_cast() const ENTT_NOEXCEPT {
|
||||
return internal::try_cast<Type>(node, instance);
|
||||
}
|
||||
|
||||
/*! @copydoc try_cast */
|
||||
template<typename Type>
|
||||
Type * try_cast() ENTT_NOEXCEPT {
|
||||
return const_cast<Type *>(std::as_const(*this).try_cast<Type>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
@@ -775,6 +733,22 @@ public:
|
||||
return const_cast<void *>(std::as_const(*this).data());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to cast an instance to a given type.
|
||||
* @tparam Type Type to which to cast the instance.
|
||||
* @return A (possibly null) pointer to the underlying object.
|
||||
*/
|
||||
template<typename Type>
|
||||
const Type * data() const ENTT_NOEXCEPT {
|
||||
return internal::try_cast<Type>(node, instance);
|
||||
}
|
||||
|
||||
/*! @copydoc data */
|
||||
template<typename Type>
|
||||
Type * data() ENTT_NOEXCEPT {
|
||||
return const_cast<Type *>(std::as_const(*this).data<Type>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns false if a handle is empty, true otherwise.
|
||||
* @return False if the handle is empty, true otherwise.
|
||||
@@ -1590,9 +1564,6 @@ inline bool operator!=(const meta_func &lhs, const meta_func &rhs) ENTT_NOEXCEPT
|
||||
* able to work through it on real objects.
|
||||
*/
|
||||
class meta_type {
|
||||
/*! @brief A meta factory is allowed to create meta objects. */
|
||||
template<typename> friend class meta_factory;
|
||||
|
||||
/*! @brief A meta node is allowed to create meta objects. */
|
||||
template<typename...> friend struct internal::meta_node;
|
||||
|
||||
@@ -2093,215 +2064,6 @@ inline meta_type meta_func::arg(size_type index) const ENTT_NOEXCEPT {
|
||||
namespace internal {
|
||||
|
||||
|
||||
template<typename...>
|
||||
struct meta_function_helper;
|
||||
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
struct meta_function_helper<Ret(Args...)> {
|
||||
using return_type = Ret;
|
||||
using args_type = std::tuple<Args...>;
|
||||
|
||||
template<std::size_t Index>
|
||||
using arg_type = std::decay_t<std::tuple_element_t<Index, args_type>>;
|
||||
|
||||
static constexpr auto size = sizeof...(Args);
|
||||
|
||||
static auto arg(typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT {
|
||||
return std::array<meta_type_node *, sizeof...(Args)>{{meta_info<Args>::resolve()...}}[index];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Class, typename Ret, typename... Args, bool Const, bool Static>
|
||||
struct meta_function_helper<Class, Ret(Args...), std::bool_constant<Const>, std::bool_constant<Static>>: meta_function_helper<Ret(Args...)> {
|
||||
using class_type = Class;
|
||||
static constexpr auto is_const = Const;
|
||||
static constexpr auto is_static = Static;
|
||||
};
|
||||
|
||||
|
||||
template<typename Ret, typename... Args, typename Class>
|
||||
constexpr meta_function_helper<Class, Ret(Args...), std::bool_constant<false>, std::bool_constant<false>>
|
||||
to_meta_function_helper(Ret(Class:: *)(Args...));
|
||||
|
||||
|
||||
template<typename Ret, typename... Args, typename Class>
|
||||
constexpr meta_function_helper<Class, Ret(Args...), std::bool_constant<true>, std::bool_constant<false>>
|
||||
to_meta_function_helper(Ret(Class:: *)(Args...) const);
|
||||
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
constexpr meta_function_helper<void, Ret(Args...), std::bool_constant<false>, std::bool_constant<true>>
|
||||
to_meta_function_helper(Ret(*)(Args...));
|
||||
|
||||
|
||||
template<auto Func>
|
||||
struct meta_function_helper<std::integral_constant<decltype(Func), Func>>: decltype(to_meta_function_helper(Func)) {};
|
||||
|
||||
|
||||
template<typename Type>
|
||||
bool destroy([[maybe_unused]] meta_handle handle) {
|
||||
bool accepted = false;
|
||||
|
||||
if constexpr(std::is_object_v<Type> && !std::is_array_v<Type>) {
|
||||
accepted = (handle.type() == meta_info<Type>::resolve()->meta());
|
||||
|
||||
if(accepted) {
|
||||
static_cast<Type *>(handle.data())->~Type();
|
||||
}
|
||||
}
|
||||
|
||||
return accepted;
|
||||
}
|
||||
|
||||
|
||||
template<typename Type, typename... Args, std::size_t... Indexes>
|
||||
meta_any construct(meta_any * const args, std::index_sequence<Indexes...>) {
|
||||
[[maybe_unused]] std::array<bool, sizeof...(Args)> can_cast{{(args+Indexes)->can_cast<std::remove_cv_t<std::remove_reference_t<Args>>>()...}};
|
||||
[[maybe_unused]] std::array<bool, sizeof...(Args)> can_convert{{(std::get<Indexes>(can_cast) ? false : (args+Indexes)->can_convert<std::remove_cv_t<std::remove_reference_t<Args>>>())...}};
|
||||
meta_any any{};
|
||||
|
||||
if(((std::get<Indexes>(can_cast) || std::get<Indexes>(can_convert)) && ...)) {
|
||||
((std::get<Indexes>(can_convert) ? void((args+Indexes)->convert<std::remove_cv_t<std::remove_reference_t<Args>>>()) : void()), ...);
|
||||
any = Type{(args+Indexes)->cast<std::remove_cv_t<std::remove_reference_t<Args>>>()...};
|
||||
}
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
template<bool Const, typename Type, auto Data>
|
||||
bool setter([[maybe_unused]] meta_handle handle, [[maybe_unused]] meta_any index, [[maybe_unused]] meta_any value) {
|
||||
bool accepted = false;
|
||||
|
||||
if constexpr(!Const) {
|
||||
if constexpr(std::is_function_v<std::remove_pointer_t<decltype(Data)>> || std::is_member_function_pointer_v<decltype(Data)>) {
|
||||
using helper_type = meta_function_helper<std::integral_constant<decltype(Data), Data>>;
|
||||
using data_type = std::decay_t<std::tuple_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename helper_type::args_type>>;
|
||||
static_assert(std::is_invocable_v<decltype(Data), Type &, data_type>);
|
||||
accepted = value.can_cast<data_type>() || value.convert<data_type>();
|
||||
auto *clazz = handle.try_cast<Type>();
|
||||
|
||||
if(accepted && clazz) {
|
||||
std::invoke(Data, *clazz, value.cast<data_type>());
|
||||
}
|
||||
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
using data_type = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>;
|
||||
static_assert(std::is_invocable_v<decltype(Data), Type>);
|
||||
auto *clazz = handle.try_cast<Type>();
|
||||
|
||||
if constexpr(std::is_array_v<data_type>) {
|
||||
using underlying_type = std::remove_extent_t<data_type>;
|
||||
accepted = index.can_cast<std::size_t>() && (value.can_cast<underlying_type>() || value.convert<underlying_type>());
|
||||
|
||||
if(accepted && clazz) {
|
||||
std::invoke(Data, clazz)[index.cast<std::size_t>()] = value.cast<underlying_type>();
|
||||
}
|
||||
} else {
|
||||
accepted = value.can_cast<data_type>() || value.convert<data_type>();
|
||||
|
||||
if(accepted && clazz) {
|
||||
std::invoke(Data, clazz) = value.cast<data_type>();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
static_assert(std::is_pointer_v<decltype(Data)>);
|
||||
using data_type = std::remove_cv_t<std::remove_reference_t<decltype(*Data)>>;
|
||||
|
||||
if constexpr(std::is_array_v<data_type>) {
|
||||
using underlying_type = std::remove_extent_t<data_type>;
|
||||
accepted = index.can_cast<std::size_t>() && (value.can_cast<underlying_type>() || value.convert<underlying_type>());
|
||||
|
||||
if(accepted) {
|
||||
(*Data)[index.cast<std::size_t>()] = value.cast<underlying_type>();
|
||||
}
|
||||
} else {
|
||||
accepted = value.can_cast<data_type>() || value.convert<data_type>();
|
||||
|
||||
if(accepted) {
|
||||
*Data = value.cast<data_type>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return accepted;
|
||||
}
|
||||
|
||||
|
||||
template<typename Type, auto Data>
|
||||
meta_any getter([[maybe_unused]] meta_handle handle, [[maybe_unused]] meta_any index) {
|
||||
if constexpr(std::is_function_v<std::remove_pointer_t<decltype(Data)>> || std::is_member_function_pointer_v<decltype(Data)>) {
|
||||
static_assert(std::is_invocable_v<decltype(Data), Type &>);
|
||||
auto *clazz = handle.try_cast<Type>();
|
||||
return clazz ? std::invoke(Data, *clazz) : meta_any{};
|
||||
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
using data_type = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>;
|
||||
static_assert(std::is_invocable_v<decltype(Data), Type *>);
|
||||
auto *clazz = handle.try_cast<Type>();
|
||||
|
||||
if constexpr(std::is_array_v<data_type>) {
|
||||
return (clazz && index.can_cast<std::size_t>()) ? std::invoke(Data, clazz)[index.cast<std::size_t>()] : meta_any{};
|
||||
} else {
|
||||
return clazz ? std::invoke(Data, clazz) : meta_any{};
|
||||
}
|
||||
} else {
|
||||
static_assert(std::is_pointer_v<decltype(Data)>);
|
||||
|
||||
if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
|
||||
return index.can_cast<std::size_t>() ? (*Data)[index.cast<std::size_t>()] : meta_any{};
|
||||
} else {
|
||||
return *Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename Type, auto Func, std::size_t... Indexes>
|
||||
std::enable_if_t<std::is_function_v<std::remove_pointer_t<decltype(Func)>>, meta_any>
|
||||
invoke(const meta_handle &, meta_any *args, std::index_sequence<Indexes...>) {
|
||||
using helper_type = meta_function_helper<std::integral_constant<decltype(Func), Func>>;
|
||||
meta_any any{};
|
||||
|
||||
if((((args+Indexes)->can_cast<typename helper_type::template arg_type<Indexes>>()
|
||||
|| (args+Indexes)->convert<typename helper_type::template arg_type<Indexes>>()) && ...))
|
||||
{
|
||||
if constexpr(std::is_void_v<typename helper_type::return_type>) {
|
||||
std::invoke(Func, (args+Indexes)->cast<typename helper_type::template arg_type<Indexes>>()...);
|
||||
any.emplace<void>();
|
||||
} else {
|
||||
any = meta_any{std::invoke(Func, (args+Indexes)->cast<typename helper_type::template arg_type<Indexes>>()...)};
|
||||
}
|
||||
}
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
template<typename Type, auto Member, std::size_t... Indexes>
|
||||
std::enable_if_t<std::is_member_function_pointer_v<decltype(Member)>, meta_any>
|
||||
invoke(meta_handle &handle, meta_any *args, std::index_sequence<Indexes...>) {
|
||||
using helper_type = meta_function_helper<std::integral_constant<decltype(Member), Member>>;
|
||||
static_assert(std::is_base_of_v<typename helper_type::class_type, Type>);
|
||||
auto *clazz = handle.try_cast<Type>();
|
||||
meta_any any{};
|
||||
|
||||
if(clazz && (((args+Indexes)->can_cast<typename helper_type::template arg_type<Indexes>>()
|
||||
|| (args+Indexes)->convert<typename helper_type::template arg_type<Indexes>>()) && ...))
|
||||
{
|
||||
if constexpr(std::is_void_v<typename helper_type::return_type>) {
|
||||
std::invoke(Member, clazz, (args+Indexes)->cast<typename helper_type::template arg_type<Indexes>>()...);
|
||||
any.emplace<void>();
|
||||
} else {
|
||||
any = meta_any{std::invoke(Member, clazz, (args+Indexes)->cast<typename helper_type::template arg_type<Indexes>>()...)};
|
||||
}
|
||||
}
|
||||
|
||||
return any;
|
||||
}
|
||||
|
||||
|
||||
template<typename Type>
|
||||
inline meta_type_node * meta_node<Type>::resolve() ENTT_NOEXCEPT {
|
||||
if(!type) {
|
||||
@@ -2324,7 +2086,18 @@ inline meta_type_node * meta_node<Type>::resolve() ENTT_NOEXCEPT {
|
||||
[]() ENTT_NOEXCEPT -> meta_type {
|
||||
return internal::meta_info<std::remove_pointer_t<Type>>::resolve();
|
||||
},
|
||||
&destroy<Type>,
|
||||
[]([[maybe_unused]] meta_handle handle) {
|
||||
bool accepted = false;
|
||||
|
||||
if constexpr(std::is_object_v<Type> && !std::is_array_v<Type>) {
|
||||
if((handle.type() == meta_info<Type>::resolve()->meta())) {
|
||||
handle.data<Type>()->~Type();
|
||||
accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
return accepted;
|
||||
},
|
||||
[]() ENTT_NOEXCEPT -> meta_type {
|
||||
return &node;
|
||||
}
|
||||
|
||||
@@ -231,14 +231,14 @@ TEST_F(Meta, MetaAnySBO) {
|
||||
entt::meta_any any{'c'};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(any.can_cast<void>());
|
||||
ASSERT_TRUE(any.can_cast<char>());
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(any.try_cast<char>());
|
||||
ASSERT_EQ(any.cast<char>(), 'c');
|
||||
ASSERT_EQ(std::as_const(any).cast<char>(), 'c');
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any, entt::meta_any{'c'});
|
||||
ASSERT_NE(any, entt::meta_any{'h'});
|
||||
ASSERT_NE(entt::meta_any{'h'}, any);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyNoSBO) {
|
||||
@@ -247,14 +247,14 @@ TEST_F(Meta, MetaAnyNoSBO) {
|
||||
entt::meta_any any{instance};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(any.can_cast<void>());
|
||||
ASSERT_TRUE(any.can_cast<fat_type>());
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(any.try_cast<fat_type>());
|
||||
ASSERT_EQ(any.cast<fat_type>(), instance);
|
||||
ASSERT_EQ(std::as_const(any).cast<fat_type>(), instance);
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any, entt::meta_any{instance});
|
||||
ASSERT_NE(any, fat_type{});
|
||||
ASSERT_NE(fat_type{}, any);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyEmpty) {
|
||||
@@ -262,27 +262,45 @@ TEST_F(Meta, MetaAnyEmpty) {
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_FALSE(any.type());
|
||||
ASSERT_FALSE(any.can_cast<void>());
|
||||
ASSERT_FALSE(any.can_cast<empty_type>());
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_FALSE(any.try_cast<empty_type>());
|
||||
ASSERT_EQ(any.data(), nullptr);
|
||||
ASSERT_EQ(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any, entt::meta_any{});
|
||||
ASSERT_NE(any, entt::meta_any{'c'});
|
||||
ASSERT_NE(entt::meta_any{'c'}, any);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnySBOInPlaceConstruction) {
|
||||
TEST_F(Meta, MetaAnySBOInPlaceTypeConstruction) {
|
||||
entt::meta_any any{std::in_place_type<int>, 42};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(any.can_cast<void>());
|
||||
ASSERT_TRUE(any.can_cast<int>());
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(any.try_cast<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 42);
|
||||
ASSERT_EQ(std::as_const(any).cast<int>(), 42);
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any, (entt::meta_any{std::in_place_type<int>, 42}));
|
||||
ASSERT_EQ(any, entt::meta_any{42});
|
||||
ASSERT_NE(any, entt::meta_any{3});
|
||||
ASSERT_NE(entt::meta_any{3}, any);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnySBOInPlaceConstruction) {
|
||||
int value = 3;
|
||||
int other = 42;
|
||||
entt::meta_any any{std::in_place, value};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(any.try_cast<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 3);
|
||||
ASSERT_EQ(std::as_const(any).cast<int>(), 3);
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any, (entt::meta_any{std::in_place, value}));
|
||||
ASSERT_NE(any, (entt::meta_any{std::in_place, other}));
|
||||
ASSERT_NE(any, entt::meta_any{42});
|
||||
ASSERT_EQ(entt::meta_any{3}, any);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnySBOCopyConstruction) {
|
||||
@@ -291,8 +309,8 @@ TEST_F(Meta, MetaAnySBOCopyConstruction) {
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_FALSE(other.can_cast<void>());
|
||||
ASSERT_TRUE(other.can_cast<int>());
|
||||
ASSERT_FALSE(other.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(other.try_cast<int>());
|
||||
ASSERT_EQ(other.cast<int>(), 42);
|
||||
ASSERT_EQ(std::as_const(other).cast<int>(), 42);
|
||||
ASSERT_EQ(other, entt::meta_any{42});
|
||||
@@ -307,8 +325,8 @@ TEST_F(Meta, MetaAnySBOCopyAssignment) {
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_FALSE(other.can_cast<void>());
|
||||
ASSERT_TRUE(other.can_cast<int>());
|
||||
ASSERT_FALSE(other.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(other.try_cast<int>());
|
||||
ASSERT_EQ(other.cast<int>(), 42);
|
||||
ASSERT_EQ(std::as_const(other).cast<int>(), 42);
|
||||
ASSERT_EQ(other, entt::meta_any{42});
|
||||
@@ -321,8 +339,8 @@ TEST_F(Meta, MetaAnySBOMoveConstruction) {
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_FALSE(other.can_cast<void>());
|
||||
ASSERT_TRUE(other.can_cast<int>());
|
||||
ASSERT_FALSE(other.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(other.try_cast<int>());
|
||||
ASSERT_EQ(other.cast<int>(), 42);
|
||||
ASSERT_EQ(std::as_const(other).cast<int>(), 42);
|
||||
ASSERT_EQ(other, entt::meta_any{42});
|
||||
@@ -337,29 +355,58 @@ TEST_F(Meta, MetaAnySBOMoveAssignment) {
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_FALSE(other.can_cast<void>());
|
||||
ASSERT_TRUE(other.can_cast<int>());
|
||||
ASSERT_FALSE(other.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(other.try_cast<int>());
|
||||
ASSERT_EQ(other.cast<int>(), 42);
|
||||
ASSERT_EQ(std::as_const(other).cast<int>(), 42);
|
||||
ASSERT_EQ(other, entt::meta_any{42});
|
||||
ASSERT_NE(other, entt::meta_any{0});
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyNoSBOInPlaceConstruction) {
|
||||
TEST_F(Meta, MetaAnySBODirectAssignment) {
|
||||
entt::meta_any any{};
|
||||
any = 42;
|
||||
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(any.try_cast<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 42);
|
||||
ASSERT_EQ(std::as_const(any).cast<int>(), 42);
|
||||
ASSERT_EQ(any, entt::meta_any{42});
|
||||
ASSERT_NE(entt::meta_any{0}, any);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyNoSBOInPlaceTypeConstruction) {
|
||||
int value = 42;
|
||||
fat_type instance{&value};
|
||||
entt::meta_any any{std::in_place_type<fat_type>, instance};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(any.can_cast<void>());
|
||||
ASSERT_TRUE(any.can_cast<fat_type>());
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(any.try_cast<fat_type>());
|
||||
ASSERT_EQ(any.cast<fat_type>(), instance);
|
||||
ASSERT_EQ(std::as_const(any).cast<fat_type>(), instance);
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any, (entt::meta_any{std::in_place_type<fat_type>, instance}));
|
||||
ASSERT_EQ(any, entt::meta_any{instance});
|
||||
ASSERT_NE(any, entt::meta_any{fat_type{}});
|
||||
ASSERT_NE(entt::meta_any{fat_type{}}, any);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyNoSBOInPlaceConstruction) {
|
||||
int value = 3;
|
||||
fat_type instance{&value};
|
||||
entt::meta_any any{std::in_place, instance};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(any.try_cast<fat_type>());
|
||||
ASSERT_EQ(any.cast<fat_type>(), instance);
|
||||
ASSERT_EQ(std::as_const(any).cast<fat_type>(), instance);
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any, (entt::meta_any{std::in_place, instance}));
|
||||
ASSERT_EQ(any, entt::meta_any{instance});
|
||||
ASSERT_NE(entt::meta_any{fat_type{}}, any);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyNoSBOCopyConstruction) {
|
||||
@@ -370,8 +417,8 @@ TEST_F(Meta, MetaAnyNoSBOCopyConstruction) {
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_FALSE(other.can_cast<void>());
|
||||
ASSERT_TRUE(other.can_cast<fat_type>());
|
||||
ASSERT_FALSE(other.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(other.try_cast<fat_type>());
|
||||
ASSERT_EQ(other.cast<fat_type>(), instance);
|
||||
ASSERT_EQ(std::as_const(other).cast<fat_type>(), instance);
|
||||
ASSERT_EQ(other, entt::meta_any{instance});
|
||||
@@ -388,8 +435,8 @@ TEST_F(Meta, MetaAnyNoSBOCopyAssignment) {
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_FALSE(other.can_cast<void>());
|
||||
ASSERT_TRUE(other.can_cast<fat_type>());
|
||||
ASSERT_FALSE(other.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(other.try_cast<fat_type>());
|
||||
ASSERT_EQ(other.cast<fat_type>(), instance);
|
||||
ASSERT_EQ(std::as_const(other).cast<fat_type>(), instance);
|
||||
ASSERT_EQ(other, entt::meta_any{instance});
|
||||
@@ -404,8 +451,8 @@ TEST_F(Meta, MetaAnyNoSBOMoveConstruction) {
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_FALSE(other.can_cast<void>());
|
||||
ASSERT_TRUE(other.can_cast<fat_type>());
|
||||
ASSERT_FALSE(other.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(other.try_cast<fat_type>());
|
||||
ASSERT_EQ(other.cast<fat_type>(), instance);
|
||||
ASSERT_EQ(std::as_const(other).cast<fat_type>(), instance);
|
||||
ASSERT_EQ(other, entt::meta_any{instance});
|
||||
@@ -422,23 +469,37 @@ TEST_F(Meta, MetaAnyNoSBOMoveAssignment) {
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_FALSE(other.can_cast<void>());
|
||||
ASSERT_TRUE(other.can_cast<fat_type>());
|
||||
ASSERT_FALSE(other.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(other.try_cast<fat_type>());
|
||||
ASSERT_EQ(other.cast<fat_type>(), instance);
|
||||
ASSERT_EQ(std::as_const(other).cast<fat_type>(), instance);
|
||||
ASSERT_EQ(other, entt::meta_any{instance});
|
||||
ASSERT_NE(other, fat_type{});
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyVoidInPlaceConstruction) {
|
||||
TEST_F(Meta, MetaAnyNoSBODirectAssignment) {
|
||||
int value = 42;
|
||||
entt::meta_any any{};
|
||||
any = fat_type{&value};
|
||||
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(any.try_cast<fat_type>());
|
||||
ASSERT_EQ(any.cast<fat_type>(), fat_type{&value});
|
||||
ASSERT_EQ(std::as_const(any).cast<fat_type>(), fat_type{&value});
|
||||
ASSERT_EQ(any, entt::meta_any{fat_type{&value}});
|
||||
ASSERT_NE(fat_type{}, any);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyVoidInPlaceTypeConstruction) {
|
||||
entt::meta_any any{std::in_place_type<void>};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<void>());
|
||||
ASSERT_FALSE(any.can_cast<char>());
|
||||
ASSERT_FALSE(any.try_cast<char>());
|
||||
ASSERT_EQ(any.data(), nullptr);
|
||||
ASSERT_EQ(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(any, entt::meta_any{std::in_place_type<void>});
|
||||
ASSERT_NE(entt::meta_any{3}, any);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyVoidCopyConstruction) {
|
||||
@@ -447,7 +508,7 @@ TEST_F(Meta, MetaAnyVoidCopyConstruction) {
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_TRUE(other.can_cast<void>());
|
||||
ASSERT_EQ(any.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(other, entt::meta_any{std::in_place_type<void>});
|
||||
}
|
||||
|
||||
@@ -459,7 +520,7 @@ TEST_F(Meta, MetaAnyVoidCopyAssignment) {
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_TRUE(other.can_cast<void>());
|
||||
ASSERT_EQ(any.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(other, entt::meta_any{std::in_place_type<void>});
|
||||
}
|
||||
|
||||
@@ -469,7 +530,7 @@ TEST_F(Meta, MetaAnyVoidMoveConstruction) {
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_TRUE(other.can_cast<void>());
|
||||
ASSERT_EQ(other.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(other, entt::meta_any{std::in_place_type<void>});
|
||||
}
|
||||
|
||||
@@ -481,7 +542,7 @@ TEST_F(Meta, MetaAnyVoidMoveAssignment) {
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_TRUE(other.can_cast<void>());
|
||||
ASSERT_EQ(other.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(other, entt::meta_any{std::in_place_type<void>});
|
||||
}
|
||||
|
||||
@@ -539,15 +600,15 @@ TEST_F(Meta, MetaAnyEmplace) {
|
||||
any.emplace<int>(42);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(any.can_cast<void>());
|
||||
ASSERT_TRUE(any.can_cast<int>());
|
||||
ASSERT_FALSE(any.try_cast<std::size_t>());
|
||||
ASSERT_TRUE(any.try_cast<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 42);
|
||||
ASSERT_EQ(std::as_const(any).cast<int>(), 42);
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any, (entt::meta_any{std::in_place_type<int>, 42}));
|
||||
ASSERT_EQ(any, entt::meta_any{42});
|
||||
ASSERT_NE(any, entt::meta_any{3});
|
||||
ASSERT_NE(entt::meta_any{3}, any);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyEmplaceVoid) {
|
||||
@@ -555,9 +616,9 @@ TEST_F(Meta, MetaAnyEmplaceVoid) {
|
||||
any.emplace<void>();
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<void>());
|
||||
ASSERT_EQ(any.data(), nullptr);
|
||||
ASSERT_EQ(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(any, (entt::meta_any{std::in_place_type<void>}));
|
||||
}
|
||||
|
||||
@@ -567,9 +628,9 @@ TEST_F(Meta, MetaAnySBOSwap) {
|
||||
|
||||
std::swap(lhs, rhs);
|
||||
|
||||
ASSERT_TRUE(lhs.can_cast<int>());
|
||||
ASSERT_TRUE(lhs.try_cast<int>());
|
||||
ASSERT_EQ(lhs.cast<int>(), 42);
|
||||
ASSERT_TRUE(rhs.can_cast<char>());
|
||||
ASSERT_TRUE(rhs.try_cast<char>());
|
||||
ASSERT_EQ(rhs.cast<char>(), 'c');
|
||||
}
|
||||
|
||||
@@ -601,9 +662,9 @@ TEST_F(Meta, MetaAnySBOWithNoSBOSwap) {
|
||||
|
||||
std::swap(lhs, rhs);
|
||||
|
||||
ASSERT_TRUE(lhs.can_cast<char>());
|
||||
ASSERT_TRUE(lhs.try_cast<char>());
|
||||
ASSERT_EQ(lhs.cast<char>(), 'c');
|
||||
ASSERT_TRUE(rhs.can_cast<fat_type>());
|
||||
ASSERT_TRUE(rhs.try_cast<fat_type>());
|
||||
ASSERT_EQ(rhs.cast<fat_type>().foo, &value);
|
||||
ASSERT_EQ(rhs.cast<fat_type>().bar, &value);
|
||||
}
|
||||
@@ -615,13 +676,13 @@ TEST_F(Meta, MetaAnySBOWithEmptySwap) {
|
||||
std::swap(lhs, rhs);
|
||||
|
||||
ASSERT_FALSE(lhs);
|
||||
ASSERT_TRUE(rhs.can_cast<char>());
|
||||
ASSERT_TRUE(rhs.try_cast<char>());
|
||||
ASSERT_EQ(rhs.cast<char>(), 'c');
|
||||
|
||||
std::swap(lhs, rhs);
|
||||
|
||||
ASSERT_FALSE(rhs);
|
||||
ASSERT_TRUE(lhs.can_cast<char>());
|
||||
ASSERT_TRUE(lhs.try_cast<char>());
|
||||
ASSERT_EQ(lhs.cast<char>(), 'c');
|
||||
}
|
||||
|
||||
@@ -631,8 +692,8 @@ TEST_F(Meta, MetaAnySBOWithVoidSwap) {
|
||||
|
||||
std::swap(lhs, rhs);
|
||||
|
||||
ASSERT_TRUE(lhs.can_cast<void>());
|
||||
ASSERT_TRUE(rhs.can_cast<char>());
|
||||
ASSERT_EQ(lhs.type(), entt::resolve<void>());
|
||||
ASSERT_TRUE(rhs.try_cast<char>());
|
||||
ASSERT_EQ(rhs.cast<char>(), 'c');
|
||||
}
|
||||
|
||||
@@ -669,7 +730,7 @@ TEST_F(Meta, MetaAnyComparable) {
|
||||
|
||||
ASSERT_EQ(any, any);
|
||||
ASSERT_EQ(any, entt::meta_any{'c'});
|
||||
ASSERT_NE(any, entt::meta_any{'a'});
|
||||
ASSERT_NE(entt::meta_any{'a'}, any);
|
||||
ASSERT_NE(any, entt::meta_any{});
|
||||
|
||||
ASSERT_TRUE(any == any);
|
||||
@@ -684,7 +745,7 @@ TEST_F(Meta, MetaAnyNotComparable) {
|
||||
|
||||
ASSERT_EQ(any, any);
|
||||
ASSERT_NE(any, entt::meta_any{not_comparable_type{}});
|
||||
ASSERT_NE(any, entt::meta_any{});
|
||||
ASSERT_NE(entt::meta_any{}, any);
|
||||
|
||||
ASSERT_TRUE(any == any);
|
||||
ASSERT_FALSE(any == entt::meta_any{not_comparable_type{}});
|
||||
@@ -696,7 +757,7 @@ TEST_F(Meta, MetaAnyCompareVoid) {
|
||||
|
||||
ASSERT_EQ(any, any);
|
||||
ASSERT_EQ(any, entt::meta_any{std::in_place_type<void>});
|
||||
ASSERT_NE(any, entt::meta_any{'a'});
|
||||
ASSERT_NE(entt::meta_any{'a'}, any);
|
||||
ASSERT_NE(any, entt::meta_any{});
|
||||
|
||||
ASSERT_TRUE(any == any);
|
||||
@@ -706,19 +767,28 @@ TEST_F(Meta, MetaAnyCompareVoid) {
|
||||
ASSERT_TRUE(any != entt::meta_any{});
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyCast) {
|
||||
TEST_F(Meta, MetaAnyTryCast) {
|
||||
entt::meta_any any{derived_type{}};
|
||||
entt::meta_handle handle{any};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<derived_type>());
|
||||
ASSERT_FALSE(any.can_cast<void>());
|
||||
ASSERT_TRUE(any.can_cast<base_type>());
|
||||
ASSERT_TRUE(any.can_cast<derived_type>());
|
||||
ASSERT_EQ(&any.cast<base_type>(), handle.try_cast<base_type>());
|
||||
ASSERT_EQ(&any.cast<derived_type>(), handle.try_cast<derived_type>());
|
||||
ASSERT_EQ(&std::as_const(any).cast<base_type>(), handle.try_cast<base_type>());
|
||||
ASSERT_EQ(&std::as_const(any).cast<derived_type>(), handle.try_cast<derived_type>());
|
||||
ASSERT_EQ(any.try_cast<void>(), nullptr);
|
||||
ASSERT_NE(any.try_cast<base_type>(), nullptr);
|
||||
ASSERT_EQ(any.try_cast<derived_type>(), any.data());
|
||||
ASSERT_EQ(std::as_const(any).try_cast<base_type>(), any.try_cast<base_type>());
|
||||
ASSERT_EQ(std::as_const(any).try_cast<derived_type>(), any.data());
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyCast) {
|
||||
entt::meta_any any{derived_type{}};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<derived_type>());
|
||||
ASSERT_EQ(any.try_cast<std::size_t>(), nullptr);
|
||||
ASSERT_NE(any.try_cast<base_type>(), nullptr);
|
||||
ASSERT_EQ(any.try_cast<derived_type>(), any.data());
|
||||
ASSERT_EQ(std::as_const(any).try_cast<base_type>(), any.try_cast<base_type>());
|
||||
ASSERT_EQ(std::as_const(any).try_cast<derived_type>(), any.data());
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyConvert) {
|
||||
@@ -726,18 +796,11 @@ TEST_F(Meta, MetaAnyConvert) {
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<double>());
|
||||
ASSERT_FALSE(any.can_convert<char>());
|
||||
ASSERT_TRUE(any.can_convert<double>());
|
||||
ASSERT_TRUE(any.can_convert<int>());
|
||||
|
||||
ASSERT_TRUE(any.convert<double>());
|
||||
ASSERT_FALSE(any.convert<char>());
|
||||
|
||||
ASSERT_EQ(any.type(), entt::resolve<double>());
|
||||
ASSERT_EQ(any.cast<double>(), 42.);
|
||||
|
||||
ASSERT_TRUE(any.convert<int>());
|
||||
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 42);
|
||||
}
|
||||
@@ -747,13 +810,8 @@ TEST_F(Meta, MetaAnyConstConvert) {
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<double>());
|
||||
ASSERT_FALSE(any.can_convert<char>());
|
||||
ASSERT_TRUE(any.can_convert<double>());
|
||||
ASSERT_TRUE(any.can_convert<int>());
|
||||
|
||||
ASSERT_TRUE(any.convert<double>());
|
||||
ASSERT_FALSE(any.convert<char>());
|
||||
|
||||
ASSERT_EQ(any.type(), entt::resolve<double>());
|
||||
ASSERT_EQ(any.cast<double>(), 42.);
|
||||
|
||||
@@ -771,9 +829,9 @@ TEST_F(Meta, MetaHandleFromObject) {
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_EQ(handle.type(), entt::resolve<empty_type>());
|
||||
ASSERT_EQ(handle.try_cast<void>(), nullptr);
|
||||
ASSERT_EQ(handle.try_cast<empty_type>(), &empty);
|
||||
ASSERT_EQ(std::as_const(handle).try_cast<empty_type>(), &empty);
|
||||
ASSERT_EQ(handle.data<std::size_t>(), nullptr);
|
||||
ASSERT_EQ(handle.data<empty_type>(), &empty);
|
||||
ASSERT_EQ(std::as_const(handle).data<empty_type>(), &empty);
|
||||
ASSERT_EQ(handle.data(), &empty);
|
||||
ASSERT_EQ(std::as_const(handle).data(), &empty);
|
||||
}
|
||||
@@ -784,9 +842,9 @@ TEST_F(Meta, MetaHandleFromMetaAny) {
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_EQ(handle.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(handle.try_cast<void>(), nullptr);
|
||||
ASSERT_EQ(handle.try_cast<int>(), any.data());
|
||||
ASSERT_EQ(std::as_const(handle).try_cast<int>(), any.data());
|
||||
ASSERT_EQ(handle.data<std::size_t>(), nullptr);
|
||||
ASSERT_EQ(handle.data<int>(), any.data());
|
||||
ASSERT_EQ(std::as_const(handle).data<int>(), any.data());
|
||||
ASSERT_EQ(handle.data(), any.data());
|
||||
ASSERT_EQ(std::as_const(handle).data(), any.data());
|
||||
}
|
||||
@@ -796,24 +854,24 @@ TEST_F(Meta, MetaHandleEmpty) {
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_FALSE(handle.type());
|
||||
ASSERT_EQ(handle.try_cast<void>(), nullptr);
|
||||
ASSERT_EQ(handle.try_cast<empty_type>(), nullptr);
|
||||
ASSERT_EQ(handle.data<std::size_t>(), nullptr);
|
||||
ASSERT_EQ(handle.data<empty_type>(), nullptr);
|
||||
ASSERT_EQ(handle.data(), nullptr);
|
||||
ASSERT_EQ(std::as_const(handle).data(), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaHandleTryCast) {
|
||||
TEST_F(Meta, MetaHandleData) {
|
||||
derived_type derived{};
|
||||
base_type *base = &derived;
|
||||
entt::meta_handle handle{derived};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_EQ(handle.type(), entt::resolve<derived_type>());
|
||||
ASSERT_EQ(handle.try_cast<void>(), nullptr);
|
||||
ASSERT_EQ(handle.try_cast<base_type>(), base);
|
||||
ASSERT_EQ(handle.try_cast<derived_type>(), &derived);
|
||||
ASSERT_EQ(std::as_const(handle).try_cast<base_type>(), base);
|
||||
ASSERT_EQ(std::as_const(handle).try_cast<derived_type>(), &derived);
|
||||
ASSERT_EQ(handle.data<std::size_t>(), nullptr);
|
||||
ASSERT_EQ(handle.data<base_type>(), base);
|
||||
ASSERT_EQ(handle.data<derived_type>(), &derived);
|
||||
ASSERT_EQ(std::as_const(handle).data<base_type>(), base);
|
||||
ASSERT_EQ(std::as_const(handle).data<derived_type>(), &derived);
|
||||
ASSERT_EQ(handle.data(), &derived);
|
||||
ASSERT_EQ(std::as_const(handle).data(), &derived);
|
||||
}
|
||||
@@ -903,7 +961,7 @@ TEST_F(Meta, MetaCtor) {
|
||||
|
||||
ASSERT_FALSE(empty);
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<derived_type>());
|
||||
ASSERT_TRUE(any.try_cast<derived_type>());
|
||||
ASSERT_EQ(any.cast<derived_type>().i, 42);
|
||||
ASSERT_EQ(any.cast<derived_type>().c, 'c');
|
||||
|
||||
@@ -937,7 +995,7 @@ TEST_F(Meta, MetaCtorFunc) {
|
||||
|
||||
ASSERT_FALSE(empty);
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<derived_type>());
|
||||
ASSERT_TRUE(any.try_cast<derived_type>());
|
||||
ASSERT_EQ(any.cast<derived_type>().i, 42);
|
||||
ASSERT_EQ(any.cast<derived_type>().c, 'c');
|
||||
|
||||
@@ -961,7 +1019,7 @@ TEST_F(Meta, MetaCtorMetaAnyArgs) {
|
||||
auto any = ctor.invoke(base_type{}, entt::meta_any{42}, entt::meta_any{'c'});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<derived_type>());
|
||||
ASSERT_TRUE(any.try_cast<derived_type>());
|
||||
ASSERT_EQ(any.cast<derived_type>().i, 42);
|
||||
ASSERT_EQ(any.cast<derived_type>().c, 'c');
|
||||
}
|
||||
@@ -976,7 +1034,7 @@ TEST_F(Meta, MetaCtorCastAndConvert) {
|
||||
auto any = ctor.invoke(entt::meta_any{derived_type{}}, entt::meta_any{42.}, entt::meta_any{'c'});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<derived_type>());
|
||||
ASSERT_TRUE(any.try_cast<derived_type>());
|
||||
ASSERT_EQ(any.cast<derived_type>().i, 42);
|
||||
ASSERT_EQ(any.cast<derived_type>().c, 'c');
|
||||
}
|
||||
@@ -986,7 +1044,7 @@ TEST_F(Meta, MetaCtorFuncMetaAnyArgs) {
|
||||
auto any = ctor.invoke(base_type{}, entt::meta_any{42});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<derived_type>());
|
||||
ASSERT_TRUE(any.try_cast<derived_type>());
|
||||
ASSERT_EQ(any.cast<derived_type>().i, 42);
|
||||
ASSERT_EQ(any.cast<derived_type>().c, 'c');
|
||||
}
|
||||
@@ -1001,7 +1059,7 @@ TEST_F(Meta, MetaCtorFuncCastAndConvert) {
|
||||
auto any = ctor.invoke(entt::meta_any{derived_type{}}, entt::meta_any{42.});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<derived_type>());
|
||||
ASSERT_TRUE(any.try_cast<derived_type>());
|
||||
ASSERT_EQ(any.cast<derived_type>().i, 42);
|
||||
ASSERT_EQ(any.cast<derived_type>().c, 'c');
|
||||
}
|
||||
@@ -1028,7 +1086,8 @@ TEST_F(Meta, MetaDtorMetaAnyArg) {
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaDtorMetaAnyInvalidArg) {
|
||||
ASSERT_FALSE(entt::resolve<empty_type>().dtor().invoke(int{}));
|
||||
auto instance = 0;
|
||||
ASSERT_FALSE(entt::resolve<empty_type>().dtor().invoke(instance));
|
||||
}
|
||||
|
||||
|
||||
@@ -1154,12 +1213,13 @@ TEST_F(Meta, MetaDataGetMetaAnyArg) {
|
||||
const auto value = data.get(any);
|
||||
|
||||
ASSERT_TRUE(value);
|
||||
ASSERT_TRUE(value.can_cast<int>());
|
||||
ASSERT_TRUE(value.cast<int>());
|
||||
ASSERT_EQ(value.cast<int>(), 99);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaDataGetInvalidArg) {
|
||||
ASSERT_FALSE(entt::resolve<data_type>().data("i"_hs).get(0));
|
||||
auto instance = 0;
|
||||
ASSERT_FALSE(entt::resolve<data_type>().data("i"_hs).get(instance));
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaDataSetMetaAnyArg) {
|
||||
@@ -1274,17 +1334,17 @@ TEST_F(Meta, MetaDataArrayStatic) {
|
||||
ASSERT_TRUE(data.is_static());
|
||||
ASSERT_TRUE(data.type().is_array());
|
||||
ASSERT_EQ(data.type().extent(), 3);
|
||||
ASSERT_EQ(data.get(nullptr, 0).cast<int>(), 3);
|
||||
ASSERT_EQ(data.get(nullptr, 1).cast<int>(), 5);
|
||||
ASSERT_EQ(data.get(nullptr, 2).cast<int>(), 7);
|
||||
ASSERT_FALSE(data.set(nullptr, 0, 'c'));
|
||||
ASSERT_EQ(data.get(nullptr, 0).cast<int>(), 3);
|
||||
ASSERT_TRUE(data.set(nullptr, 0, data.get(nullptr, 0).cast<int>()+2));
|
||||
ASSERT_TRUE(data.set(nullptr, 1, data.get(nullptr, 1).cast<int>()+2));
|
||||
ASSERT_TRUE(data.set(nullptr, 2, data.get(nullptr, 2).cast<int>()+2));
|
||||
ASSERT_EQ(data.get(nullptr, 0).cast<int>(), 5);
|
||||
ASSERT_EQ(data.get(nullptr, 1).cast<int>(), 7);
|
||||
ASSERT_EQ(data.get(nullptr, 2).cast<int>(), 9);
|
||||
ASSERT_EQ(data.get({}, 0).cast<int>(), 3);
|
||||
ASSERT_EQ(data.get({}, 1).cast<int>(), 5);
|
||||
ASSERT_EQ(data.get({}, 2).cast<int>(), 7);
|
||||
ASSERT_FALSE(data.set({}, 0, 'c'));
|
||||
ASSERT_EQ(data.get({}, 0).cast<int>(), 3);
|
||||
ASSERT_TRUE(data.set({}, 0, data.get({}, 0).cast<int>()+2));
|
||||
ASSERT_TRUE(data.set({}, 1, data.get({}, 1).cast<int>()+2));
|
||||
ASSERT_TRUE(data.set({}, 2, data.get({}, 2).cast<int>()+2));
|
||||
ASSERT_EQ(data.get({}, 0).cast<int>(), 5);
|
||||
ASSERT_EQ(data.get({}, 1).cast<int>(), 7);
|
||||
ASSERT_EQ(data.get({}, 2).cast<int>(), 9);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaDataArray) {
|
||||
@@ -1411,7 +1471,7 @@ TEST_F(Meta, MetaFuncRetVoid) {
|
||||
auto any = func.invoke(instance, 5);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<void>());
|
||||
ASSERT_EQ(any.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(func_type::value, 25);
|
||||
|
||||
func.prop([](auto prop) {
|
||||
@@ -1481,7 +1541,7 @@ TEST_F(Meta, MetaFuncStaticRetVoid) {
|
||||
auto any = func.invoke({}, 42);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<void>());
|
||||
ASSERT_EQ(any.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(func_type::value, 42);
|
||||
|
||||
func.prop([](auto *prop) {
|
||||
@@ -1501,7 +1561,9 @@ TEST_F(Meta, MetaFuncStaticRetVoid) {
|
||||
|
||||
TEST_F(Meta, MetaFuncMetaAnyArgs) {
|
||||
auto func = entt::resolve<func_type>().func("f1"_hs);
|
||||
auto any = func.invoke(func_type{}, entt::meta_any{3});
|
||||
func_type instance;
|
||||
|
||||
auto any = func.invoke(instance, entt::meta_any{3});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
@@ -1510,12 +1572,16 @@ TEST_F(Meta, MetaFuncMetaAnyArgs) {
|
||||
|
||||
TEST_F(Meta, MetaFuncInvalidArgs) {
|
||||
auto func = entt::resolve<func_type>().func("f1"_hs);
|
||||
ASSERT_FALSE(func.invoke(empty_type{}, entt::meta_any{'c'}));
|
||||
empty_type instance;
|
||||
|
||||
ASSERT_FALSE(func.invoke(instance, entt::meta_any{'c'}));
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaFuncCastAndConvert) {
|
||||
auto func = entt::resolve<func_type>().func("f3"_hs);
|
||||
auto any = func.invoke(func_type{}, derived_type{}, 0, 3.);
|
||||
func_type instance;
|
||||
|
||||
auto any = func.invoke(instance, derived_type{}, 0, 3.);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
@@ -1640,7 +1706,7 @@ TEST_F(Meta, MetaTypeConstruct) {
|
||||
auto any = type.construct(base_type{}, 42, 'c');
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<derived_type>());
|
||||
ASSERT_TRUE(any.try_cast<derived_type>());
|
||||
ASSERT_EQ(any.cast<derived_type>().i, 42);
|
||||
ASSERT_EQ(any.cast<derived_type>().c, 'c');
|
||||
}
|
||||
@@ -1650,7 +1716,7 @@ TEST_F(Meta, MetaTypeConstructMetaAnyArgs) {
|
||||
auto any = type.construct(entt::meta_any{base_type{}}, entt::meta_any{42}, entt::meta_any{'c'});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<derived_type>());
|
||||
ASSERT_TRUE(any.try_cast<derived_type>());
|
||||
ASSERT_EQ(any.cast<derived_type>().i, 42);
|
||||
ASSERT_EQ(any.cast<derived_type>().c, 'c');
|
||||
}
|
||||
@@ -1672,42 +1738,46 @@ TEST_F(Meta, MetaTypeConstructCastAndConvert) {
|
||||
auto any = type.construct(entt::meta_any{derived_type{}}, entt::meta_any{42.}, entt::meta_any{'c'});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.can_cast<derived_type>());
|
||||
ASSERT_TRUE(any.try_cast<derived_type>());
|
||||
ASSERT_EQ(any.cast<derived_type>().i, 42);
|
||||
ASSERT_EQ(any.cast<derived_type>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaTypeDestroyDtor) {
|
||||
auto type = entt::resolve<empty_type>();
|
||||
empty_type instance;
|
||||
|
||||
ASSERT_EQ(empty_type::counter, 0);
|
||||
ASSERT_TRUE(type.destroy(empty_type{}));
|
||||
ASSERT_TRUE(type.destroy(instance));
|
||||
ASSERT_EQ(empty_type::counter, 1);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaTypeDestroyDtorInvalidArg) {
|
||||
auto type = entt::resolve<empty_type>();
|
||||
auto instance = 'c';
|
||||
|
||||
ASSERT_EQ(empty_type::counter, 0);
|
||||
ASSERT_FALSE(type.destroy('c'));
|
||||
ASSERT_FALSE(type.destroy(instance));
|
||||
ASSERT_EQ(empty_type::counter, 0);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaTypeDestroyDtorCastAndConvert) {
|
||||
auto type = entt::resolve<empty_type>();
|
||||
fat_type instance{};
|
||||
|
||||
ASSERT_EQ(empty_type::counter, 0);
|
||||
ASSERT_FALSE(type.destroy(fat_type{}));
|
||||
ASSERT_FALSE(type.destroy(instance));
|
||||
ASSERT_EQ(empty_type::counter, 0);
|
||||
ASSERT_FALSE(entt::resolve<int>().destroy(42.));
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaTypeDestroyNoDtor) {
|
||||
ASSERT_TRUE(entt::resolve<char>().destroy('c'));
|
||||
auto instance = 'c';
|
||||
ASSERT_TRUE(entt::resolve<char>().destroy(instance));
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaTypeDestroyNoDtorInvalidArg) {
|
||||
ASSERT_FALSE(entt::resolve<char>().destroy(42));
|
||||
auto instance = 42;
|
||||
ASSERT_FALSE(entt::resolve<char>().destroy(instance));
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaTypeDestroyNoDtorVoid) {
|
||||
@@ -1715,7 +1785,8 @@ TEST_F(Meta, MetaTypeDestroyNoDtorVoid) {
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaTypeDestroyNoDtorCastAndConvert) {
|
||||
ASSERT_FALSE(entt::resolve<int>().destroy(42.));
|
||||
auto instance = 42.;
|
||||
ASSERT_FALSE(entt::resolve<int>().destroy(instance));
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaDataFromBase) {
|
||||
@@ -1853,8 +1924,8 @@ TEST_F(Meta, Unregister) {
|
||||
entt::meta_any any{42.};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(any.can_convert<int>());
|
||||
ASSERT_TRUE(any.can_convert<float>());
|
||||
ASSERT_FALSE(any.convert<int>());
|
||||
ASSERT_TRUE(any.convert<float>());
|
||||
|
||||
ASSERT_FALSE(entt::resolve("derived"_hs));
|
||||
ASSERT_TRUE(entt::resolve("my_type"_hs));
|
||||
|
||||
Reference in New Issue
Block a user