Răsfoiți Sursa

meta_any: drastically reduce the number of instantiations/size of vtable

Michele Caini 4 ani în urmă
părinte
comite
3576c80d33
2 a modificat fișierele cu 40 adăugiri și 41 ștergeri
  1. 1 0
      TODO
  2. 39 41
      src/entt/meta/meta.hpp

+ 1 - 0
TODO

@@ -10,6 +10,7 @@ WIP:
 * isolate view iterator, unwrap iterators in registry ::remove/::erase/::destroy to use the faster solution for non-view iterators
 * compressed pair to exploit ebo in sparse set and the others
 * rename sparse_set::entity_type (and the others) to value_type
+* meta: use forward_as_any to forward arguments from eg meta_func::invoke, so as to remove the need for the user to explicitly forward references
 * any/meta: remove dependency on <functional> (reference_wrapper, invoke), remove meta_any::type and use something like entt::type_from_meta
 * scheduler, use any (or poly?) instead of unique_ptr
 * resource, forward the id to the loader from the cache and if constexpr the call to load, update doc and describe customization points

+ 39 - 41
src/entt/meta/meta.hpp

@@ -156,76 +156,76 @@ private:
 
 /*! @brief Opaque wrapper for values of any type. */
 class meta_any {
-    enum class operation { DTOR, REF, CREF, DEREF, CDEREF, SEQ, CSEQ, ASSOC, CASSOC };
+    enum class operation { DTOR, DEREF, CDEREF, SEQ, CSEQ, ASSOC, CASSOC };
 
     using vtable_type = void(const operation, const any &, void *);
 
     template<typename Type>
     static void basic_vtable(const operation op, [[maybe_unused]] const any &from, [[maybe_unused]] void *to) {
+        static_assert(std::is_same_v<std::remove_reference_t<std::remove_const_t<Type>>, Type>, "Invalid type");
+
         if constexpr(!std::is_void_v<Type>) {
             switch(op) {
             case operation::DTOR:
-                if constexpr(!std::is_lvalue_reference_v<Type>) {
-                    if(auto *curr = static_cast<internal::meta_type_node *>(to); curr->dtor) {
-                        curr->dtor(const_cast<any &>(from).data());
-                    }
+                if(auto *curr = static_cast<internal::meta_type_node *>(to); curr->dtor && from.owner()) {
+                    curr->dtor(const_cast<any &>(from).data());
                 }
                 break;
-            case operation::REF:
-                static_cast<meta_any *>(to)->emplace<Type &>(any_cast<Type &>(const_cast<any &>(from)));
-                break;
-            case operation::CREF:
-                static_cast<meta_any *>(to)->emplace<const std::remove_reference_t<Type> &>(any_cast<const std::remove_reference_t<Type> &>(from));
-                break;
             case operation::DEREF:
-                if constexpr(is_meta_pointer_like_v<std::remove_const_t<std::remove_reference_t<Type>>>) {
-                    using element_type = std::remove_const_t<typename std::pointer_traits<std::decay_t<Type>>::element_type>;
+                if constexpr(is_meta_pointer_like_v<Type>) {
+                    using element_type = std::remove_const_t<typename std::pointer_traits<Type>::element_type>;
 
                     if constexpr(std::is_function_v<element_type>) {
-                        *static_cast<meta_any *>(to) = any_cast<std::decay_t<Type>>(from);
-                    } else if constexpr(!std::is_same_v<std::remove_const_t<typename std::pointer_traits<std::decay_t<Type>>::element_type>, void>) {
-                        using in_place_type = decltype(adl_meta_pointer_like<std::decay_t<Type>>::dereference(any_cast<const std::decay_t<Type> &>(from)));
-                        static_cast<meta_any *>(to)->emplace<in_place_type>(adl_meta_pointer_like<std::decay_t<Type>>::dereference(any_cast<const std::decay_t<Type> &>(from)));
+                        *static_cast<meta_any *>(to) = any_cast<Type>(from);
+                    } else if constexpr(!std::is_same_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>, void>) {
+                        using in_place_type = decltype(adl_meta_pointer_like<Type>::dereference(any_cast<const Type &>(from)));
+                        static_cast<meta_any *>(to)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(any_cast<const Type &>(from)));
                     }
                 }
                 break;
             case operation::CDEREF:
-                if constexpr(is_meta_pointer_like_v<std::remove_const_t<std::remove_reference_t<Type>>>) {
-                    using element_type = std::remove_const_t<typename std::pointer_traits<std::decay_t<Type>>::element_type>;
+                if constexpr(is_meta_pointer_like_v<Type>) {
+                    using element_type = std::remove_const_t<typename std::pointer_traits<Type>::element_type>;
 
                     if constexpr(std::is_function_v<element_type>) {
-                        *static_cast<meta_any *>(to) = any_cast<std::decay_t<Type>>(from);
-                    } else if constexpr(!std::is_same_v<std::remove_const_t<typename std::pointer_traits<std::decay_t<Type>>::element_type>, void>) {
-                        using deref_type = decltype(adl_meta_pointer_like<std::decay_t<Type>>::dereference(any_cast<const std::decay_t<Type> &>(from)));
+                        *static_cast<meta_any *>(to) = any_cast<Type>(from);
+                    } else if constexpr(!std::is_same_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>, void>) {
+                        using deref_type = decltype(adl_meta_pointer_like<Type>::dereference(any_cast<const Type &>(from)));
                         using in_place_type = std::conditional_t<std::is_lvalue_reference_v<deref_type>, const std::remove_reference_t<deref_type> &, deref_type>;
-                        static_cast<meta_any *>(to)->emplace<in_place_type>(adl_meta_pointer_like<std::decay_t<Type>>::dereference(any_cast<const std::decay_t<Type> &>(from)));
+                        static_cast<meta_any *>(to)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(any_cast<const Type &>(from)));
                     }
                 }
                 break;
             case operation::SEQ:
-                if constexpr(is_complete_v<meta_sequence_container_traits<std::decay_t<Type>>>) {
-                    *static_cast<meta_sequence_container *>(to) = { std::in_place_type<std::decay_t<Type>>, const_cast<any &>(from).as_ref() };
+                if constexpr(is_complete_v<meta_sequence_container_traits<Type>>) {
+                    *static_cast<meta_sequence_container *>(to) = { std::in_place_type<Type>, const_cast<any &>(from).as_ref() };
                 }
                 break;
             case operation::CSEQ:
-                if constexpr(is_complete_v<meta_sequence_container_traits<std::decay_t<Type>>>) {
-                    *static_cast<meta_sequence_container *>(to) = { std::in_place_type<std::decay_t<Type>>, from.as_ref() };
+                if constexpr(is_complete_v<meta_sequence_container_traits<Type>>) {
+                    *static_cast<meta_sequence_container *>(to) = { std::in_place_type<Type>, from.as_ref() };
                 }
                 break;
             case operation::ASSOC:
-                if constexpr(is_complete_v<meta_associative_container_traits<std::decay_t<Type>>>) {
-                    *static_cast<meta_associative_container *>(to) = { std::in_place_type<std::decay_t<Type>>, const_cast<any &>(from).as_ref() };
+                if constexpr(is_complete_v<meta_associative_container_traits<Type>>) {
+                    *static_cast<meta_associative_container *>(to) = { std::in_place_type<Type>, const_cast<any &>(from).as_ref() };
                 }
                 break;
             case operation::CASSOC:
-                if constexpr(is_complete_v<meta_associative_container_traits<std::decay_t<Type>>>) {
-                    *static_cast<meta_associative_container *>(to) = { std::in_place_type<std::decay_t<Type>>, from.as_ref() };
+                if constexpr(is_complete_v<meta_associative_container_traits<Type>>) {
+                    *static_cast<meta_associative_container *>(to) = { std::in_place_type<Type>, from.as_ref() };
                 }
                 break;
             }
         }
     }
 
+    meta_any(const meta_any &other, any ref) ENTT_NOEXCEPT
+        : storage{std::move(ref)},
+          node{storage ? other.node : nullptr},
+          vtable{storage ? other.vtable : &basic_vtable<void>}
+    {}
+
 public:
     /*! @brief Default constructor. */
     meta_any() ENTT_NOEXCEPT
@@ -244,7 +244,7 @@ public:
     explicit meta_any(std::in_place_type_t<Type>, Args &&... args)
         : storage{std::in_place_type<Type>, std::forward<Args>(args)...},
           node{internal::meta_info<Type>::resolve()},
-          vtable{&basic_vtable<Type>}
+          vtable{&basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>}
     {}
 
     /**
@@ -267,7 +267,9 @@ public:
      */
     template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
     meta_any(Type &&value)
-        : meta_any{std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)}
+        : storage{std::forward<Type>(value)},
+          node{internal::meta_info<std::decay_t<Type>>::resolve()},
+          vtable{&basic_vtable<std::decay_t<Type>>}
     {}
 
     /**
@@ -308,7 +310,7 @@ public:
      * @param other The instance to move from.
      * @return This meta any object.
      */
-    meta_any & operator=(meta_any &&other) {
+    meta_any & operator=(meta_any &&other) ENTT_NOEXCEPT {
         std::exchange(vtable, std::exchange(other.vtable, &basic_vtable<void>))(operation::DTOR, storage, node);
         storage = std::move(other.storage);
         node = std::exchange(other.node, nullptr);
@@ -507,7 +509,7 @@ public:
      */
     template<typename Type, typename... Args>
     void emplace(Args &&... args) {
-        std::exchange(vtable, &basic_vtable<Type>)(operation::DTOR, storage, node);
+        std::exchange(vtable, &basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>)(operation::DTOR, storage, node);
         storage.emplace<Type>(std::forward<Args>(args)...);
         node = internal::meta_info<Type>::resolve();
     }
@@ -593,16 +595,12 @@ public:
      * @return A wrapper that shares a reference to an unmanaged object.
      */
     [[nodiscard]] meta_any as_ref() ENTT_NOEXCEPT {
-        meta_any ref{};
-        vtable(operation::REF, storage, &ref);
-        return ref;
+        return meta_any{*this, storage.as_ref()};
     }
 
     /*! @copydoc as_ref */
     [[nodiscard]] meta_any as_ref() const ENTT_NOEXCEPT {
-        meta_any ref{};
-        vtable(operation::CREF, storage, &ref);
-        return ref;
+        return meta_any{*this, storage.as_ref()};
     }
 
 private: