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