registry: truly const registry

This commit is contained in:
Michele Caini
2020-11-09 18:39:43 +01:00
parent cd98ecff88
commit b1cd794b2c

View File

@@ -61,20 +61,20 @@ class basic_registry {
template<typename Component>
void maybe_valid_if(basic_registry &owner, const Entity entt) {
[[maybe_unused]] const auto cpools = std::forward_as_tuple(owner.assure<Owned>()...);
[[maybe_unused]] const auto cpools = std::make_tuple(owner.assure<Owned>()...);
const auto is_valid = ((std::is_same_v<Component, Owned> || std::get<storage_type<Owned> &>(cpools).contains(entt)) && ...)
&& ((std::is_same_v<Component, Get> || owner.assure<Get>().contains(entt)) && ...)
&& ((std::is_same_v<Component, Exclude> || !owner.assure<Exclude>().contains(entt)) && ...);
const auto is_valid = ((std::is_same_v<Component, Owned> || std::get<storage_type<Owned> *>(cpools)->contains(entt)) && ...)
&& ((std::is_same_v<Component, Get> || owner.assure<Get>()->contains(entt)) && ...)
&& ((std::is_same_v<Component, Exclude> || !owner.assure<Exclude>()->contains(entt)) && ...);
if constexpr(sizeof...(Owned) == 0) {
if(is_valid && !current.contains(entt)) {
current.emplace(entt);
}
} else {
if(is_valid && !(std::get<0>(cpools).index(entt) < current)) {
if(is_valid && !(std::get<0>(cpools)->index(entt) < current)) {
const auto pos = current++;
(std::get<storage_type<Owned> &>(cpools).swap(std::get<storage_type<Owned> &>(cpools).data()[pos], entt), ...);
(std::get<storage_type<Owned> *>(cpools)->swap(std::get<storage_type<Owned> *>(cpools)->data()[pos], entt), ...);
}
}
}
@@ -85,9 +85,9 @@ class basic_registry {
current.remove(entt);
}
} else {
if(const auto cpools = std::forward_as_tuple(owner.assure<Owned>()...); std::get<0>(cpools).contains(entt) && (std::get<0>(cpools).index(entt) < current)) {
if(const auto cpools = std::make_tuple(owner.assure<Owned>()...); std::get<0>(cpools)->contains(entt) && (std::get<0>(cpools)->index(entt) < current)) {
const auto pos = --current;
(std::get<storage_type<Owned> &>(cpools).swap(std::get<storage_type<Owned> &>(cpools).data()[pos], entt), ...);
(std::get<storage_type<Owned> *>(cpools)->swap(std::get<storage_type<Owned> *>(cpools)->data()[pos], entt), ...);
}
}
}
@@ -107,7 +107,7 @@ class basic_registry {
};
template<typename Component>
[[nodiscard]] const storage_type<Component> & assure() const {
[[nodiscard]] storage_type<Component> * assure() {
const auto index = type_seq<Component>::value();
if(!(index < pools.size())) {
@@ -122,12 +122,13 @@ class basic_registry {
};
}
return static_cast<const storage_type<Component> &>(*pools[index].pool);
return static_cast<storage_type<Component> *>(pools[index].pool.get());
}
template<typename Component>
[[nodiscard]] storage_type<Component> & assure() {
return const_cast<storage_type<Component> &>(std::as_const(*this).template assure<Component>());
[[nodiscard]] const storage_type<Component> * assure() const {
const auto index = type_seq<Component>::value();
return (!(index < pools.size()) || !pools[index].pool) ? nullptr : static_cast<const storage_type<Component> *>(pools[index].pool.get());
}
Entity generate_identifier() {
@@ -184,7 +185,8 @@ public:
*/
template<typename Component>
[[nodiscard]] size_type size() const {
return assure<Component>().size();
const auto *cpool = assure<Component>();
return cpool ? cpool->size() : size_type{};
}
/**
@@ -228,7 +230,7 @@ public:
if constexpr(sizeof...(Component) == 0) {
entities.reserve(cap);
} else {
(assure<Component>().reserve(cap), ...);
(assure<Component>()->reserve(cap), ...);
}
}
@@ -239,7 +241,8 @@ public:
*/
template<typename Component>
[[nodiscard]] size_type capacity() const {
return assure<Component>().capacity();
const auto *cpool = assure<Component>();
return cpool ? cpool->capacity() : size_type{};
}
/**
@@ -258,7 +261,7 @@ public:
*/
template<typename... Component>
void shrink_to_fit() {
(assure<Component>().shrink_to_fit(), ...);
(assure<Component>()->shrink_to_fit(), ...);
}
/**
@@ -277,7 +280,7 @@ public:
if constexpr(sizeof...(Component) == 0) {
return !alive();
} else {
return (assure<Component>().empty() && ...);
return [](auto *... cpool) { return ((!cpool || cpool->empty()) && ...); }(assure<Component>()...);
}
}
@@ -300,13 +303,14 @@ public:
*/
template<typename Component>
[[nodiscard]] const Component * raw() const {
return assure<Component>().raw();
const auto *cpool = assure<Component>();
return cpool ? cpool->raw() : nullptr;
}
/*! @copydoc raw */
template<typename Component>
[[nodiscard]] Component * raw() {
return const_cast<Component *>(std::as_const(*this).template raw<Component>());
return assure<Component>()->raw();
}
/**
@@ -324,7 +328,8 @@ public:
*/
template<typename Component>
[[nodiscard]] const entity_type * data() const {
return assure<Component>().data();
const auto *cpool = assure<Component>();
return cpool ? cpool->data() : nullptr;
}
/**
@@ -559,7 +564,7 @@ public:
template<typename Component, typename... Args>
decltype(auto) emplace(const entity_type entity, Args &&... args) {
ENTT_ASSERT(valid(entity));
return assure<Component>().emplace(*this, entity, std::forward<Args>(args)...);
return assure<Component>()->emplace(*this, entity, std::forward<Args>(args)...);
}
/**
@@ -576,7 +581,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); }));
assure<Component>().insert(*this, first, last, value);
assure<Component>()->insert(*this, first, last, value);
}
/**
@@ -596,7 +601,7 @@ public:
void insert(EIt first, EIt last, CIt from, CIt to) {
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); }));
assure<Component>().insert(*this, first, last, from, to);
assure<Component>()->insert(*this, first, last, from, to);
}
/**
@@ -622,11 +627,11 @@ public:
template<typename Component, typename... Args>
decltype(auto) emplace_or_replace(const entity_type entity, Args &&... args) {
ENTT_ASSERT(valid(entity));
auto &cpool = assure<Component>();
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)...);
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)...);
}
/**
@@ -656,7 +661,7 @@ public:
template<typename Component, typename... Func>
decltype(auto) patch(const entity_type entity, Func &&... func) {
ENTT_ASSERT(valid(entity));
return assure<Component>().patch(*this, entity, std::forward<Func>(func)...);
return assure<Component>()->patch(*this, entity, std::forward<Func>(func)...);
}
/**
@@ -678,7 +683,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(*this, entity, [&args...](auto &curr) { curr = Component{std::forward<Args>(args)...}; });
}
/**
@@ -694,7 +699,7 @@ public:
template<typename... Component>
void remove(const entity_type entity) {
ENTT_ASSERT(valid(entity));
(assure<Component>().remove(*this, entity), ...);
(assure<Component>()->remove(*this, entity), ...);
}
/**
@@ -710,7 +715,7 @@ public:
template<typename... Component, typename It>
void remove(It first, It last) {
ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }));
(assure<Component>().remove(*this, first, last), ...);
(assure<Component>()->remove(*this, first, last), ...);
}
/**
@@ -735,8 +740,8 @@ public:
size_type remove_if_exists(const entity_type entity) {
ENTT_ASSERT(valid(entity));
return ([this, entity](auto &&cpool) {
return cpool.contains(entity) ? (cpool.remove(*this, entity), true) : false;
return ([this, entity](auto *cpool) {
return cpool->contains(entity) ? (cpool->remove(*this, entity), true) : false;
}(assure<Component>()) + ... + size_type{});
}
@@ -778,7 +783,7 @@ public:
template<typename... Component>
[[nodiscard]] bool has(const entity_type entity) const {
ENTT_ASSERT(valid(entity));
return (assure<Component>().contains(entity) && ...);
return [entity](auto *... cpool) { return ((cpool && cpool->contains(entity)) && ...); }(assure<Component>()...);
}
/**
@@ -795,7 +800,7 @@ public:
template<typename... Component>
[[nodiscard]] bool any(const entity_type entity) const {
ENTT_ASSERT(valid(entity));
return (assure<Component>().contains(entity) || ...);
return [entity](auto *... cpool) { return ((cpool && cpool->contains(entity)) || ...); }(assure<Component>()...);
}
/**
@@ -814,9 +819,9 @@ public:
ENTT_ASSERT(valid(entity));
if constexpr(sizeof...(Component) == 1) {
return (assure<Component>().get(entity), ...);
return (assure<Component>()->get(entity), ...);
} else {
return std::forward_as_tuple(assure<Component>().get(entity)...);
return std::forward_as_tuple(assure<Component>()->get(entity)...);
}
}
@@ -826,9 +831,9 @@ public:
ENTT_ASSERT(valid(entity));
if constexpr(sizeof...(Component) == 1) {
return (assure<Component>().get(entity), ...);
return (assure<Component>()->get(entity), ...);
} else {
return std::forward_as_tuple(assure<Component>().get(entity)...);
return std::forward_as_tuple(assure<Component>()->get(entity)...);
}
}
@@ -857,8 +862,8 @@ public:
template<typename Component, typename... Args>
[[nodiscard]] decltype(auto) get_or_emplace(const entity_type entity, Args &&... args) {
ENTT_ASSERT(valid(entity));
auto &cpool = assure<Component>();
return cpool.contains(entity) ? cpool.get(entity) : cpool.emplace(*this, entity, std::forward<Args>(args)...);
auto *cpool = assure<Component>();
return cpool->contains(entity) ? cpool->get(entity) : cpool->emplace(*this, entity, std::forward<Args>(args)...);
}
/**
@@ -879,8 +884,8 @@ public:
ENTT_ASSERT(valid(entity));
if constexpr(sizeof...(Component) == 1) {
auto &cpool = assure<Component...>();
return cpool.contains(entity) ? &cpool.get(entity) : nullptr;
auto *cpool = assure<Component...>();
return (cpool && cpool->contains(entity)) ? &cpool->get(entity) : nullptr;
} else {
return std::make_tuple(try_get<Component>(entity)...);
}
@@ -892,8 +897,8 @@ public:
ENTT_ASSERT(valid(entity));
if constexpr(sizeof...(Component) == 1) {
auto &cpool = assure<Component...>();
return cpool.contains(entity) ? &cpool.get(entity) : nullptr;
auto *cpool = assure<Component...>();
return cpool->contains(entity) ? &cpool->get(entity) : nullptr;
} else {
return std::make_tuple(try_get<Component>(entity)...);
}
@@ -918,8 +923,8 @@ public:
}
}
} else {
([this](auto &&cpool) {
cpool.remove(*this, cpool.basic_sparse_set<entity_type>::begin(), cpool.basic_sparse_set<entity_type>::end());
([this](auto *cpool) {
cpool->remove(*this, cpool->basic_sparse_set<entity_type>::begin(), cpool->basic_sparse_set<entity_type>::end());
}(assure<Component>()), ...);
}
}
@@ -1013,7 +1018,7 @@ public:
*/
template<typename Component>
[[nodiscard]] auto on_construct() {
return assure<Component>().on_construct();
return assure<Component>()->on_construct();
}
/**
@@ -1036,7 +1041,7 @@ public:
*/
template<typename Component>
[[nodiscard]] auto on_update() {
return assure<Component>().on_update();
return assure<Component>()->on_update();
}
/**
@@ -1061,7 +1066,7 @@ public:
*/
template<typename Component>
[[nodiscard]] auto on_destroy() {
return assure<Component>().on_destroy();
return assure<Component>()->on_destroy();
}
/**
@@ -1099,14 +1104,15 @@ public:
template<typename... Component, typename... Exclude>
[[nodiscard]] basic_view<Entity, exclude_t<Exclude...>, Component...> view(exclude_t<Exclude...> = {}) const {
static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported");
return { assure<std::decay_t<Component>>()..., assure<Exclude>()... };
using view_type = basic_view<Entity, exclude_t<Exclude...>, Component...>;
return [](auto *... cpools) { return (cpools && ...) ? view_type{*cpools...} : view_type{}; }(assure<std::decay_t<Component>>()..., assure<Exclude>()...);
}
/*! @copydoc view */
template<typename... Component, typename... Exclude>
[[nodiscard]] basic_view<Entity, exclude_t<Exclude...>, Component...> view(exclude_t<Exclude...> = {}) {
static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported");
return { assure<std::decay_t<Component>>()..., assure<Exclude>()... };
return { *assure<std::decay_t<Component>>()..., *assure<Exclude>()... };
}
/**
@@ -1189,7 +1195,7 @@ public:
using handler_type = group_handler<exclude_t<Exclude...>, get_t<std::decay_t<Get>...>, std::decay_t<Owned>...>;
const auto cpools = std::forward_as_tuple(assure<std::decay_t<Owned>>()..., assure<std::decay_t<Get>>()...);
const auto cpools = std::make_tuple(assure<std::decay_t<Owned>>()..., assure<std::decay_t<Get>>()...);
constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude);
handler_type *handler = nullptr;
@@ -1253,17 +1259,13 @@ public:
}
} else {
// we cannot iterate backwards because we want to leave behind valid entities in case of owned types
for(auto *first = std::get<0>(cpools).data(), *last = first + std::get<0>(cpools).size(); first != last; ++first) {
for(auto *first = std::get<0>(cpools)->data(), *last = first + std::get<0>(cpools)->size(); first != last; ++first) {
handler->template maybe_valid_if<std::tuple_element_t<0, std::tuple<std::decay_t<Owned>...>>>(*this, *first);
}
}
}
if constexpr(sizeof...(Owned) == 0) {
return { handler->current, std::get<storage_type<std::decay_t<Get>> &>(cpools)... };
} else {
return { handler->current, std::get<storage_type<std::decay_t<Owned>> &>(cpools)... , std::get<storage_type<std::decay_t<Get>> &>(cpools)... };
}
return { handler->current, *std::get<storage_type<std::decay_t<Owned>> *>(cpools)..., *std::get<storage_type<std::decay_t<Get>> *>(cpools)... };
}
/**
@@ -1279,7 +1281,19 @@ public:
template<typename... Owned, typename... Get, typename... Exclude>
[[nodiscard]] basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> group(get_t<Get...>, exclude_t<Exclude...> = {}) const {
static_assert(std::conjunction_v<std::is_const<Owned>..., std::is_const<Get>...>, "Invalid non-const type");
return const_cast<basic_registry *>(this)->group<Owned...>(get_t<Get...>{}, exclude<Exclude...>);
if(auto it = std::find_if(groups.cbegin(), groups.cend(), [](const auto &gdata) {
return gdata.size == (sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude))
&& (gdata.owned(type_hash<std::decay_t<Owned>>::value()) && ...)
&& (gdata.get(type_hash<std::decay_t<Get>>::value()) && ...)
&& (gdata.exclude(type_hash<Exclude>::value()) && ...);
}); it == groups.cend())
{
return {};
} else {
using handler_type = group_handler<exclude_t<Exclude...>, get_t<std::decay_t<Get>...>, std::decay_t<Owned>...>;
return { static_cast<handler_type *>(it->group.get())->current, *assure<std::decay_t<Owned>>()... , *assure<std::decay_t<Get>>()... };
}
}
/**
@@ -1307,8 +1321,7 @@ public:
*/
template<typename... Owned, typename... Exclude>
[[nodiscard]] basic_group<Entity, exclude_t<Exclude...>, get_t<>, Owned...> group(exclude_t<Exclude...> = {}) const {
static_assert(std::conjunction_v<std::is_const<Owned>...>, "Invalid non-const type");
return const_cast<basic_registry *>(this)->group<Owned...>(exclude<Exclude...>);
return group<Owned...>(get_t<>{}, exclude<Exclude...>);
}
/**
@@ -1385,7 +1398,7 @@ public:
template<typename Component, typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
ENTT_ASSERT(sortable<Component>());
assure<Component>().sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
assure<Component>()->sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
}
/**
@@ -1424,7 +1437,7 @@ public:
template<typename To, typename From>
void sort() {
ENTT_ASSERT(sortable<To>());
assure<To>().respect(assure<From>());
assure<To>()->respect(*assure<From>());
}
/**
@@ -1602,8 +1615,8 @@ public:
}
private:
std::vector<pool_data> pools{};
std::vector<group_data> groups{};
mutable std::vector<pool_data> pools{};
std::vector<entity_type> entities{};
std::vector<variable_data> vars{};
entity_type available{null};