|
|
@@ -230,7 +230,7 @@ public:
|
|
|
* @return Number of entities still in use.
|
|
|
*/
|
|
|
size_type size() const noexcept {
|
|
|
- return entities.size() - available.size();
|
|
|
+ return entities.size() - available;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -257,7 +257,6 @@ public:
|
|
|
*/
|
|
|
void reserve(size_type cap) {
|
|
|
entities.reserve(cap);
|
|
|
- available.reserve(cap);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -284,7 +283,7 @@ public:
|
|
|
* @return True if at least an entity is still in use, false otherwise.
|
|
|
*/
|
|
|
bool empty() const noexcept {
|
|
|
- return entities.size() == available.size();
|
|
|
+ return entities.size() == available;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -408,14 +407,18 @@ public:
|
|
|
entity_type create() noexcept {
|
|
|
entity_type entity;
|
|
|
|
|
|
- if(available.empty()) {
|
|
|
+ if(available) {
|
|
|
+ const auto entt = next;
|
|
|
+ const auto version = entities[entt] & (~traits_type::entity_mask);
|
|
|
+
|
|
|
+ entity = entt | version;
|
|
|
+ next = entities[entt] & traits_type::entity_mask;
|
|
|
+ entities[entt] = entity;
|
|
|
+ --available;
|
|
|
+ } else {
|
|
|
entity = entity_type(entities.size());
|
|
|
assert(entity < traits_type::entity_mask);
|
|
|
- assert((entity >> traits_type::entity_shift) == entity_type{});
|
|
|
entities.push_back(entity);
|
|
|
- } else {
|
|
|
- entity = available.back();
|
|
|
- available.pop_back();
|
|
|
}
|
|
|
|
|
|
return entity;
|
|
|
@@ -439,11 +442,12 @@ public:
|
|
|
void destroy(entity_type entity) {
|
|
|
assert(valid(entity));
|
|
|
const auto entt = entity & traits_type::entity_mask;
|
|
|
- const auto version = version_type{1} + ((entity >> traits_type::entity_shift) & traits_type::version_mask);
|
|
|
- const auto next = entt | (version << traits_type::entity_shift);
|
|
|
+ const auto version = (entity & (~traits_type::entity_mask)) + (typename traits_type::entity_type{1} << traits_type::entity_shift);
|
|
|
+ const auto node = (available ? next : ((entt + 1) & traits_type::entity_mask)) | version;
|
|
|
|
|
|
- entities[entt] = next;
|
|
|
- available.push_back(next);
|
|
|
+ entities[entt] = node;
|
|
|
+ next = entt;
|
|
|
+ ++available;
|
|
|
|
|
|
for(auto &&cpool: pools) {
|
|
|
if(cpool && cpool->has(entity)) {
|
|
|
@@ -879,11 +883,11 @@ public:
|
|
|
if(managed<Component>()) {
|
|
|
auto &cpool = pool<Component>();
|
|
|
|
|
|
- for(auto entity: entities) {
|
|
|
+ each([&cpool](auto entity) {
|
|
|
if(cpool.has(entity)) {
|
|
|
cpool.destroy(entity);
|
|
|
}
|
|
|
- }
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -891,41 +895,20 @@ public:
|
|
|
* @brief Resets a whole registry.
|
|
|
*
|
|
|
* Destroys all the entities. After a call to `reset`, all the entities
|
|
|
- * previously created are recycled with a new version number. In case entity
|
|
|
+ * still in use are recycled with a new version number. In case entity
|
|
|
* identifers are stored around, the `current` member function can be used
|
|
|
* to know if they are still valid.
|
|
|
*/
|
|
|
void reset() {
|
|
|
- available.clear();
|
|
|
-
|
|
|
- for(auto &&entity: entities) {
|
|
|
- const auto version = version_type{1} + ((entity >> traits_type::entity_shift) & traits_type::version_mask);
|
|
|
- entity = (entity & traits_type::entity_mask) | (version << traits_type::entity_shift);
|
|
|
- available.push_back(entity);
|
|
|
- }
|
|
|
-
|
|
|
- for(auto &&handler: handlers) {
|
|
|
- if(handler) {
|
|
|
- handler->reset();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for(auto &&pool: pools) {
|
|
|
- if(pool) {
|
|
|
- pool->reset();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for(auto &&tag: tags) {
|
|
|
- tag.reset();
|
|
|
- }
|
|
|
+ each([this](auto entity) {
|
|
|
+ destroy(entity);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @brief Iterate entities and applies them the given function object.
|
|
|
*
|
|
|
- * The function object is invoked for each entity, no matter if it's in use
|
|
|
- * or not.<br/>
|
|
|
+ * The function object is invoked for each entity still in use.<br/>
|
|
|
* The signature of the function should be equivalent to the following:
|
|
|
*
|
|
|
* @code{.cpp}
|
|
|
@@ -941,8 +924,19 @@ public:
|
|
|
*/
|
|
|
template<typename Func>
|
|
|
void each(Func func) const {
|
|
|
- for(auto pos = entities.size(); pos > size_type{0}; --pos) {
|
|
|
- func(entities[pos-1]);
|
|
|
+ if(available) {
|
|
|
+ for(auto pos = entities.size(); pos > size_type{0}; --pos) {
|
|
|
+ const entity_type curr = pos - 1;
|
|
|
+ const auto entt = entities[curr] & traits_type::entity_mask;
|
|
|
+
|
|
|
+ if(curr == entt) {
|
|
|
+ func(entities[curr]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ for(auto pos = entities.size(); pos > size_type{0}; --pos) {
|
|
|
+ func(entities[pos-1]);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1091,8 +1085,9 @@ private:
|
|
|
std::vector<std::unique_ptr<SparseSet<Entity>>> handlers;
|
|
|
std::vector<std::unique_ptr<SparseSet<Entity>>> pools;
|
|
|
std::vector<std::unique_ptr<Attachee>> tags;
|
|
|
- std::vector<entity_type> available;
|
|
|
std::vector<entity_type> entities;
|
|
|
+ size_type available{};
|
|
|
+ entity_type next{};
|
|
|
};
|
|
|
|
|
|
|