diff --git a/TODO b/TODO
index c4c1393cd..dd2a592a6 100644
--- a/TODO
+++ b/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
diff --git a/docs/md/meta.md b/docs/md/meta.md
index 26e08af56..b3da10354 100644
--- a/docs/md/meta.md
+++ b/docs/md/meta.md
@@ -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.
+It takes the burden of destroying the contained instance when required.
+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
diff --git a/src/entt/meta/factory.hpp b/src/entt/meta/factory.hpp
index bf863d9b2..6726b1023 100644
--- a/src/entt/meta/factory.hpp
+++ b/src/entt/meta/factory.hpp
@@ -2,8 +2,11 @@
#define ENTT_META_FACTORY_HPP
+#include
+#include
+#include
#include
-#include
+#include
#include
#include "../config/config.h"
#include "meta.hpp"
@@ -12,16 +15,220 @@
namespace entt {
-template
-class meta_factory;
+/**
+ * @cond TURN_OFF_DOXYGEN
+ * Internal details not to be documented.
+ */
-template
-meta_factory reflect(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT;
+namespace internal {
-template
-bool unregister() ENTT_NOEXCEPT;
+template
+struct meta_function_helper;
+
+
+template
+struct meta_function_helper {
+ using return_type = Ret;
+ using args_type = std::tuple;
+
+ template
+ using arg_type = std::decay_t>;
+
+ static constexpr auto size = sizeof...(Args);
+
+ static auto arg(typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT {
+ return std::array{{meta_info::resolve()...}}[index];
+ }
+};
+
+
+template
+struct meta_function_helper, std::bool_constant>: meta_function_helper {
+ using class_type = Class;
+ static constexpr auto is_const = Const;
+ static constexpr auto is_static = Static;
+};
+
+
+template
+constexpr meta_function_helper, std::bool_constant>
+to_meta_function_helper(Ret(Class:: *)(Args...));
+
+
+template
+constexpr meta_function_helper, std::bool_constant>
+to_meta_function_helper(Ret(Class:: *)(Args...) const);
+
+
+template
+constexpr meta_function_helper, std::bool_constant>
+to_meta_function_helper(Ret(*)(Args...));
+
+
+template
+struct meta_function_helper>: decltype(to_meta_function_helper(Func)) {};
+
+
+template
+meta_any construct(meta_any * const args, std::index_sequence) {
+ [[maybe_unused]] auto direct = std::make_tuple((args+Indexes)->try_cast>>()...);
+ meta_any any{};
+
+ if(((std::get(direct) || (args+Indexes)->convert>>()) && ...)) {
+ any = Type{(std::get(direct) ? *std::get(direct) : (args+Indexes)->cast>>())...};
+ }
+
+ return any;
+}
+
+
+template
+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::is_member_function_pointer_v) {
+ using helper_type = meta_function_helper>;
+ using data_type = std::decay_t, typename helper_type::args_type>>;
+ static_assert(std::is_invocable_v);
+ auto *direct = value.try_cast();
+ auto *clazz = handle.data();
+
+ if(clazz && (direct || value.convert())) {
+ std::invoke(Data, *clazz, direct ? *direct : value.cast());
+ accepted = true;
+ }
+ } else if constexpr(std::is_member_object_pointer_v) {
+ using data_type = std::remove_cv_t().*Data)>>;
+ static_assert(std::is_invocable_v);
+ auto *clazz = handle.data();
+
+ if constexpr(std::is_array_v) {
+ using underlying_type = std::remove_extent_t;
+ auto *direct = value.try_cast();
+ auto *idx = index.try_cast();
+
+ if(clazz && idx && (direct || value.convert())) {
+ std::invoke(Data, clazz)[*idx] = direct ? *direct : value.cast();
+ accepted = true;
+ }
+ } else {
+ auto *direct = value.try_cast();
+
+ if(clazz && (direct || value.convert())) {
+ std::invoke(Data, clazz) = (direct ? *direct : value.cast());
+ accepted = true;
+ }
+ }
+ } else {
+ static_assert(std::is_pointer_v);
+ using data_type = std::remove_cv_t>;
+
+ if constexpr(std::is_array_v) {
+ using underlying_type = std::remove_extent_t;
+ auto *direct = value.try_cast();
+ auto *idx = index.try_cast();
+
+ if(idx && (direct || value.convert())) {
+ (*Data)[*idx] = (direct ? *direct : value.cast());
+ accepted = true;
+ }
+ } else {
+ auto *direct = value.try_cast();
+
+ if(direct || value.convert()) {
+ *Data = (direct ? *direct : value.cast());
+ accepted = true;
+ }
+ }
+ }
+ }
+
+ return accepted;
+}
+
+
+template
+meta_any getter([[maybe_unused]] meta_handle handle, [[maybe_unused]] meta_any index) {
+ if constexpr(std::is_function_v> || std::is_member_function_pointer_v) {
+ static_assert(std::is_invocable_v);
+ auto *clazz = handle.data();
+ return clazz ? std::invoke(Data, *clazz) : meta_any{};
+ } else if constexpr(std::is_member_object_pointer_v) {
+ using data_type = std::remove_cv_t().*Data)>>;
+ static_assert(std::is_invocable_v);
+ auto *clazz = handle.data();
+
+ if constexpr(std::is_array_v) {
+ auto *idx = index.try_cast();
+ 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);
+
+ if constexpr(std::is_array_v>) {
+ auto *idx = index.try_cast();
+ return idx ? (*Data)[*idx] : meta_any{};
+ } else {
+ return *Data;
+ }
+ }
+}
+
+
+template
+std::enable_if_t>, meta_any>
+invoke(meta_handle, meta_any *args, std::index_sequence) {
+ using helper_type = meta_function_helper>;
+ [[maybe_unused]] auto direct = std::make_tuple((args+Indexes)->try_cast>()...);
+ meta_any any{};
+
+ if(((std::get(direct) || (args+Indexes)->convert>()) && ...)) {
+ if constexpr(std::is_void_v) {
+ std::invoke(Func, (std::get(direct) ? *std::get(direct) : (args+Indexes)->cast>())...);
+ any.emplace();
+ } else {
+ any = std::invoke(Func, (std::get(direct) ? *std::get(direct) : (args+Indexes)->cast>())...);
+ }
+ }
+
+ return any;
+}
+
+
+template
+std::enable_if_t, meta_any>
+invoke(meta_handle handle, meta_any *args, std::index_sequence) {
+ using helper_type = meta_function_helper>;
+ static_assert(std::is_base_of_v);
+ [[maybe_unused]] auto direct = std::make_tuple((args+Indexes)->try_cast>()...);
+ auto *clazz = handle.data();
+ meta_any any{};
+
+ if(clazz && ((std::get(direct) || (args+Indexes)->convert>()) && ...)) {
+ if constexpr(std::is_void_v) {
+ std::invoke(Member, clazz, (std::get(direct) ? *std::get(direct) : (args+Indexes)->cast>())...);
+ any.emplace();
+ } else {
+ any = std::invoke(Member, clazz, (std::get(direct) ? *std::get(direct) : (args+Indexes)->cast>())...);
+ }
+ }
+
+ return any;
+}
+
+
+}
+
+
+/**
+ * Internal details not to be documented.
+ * @endcond TURN_OFF_DOXYGEN
+ */
/**
@@ -75,44 +282,6 @@ class meta_factory {
return &node;
}
- template
- meta_factory type(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT {
- static internal::meta_type_node node{
- {},
- nullptr,
- nullptr,
- std::is_void_v,
- std::is_integral_v,
- std::is_floating_point_v,
- std::is_array_v,
- std::is_enum_v,
- std::is_union_v,
- std::is_class_v,
- std::is_pointer_v,
- std::is_function_v,
- std::is_member_object_pointer_v,
- std::is_member_function_pointer_v,
- std::extent_v,
- []() ENTT_NOEXCEPT -> meta_type {
- return internal::meta_info>::resolve();
- },
- &internal::destroy,
- []() ENTT_NOEXCEPT -> meta_type {
- return &node;
- }
- };
-
- node.identifier = identifier;
- node.next = internal::meta_info<>::type;
- node.prop = properties(std::forward(property)...);
- ENTT_ASSERT(!duplicate(identifier, node.next));
- ENTT_ASSERT(!internal::meta_info::type);
- internal::meta_info::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;
-
- if(registered) {
- if(auto *curr = internal::meta_info<>::type; curr == internal::meta_info::type) {
- internal::meta_info<>::type = internal::meta_info::type->next;
- } else {
- while(curr && curr->next != internal::meta_info::type) {
- curr = curr->next;
- }
-
- if(curr) {
- curr->next = internal::meta_info::type->next;
- }
- }
-
- unregister_prop(&internal::meta_info::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->identifier = {};
- internal::meta_info::type->next = nullptr;
- internal::meta_info::type = nullptr;
- }
-
- return registered;
- }
-
meta_factory() ENTT_NOEXCEPT = default;
public:
- template
- friend meta_factory 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
+ meta_factory type(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT {
+ ENTT_ASSERT(!internal::meta_info::type);
+ auto *node = internal::meta_info::resolve();
+ node->identifier = identifier;
+ node->next = internal::meta_info<>::type;
+ node->prop = properties(std::forward(property)...);
+ ENTT_ASSERT(!duplicate(identifier, node->next));
+ internal::meta_info::type = node;
+ internal::meta_info<>::type = node;
- template
- 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(nullptr, any, std::make_index_sequence{});
+ return internal::invoke({}, any, std::make_index_sequence{});
},
[]() ENTT_NOEXCEPT -> meta_ctor {
return &node;
@@ -409,7 +561,7 @@ public:
type,
[](meta_handle handle) {
return handle.type() == internal::meta_info::resolve()->meta()
- ? ((*Func)(static_cast(handle.data())), true)
+ ? ((*Func)(handle.data()), 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.
+ * 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;
+
+ if(registered) {
+ if(auto *curr = internal::meta_info<>::type; curr == internal::meta_info::type) {
+ internal::meta_info<>::type = internal::meta_info::type->next;
+ } else {
+ while(curr && curr->next != internal::meta_info::type) {
+ curr = curr->next;
+ }
+
+ if(curr) {
+ curr->next = internal::meta_info::type->next;
+ }
+ }
+
+ unregister_prop(&internal::meta_info::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->identifier = {};
+ internal::meta_info::type->next = nullptr;
+ internal::meta_info::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.
* By invoking this function with a type that is not yet reflected, a meta type
@@ -646,7 +841,7 @@ inline meta_factory 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.
* By invoking this function with a type that is not yet reflected, a meta type
@@ -663,7 +858,7 @@ inline meta_factory 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 reflect() ENTT_NOEXCEPT {
*/
template
inline bool unregister() ENTT_NOEXCEPT {
- return meta_factory().unregister();
+ return meta_factory{}.unregister();
}
diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp
index eb4fc6829..54524ced7 100644
--- a/src/entt/meta/meta.hpp
+++ b/src/entt/meta/meta.hpp
@@ -2,13 +2,11 @@
#define ENTT_META_META_HPP
-#include
#include
#include
#include
#include
#include
-#include
#include
#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, 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;
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>
struct type_traits {
- using chunk_type = std::aligned_storage_t;
-
template
static void * instance(storage_type &storage, Args &&... args) {
- auto chunk = std::make_unique();
- auto *instance = new (chunk.get()) Type{std::forward(args)...};
- new (&storage) chunk_type *{chunk.get()};
- chunk.release();
- return instance;
+ auto instance = std::make_unique(std::forward(args)...);
+ new (&storage) Type *{instance.get()};
+ return instance.release();
}
static void destroy(storage_type &storage) {
auto *node = internal::meta_info::resolve();
- auto *chunk = *reinterpret_cast(&storage);
- auto *instance = reinterpret_cast(chunk);
+ auto *instance = *reinterpret_cast(&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();
- new (&storage) chunk_type *{chunk.get()};
- auto *other = new (chunk.get()) Type{*static_cast(instance)};
- chunk.release();
- return other;
+ static void * copy(storage_type &storage, const void *other) {
+ auto instance = std::make_unique(*static_cast(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(&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(&from);
+ new (&to) Type *{instance};
return instance;
}
-
- static bool compare(const void *lhs, const void *rhs) {
- return meta_any::compare(0, *static_cast(lhs), *static_cast(rhs));
- }
- };
-
- template
- struct type_traits>> {
- 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
@@ -381,25 +346,23 @@ class meta_any {
auto *node = internal::meta_info::resolve();
auto *instance = reinterpret_cast(&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(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(&from))};
destroy_fn(from);
return instance;
}
-
- static bool compare(const void *lhs, const void *rhs) {
- return meta_any::compare(0, *static_cast(lhs), *static_cast(rhs));
- }
};
template
- 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.
- * 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
- meta_any(std::in_place_type_t, Args &&... args) {
- using actual_type = std::remove_cv_t>;
- using traits_type = type_traits;
-
+ explicit meta_any(std::in_place_type_t, [[maybe_unused]] Args &&... args)
+ : meta_any{}
+ {
node = internal::meta_info::resolve();
- instance = traits_type::instance(storage, std::forward(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) {
+ using traits_type = type_traits>>;
+ instance = traits_type::instance(storage, std::forward(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(lhs), *static_cast(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
+ explicit meta_any(std::in_place_t, Type &type)
+ : meta_any{}
+ {
+ node = internal::meta_info::resolve();
+ instance = &type;
+
+ compare_fn = [](const void *lhs, const void *rhs) {
+ return compare(0, *static_cast(lhs), *static_cast(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.
- * 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>, meta_any>>>
+ meta_any & operator=(Type &&type) {
+ return (*this = meta_any{std::forward(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
- bool can_cast() const ENTT_NOEXCEPT {
- const auto *type = internal::meta_info::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(node, instance);
+ }
+
+ /*! @copydoc try_cast */
+ template
+ Type * try_cast() ENTT_NOEXCEPT {
+ return const_cast(std::as_const(*this).try_cast());
}
/**
@@ -560,8 +554,8 @@ public:
*/
template
const Type & cast() const ENTT_NOEXCEPT {
- ENTT_ASSERT(can_cast());
- return *internal::try_cast(node, instance);
+ ENTT_ASSERT(try_cast());
+ return *try_cast();
}
/*! @copydoc cast */
@@ -570,17 +564,6 @@ public:
return const_cast(std::as_const(*this).cast());
}
- /**
- * @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
- bool can_convert() const ENTT_NOEXCEPT {
- const auto *type = internal::meta_info::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
- meta_handle(char, Type &&obj) ENTT_NOEXCEPT
- : node{internal::meta_info