Răsfoiți Sursa

meta: reduced instantiations due to meta any, use a fake vtable function

Michele Caini 5 ani în urmă
părinte
comite
cd0ec69446
2 a modificat fișierele cu 57 adăugiri și 71 ștergeri
  1. 1 5
      TODO
  2. 56 66
      src/entt/meta/internal.hpp

+ 1 - 5
TODO

@@ -2,7 +2,6 @@
 * custom allocators and EnTT allocator-aware in general (long term feature, I don't actually need it at the moment) - see #22
 * debugging tools (#60): the issue online already contains interesting tips on this, look at it
 * work stealing job system (see #100) + mt scheduler based on const awareness for types
-* meta: sort of meta view based on meta stuff to iterate entities, void * and meta info objects (remove runtime views, welcome reflection)
 * allow to replace std:: with custom implementations
 * add examples (and credits) from @alanjfs :)
 * static reflection, hint: template<> meta_type_t<Type>: meta_descriptor<name, func..., props..., etc...> (see #342)
@@ -19,17 +18,14 @@
   - ...
 
 WIP:
-* HP: headless view
-* HP: inject the registry to pools rather than passing it every time (fake vtable prep)
+* HP: headless (sparse set only) view
 * HP: fake vtable, see dino:: for a reasonable and customizable (pay-per-use) approach
-* HP: meta any/meta container: reduce instantiations with a single function fake vtable
 * HP: make view pack work also with groups, make packs input iterator only, add view adapter for external sources
 * HP: write documentation for custom storages and views!!
 * suppress warnings in meta.hpp (uninitialized members)
 * add exclude-only views to combine with packs
 * deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
 * view pack: plain function as an alias for operator|, reverse iterators, rbegin and rend
-* what about using hashed string rather than hash values for meta types?
 * pagination doesn't work nicely across boundaries probably, give it a look. RO operations are fine, adding components maybe not.
 * add observer functions aside observer class
 * snapshot: support for range-based archives

+ 56 - 66
src/entt/meta/internal.hpp

@@ -32,52 +32,55 @@ namespace internal {
 
 
 class meta_storage {
+    enum class operation { COPY, MOVE, DTOR };
+
     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 &);
+    using vtable_type = void(const operation, meta_storage &, void *);
 
     template<typename Type, typename = void>
     struct type_traits {
         template<typename... Args>
-        static void instance(meta_storage &buffer, Args &&... args) {
+        static void ctor(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;
+        static void vtable(const operation op, meta_storage &self, void *instance) {
+            switch(op) {
+            case operation::COPY:
+                self.instance = new Type{std::as_const(*static_cast<Type *>(instance))};
+                new (&self.storage) Type *{static_cast<Type *>(self.instance)};
+                break;
+            case operation::MOVE:
+                new (&self.storage) Type *{static_cast<Type *>(instance)};
+                self.instance = instance;
+                break;
+            case operation::DTOR:
+                delete static_cast<Type *>(instance);
+                break;
+            }
         }
     };
 
     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) {
+        static void ctor(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);
+        static void vtable(const operation op, meta_storage &self, void *instance) {
+            switch(op) {
+            case operation::COPY:
+                self.instance = new (&self.storage) Type{std::as_const(*static_cast<Type *>(instance))};
+                break;
+            case operation::MOVE:
+                self.instance = new (&self.storage) Type{std::move(*static_cast<Type *>(instance))};
+                [[fallthrough]];
+            case operation::DTOR:
+                static_cast<Type *>(instance)->~Type();
+                break;
+            }
         }
     };
 
@@ -85,10 +88,8 @@ public:
     /*! @brief Default constructor. */
     meta_storage() ENTT_NOEXCEPT
         : storage{},
-          instance{},
-          destroy_fn{},
-          copy_fn{},
-          steal_fn{}
+          vtable{},
+          instance{}
     {}
 
     template<typename Type, typename... Args>
@@ -96,10 +97,8 @@ public:
         : 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;
+            type_traits<Type>::ctor(*this, std::forward<Args>(args)...);
+            vtable = &type_traits<Type>::vtable;
         }
     }
 
@@ -118,26 +117,32 @@ public:
     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;
+        if(vtable = other.vtable; vtable) {
+            vtable(operation::COPY, *this, other.instance);
+        } else {
+            instance = other.instance;
+        }
     }
 
-    meta_storage(meta_storage &&other)
+    meta_storage(meta_storage &&other) ENTT_NOEXCEPT
         : meta_storage{}
     {
-        swap(*this, other);
+        if(vtable = other.vtable; vtable) {
+            vtable(operation::MOVE, *this, other.instance);
+            other.vtable = nullptr;
+        } else {
+            instance = other.instance;
+        }
     }
 
     ~meta_storage() {
-        if(destroy_fn) {
-            destroy_fn(*this);
+        if(vtable) {
+            vtable(operation::DTOR, *this, instance);
         }
     }
 
     meta_storage & operator=(meta_storage other) {
-        swap(other, *this);
+        swap(*this, other);
         return *this;
     }
 
@@ -165,32 +170,17 @@ public:
     }
 
     friend void swap(meta_storage &lhs, meta_storage &rhs) {
-        using std::swap;
-
-        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 {
-            swap(lhs.instance, rhs.instance);
-        }
-
-        swap(lhs.destroy_fn, rhs.destroy_fn);
-        swap(lhs.copy_fn, rhs.copy_fn);
-        swap(lhs.steal_fn, rhs.steal_fn);
+        meta_storage tmp{};
+        lhs.vtable ? lhs.vtable(operation::MOVE, tmp, lhs.instance) : std::swap(tmp.instance, lhs.instance);
+        rhs.vtable ? rhs.vtable(operation::MOVE, lhs, rhs.instance) : std::swap(lhs.instance, rhs.instance);
+        lhs.vtable ? lhs.vtable(operation::MOVE, rhs, tmp.instance) : std::swap(rhs.instance, tmp.instance);
+        std::swap(lhs.vtable, rhs.vtable);
     }
 
 private:
     storage_type storage;
+    vtable_type *vtable;
     void *instance;
-    destroy_fn_type *destroy_fn;
-    copy_fn_type *copy_fn;
-    steal_fn_type *steal_fn;
 };