registry::stomp (to be tested yet)

This commit is contained in:
Michele Caini
2019-08-13 15:58:26 +02:00
parent 688e6ad79f
commit 2ba4c36af0
2 changed files with 79 additions and 18 deletions

2
TODO
View File

@@ -16,6 +16,7 @@
* registry.each<T...>(first, last) by iterators, entities/components guaranteed
* multi component registry::remove and some others?
* built-in support for dual (or N-) buffering
* allow to "merge" registries easily
TODO
* custom (decoupled) pools ==> double buffering, shared components, multi-model
@@ -25,3 +26,4 @@ TODO
- cloning all/part of the components are both required and a target entity on which to stomp your stuff could help
- clone is just clone, creating new entity. But yeah, both "clone-all", and "clone-components"
- for "apply", again both All and Components, and maybe an enum of what kind of apply "dont overwrite, overwrite, add-only"
- deprecate prototype

View File

@@ -205,6 +205,7 @@ class basic_registry {
std::unique_ptr<sparse_set<Entity>> pool;
void(* remove)(sparse_set<Entity> &, basic_registry &, const Entity);
std::unique_ptr<sparse_set<Entity>>(* clone)(const sparse_set<Entity> &);
void(* accommodate)(const sparse_set<Entity> &, const Entity, registry &, const Entity);
ENTT_ID_TYPE runtime_type;
};
@@ -239,7 +240,7 @@ class basic_registry {
}
template<typename Component>
const auto * pool() const ENTT_NOEXCEPT {
const pool_type<Component> * pool() const ENTT_NOEXCEPT {
const auto ctype = to_integer(type<Component>());
if constexpr(is_named_type_v<Component>) {
@@ -254,12 +255,12 @@ class basic_registry {
}
template<typename Component>
auto * pool() ENTT_NOEXCEPT {
pool_type<Component> * pool() ENTT_NOEXCEPT {
return const_cast<pool_type<Component> *>(std::as_const(*this).template pool<Component>());
}
template<typename Component>
auto * assure() {
pool_type<Component> * assure() {
const auto ctype = to_integer(type<Component>());
pool_data *pdata = nullptr;
@@ -285,17 +286,22 @@ class basic_registry {
pdata->runtime_type = ctype;
pdata->pool = std::make_unique<pool_type<Component>>();
pdata->remove = [](sparse_set<Entity> &other, basic_registry &registry, const Entity entt) {
static_cast<pool_type<Component> &>(other).remove(registry, entt);
pdata->remove = [](sparse_set<Entity> &cpool, basic_registry &registry, const Entity entt) {
static_cast<pool_type<Component> &>(cpool).remove(registry, entt);
};
pdata->clone = []([[maybe_unused]] const sparse_set<Entity> &other) -> std::unique_ptr<sparse_set<Entity>> {
if constexpr(std::is_copy_constructible_v<std::decay_t<Component>>) {
return std::make_unique<pool_type<Component>>(static_cast<const pool_type<Component> &>(other));
} else {
return nullptr;
}
};
if constexpr(std::is_copy_constructible_v<std::decay_t<Component>>) {
pdata->clone = [](const sparse_set<Entity> &cpool) -> std::unique_ptr<sparse_set<Entity>> {
return std::make_unique<pool_type<Component>>(static_cast<const pool_type<Component> &>(cpool));
};
pdata->accommodate = [](const sparse_set<Entity> &cpool, const Entity from, registry &other, const Entity to) {
other.assign_or_replace<Component>(to, static_cast<const pool_type<Component> &>(cpool).get(from));
};
} else {
pdata->clone = nullptr;
pdata->accommodate = nullptr;
}
}
return static_cast<pool_type<Component> *>(pdata->pool.get());
@@ -319,14 +325,14 @@ public:
basic_registry & operator=(basic_registry &&) = default;
/**
* @brief Returns the numeric identifier of a component.
* @brief Returns the opaque identifier of a component.
*
* The given component doesn't need to be necessarily in use.<br/>
* Do not use this functionality to generate numeric identifiers for types
* at runtime. They aren't guaranteed to be stable between different runs.
*
* @tparam Component Type of component to query.
* @return Runtime numeric identifier of the given type of component.
* @return Runtime the opaque identifier of the given type of component.
*/
template<typename Component>
static component type() ENTT_NOEXCEPT {
@@ -1440,7 +1446,7 @@ public:
}
/**
* @brief Clones the given components and all the entity identifiers.
* @brief Returns a full or partial copy of a registry.
*
* The components must be copyable for obvious reasons. The entities
* maintain their versions once copied.<br/>
@@ -1480,16 +1486,19 @@ public:
other.pools.resize(pools.size());
for(auto pos = pools.size(); pos; --pos) {
if(auto &pdata = pools[pos-1]; pdata.pool
const auto &pdata = pools[pos-1];
ENTT_ASSERT(!sizeof...(Component) || !pdata.pool || pdata.clone);
if(pdata.pool && pdata.clone
&& (!sizeof...(Component) || ... || (pdata.runtime_type == to_integer(type<Component>())))
&& !((pdata.runtime_type == to_integer(type<Exclude>())) || ...))
{
auto &curr = other.pools[pos-1];
curr.remove = pdata.remove;
curr.clone = pdata.clone;
curr.pool = pdata.clone(*pdata.pool);
curr.accommodate = pdata.accommodate;
curr.pool = pdata.clone ? pdata.clone(*pdata.pool) : nullptr;
curr.runtime_type = pdata.runtime_type;
ENTT_ASSERT(!sizeof...(Component) || curr.pool);
}
}
@@ -1505,6 +1514,56 @@ public:
return other;
}
/**
* @brief Makes a full or partial copy of an entity.
*
* The components must be copyable for obvious reasons. The entities
* must be both valid.<br/>
* If no components are provided, the registry will try to copy all the
* existing types. The non-copyable ones will be ignored.
*
* This feature supports exclusion lists. The excluded types have higher
* priority than those indicated for copying. An excluded type will never be
* copied.
*
* @warning
* Attempting to copy components that aren't copyable results in unexpected
* behaviors.<br/>
* A static assertion will abort the compilation when the components
* provided aren't copy constructible. Otherwise, an assertion will abort
* the execution at runtime in debug mode in case one or more types cannot
* be copied.
*
* @warning
* Attempting to use invalid entities results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode in case of
* invalid entities.
*
* @tparam Component Types of components to copy.
* @tparam Exclude Types of components not to be copied.
* @param from A valid entity identifier to be copied.
* @param other The registry that owns the target entity.
* @param to A valid entity identifier to copy to.
*/
template<typename... Component, typename... Exclude>
void clone(const Entity from, registry &other, const Entity to, exclude_t<Exclude...> = {}) {
static_assert(std::conjunction_v<std::is_copy_constructible<Component>...>);
ENTT_ASSERT(valid(from) && other.valid(to));
for(auto pos = pools.size(); pos; --pos) {
const auto &pdata = pools[pos-1];
ENTT_ASSERT(!sizeof...(Component) || !pdata.pool || pdata->accommodate);
if(pdata.pool && pdata.accommodate
&& (!sizeof...(Component) || ... || (pdata.runtime_type == to_integer(type<Component>())))
&& !((pdata.runtime_type == to_integer(type<Exclude>())) || ...)
&& pdata.pool->has(from))
{
pdata.accommodate(*pdata.pool, from, other, to);
}
}
}
/**
* @brief Returns a temporary object to use to create snapshots.
*