Jelajahi Sumber

meta_any: single vtable function to reduce instantiations and storage requirements

Michele Caini 5 tahun lalu
induk
melakukan
d7ed72ac06
1 mengubah file dengan 45 tambahan dan 57 penghapusan
  1. 45 57
      src/entt/meta/meta.hpp

+ 45 - 57
src/entt/meta/meta.hpp

@@ -164,42 +164,36 @@ private:
  * of memory allocations if possible. This should improve overall performance.
  */
 class meta_any {
-    using dereference_operator_type = meta_any(meta_any &);
+    enum class operation { DEREF, SEQ, ASSOC };
 
-    template<typename Type>
-    [[nodiscard]] static meta_any dereference_operator(meta_any &any) {
-        if constexpr(is_meta_pointer_like_v<Type>) {
-            using pointed_type = std::remove_reference_t<decltype(*std::declval<Type>())>;
-
-            if constexpr(std::is_const_v<pointed_type> && std::is_copy_constructible_v<pointed_type>) {
-                auto ptr = any.cast<Type>();
-                return ptr ? std::as_const(*ptr) : meta_any{};
-            } else if constexpr(!std::is_const_v<pointed_type>) {
-                auto ptr = any.cast<Type>();
-                return ptr ? std::ref(*ptr) : meta_any{};
-            } else {
-                return {};
-            }
-        } else {
-            return {};
-        }
-    }
-
-    template<typename Type>
-    [[nodiscard]] static meta_sequence_container meta_sequence_container_factory([[maybe_unused]] void *container) ENTT_NOEXCEPT {
-        if constexpr(has_meta_sequence_container_traits_v<Type>) {
-            return static_cast<Type *>(container);
-        } else {
-            return {};
-        }
-    }
+    using vtable_type = void(const operation, meta_any &, void *);
 
     template<typename Type>
-    [[nodiscard]] static meta_associative_container meta_associative_container_factory([[maybe_unused]] void *container) ENTT_NOEXCEPT {
-        if constexpr(has_meta_associative_container_traits_v<Type>) {
-            return static_cast<Type *>(container);
-        } else {
-            return {};
+    static void basic_vtable(const operation op, [[maybe_unused]] meta_any &from, [[maybe_unused]] void *to) {
+        switch(op) {
+        case operation::DEREF:
+            if constexpr(is_meta_pointer_like_v<Type>) {
+                if(auto ptr = from.cast<Type>(); ptr) {
+                    using pointed_type = std::remove_reference_t<decltype(*std::declval<Type>())>;
+
+                    if constexpr(std::is_const_v<pointed_type> && std::is_copy_constructible_v<pointed_type>) {
+                        *static_cast<meta_any *>(to) = std::as_const(*ptr);
+                    } else if constexpr(!std::is_const_v<pointed_type>) {
+                        *static_cast<meta_any *>(to) = std::ref(*ptr);
+                    }
+                }
+            }
+            break;
+        case operation::SEQ:
+            if constexpr(has_meta_sequence_container_traits_v<Type>) {
+                *static_cast<meta_sequence_container *>(to) = static_cast<Type *>(from.data());
+            }
+            break;
+        case operation::ASSOC:
+            if constexpr(has_meta_associative_container_traits_v<Type>) {
+                *static_cast<meta_associative_container *>(to) = static_cast<Type *>(from.data());
+            }
+            break;
         }
     }
 
@@ -207,10 +201,8 @@ public:
     /*! @brief Default constructor. */
     meta_any() ENTT_NOEXCEPT
         : storage{},
-          node{},
-          deref{nullptr},
-          seq_factory{nullptr},
-          assoc_factory{nullptr}
+          vtable{},
+          node{}
     {}
 
     /**
@@ -222,10 +214,8 @@ public:
     template<typename Type, typename... Args>
     explicit meta_any(std::in_place_type_t<Type>, [[maybe_unused]] Args &&... args)
         : storage(std::in_place_type<Type>, std::forward<Args>(args)...),
-          node{internal::meta_info<Type>::resolve()},
-          deref{&dereference_operator<Type>},
-          seq_factory{&meta_sequence_container_factory<Type>},
-          assoc_factory{&meta_associative_container_factory<Type>}
+          vtable{&basic_vtable<Type>},
+          node{internal::meta_info<Type>::resolve()}
     {}
 
     /**
@@ -236,10 +226,8 @@ public:
     template<typename Type>
     meta_any(std::reference_wrapper<Type> value)
         : storage{value},
-          node{internal::meta_info<Type>::resolve()},
-          deref{&dereference_operator<Type>},
-          seq_factory{&meta_sequence_container_factory<Type>},
-          assoc_factory{&meta_associative_container_factory<Type>}
+          vtable{&basic_vtable<Type>},
+          node{internal::meta_info<Type>::resolve()}
     {}
 
     /**
@@ -444,9 +432,7 @@ public:
         meta_any other{};
         other.node = node;
         other.storage = storage.ref();
-        other.deref = deref;
-        other.seq_factory = seq_factory;
-        other.assoc_factory = assoc_factory;
+        other.vtable = vtable;
         return other;
     }
 
@@ -455,7 +441,9 @@ public:
      * @return A sequence container proxy for the underlying object.
      */
     [[nodiscard]] meta_sequence_container as_sequence_container() ENTT_NOEXCEPT {
-        return seq_factory(storage.data());
+        meta_sequence_container proxy;
+        vtable(operation::SEQ, *this, &proxy);
+        return proxy;
     }
 
     /**
@@ -463,7 +451,9 @@ public:
      * @return An associative container proxy for the underlying object.
      */
     [[nodiscard]] meta_associative_container as_associative_container() ENTT_NOEXCEPT {
-        return assoc_factory(storage.data());
+        meta_associative_container proxy;
+        vtable(operation::ASSOC, *this, &proxy);
+        return proxy;
     }
 
     /**
@@ -472,7 +462,9 @@ public:
      * wrapped element is dereferenceable, an invalid meta any otherwise.
      */
     [[nodiscard]] meta_any operator*() ENTT_NOEXCEPT {
-        return deref(*this);
+        meta_any any{};
+        vtable(operation::DEREF, *this, &any);
+        return any;
     }
 
     /**
@@ -500,18 +492,14 @@ public:
     friend void swap(meta_any &lhs, meta_any &rhs) {
         using std::swap;
         swap(lhs.storage, rhs.storage);
+        swap(lhs.vtable, rhs.vtable);
         swap(lhs.node, rhs.node);
-        swap(lhs.deref, rhs.deref);
-        swap(lhs.seq_factory, rhs.seq_factory);
-        swap(lhs.assoc_factory, rhs.assoc_factory);
     }
 
 private:
     any storage;
+    vtable_type *vtable;
     internal::meta_type_node *node;
-    dereference_operator_type *deref;
-    meta_sequence_container(* seq_factory)(void *);
-    meta_associative_container(* assoc_factory)(void *);
 };