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

This commit is contained in:
Michele Caini
2020-11-25 17:31:49 +01:00
parent 909415d167
commit cd0ec69446
2 changed files with 57 additions and 71 deletions

6
TODO
View File

@@ -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

View File

@@ -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;
};