From cd0ec69446e34282785219864fbe4cb1e56f87a2 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Wed, 25 Nov 2020 17:31:49 +0100 Subject: [PATCH] meta: reduced instantiations due to meta any, use a fake vtable function --- TODO | 6 +- src/entt/meta/internal.hpp | 122 +++++++++++++++++-------------------- 2 files changed, 57 insertions(+), 71 deletions(-) diff --git a/TODO b/TODO index 0eff4330b..b7b86a789 100644 --- a/TODO +++ b/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: meta_descriptor (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 diff --git a/src/entt/meta/internal.hpp b/src/entt/meta/internal.hpp index 690347002..24f7bb1c5 100644 --- a/src/entt/meta/internal.hpp +++ b/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; - 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 struct type_traits { template - static void instance(meta_storage &buffer, Args &&... args) { + static void ctor(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; + 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(instance))}; + new (&self.storage) Type *{static_cast(self.instance)}; + break; + case operation::MOVE: + new (&self.storage) Type *{static_cast(instance)}; + self.instance = instance; + break; + case operation::DTOR: + delete static_cast(instance); + break; + } } }; template struct type_traits>> { template - 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)...}; } - 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); + 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(instance))}; + break; + case operation::MOVE: + self.instance = new (&self.storage) Type{std::move(*static_cast(instance))}; + [[fallthrough]]; + case operation::DTOR: + static_cast(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 @@ -96,10 +97,8 @@ public: : 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; + type_traits::ctor(*this, std::forward(args)...); + vtable = &type_traits::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; };