* custom move ctor/op for the registry class
* no registry argument from storage emplace, remove, ...
* added sparse set context to forward variables to mixins
* removed sparse set user data
This commit is contained in:
Michele Caini
2021-11-13 12:04:17 +01:00
parent 17a9cd5666
commit e376a53b09
9 changed files with 157 additions and 230 deletions

1
TODO
View File

@@ -4,6 +4,7 @@
* add examples (and credits) from @alanjfs :)
WIP:
* remove the const_cast within registry::assure (view<const E, ...> vs view<E, ...>, thread safe const registry)
* fast-contains for sparse sets (low prio but nice-to-have)
* runtime components (registry), runtime events (dispatcher/emitter), runtime context variables ...
* runtime_view/registry, remove reference to basic_sparse_set<E>

View File

@@ -110,6 +110,7 @@ class basic_registry {
if(auto &&pdata = pools[type_id<Component>().hash()]; !pdata.pool) {
auto *cpool = new storage_type<Component>{};
pdata.pool.reset(cpool);
pdata.pool->context(forward_as_any(const_cast<basic_registry &>(*this)));
pdata.poly.template emplace<storage_type<Component> &>(*static_cast<storage_type<Component> *>(pdata.pool.get()));
return cpool;
} else {
@@ -156,11 +157,39 @@ public:
/*! @brief Default constructor. */
basic_registry() = default;
/*! @brief Default move constructor. */
basic_registry(basic_registry &&) = default;
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
basic_registry(basic_registry &&other) ENTT_NOEXCEPT
: pools{std::move(other.pools)},
vars{std::move(other.vars)},
groups{std::move(other.groups)},
entities{std::move(other.entities)},
free_list{other.free_list} {
for(auto &&pdata: pools) {
pdata.second.pool->context(forward_as_any(*this));
}
}
/*! @brief Default move assignment operator. @return This registry. */
basic_registry &operator=(basic_registry &&) = default;
/**
* @brief Move assignment operator.
* @param other The instance to move from.
* @return This registry.
*/
basic_registry &operator=(basic_registry &&other) ENTT_NOEXCEPT {
pools = std::move(other.pools);
vars = std::move(other.vars);
groups = std::move(other.groups);
entities = std::move(other.entities);
free_list = other.free_list;
for(auto &&pdata: pools) {
pdata.second.pool->context(forward_as_any(*this));
}
return *this;
}
/**
* @brief Prepares a pool for the given type if required.
@@ -519,7 +548,7 @@ public:
ENTT_ASSERT(valid(entity), "Invalid entity");
for(auto &&pdata: pools) {
pdata.second.pool->remove(entity, this);
pdata.second.pool->remove(entity);
}
return release_entity(entity, version);
@@ -542,7 +571,7 @@ public:
}
} else {
for(auto &&pdata: pools) {
pdata.second.pool->remove(first, last, this);
pdata.second.pool->remove(first, last);
}
release(first, last);
@@ -569,7 +598,7 @@ public:
template<typename Component, typename... Args>
decltype(auto) emplace(const entity_type entity, Args &&...args) {
ENTT_ASSERT(valid(entity), "Invalid entity");
return assure<Component>()->emplace(*this, entity, std::forward<Args>(args)...);
return assure<Component>()->emplace(entity, std::forward<Args>(args)...);
}
/**
@@ -586,7 +615,7 @@ public:
template<typename Component, typename It>
void insert(It first, It last, const Component &value = {}) {
ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity");
assure<Component>()->insert(*this, first, last, value);
assure<Component>()->insert(first, last, value);
}
/**
@@ -605,7 +634,7 @@ public:
void insert(EIt first, EIt last, CIt from) {
static_assert(std::is_constructible_v<Component, typename std::iterator_traits<CIt>::value_type>, "Invalid value type");
ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity");
assure<Component>()->insert(*this, first, last, from);
assure<Component>()->insert(first, last, from);
}
/**
@@ -626,8 +655,8 @@ public:
auto *cpool = assure<Component>();
return cpool->contains(entity)
? cpool->patch(*this, entity, [&args...](auto &...curr) { ((curr = Component{std::forward<Args>(args)...}), ...); })
: cpool->emplace(*this, entity, std::forward<Args>(args)...);
? cpool->patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward<Args>(args)...}), ...); })
: cpool->emplace(entity, std::forward<Args>(args)...);
}
/**
@@ -657,7 +686,7 @@ public:
template<typename Component, typename... Func>
decltype(auto) patch(const entity_type entity, Func &&...func) {
ENTT_ASSERT(valid(entity), "Invalid entity");
return assure<Component>()->patch(*this, entity, std::forward<Func>(func)...);
return assure<Component>()->patch(entity, std::forward<Func>(func)...);
}
/**
@@ -679,7 +708,7 @@ public:
*/
template<typename Component, typename... Args>
decltype(auto) replace(const entity_type entity, Args &&...args) {
return assure<Component>()->patch(*this, entity, [&args...](auto &...curr) { ((curr = Component{std::forward<Args>(args)...}), ...); });
return assure<Component>()->patch(entity, [&args...](auto &...curr) { ((curr = Component{std::forward<Args>(args)...}), ...); });
}
/**
@@ -696,7 +725,7 @@ public:
size_type remove(const entity_type entity) {
ENTT_ASSERT(valid(entity), "Invalid entity");
static_assert(sizeof...(Component) > 0, "Provide one or more component types");
return (assure<Component>()->remove(entity, this) + ... + size_type{});
return (assure<Component>()->remove(entity) + ... + size_type{});
}
/**
@@ -719,7 +748,7 @@ public:
for(; first != last; ++first) {
const auto entity = *first;
ENTT_ASSERT(valid(entity), "Invalid entity");
count += (std::get<storage_type<Component> *>(cpools)->remove(entity, this) + ...);
count += (std::get<storage_type<Component> *>(cpools)->remove(entity) + ...);
}
return count;
@@ -739,7 +768,7 @@ public:
void erase(const entity_type entity) {
ENTT_ASSERT(valid(entity), "Invalid entity");
static_assert(sizeof...(Component) > 0, "Provide one or more component types");
(assure<Component>()->erase(entity, this), ...);
(assure<Component>()->erase(entity), ...);
}
/**
@@ -760,7 +789,7 @@ public:
for(; first != last; ++first) {
const auto entity = *first;
ENTT_ASSERT(valid(entity), "Invalid entity");
(std::get<storage_type<Component> *>(cpools)->erase(entity, this), ...);
(std::get<storage_type<Component> *>(cpools)->erase(entity), ...);
}
}
@@ -868,7 +897,7 @@ public:
[[nodiscard]] decltype(auto) get_or_emplace(const entity_type entity, Args &&...args) {
ENTT_ASSERT(valid(entity), "Invalid entity");
auto *cpool = assure<Component>();
return cpool->contains(entity) ? cpool->get(entity) : cpool->emplace(*this, entity, std::forward<Args>(args)...);
return cpool->contains(entity) ? cpool->get(entity) : cpool->emplace(entity, std::forward<Args>(args)...);
}
/**
@@ -916,12 +945,12 @@ public:
void clear() {
if constexpr(sizeof...(Component) == 0) {
for(auto &&pdata: pools) {
pdata.second.pool->clear(this);
pdata.second.pool->clear();
}
each([this](const auto entity) { release_entity(entity, entity_traits::to_version(entity) + 1u); });
} else {
(assure<Component>()->clear(this), ...);
(assure<Component>()->clear(), ...);
}
}

View File

@@ -9,6 +9,7 @@
#include <vector>
#include "../config/config.h"
#include "../core/algorithm.hpp"
#include "../core/any.hpp"
#include "../core/memory.hpp"
#include "entity.hpp"
#include "fwd.hpp"
@@ -207,7 +208,7 @@ protected:
* @brief Erase an entity from a sparse set.
* @param entt A valid identifier.
*/
virtual void swap_and_pop(const Entity entt, void *) {
virtual void swap_and_pop(const Entity entt) {
auto &ref = sparse_ref(entt);
const auto pos = static_cast<size_type>(entity_traits::to_entity(ref));
ENTT_ASSERT(packed[pos] == entt, "Invalid identifier");
@@ -226,7 +227,7 @@ protected:
* @brief Erase an entity from a sparse set.
* @param entt A valid identifier.
*/
virtual void in_place_pop(const Entity entt, void *) {
virtual void in_place_pop(const Entity entt) {
auto &ref = sparse_ref(entt);
const auto pos = static_cast<size_type>(entity_traits::to_entity(ref));
ENTT_ASSERT(packed[pos] == entt, "Invalid identifier");
@@ -240,7 +241,7 @@ protected:
* @brief Assigns an entity to a sparse set.
* @param entt A valid identifier.
*/
virtual void try_emplace(const Entity entt, void *) {
virtual void try_emplace(const Entity entt) {
const auto pos = static_cast<size_type>(entity_traits::to_entity(entt));
const auto page = pos / sparse_page_v;
@@ -301,7 +302,6 @@ public:
explicit basic_sparse_set(deletion_policy pol, const allocator_type &allocator = {})
: sparse{allocator},
packed{allocator},
udata{},
free_list{tombstone},
mode{pol} {}
@@ -312,7 +312,6 @@ public:
basic_sparse_set(basic_sparse_set &&other) ENTT_NOEXCEPT
: sparse{std::move(other.sparse)},
packed{std::move(other.packed)},
udata{std::exchange(other.udata, nullptr)},
free_list{std::exchange(other.free_list, tombstone)},
mode{other.mode} {}
@@ -324,7 +323,6 @@ public:
basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator) ENTT_NOEXCEPT
: sparse{std::move(other.sparse), allocator},
packed{std::move(other.packed), allocator},
udata{std::exchange(other.udata, nullptr)},
free_list{std::exchange(other.free_list, tombstone)},
mode{other.mode} {
ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(), "Copying a sparse set is not allowed");
@@ -346,7 +344,6 @@ public:
release_sparse_pages();
sparse = std::move(other.sparse);
packed = std::move(other.packed);
udata = std::exchange(other.udata, nullptr);
free_list = std::exchange(other.free_list, tombstone);
mode = other.mode;
return *this;
@@ -361,7 +358,6 @@ public:
swap_contents(other);
swap(sparse, other.sparse);
swap(packed, other.packed);
swap(udata, other.udata);
swap(free_list, other.free_list);
swap(mode, other.mode);
}
@@ -592,10 +588,9 @@ public:
* results in undefined behavior.
*
* @param entt A valid identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
void emplace(const entity_type entt, void *ud = nullptr) {
try_emplace(entt, ud);
void emplace(const entity_type entt) {
try_emplace(entt);
ENTT_ASSERT(contains(entt), "Emplace did not take place");
}
@@ -609,18 +604,17 @@ public:
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
template<typename It>
void insert(It first, It last, void *ud = nullptr) {
void insert(It first, It last) {
for(; first != last && free_list != null; ++first) {
emplace(*first, ud);
emplace(*first);
}
reserve(packed.size() + std::distance(first, last));
for(; first != last; ++first) {
emplace(*first, ud);
emplace(*first);
}
}
@@ -632,11 +626,10 @@ public:
* results in undefined behavior.
*
* @param entt A valid identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
void erase(const entity_type entt, void *ud = nullptr) {
void erase(const entity_type entt) {
ENTT_ASSERT(contains(entt), "Set does not contain entity");
(mode == deletion_policy::in_place) ? in_place_pop(entt, ud) : swap_and_pop(entt, ud);
(mode == deletion_policy::in_place) ? in_place_pop(entt) : swap_and_pop(entt);
ENTT_ASSERT(!contains(entt), "Destruction did not take place");
}
@@ -648,23 +641,21 @@ public:
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
template<typename It>
void erase(It first, It last, void *ud = nullptr) {
void erase(It first, It last) {
for(; first != last; ++first) {
erase(*first, ud);
erase(*first);
}
}
/**
* @brief Removes an entity from a sparse set if it exists.
* @param entt A valid identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
* @return True if the entity is actually removed, false otherwise.
*/
bool remove(const entity_type entt, void *ud = nullptr) {
return contains(entt) && (erase(entt, ud), true);
bool remove(const entity_type entt) {
return contains(entt) && (erase(entt), true);
}
/**
@@ -672,15 +663,14 @@ public:
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
* @param ud Optional user data that are forwarded as-is to derived classes.
* @return The number of entities actually removed.
*/
template<typename It>
size_type remove(It first, It last, void *ud = nullptr) {
size_type remove(It first, It last) {
size_type found{};
for(; first != last; ++first) {
found += remove(*first, ud);
found += remove(*first);
}
return found;
@@ -840,42 +830,20 @@ public:
}
}
/**
* @brief Clears a sparse set.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
void clear(void *ud = nullptr) {
/*! @brief Clears a sparse set. */
void clear() {
for(auto &&entity: *this) {
// honor the modality and filter all tombstones
remove(entity, ud);
remove(entity);
}
}
/**
* @brief User defined arbitrary data.
* @return An opaque pointer to user defined arbitrary data.
*/
void *user_data() ENTT_NOEXCEPT {
return udata;
}
/*! @copydoc user_data */
const void *user_data() const ENTT_NOEXCEPT {
return udata;
}
/**
* @brief User defined arbitrary data.
* @param ptr An opaque pointer to user defined arbitrary data.
*/
void user_data(void *ptr) ENTT_NOEXCEPT {
udata = ptr;
}
/*! @brief Forwards context variables to mixins, if any. */
virtual void context(any) ENTT_NOEXCEPT {}
private:
sparse_container_type sparse;
packed_container_type packed;
void *udata;
entity_type free_list;
deletion_policy mode;
};

View File

@@ -10,6 +10,7 @@
#include <vector>
#include "../config/config.h"
#include "../core/algorithm.hpp"
#include "../core/any.hpp"
#include "../core/compressed_pair.hpp"
#include "../core/memory.hpp"
#include "../core/type_traits.hpp"
@@ -316,9 +317,8 @@ protected:
/**
* @brief Erase an element from a storage.
* @param entt A valid identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
void swap_and_pop(const Entity entt, void *ud) override {
void swap_and_pop(const Entity entt) override {
const auto pos = base_type::index(entt);
const auto last = base_type::size() - 1u;
@@ -330,17 +330,16 @@ protected:
target = std::move(elem);
std::destroy_at(std::addressof(elem));
base_type::swap_and_pop(entt, ud);
base_type::swap_and_pop(entt);
}
/**
* @brief Erases an element from a storage.
* @param entt A valid identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
void in_place_pop(const Entity entt, void *ud) override {
void in_place_pop(const Entity entt) override {
const auto pos = base_type::index(entt);
base_type::in_place_pop(entt, ud);
base_type::in_place_pop(entt);
// support for nosy destructors
std::destroy_at(std::addressof(element_at(pos)));
}
@@ -348,15 +347,14 @@ protected:
/**
* @brief Assigns an entity to a storage.
* @param entt A valid identifier.
* @param ud Optional user data that are forwarded as-is to derived classes.
*/
void try_emplace([[maybe_unused]] const Entity entt, [[maybe_unused]] void *ud) override {
void try_emplace([[maybe_unused]] const Entity entt) override {
if constexpr(std::is_default_constructible_v<value_type>) {
const auto pos = base_type::slot();
construct(assure_at_least(pos));
ENTT_TRY {
base_type::try_emplace(entt, ud);
base_type::try_emplace(entt);
ENTT_ASSERT(pos == base_type::index(entt), "Misplaced component");
}
ENTT_CATCH {
@@ -648,7 +646,7 @@ public:
construct(elem, std::forward<Args>(args)...);
ENTT_TRY {
base_type::try_emplace(entt, nullptr);
base_type::try_emplace(entt);
ENTT_ASSERT(pos == base_type::index(entt), "Misplaced component");
}
ENTT_CATCH {
@@ -814,7 +812,7 @@ public:
template<typename... Args>
void emplace(const entity_type entt, Args &&...args) {
[[maybe_unused]] const value_type elem{std::forward<Args>(args)...};
base_type::try_emplace(entt, nullptr);
base_type::try_emplace(entt);
}
/**
@@ -850,62 +848,6 @@ public:
}
};
/**
* @brief Mixin type to use to wrap basic storage classes.
* @tparam Type The type of the underlying storage.
*/
template<typename Type>
struct storage_adapter_mixin: Type {
static_assert(std::is_same_v<typename Type::value_type, std::decay_t<typename Type::value_type>>, "Invalid object type");
/*! @brief Type of the objects assigned to entities. */
using value_type = typename Type::value_type;
/*! @brief Underlying entity identifier. */
using entity_type = typename Type::entity_type;
/*! @brief Inherited constructors. */
using Type::Type;
/**
* @brief Assigns entities to a storage.
* @tparam Args Types of arguments to use to construct the object.
* @param entt A valid identifier.
* @param args Parameters to use to initialize the object.
* @return A reference to the newly created object.
*/
template<typename... Args>
decltype(auto) emplace(basic_registry<entity_type> &, const entity_type entt, Args &&...args) {
return Type::emplace(entt, std::forward<Args>(args)...);
}
/**
* @brief Patches the given instance for an entity.
* @tparam Func Types of the function objects to invoke.
* @param entt A valid identifier.
* @param func Valid function objects.
* @return A reference to the patched instance.
*/
template<typename... Func>
decltype(auto) patch(basic_registry<entity_type> &, const entity_type entt, Func &&...func) {
return Type::patch(entt, std::forward<Func>(func)...);
}
/**
* @brief Assigns entities to a storage.
* @tparam It Type of input iterator.
* @tparam Args Types of arguments to use to construct the objects assigned
* to the entities.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
* @param args Parameters to use to initialize the objects assigned to the
* entities.
*/
template<typename It, typename... Args>
void insert(basic_registry<entity_type> &, It first, It last, Args &&...args) {
Type::insert(std::move(first), std::move(last), std::forward<Args>(args)...);
}
};
/**
* @brief Mixin type to use to add signal support to storage types.
* @tparam Type The type of the underlying storage.
@@ -913,24 +855,24 @@ struct storage_adapter_mixin: Type {
template<typename Type>
class sigh_storage_mixin final: public Type {
/*! @copydoc basic_sparse_set::swap_and_pop */
void swap_and_pop(const typename Type::entity_type entt, void *ud) final {
ENTT_ASSERT(ud != nullptr, "Invalid pointer to registry");
destruction.publish(*static_cast<basic_registry<typename Type::entity_type> *>(ud), entt);
Type::swap_and_pop(entt, ud);
void swap_and_pop(const typename Type::entity_type entt) final {
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
destruction.publish(*owner, entt);
Type::swap_and_pop(entt);
}
/*! @copydoc basic_sparse_set::in_place_pop */
void in_place_pop(const typename Type::entity_type entt, void *ud) final {
ENTT_ASSERT(ud != nullptr, "Invalid pointer to registry");
destruction.publish(*static_cast<basic_registry<typename Type::entity_type> *>(ud), entt);
Type::in_place_pop(entt, ud);
void in_place_pop(const typename Type::entity_type entt) final {
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
destruction.publish(*owner, entt);
Type::in_place_pop(entt);
}
/*! @copydoc basic_sparse_set::try_emplace */
void try_emplace(const typename Type::entity_type entt, void *ud) final {
ENTT_ASSERT(ud != nullptr, "Invalid pointer to registry");
Type::try_emplace(entt, ud);
construction.publish(*static_cast<basic_registry<typename Type::entity_type> *>(ud), entt);
void try_emplace(const typename Type::entity_type entt) final {
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
Type::try_emplace(entt);
construction.publish(*owner, entt);
}
public:
@@ -1010,30 +952,28 @@ public:
/**
* @brief Assigns entities to a storage.
* @tparam Args Types of arguments to use to construct the object.
* @param owner The registry that issued the request.
* @param entt A valid identifier.
* @param args Parameters to use to initialize the object.
* @return A reference to the newly created object.
*/
template<typename... Args>
decltype(auto) emplace(basic_registry<entity_type> &owner, const entity_type entt, Args &&...args) {
decltype(auto) emplace(const entity_type entt, Args &&...args) {
Type::emplace(entt, std::forward<Args>(args)...);
construction.publish(owner, entt);
construction.publish(*owner, entt);
return this->get(entt);
}
/**
* @brief Patches the given instance for an entity.
* @tparam Func Types of the function objects to invoke.
* @param owner The registry that issued the request.
* @param entt A valid identifier.
* @param func Valid function objects.
* @return A reference to the patched instance.
*/
template<typename... Func>
decltype(auto) patch(basic_registry<entity_type> &owner, const entity_type entt, Func &&...func) {
decltype(auto) patch(const entity_type entt, Func &&...func) {
Type::patch(entt, std::forward<Func>(func)...);
update.publish(owner, entt);
update.publish(*owner, entt);
return this->get(entt);
}
@@ -1042,27 +982,37 @@ public:
* @tparam It Type of input iterator.
* @tparam Args Types of arguments to use to construct the objects assigned
* to the entities.
* @param owner The registry that issued the request.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
* @param args Parameters to use to initialize the objects assigned to the
* entities.
*/
template<typename It, typename... Args>
void insert(basic_registry<entity_type> &owner, It first, It last, Args &&...args) {
void insert(It first, It last, Args &&...args) {
Type::insert(first, last, std::forward<Args>(args)...);
if(!construction.empty()) {
for(; first != last; ++first) {
construction.publish(owner, *first);
construction.publish(*owner, *first);
}
}
}
/**
* @brief Forwards context variables to mixins, if any.
* @param value A context variable wrapped in an opaque container.
*/
void context(any value) ENTT_NOEXCEPT final {
auto *reg = any_cast<basic_registry<entity_type>>(&value);
owner = reg ? reg : owner;
Type::context(std::move(value));
}
private:
sigh<void(basic_registry<entity_type> &, const entity_type)> construction{};
sigh<void(basic_registry<entity_type> &, const entity_type)> destruction{};
sigh<void(basic_registry<entity_type> &, const entity_type)> update{};
basic_registry<entity_type> *owner{};
};
/**

View File

@@ -12,8 +12,8 @@ struct PolyStorage
: entt::type_list_cat_t<
decltype(as_type_list(std::declval<entt::Storage<Entity>>())),
entt::type_list<
void(const Entity *, const Entity *, void *),
void(entt::basic_registry<Entity> &, const Entity, const void *),
void(const Entity *, const Entity *),
void(const Entity, const void *),
const void *(const Entity) const,
void(entt::basic_registry<Entity> &) const>> {
using entity_type = Entity;
@@ -23,12 +23,12 @@ struct PolyStorage
struct type: entt::Storage<Entity>::template type<Base> {
static constexpr auto base = decltype(as_type_list(std::declval<entt::Storage<Entity>>()))::size;
void erase(entt::basic_registry<Entity> &owner, const entity_type *first, const entity_type *last) {
entt::poly_call<base + 0>(*this, first, last, &owner);
void erase(const entity_type *first, const entity_type *last) {
entt::poly_call<base + 0>(*this, first, last);
}
void emplace(entt::basic_registry<Entity> &owner, const entity_type entity, const void *instance) {
entt::poly_call<base + 1>(*this, owner, entity, instance);
void emplace(const entity_type entity, const void *instance) {
entt::poly_call<base + 1>(*this, entity, instance);
}
const void *get(const entity_type entity) const {
@@ -42,8 +42,8 @@ struct PolyStorage
template<typename Type>
struct members {
static void emplace(Type &self, entt::basic_registry<Entity> &owner, const entity_type entity, const void *instance) {
self.emplace(owner, entity, *static_cast<const typename Type::value_type *>(instance));
static void emplace(Type &self, const entity_type entity, const void *instance) {
self.emplace(entity, *static_cast<const typename Type::value_type *>(instance));
}
static const typename Type::value_type *get(const Type &self, const entity_type entity) {
@@ -84,7 +84,7 @@ TEST(PolyStorage, CopyEntity) {
registry.visit(entity, [&](const auto &info) {
auto &&storage = registry.storage(info);
storage->emplace(registry, other, storage->get(entity));
storage->emplace(other, storage->get(entity));
});
ASSERT_TRUE((registry.all_of<int, char>(entity)));
@@ -129,11 +129,11 @@ TEST(PolyStorage, Constness) {
// cannot invoke erase on a const storage, let's copy the returned value
auto cstorage = cregistry.storage(entt::type_id<int>());
ASSERT_DEATH(cstorage->erase(registry, std::begin(entity), std::end(entity)), "");
ASSERT_DEATH(cstorage->erase(std::begin(entity), std::end(entity)), "");
ASSERT_TRUE(registry.all_of<int>(entity[0]));
auto &&storage = registry.storage(entt::type_id<int>());
storage->erase(registry, std::begin(entity), std::end(entity));
storage->erase(std::begin(entity), std::end(entity));
ASSERT_FALSE(registry.all_of<int>(entity[0]));
}

View File

@@ -39,14 +39,16 @@ TEST(SighStorageMixin, GenericType) {
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
entt::registry registry{};
pool.context(entt::forward_as_any(registry));
counter on_construct{};
counter on_destroy{};
pool.on_construct().connect<&listener>(on_construct);
pool.on_destroy().connect<&listener>(on_destroy);
base.emplace(entities[0u], &registry);
pool.emplace(registry, entities[1u]);
base.emplace(entities[0u]);
pool.emplace(entities[1u]);
ASSERT_EQ(on_construct.value, 2);
ASSERT_EQ(on_destroy.value, 0);
@@ -55,32 +57,32 @@ TEST(SighStorageMixin, GenericType) {
ASSERT_EQ(pool.get(entities[0u]), 0);
ASSERT_EQ(pool.get(entities[1u]), 0);
base.erase(entities[0u], &registry);
pool.erase(entities[1u], &registry);
base.erase(entities[0u]);
pool.erase(entities[1u]);
ASSERT_EQ(on_construct.value, 2);
ASSERT_EQ(on_destroy.value, 2);
ASSERT_TRUE(pool.empty());
base.insert(std::begin(entities), std::end(entities), &registry);
base.insert(std::begin(entities), std::end(entities));
ASSERT_EQ(pool.get(entities[0u]), 0);
ASSERT_EQ(pool.get(entities[1u]), 0);
ASSERT_FALSE(pool.empty());
base.erase(entities[1u], &registry);
base.erase(entities[1u]);
ASSERT_EQ(on_construct.value, 4);
ASSERT_EQ(on_destroy.value, 3);
ASSERT_FALSE(pool.empty());
base.erase(entities[0u], &registry);
base.erase(entities[0u]);
ASSERT_EQ(on_construct.value, 4);
ASSERT_EQ(on_destroy.value, 4);
ASSERT_TRUE(pool.empty());
pool.insert(registry, std::begin(entities), std::end(entities), 3);
pool.insert(std::begin(entities), std::end(entities), 3);
ASSERT_EQ(on_construct.value, 6);
ASSERT_EQ(on_destroy.value, 4);
@@ -89,7 +91,7 @@ TEST(SighStorageMixin, GenericType) {
ASSERT_EQ(pool.get(entities[0u]), 3);
ASSERT_EQ(pool.get(entities[1u]), 3);
pool.erase(std::begin(entities), std::end(entities), &registry);
pool.erase(std::begin(entities), std::end(entities));
ASSERT_EQ(on_construct.value, 6);
ASSERT_EQ(on_destroy.value, 6);
@@ -102,14 +104,16 @@ TEST(SighStorageMixin, EmptyType) {
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
entt::registry registry{};
pool.context(entt::forward_as_any(registry));
counter on_construct{};
counter on_destroy{};
pool.on_construct().connect<&listener>(on_construct);
pool.on_destroy().connect<&listener>(on_destroy);
base.emplace(entities[0u], &registry);
pool.emplace(registry, entities[1u]);
base.emplace(entities[0u]);
pool.emplace(entities[1u]);
ASSERT_EQ(on_construct.value, 2);
ASSERT_EQ(on_destroy.value, 0);
@@ -118,32 +122,32 @@ TEST(SighStorageMixin, EmptyType) {
ASSERT_TRUE(pool.contains(entities[0u]));
ASSERT_TRUE(pool.contains(entities[1u]));
base.erase(entities[0u], &registry);
pool.erase(entities[1u], &registry);
base.erase(entities[0u]);
pool.erase(entities[1u]);
ASSERT_EQ(on_construct.value, 2);
ASSERT_EQ(on_destroy.value, 2);
ASSERT_TRUE(pool.empty());
base.insert(std::begin(entities), std::end(entities), &registry);
base.insert(std::begin(entities), std::end(entities));
ASSERT_TRUE(pool.contains(entities[0u]));
ASSERT_TRUE(pool.contains(entities[1u]));
ASSERT_FALSE(pool.empty());
base.erase(entities[1u], &registry);
base.erase(entities[1u]);
ASSERT_EQ(on_construct.value, 4);
ASSERT_EQ(on_destroy.value, 3);
ASSERT_FALSE(pool.empty());
base.erase(entities[0u], &registry);
base.erase(entities[0u]);
ASSERT_EQ(on_construct.value, 4);
ASSERT_EQ(on_destroy.value, 4);
ASSERT_TRUE(pool.empty());
pool.insert(registry, std::begin(entities), std::end(entities));
pool.insert(std::begin(entities), std::end(entities));
ASSERT_EQ(on_construct.value, 6);
ASSERT_EQ(on_destroy.value, 4);
@@ -152,7 +156,7 @@ TEST(SighStorageMixin, EmptyType) {
ASSERT_TRUE(pool.contains(entities[0u]));
ASSERT_TRUE(pool.contains(entities[1u]));
pool.erase(std::begin(entities), std::end(entities), &registry);
pool.erase(std::begin(entities), std::end(entities));
ASSERT_EQ(on_construct.value, 6);
ASSERT_EQ(on_destroy.value, 6);
@@ -165,15 +169,17 @@ TEST(SighStorageMixin, NonDefaultConstructibleType) {
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
entt::registry registry{};
pool.context(entt::forward_as_any(registry));
counter on_construct{};
counter on_destroy{};
pool.on_construct().connect<&listener>(on_construct);
pool.on_destroy().connect<&listener>(on_destroy);
ASSERT_DEATH(base.emplace(entities[0u], &registry), "");
ASSERT_DEATH(base.emplace(entities[0u]), "");
pool.emplace(registry, entities[1u], 3);
pool.emplace(entities[1u], 3);
ASSERT_EQ(on_construct.value, 1);
ASSERT_EQ(on_destroy.value, 0);
@@ -182,19 +188,19 @@ TEST(SighStorageMixin, NonDefaultConstructibleType) {
ASSERT_FALSE(pool.contains(entities[0u]));
ASSERT_EQ(pool.get(entities[1u]).value, 3);
base.erase(entities[1u], &registry);
base.erase(entities[1u]);
ASSERT_EQ(on_construct.value, 1);
ASSERT_EQ(on_destroy.value, 1);
ASSERT_TRUE(pool.empty());
ASSERT_DEATH(base.insert(std::begin(entities), std::end(entities), &registry), "");
ASSERT_DEATH(base.insert(std::begin(entities), std::end(entities)), "");
ASSERT_FALSE(pool.contains(entities[0u]));
ASSERT_FALSE(pool.contains(entities[1u]));
ASSERT_TRUE(pool.empty());
pool.insert(registry, std::begin(entities), std::end(entities), 3);
pool.insert(std::begin(entities), std::end(entities), 3);
ASSERT_EQ(on_construct.value, 3);
ASSERT_EQ(on_destroy.value, 1);
@@ -203,7 +209,7 @@ TEST(SighStorageMixin, NonDefaultConstructibleType) {
ASSERT_EQ(pool.get(entities[0u]).value, 3);
ASSERT_EQ(pool.get(entities[1u]).value, 3);
pool.erase(std::begin(entities), std::end(entities), &registry);
pool.erase(std::begin(entities), std::end(entities));
ASSERT_EQ(on_construct.value, 3);
ASSERT_EQ(on_destroy.value, 3);

View File

@@ -75,6 +75,8 @@ TEST(SparseSet, Functionalities) {
ASSERT_EQ(set.begin(), set.end());
ASSERT_FALSE(set.contains(entt::entity{0}));
ASSERT_FALSE(set.contains(entt::entity{42}));
ASSERT_NO_THROW(set.context(entt::any{}));
}
TEST(SparseSet, Contains) {
@@ -1169,35 +1171,6 @@ TEST(SparseSet, CanModifyDuringIteration) {
[[maybe_unused]] const auto entity = *it;
}
TEST(SparseSet, UserData) {
entt::sparse_set set;
int value = 42;
ASSERT_EQ(set.user_data(), nullptr);
set.user_data(&value);
entt::sparse_set other{std::move(set)};
ASSERT_EQ(std::as_const(set).user_data(), nullptr);
ASSERT_EQ(other.user_data(), &value);
std::swap(set, other);
ASSERT_EQ(set.user_data(), &value);
ASSERT_EQ(std::as_const(other).user_data(), nullptr);
other = std::move(set);
ASSERT_EQ(set.user_data(), nullptr);
ASSERT_EQ(other.user_data(), &value);
entt::sparse_set last{std::move(other), std::allocator<entt::entity>{}};
ASSERT_EQ(set.user_data(), nullptr);
ASSERT_EQ(other.user_data(), nullptr);
ASSERT_EQ(last.user_data(), &value);
}
TEST(SparseSet, CustomAllocator) {
test::throwing_allocator<entt::entity> allocator{};
entt::basic_sparse_set<entt::entity, test::throwing_allocator<entt::entity>> set{allocator};

View File

@@ -1213,9 +1213,9 @@ TEST(MultiComponentView, SameComponentTypes) {
const entt::entity e0{42u};
const entt::entity e1{3u};
storage.emplace(registry, e0, 7);
other.emplace(registry, e0, 9);
other.emplace(registry, e1, 1);
storage.emplace(e0, 7);
other.emplace(e0, 9);
other.emplace(e1, 1);
ASSERT_TRUE(view.contains(e0));
ASSERT_FALSE(view.contains(e1));

View File

@@ -7,7 +7,7 @@
template<typename Entity, typename Type>
struct entt::storage_traits<Entity, Type> {
// no signal regardless of component type ...
using storage_type = storage_adapter_mixin<basic_storage<Entity, Type>>;
using storage_type = basic_storage<Entity, Type>;
};
template<typename Entity>