Explorar el Código

meta: split meta_storage from meta_any

Michele Caini hace 5 años
padre
commit
e113fa53a4
Se han modificado 4 ficheros con 202 adiciones y 129 borrados
  1. 1 0
      TODO
  2. 2 2
      src/entt/meta/factory.hpp
  3. 168 1
      src/entt/meta/internal.hpp
  4. 31 126
      src/entt/meta/meta.hpp

+ 1 - 0
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

+ 2 - 2
src/entt/meta/factory.hpp

@@ -374,8 +374,8 @@ public:
             type,
             nullptr,
             &internal::meta_info<Base>::resolve,
-            [](void *instance) ENTT_NOEXCEPT -> void * {
-                return static_cast<Base *>(static_cast<Type *>(instance));
+            [](const void *instance) ENTT_NOEXCEPT -> const void * {
+                return static_cast<const Base *>(static_cast<const Type *>(instance));
             }
         };
 

+ 168 - 1
src/entt/meta/internal.hpp

@@ -3,6 +3,7 @@
 
 
 #include <cstddef>
+#include <functional>
 #include <iterator>
 #include <type_traits>
 #include <utility>
@@ -29,6 +30,172 @@ struct meta_handle;
 namespace internal {
 
 
+class meta_storage {
+    using storage_type = std::aligned_storage_t<sizeof(void *), alignof(void *)>;
+    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<typename Type, typename = std::void_t<>>
+    struct type_traits {
+        template<typename... Args>
+        static void instance(meta_storage &buffer, Args &&... args) {
+            buffer.instance = new Type{std::forward<Args>(args)...};
+            new (&buffer.storage) Type *{static_cast<Type *>(buffer.instance)};
+        }
+
+        static void destroy(meta_storage &buffer) {
+            delete static_cast<Type *>(buffer.instance);
+        }
+
+        static void copy(meta_storage &to, const meta_storage &from) {
+            to.instance = new Type{*static_cast<const Type *>(from.instance)};
+            new (&to.storage) Type *{static_cast<Type *>(to.instance)};
+        }
+
+        static void steal(meta_storage &to, meta_storage &from) {
+            new (&to.storage) Type *{static_cast<Type *>(from.instance)};
+            to.instance = from.instance;
+        }
+    };
+
+    template<typename Type>
+    struct type_traits<Type, std::enable_if_t<sizeof(Type) <= sizeof(void *) && std::is_nothrow_move_constructible_v<Type>>> {
+        template<typename... Args>
+        static void instance(meta_storage &buffer, Args &&... args) {
+            buffer.instance = new (&buffer.storage) Type{std::forward<Args>(args)...};
+        }
+
+        static void destroy(meta_storage &buffer) {
+            static_cast<Type *>(buffer.instance)->~Type();
+        }
+
+        static void copy(meta_storage &to, const meta_storage &from) {
+            to.instance = new (&to.storage) Type{*static_cast<const Type *>(from.instance)};
+        }
+
+        static void steal(meta_storage &to, meta_storage &from) {
+            to.instance = new (&to.storage) Type{std::move(*static_cast<Type *>(from.instance))};
+            destroy(from);
+        }
+    };
+
+public:
+    /*! @brief Default constructor. */
+    meta_storage() ENTT_NOEXCEPT
+        : storage{},
+          instance{},
+          destroy_fn{},
+          copy_fn{},
+          steal_fn{}
+    {}
+
+    template<typename Type, typename... Args>
+    explicit meta_storage(std::in_place_type_t<Type>, [[maybe_unused]] Args &&... args)
+        : meta_storage{}
+    {
+        if constexpr(!std::is_void_v<Type>) {
+            type_traits<Type>::instance(*this, std::forward<Args>(args)...);
+            destroy_fn = &type_traits<Type>::destroy;
+            copy_fn = &type_traits<Type>::copy;
+            steal_fn = &type_traits<Type>::steal;
+        }
+    }
+
+    template<typename Type>
+    meta_storage(std::reference_wrapper<Type> value)
+        : meta_storage{}
+    {
+        instance = &value.get();
+    }
+
+    template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, meta_storage>>>
+    meta_storage(Type &&value)
+        : meta_storage{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(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<typename Type>
+    meta_storage & operator=(Type &&value) {
+        return (*this = meta_storage{std::forward<Type>(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<void *>(std::as_const(*this).data());
+    }
+
+    template<typename Type, typename... Args>
+    void emplace(Args &&... args) {
+        *this = meta_storage{std::in_place_type<Type>, std::forward<Args>(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;
 };
 
 

+ 31 - 126
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<sizeof(void *), alignof(void *)>;
-    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<typename Type, typename = std::void_t<>>
-    struct type_traits {
-        template<typename... Args>
-        static void instance(meta_any &any, Args &&... args) {
-            any.instance = new Type{std::forward<Args>(args)...};
-            new (&any.storage) Type *{static_cast<Type *>(any.instance)};
-        }
-
-        static void destroy(meta_any &any) {
-            if(const auto * const node = internal::meta_info<Type>::resolve(); node->dtor) {
-                node->dtor->invoke(any.instance);
-            }
-
-            delete static_cast<Type *>(any.instance);
-        }
-
-        static void copy(meta_any &to, const meta_any &from) {
-            to.instance = new Type{*static_cast<const Type *>(from.instance)};
-            new (&to.storage) Type *{static_cast<Type *>(to.instance)};
-        }
-
-        static void steal(meta_any &to, meta_any &from) {
-            new (&to.storage) Type *{static_cast<Type *>(from.instance)};
-            to.instance = from.instance;
-        }
-    };
-
-    template<typename Type>
-    struct type_traits<Type, std::enable_if_t<sizeof(Type) <= sizeof(void *) && std::is_nothrow_move_constructible_v<Type>>> {
-        template<typename... Args>
-        static void instance(meta_any &any, Args &&... args) {
-            any.instance = new (&any.storage) Type{std::forward<Args>(args)...};
-        }
-
-        static void destroy(meta_any &any) {
-            if(const auto * const node = internal::meta_info<Type>::resolve(); node->dtor) {
-                node->dtor->invoke(any.instance);
-            }
-
-            static_cast<Type *>(any.instance)->~Type();
-        }
-
-        static void copy(meta_any &to, const meta_any &from) {
-            to.instance = new (&to.storage) Type{*static_cast<const Type *>(from.instance)};
-        }
-
-        static void steal(meta_any &to, meta_any &from) {
-            to.instance = new (&to.storage) Type{std::move(*static_cast<Type *>(from.instance))};
-            destroy(from);
-        }
-    };
-
     template<typename, typename = void>
     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<typename Type, typename... Args>
     explicit meta_any(std::in_place_type_t<Type>, [[maybe_unused]] Args &&... args)
-        : meta_any{}
-    {
-        node = internal::meta_info<Type>::resolve();
-
-        if constexpr(!std::is_void_v<Type>) {
-            type_traits<Type>::instance(*this, std::forward<Args>(args)...);
-            destroy_fn = &type_traits<Type>::destroy;
-            copy_fn = &type_traits<Type>::copy;
-            steal_fn = &type_traits<Type>::steal;
-            cview = container_view<Type>::instance();
-        }
-    }
+        : storage(std::in_place_type<Type>, std::forward<Args>(args)...),
+          node{internal::meta_info<Type>::resolve()},
+          cview{container_view<Type>::instance()}
+    {}
 
     /**
      * @brief Constructs a meta any that holds an unmanaged object.
@@ -329,12 +260,10 @@ public:
      */
     template<typename Type>
     meta_any(std::reference_wrapper<Type> value)
-        : meta_any{}
-    {
-        node = internal::meta_info<Type>::resolve();
-        instance = &value.get();
-        cview = container_view<Type>::instance();
-    }
+        : storage{value},
+          node{internal::meta_info<Type>::resolve()},
+          cview{container_view<Type>::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<void *>(std::as_const(*this).data());
+        return storage.data();
     }
 
     /**
@@ -425,13 +349,13 @@ public:
      */
     template<typename Type>
     [[nodiscard]] const Type * try_cast() const {
-        void *ret = nullptr;
+        const void *ret = nullptr;
 
         if(node) {
             if(const auto type_id = internal::meta_info<Type>::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<Type>::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);
     }