diff --git a/TODO b/TODO
index a3132f78d..00753a3b8 100644
--- a/TODO
+++ b/TODO
@@ -31,3 +31,4 @@ Next:
- add meta_handle::operator-> that returns a meta_any * (easier to use directly)
- use a dedicate class template to specialize meta views for a better support to customizations
- remove operator* from meta_any, meta_handle
+ - add const meta container support to meta any
diff --git a/src/entt/meta/factory.hpp b/src/entt/meta/factory.hpp
index ba655e402..409affe0d 100644
--- a/src/entt/meta/factory.hpp
+++ b/src/entt/meta/factory.hpp
@@ -374,8 +374,8 @@ public:
type,
nullptr,
&internal::meta_info::resolve,
- [](void *instance) ENTT_NOEXCEPT -> void * {
- return static_cast(static_cast(instance));
+ [](const void *instance) ENTT_NOEXCEPT -> const void * {
+ return static_cast(static_cast(instance));
}
};
diff --git a/src/entt/meta/internal.hpp b/src/entt/meta/internal.hpp
index 2307d7633..e7c542f4d 100644
--- a/src/entt/meta/internal.hpp
+++ b/src/entt/meta/internal.hpp
@@ -3,6 +3,7 @@
#include
+#include
#include
#include
#include
@@ -29,6 +30,172 @@ struct meta_handle;
namespace internal {
+class meta_storage {
+ using storage_type = std::aligned_storage_t;
+ using copy_fn_type = void(meta_storage &, const meta_storage &);
+ using steal_fn_type = void(meta_storage &, meta_storage &);
+ using destroy_fn_type = void(meta_storage &);
+
+ template>
+ struct type_traits {
+ template
+ static void instance(meta_storage &buffer, Args &&... args) {
+ buffer.instance = new Type{std::forward(args)...};
+ new (&buffer.storage) Type *{static_cast(buffer.instance)};
+ }
+
+ static void destroy(meta_storage &buffer) {
+ delete static_cast(buffer.instance);
+ }
+
+ static void copy(meta_storage &to, const meta_storage &from) {
+ to.instance = new Type{*static_cast(from.instance)};
+ new (&to.storage) Type *{static_cast(to.instance)};
+ }
+
+ static void steal(meta_storage &to, meta_storage &from) {
+ new (&to.storage) Type *{static_cast(from.instance)};
+ to.instance = from.instance;
+ }
+ };
+
+ template
+ struct type_traits>> {
+ template
+ static void instance(meta_storage &buffer, Args &&... args) {
+ buffer.instance = new (&buffer.storage) Type{std::forward(args)...};
+ }
+
+ static void destroy(meta_storage &buffer) {
+ static_cast(buffer.instance)->~Type();
+ }
+
+ static void copy(meta_storage &to, const meta_storage &from) {
+ to.instance = new (&to.storage) Type{*static_cast(from.instance)};
+ }
+
+ static void steal(meta_storage &to, meta_storage &from) {
+ to.instance = new (&to.storage) Type{std::move(*static_cast(from.instance))};
+ destroy(from);
+ }
+ };
+
+public:
+ /*! @brief Default constructor. */
+ meta_storage() ENTT_NOEXCEPT
+ : storage{},
+ instance{},
+ destroy_fn{},
+ copy_fn{},
+ steal_fn{}
+ {}
+
+ template
+ explicit meta_storage(std::in_place_type_t, [[maybe_unused]] Args &&... args)
+ : meta_storage{}
+ {
+ if constexpr(!std::is_void_v) {
+ type_traits::instance(*this, std::forward(args)...);
+ destroy_fn = &type_traits::destroy;
+ copy_fn = &type_traits::copy;
+ steal_fn = &type_traits::steal;
+ }
+ }
+
+ template
+ meta_storage(std::reference_wrapper value)
+ : meta_storage{}
+ {
+ instance = &value.get();
+ }
+
+ template>, meta_storage>>>
+ meta_storage(Type &&value)
+ : meta_storage{std::in_place_type>>, std::forward(value)}
+ {}
+
+ meta_storage(const meta_storage &other)
+ : meta_storage{}
+ {
+ (other.copy_fn ? other.copy_fn : [](auto &to, const auto &from) { to.instance = from.instance; })(*this, other);
+ destroy_fn = other.destroy_fn;
+ copy_fn = other.copy_fn;
+ steal_fn = other.steal_fn;
+ }
+
+ meta_storage(meta_storage &&other)
+ : meta_storage{}
+ {
+ swap(*this, other);
+ }
+
+ ~meta_storage() {
+ if(destroy_fn) {
+ destroy_fn(*this);
+ }
+ }
+
+ template
+ meta_storage & operator=(Type &&value) {
+ return (*this = meta_storage{std::forward(value)});
+ }
+
+ meta_storage & operator=(meta_storage other) {
+ swap(other, *this);
+ return *this;
+ }
+
+ [[nodiscard]] const void * data() const ENTT_NOEXCEPT {
+ return instance;
+ }
+
+ [[nodiscard]] void * data() ENTT_NOEXCEPT {
+ return const_cast(std::as_const(*this).data());
+ }
+
+ template
+ void emplace(Args &&... args) {
+ *this = meta_storage{std::in_place_type, std::forward(args)...};
+ }
+
+ [[nodiscard]] meta_storage ref() const ENTT_NOEXCEPT {
+ meta_storage other{};
+ other.instance = instance;
+ return other;
+ }
+
+ [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
+ return !(instance == nullptr);
+ }
+
+ friend void swap(meta_storage &lhs, meta_storage &rhs) {
+ if(lhs.steal_fn && rhs.steal_fn) {
+ meta_storage buffer{};
+ lhs.steal_fn(buffer, lhs);
+ rhs.steal_fn(lhs, rhs);
+ lhs.steal_fn(rhs, buffer);
+ } else if(lhs.steal_fn) {
+ lhs.steal_fn(rhs, lhs);
+ } else if(rhs.steal_fn) {
+ rhs.steal_fn(lhs, rhs);
+ } else {
+ std::swap(lhs.instance, rhs.instance);
+ }
+
+ std::swap(lhs.destroy_fn, rhs.destroy_fn);
+ std::swap(lhs.copy_fn, rhs.copy_fn);
+ std::swap(lhs.steal_fn, rhs.steal_fn);
+ }
+
+private:
+ storage_type storage;
+ void *instance;
+ destroy_fn_type *destroy_fn;
+ copy_fn_type *copy_fn;
+ steal_fn_type *steal_fn;
+};
+
+
struct meta_type_node;
@@ -43,7 +210,7 @@ struct meta_base_node {
meta_type_node * const parent;
meta_base_node * next;
meta_type_node *(* const type)() ENTT_NOEXCEPT;
- void *(* const cast)(void *) ENTT_NOEXCEPT;
+ const void *(* const cast)(const void *) ENTT_NOEXCEPT;
};
diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp
index 6b8339900..a600d0e0b 100644
--- a/src/entt/meta/meta.hpp
+++ b/src/entt/meta/meta.hpp
@@ -79,63 +79,6 @@ private:
* of memory allocations if possible. This should improve overall performance.
*/
class meta_any {
- using storage_type = std::aligned_storage_t;
- using copy_fn_type = void(meta_any &, const meta_any &);
- using steal_fn_type = void(meta_any &, meta_any &);
- using destroy_fn_type = void(meta_any &);
-
- template>
- struct type_traits {
- template
- static void instance(meta_any &any, Args &&... args) {
- any.instance = new Type{std::forward(args)...};
- new (&any.storage) Type *{static_cast(any.instance)};
- }
-
- static void destroy(meta_any &any) {
- if(const auto * const node = internal::meta_info::resolve(); node->dtor) {
- node->dtor->invoke(any.instance);
- }
-
- delete static_cast(any.instance);
- }
-
- static void copy(meta_any &to, const meta_any &from) {
- to.instance = new Type{*static_cast(from.instance)};
- new (&to.storage) Type *{static_cast(to.instance)};
- }
-
- static void steal(meta_any &to, meta_any &from) {
- new (&to.storage) Type *{static_cast(from.instance)};
- to.instance = from.instance;
- }
- };
-
- template
- struct type_traits>> {
- template
- static void instance(meta_any &any, Args &&... args) {
- any.instance = new (&any.storage) Type{std::forward(args)...};
- }
-
- static void destroy(meta_any &any) {
- if(const auto * const node = internal::meta_info::resolve(); node->dtor) {
- node->dtor->invoke(any.instance);
- }
-
- static_cast(any.instance)->~Type();
- }
-
- static void copy(meta_any &to, const meta_any &from) {
- to.instance = new (&to.storage) Type{*static_cast(from.instance)};
- }
-
- static void steal(meta_any &to, meta_any &from) {
- to.instance = new (&to.storage) Type{std::move(*static_cast(from.instance))};
- destroy(from);
- }
- };
-
template
struct container_view {
[[nodiscard]] static meta_container::meta_view * instance() {
@@ -293,11 +236,7 @@ public:
/*! @brief Default constructor. */
meta_any() ENTT_NOEXCEPT
: storage{},
- instance{},
node{},
- destroy_fn{},
- copy_fn{},
- steal_fn{},
cview{}
{}
@@ -309,18 +248,10 @@ public:
*/
template
explicit meta_any(std::in_place_type_t, [[maybe_unused]] Args &&... args)
- : meta_any{}
- {
- node = internal::meta_info::resolve();
-
- if constexpr(!std::is_void_v) {
- type_traits::instance(*this, std::forward(args)...);
- destroy_fn = &type_traits::destroy;
- copy_fn = &type_traits::copy;
- steal_fn = &type_traits::steal;
- cview = container_view::instance();
- }
- }
+ : storage(std::in_place_type, std::forward(args)...),
+ node{internal::meta_info::resolve()},
+ cview{container_view::instance()}
+ {}
/**
* @brief Constructs a meta any that holds an unmanaged object.
@@ -329,12 +260,10 @@ public:
*/
template
meta_any(std::reference_wrapper value)
- : meta_any{}
- {
- node = internal::meta_info::resolve();
- instance = &value.get();
- cview = container_view::instance();
- }
+ : storage{value},
+ node{internal::meta_info::resolve()},
+ cview{container_view::instance()}
+ {}
/**
* @brief Constructs a meta any from a given value.
@@ -351,15 +280,10 @@ public:
* @param other The instance to copy from.
*/
meta_any(const meta_any &other)
- : meta_any{}
- {
- node = other.node;
- (other.copy_fn ? other.copy_fn : [](meta_any &to, const meta_any &from) { to.instance = from.instance; })(*this, other);
- destroy_fn = other.destroy_fn;
- copy_fn = other.copy_fn;
- steal_fn = other.steal_fn;
- cview = other.cview;
- }
+ : storage{other.storage},
+ node{other.node},
+ cview{other.cview}
+ {}
/**
* @brief Move constructor.
@@ -373,8 +297,8 @@ public:
/*! @brief Frees the internal storage, whatever it means. */
~meta_any() {
- if(destroy_fn) {
- destroy_fn(*this);
+ if(node && node->dtor) {
+ node->dtor->invoke(storage.data());
}
}
@@ -410,12 +334,12 @@ public:
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] const void * data() const ENTT_NOEXCEPT {
- return instance;
+ return storage.data();
}
/*! @copydoc data */
[[nodiscard]] void * data() ENTT_NOEXCEPT {
- return const_cast(std::as_const(*this).data());
+ return storage.data();
}
/**
@@ -425,13 +349,13 @@ public:
*/
template
[[nodiscard]] const Type * try_cast() const {
- void *ret = nullptr;
+ const void *ret = nullptr;
if(node) {
if(const auto type_id = internal::meta_info::resolve()->type_id; node->type_id == type_id) {
- ret = instance;
+ ret = storage.data();
} else if(const auto *base = internal::find_if<&internal::meta_type_node::base>([type_id](const auto *curr) { return curr->type()->type_id == type_id; }, node); base) {
- ret = base->cast(instance);
+ ret = base->cast(storage.data());
}
}
@@ -485,7 +409,7 @@ public:
if(const auto type_id = internal::meta_info::resolve()->type_id; node->type_id == type_id) {
any = *this;
} else if(const auto * const conv = internal::find_if<&internal::meta_type_node::conv>([type_id](const auto *curr) { return curr->type()->type_id == type_id; }, node); conv) {
- any = conv->conv(instance);
+ any = conv->conv(storage.data());
}
}
@@ -527,19 +451,19 @@ public:
* @return A meta any that shares a reference to an unmanaged object.
*/
[[nodiscard]] meta_any ref() const ENTT_NOEXCEPT {
- meta_any alias{};
- alias.node = node;
- alias.instance = instance;
- alias.cview = cview;
- return alias;
+ meta_any other{};
+ other.node = node;
+ other.storage = storage.ref();
+ other.cview = cview;
+ return other;
}
/**
* @brief Returns a container view.
* @return A container view for the underlying object.
*/
- [[nodiscard]] meta_container view() const ENTT_NOEXCEPT {
- return { cview, instance };
+ [[nodiscard]] meta_container view() ENTT_NOEXCEPT {
+ return { cview, storage.data() };
}
/**
@@ -564,7 +488,7 @@ public:
* @return False if the two objects differ in their content, true otherwise.
*/
[[nodiscard]] bool operator==(const meta_any &other) const {
- return (!node && !other.node) || (node && other.node && node->type_id == other.node->type_id && node->compare(instance, other.instance));
+ return (!node && !other.node) || (node && other.node && node->type_id == other.node->type_id && node->compare(storage.data(), other.storage.data()));
}
/**
@@ -573,33 +497,14 @@ public:
* @param rhs A valid meta any object.
*/
friend void swap(meta_any &lhs, meta_any &rhs) {
- if(lhs.steal_fn && rhs.steal_fn) {
- meta_any buffer{};
- lhs.steal_fn(buffer, lhs);
- rhs.steal_fn(lhs, rhs);
- lhs.steal_fn(rhs, buffer);
- } else if(lhs.steal_fn) {
- lhs.steal_fn(rhs, lhs);
- } else if(rhs.steal_fn) {
- rhs.steal_fn(lhs, rhs);
- } else {
- std::swap(lhs.instance, rhs.instance);
- }
-
std::swap(lhs.node, rhs.node);
- std::swap(lhs.destroy_fn, rhs.destroy_fn);
- std::swap(lhs.copy_fn, rhs.copy_fn);
- std::swap(lhs.steal_fn, rhs.steal_fn);
+ std::swap(lhs.storage, rhs.storage);
std::swap(lhs.cview, rhs.cview);
}
private:
- storage_type storage;
- void *instance;
+ internal::meta_storage storage;
const internal::meta_type_node *node;
- destroy_fn_type *destroy_fn;
- copy_fn_type *copy_fn;
- steal_fn_type *steal_fn;
meta_container::meta_view *cview;
};
@@ -896,7 +801,7 @@ struct meta_base {
* @param instance The instance to cast.
* @return An opaque pointer to the base type.
*/
- [[nodiscard]] void * cast(void *instance) const ENTT_NOEXCEPT {
+ [[nodiscard]] const void * cast(const void *instance) const ENTT_NOEXCEPT {
return node->cast(instance);
}