tests, tags and few other features
This commit is contained in:
64
README.md
64
README.md
@@ -461,7 +461,7 @@ their components are destroyed:
|
||||
registry.reset();
|
||||
```
|
||||
|
||||
Finally, references to components can be retrieved by just doing this:
|
||||
Finally, references to components can be retrieved simply by doing this:
|
||||
|
||||
```cpp
|
||||
// either a non-const reference ...
|
||||
@@ -476,6 +476,68 @@ const auto &position = cregistry.get<Position>(entity);
|
||||
The `get` member function template gives direct access to the component of an
|
||||
entity stored in the underlying data structures of the registry.
|
||||
|
||||
### Single instance components
|
||||
|
||||
In those cases where all what is needed is a single instance component, tags are
|
||||
the right tool to achieve the purpose.<br/>
|
||||
Tags undergo the same requirements of components. They can be either plain old
|
||||
data structures or more complex and moveable data structures with a proper
|
||||
constructor.<br/>
|
||||
Actually, the same type can be used both as a tag and as a component and the
|
||||
registry will not complain about it. It is up to the users to properly manage
|
||||
their own types.
|
||||
|
||||
Attaching tags to entities and removing them is trivial:
|
||||
|
||||
```cpp
|
||||
auto player = registry.create();
|
||||
auto camera = registry.create();
|
||||
|
||||
// attaches a default-initialized tag to an entity
|
||||
registry.attach<PlayingCharacter>(player);
|
||||
|
||||
// attaches a tag to an entity and initializes it
|
||||
registry.attach<Camera>(camera, player);
|
||||
|
||||
// removes tags from their owners
|
||||
registry.remove<PlayingCharacter>();
|
||||
registry.remove<Camera>();
|
||||
```
|
||||
|
||||
If in doubt about whether or not a tag has already an owner, the `has` member
|
||||
function template may be useful:
|
||||
|
||||
```cpp
|
||||
bool b = registry.has<PlayingCharacter>();
|
||||
```
|
||||
|
||||
References to tags can be retrieved simply by doing this:
|
||||
|
||||
```cpp
|
||||
// either a non-const reference ...
|
||||
entt::DefaultRegistry registry;
|
||||
auto &player = registry.get<PlayingCharacter>();
|
||||
|
||||
// ... or a const one
|
||||
const auto &cregistry = registry;
|
||||
const auto &camera = cregistry.get<Camera>();
|
||||
```
|
||||
|
||||
The `get` member function template gives direct access to the tag as stored in
|
||||
the underlying data structures of the registry.
|
||||
|
||||
As shown above, in almost all the cases the entity identifier isn't required,
|
||||
since a single instance component can have only one associated entity and
|
||||
therefore it doesn't make much sense to mention it explicitly.<br/>
|
||||
To find out who the owner is, just do the following:
|
||||
|
||||
```cpp
|
||||
auto player = registry.attachee<PlayingCharacter>();
|
||||
```
|
||||
|
||||
Note that iterating tags isn't possible for obvious reasons. Tags give direct
|
||||
access to single entities and nothing more.
|
||||
|
||||
### Sorting: is it possible?
|
||||
|
||||
It goes without saying that sorting entities and components is possible with
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include "../core/family.hpp"
|
||||
#include "sparse_set.hpp"
|
||||
#include "traits.hpp"
|
||||
@@ -28,10 +29,26 @@ namespace entt {
|
||||
*/
|
||||
template<typename Entity>
|
||||
class Registry {
|
||||
using tag_family = Family<struct InternalRegistryTagFamily>;
|
||||
using component_family = Family<struct InternalRegistryComponentFamily>;
|
||||
using view_family = Family<struct InternalRegistryViewFamily>;
|
||||
using traits_type = entt_traits<Entity>;
|
||||
|
||||
struct Attachee {
|
||||
Entity entity;
|
||||
};
|
||||
|
||||
template<typename Tag>
|
||||
struct Attaching: Attachee {
|
||||
// requirements for aggregates are relaxed only since C++17
|
||||
template<typename... Args>
|
||||
Attaching(Entity entity, Tag tag)
|
||||
: Attachee{entity}, tag{std::move(tag)}
|
||||
{}
|
||||
|
||||
Tag tag;
|
||||
};
|
||||
|
||||
template<typename Component>
|
||||
struct Pool: SparseSet<Entity, Component> {
|
||||
using test_fn_type = bool(Registry::*)(Entity) const;
|
||||
@@ -42,7 +59,7 @@ class Registry {
|
||||
|
||||
for(auto &&listener: listeners) {
|
||||
if((registry.*listener.second)(entity)) {
|
||||
listener.first.construct(entity);
|
||||
listener.first->construct(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,20 +70,26 @@ class Registry {
|
||||
SparseSet<Entity, Component>::destroy(entity);
|
||||
|
||||
for(auto &&listener: listeners) {
|
||||
auto &handler = listener.first;
|
||||
auto *handler = listener.first;
|
||||
|
||||
if(handler.has(entity)) {
|
||||
handler.destroy(entity);
|
||||
if(handler->has(entity)) {
|
||||
handler->destroy(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void append(SparseSet<Entity> &handler, test_fn_type fn) {
|
||||
inline void append(SparseSet<Entity> *handler, test_fn_type fn) {
|
||||
listeners.emplace_back(handler, fn);
|
||||
}
|
||||
|
||||
inline void remove(SparseSet<Entity> *handler) {
|
||||
listeners.erase(std::remove_if(listeners.begin(), listeners.end(), [handler](auto &listener) {
|
||||
return listener.first == handler;
|
||||
}), listeners.end());
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<SparseSet<Entity> &, test_fn_type>> listeners;
|
||||
std::vector<std::pair<SparseSet<Entity> *, test_fn_type>> listeners;
|
||||
};
|
||||
|
||||
template<typename Component>
|
||||
@@ -121,7 +144,7 @@ class Registry {
|
||||
}
|
||||
|
||||
accumulator_type accumulator = {
|
||||
(ensure<Component>().append(*set, &Registry::has<Component...>), 0)...
|
||||
(ensure<Component>().append(set.get(), &Registry::has<Component...>), 0)...
|
||||
};
|
||||
|
||||
handlers[vtype] = std::move(set);
|
||||
@@ -358,6 +381,122 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attaches a tag to an entity.
|
||||
*
|
||||
* Usually, pools of components allocate enough memory to store a bunch of
|
||||
* elements even if only one of them is used. On the other hand, there are
|
||||
* cases where all what is needed is a single instance component to attach
|
||||
* to an entity.<br/>
|
||||
* Tags are the right tool to achieve the purpose.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an invalid entity or to attach to an entity a tag that
|
||||
* already has an owner results in undefined behavior.<br/>
|
||||
* An assertion will abort the execution at runtime in debug mode in case of
|
||||
* invalid entity or if the tag has been already attached to another entity.
|
||||
*
|
||||
* @tparam Tag Type of tag to create.
|
||||
* @tparam Args Types of arguments to use to construct the tag.
|
||||
* @param entity A valid entity identifier
|
||||
* @param args Parameters to use to initialize the tag.
|
||||
* @return A reference to the newly created tag.
|
||||
*/
|
||||
template<typename Tag, typename... Args>
|
||||
Tag & attach(entity_type entity, Args&&... args) {
|
||||
assert(valid(entity));
|
||||
assert(!has<Tag>());
|
||||
const auto ttype = tag_family::type<Tag>();
|
||||
|
||||
if(!(ttype < tags.size())) {
|
||||
tags.resize(ttype + 1);
|
||||
}
|
||||
|
||||
tags[ttype].reset(new Attaching<Tag>{entity, { std::forward<Args>(args)... }});
|
||||
tags[ttype]->entity = entity;
|
||||
|
||||
return static_cast<Attaching<Tag> *>(tags[ttype].get())->tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes a tag from its owner, if any.
|
||||
* @tparam Tag Type of tag to remove.
|
||||
*/
|
||||
template<typename Tag>
|
||||
void remove() {
|
||||
if(has<Tag>()) {
|
||||
tags[tag_family::type<Tag>()].reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a tag has an owner.
|
||||
* @tparam Tag Type of tag for which to perform the check.
|
||||
* @return True if the tag already has an owner, false otherwise.
|
||||
*/
|
||||
template<typename Tag>
|
||||
bool has() const noexcept {
|
||||
const auto ttype = tag_family::type<Tag>();
|
||||
return (ttype < tags.size() &&
|
||||
// it's a valid tag
|
||||
tags[ttype] &&
|
||||
// the associated entity hasn't been destroyed in the meantime
|
||||
tags[ttype]->entity == (entities[tags[ttype]->entity & traits_type::entity_mask]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to a tag.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to get a tag that hasn't an owner results in undefined
|
||||
* behavior.<br/>
|
||||
* An assertion will abort the execution at runtime in debug mode if the
|
||||
* tag hasn't been previously attached to an entity.
|
||||
*
|
||||
* @tparam Tag Type of tag to get.
|
||||
* @return A reference to the tag.
|
||||
*/
|
||||
template<typename Tag>
|
||||
const Tag & get() const noexcept {
|
||||
assert(has<Tag>());
|
||||
return static_cast<Attaching<Tag> *>(tags[tag_family::type<Tag>()].get())->tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to a tag.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to get a tag that hasn't an owner results in undefined
|
||||
* behavior.<br/>
|
||||
* An assertion will abort the execution at runtime in debug mode if the
|
||||
* tag hasn't been previously attached to an entity.
|
||||
*
|
||||
* @tparam Tag Type of tag to get.
|
||||
* @return A reference to the tag.
|
||||
*/
|
||||
template<typename Tag>
|
||||
Tag & get() noexcept {
|
||||
return const_cast<Tag &>(const_cast<const Registry *>(this)->get<Tag>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the owner of a tag, if any.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to get the owner of a tag that hasn't been previously attached
|
||||
* to an entity results in undefined behavior.<br/>
|
||||
* An assertion will abort the execution at runtime in debug mode if the
|
||||
* tag hasn't an owner.
|
||||
*
|
||||
* @tparam Tag Type of tag of which to get the owner.
|
||||
* @return A valid entity identifier.
|
||||
*/
|
||||
template<typename Tag>
|
||||
entity_type attachee() const noexcept {
|
||||
assert(has<Tag>());
|
||||
return tags[tag_family::type<Tag>()]->entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns the given component to an entity.
|
||||
*
|
||||
@@ -372,7 +511,7 @@ public:
|
||||
* invalid entity or if the entity already owns an instance of the given
|
||||
* component.
|
||||
*
|
||||
* @tparam Component Type of the component to create.
|
||||
* @tparam Component Type of component to create.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param entity A valid entity identifier.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
@@ -394,7 +533,7 @@ public:
|
||||
* invalid entity or if the entity doesn't own an instance of the given
|
||||
* component.
|
||||
*
|
||||
* @tparam Component Type of the component to remove.
|
||||
* @tparam Component Type of component to remove.
|
||||
* @param entity A valid entity identifier.
|
||||
*/
|
||||
template<typename Component>
|
||||
@@ -436,7 +575,7 @@ public:
|
||||
* invalid entity or if the entity doesn't own an instance of the given
|
||||
* component.
|
||||
*
|
||||
* @tparam Component Type of the component to get.
|
||||
* @tparam Component Type of component to get.
|
||||
* @param entity A valid entity identifier.
|
||||
* @return A reference to the instance of the component owned by the entity.
|
||||
*/
|
||||
@@ -456,7 +595,7 @@ public:
|
||||
* invalid entity or if the entity doesn't own an instance of the given
|
||||
* component.
|
||||
*
|
||||
* @tparam Component Type of the component to get.
|
||||
* @tparam Component Type of component to get.
|
||||
* @param entity A valid entity identifier.
|
||||
* @return A reference to the instance of the component owned by the entity.
|
||||
*/
|
||||
@@ -479,7 +618,7 @@ public:
|
||||
* invalid entity or if the entity doesn't own an instance of the given
|
||||
* component.
|
||||
*
|
||||
* @tparam Component Type of the component to replace.
|
||||
* @tparam Component Type of component to replace.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param entity A valid entity identifier.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
@@ -512,7 +651,7 @@ public:
|
||||
* An assertion will abort the execution at runtime in debug mode in case of
|
||||
* invalid entity.
|
||||
*
|
||||
* @tparam Component Type of the component to assign or replace.
|
||||
* @tparam Component Type of component to assign or replace.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param entity A valid entity identifier.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
@@ -549,8 +688,8 @@ public:
|
||||
*
|
||||
* Where `e1` and `e2` are valid entity identifiers.
|
||||
*
|
||||
* @tparam Component Type of the components to sort.
|
||||
* @tparam Compare Type of the comparison function object.
|
||||
* @tparam Component Type of components to sort.
|
||||
* @tparam Compare Type of comparison function object.
|
||||
* @param compare A valid comparison function object.
|
||||
*/
|
||||
template<typename Component, typename Compare>
|
||||
@@ -589,8 +728,8 @@ public:
|
||||
*
|
||||
* Any subsequent change to `B` won't affect the order in `A`.
|
||||
*
|
||||
* @tparam To Type of the components to sort.
|
||||
* @tparam From Type of the components to use to sort.
|
||||
* @tparam To Type of components to sort.
|
||||
* @tparam From Type of components to use to sort.
|
||||
*/
|
||||
template<typename To, typename From>
|
||||
void sort() {
|
||||
@@ -608,7 +747,7 @@ public:
|
||||
* An assertion will abort the execution at runtime in debug mode in case of
|
||||
* invalid entity.
|
||||
*
|
||||
* @tparam Component Type of the component to reset.
|
||||
* @tparam Component Type of component to reset.
|
||||
* @param entity A valid entity identifier.
|
||||
*/
|
||||
template<typename Component>
|
||||
@@ -630,7 +769,7 @@ public:
|
||||
* For each entity that has an instance of the given component, the
|
||||
* component itself is removed and thus destroyed.
|
||||
*
|
||||
* @tparam Component type of the component whose pool must be reset.
|
||||
* @tparam Component Type of component whose pool must be reset.
|
||||
*/
|
||||
template<typename Component>
|
||||
void reset() {
|
||||
@@ -673,6 +812,10 @@ public:
|
||||
pool->reset();
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &&tag: tags) {
|
||||
tag.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -733,6 +876,46 @@ public:
|
||||
handler<Component...>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Discards all the data structures used for a given persitent view.
|
||||
*
|
||||
* Persistent views occupy memory, no matter if they are in use or not.<br/>
|
||||
* This function can be used to discard all the internal data structures
|
||||
* dedicated to a specific persisten view, with the goal of reducing the
|
||||
* memory pressure.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use a persistent view created before calling this function
|
||||
* results in undefined behavior. No assertion available in this case,
|
||||
* neither in debug mode nor in release mode.
|
||||
*
|
||||
* @tparam Component Types of components of the persistent view.
|
||||
*/
|
||||
template<typename... Component>
|
||||
void discard() {
|
||||
if(contains<Component...>()) {
|
||||
using accumulator_type = int[];
|
||||
const auto vtype = view_family::type<Component...>();
|
||||
auto *set = handlers[vtype].get();
|
||||
// if a set exists, pools have already been created for it
|
||||
accumulator_type accumulator = { (pool<Component>().remove(set), 0)... };
|
||||
handlers[vtype].reset();
|
||||
(void)accumulator;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a persistent view has already been prepared.
|
||||
* @tparam Component Types of components of the persistent view.
|
||||
* @return True if the view has already been prepared, false otherwise.
|
||||
*/
|
||||
template<typename... Component>
|
||||
bool contains() const noexcept {
|
||||
static_assert(sizeof...(Component) > 1, "!");
|
||||
const auto vtype = view_family::type<Component...>();
|
||||
return vtype < handlers.size() && handlers[vtype];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a persistent view for the given components.
|
||||
*
|
||||
@@ -772,12 +955,14 @@ public:
|
||||
*/
|
||||
template<typename... Component>
|
||||
PersistentView<Entity, Component...> persistent() {
|
||||
return PersistentView<Entity, Component...>{handler<Component...>(), ensure<Component>()...};
|
||||
// after the calls to handler, pools have already been created
|
||||
return PersistentView<Entity, Component...>{handler<Component...>(), pool<Component>()...};
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -264,7 +264,7 @@ public:
|
||||
// has size 1), switching the two lines below doesn't work as expected
|
||||
reverse[back] = pos | in_use;
|
||||
reverse[entt] = pos;
|
||||
// swap-and-pop the last element with the selected ont
|
||||
// swapping isn't required here, we are getting rid of the last element
|
||||
direct[pos] = direct.back();
|
||||
direct.pop_back();
|
||||
}
|
||||
@@ -412,7 +412,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
|
||||
|
||||
public:
|
||||
/*! @brief Type of the objects associated to the entities. */
|
||||
using type = Type;
|
||||
using object_type = Type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename underlying_type::entity_type;
|
||||
/*! @brief Entity dependent position type. */
|
||||
@@ -450,7 +450,7 @@ public:
|
||||
*
|
||||
* @return A pointer to the array of objects.
|
||||
*/
|
||||
const type * raw() const noexcept {
|
||||
const object_type * raw() const noexcept {
|
||||
return instances.data();
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ public:
|
||||
*
|
||||
* @return A pointer to the array of objects.
|
||||
*/
|
||||
type * raw() noexcept {
|
||||
object_type * raw() noexcept {
|
||||
return instances.data();
|
||||
}
|
||||
|
||||
@@ -485,7 +485,7 @@ public:
|
||||
* @param entity A valid entity identifier.
|
||||
* @return The object associated to the entity.
|
||||
*/
|
||||
const type & get(entity_type entity) const noexcept {
|
||||
const object_type & get(entity_type entity) const noexcept {
|
||||
return instances[underlying_type::get(entity)];
|
||||
}
|
||||
|
||||
@@ -501,8 +501,8 @@ public:
|
||||
* @param entity A valid entity identifier.
|
||||
* @return The object associated to the entity.
|
||||
*/
|
||||
type & get(entity_type entity) noexcept {
|
||||
return const_cast<type &>(const_cast<const SparseSet *>(this)->get(entity));
|
||||
object_type & get(entity_type entity) noexcept {
|
||||
return const_cast<object_type &>(const_cast<const SparseSet *>(this)->get(entity));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -520,8 +520,9 @@ public:
|
||||
* @return The object associated to the entity.
|
||||
*/
|
||||
template<typename... Args>
|
||||
type & construct(entity_type entity, Args&&... args) {
|
||||
object_type & construct(entity_type entity, Args&&... args) {
|
||||
underlying_type::construct(entity);
|
||||
// emplace_back doesn't work well with PODs because of its placement new
|
||||
instances.push_back({ std::forward<Args>(args)... });
|
||||
return instances.back();
|
||||
}
|
||||
@@ -538,7 +539,7 @@ public:
|
||||
* @param entity A valid entity identifier.
|
||||
*/
|
||||
void destroy(entity_type entity) override {
|
||||
// swaps isn't required here, we are getting rid of the last element
|
||||
// swapping isn't required here, we are getting rid of the last element
|
||||
instances[underlying_type::get(entity)] = std::move(instances.back());
|
||||
instances.pop_back();
|
||||
underlying_type::destroy(entity);
|
||||
@@ -574,7 +575,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<type> instances;
|
||||
std::vector<object_type> instances;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -571,7 +571,7 @@ public:
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename pool_type::size_type;
|
||||
/*! Type of the component iterated by the view. */
|
||||
using raw_type = typename pool_type::type;
|
||||
using raw_type = typename pool_type::object_type;
|
||||
|
||||
/**
|
||||
* @brief Constructs a view out of a pool of components.
|
||||
|
||||
@@ -292,7 +292,7 @@ public:
|
||||
* Unless an immediate operation is requested, the abort is scheduled for
|
||||
* the next tick. Processes won't be executed anymore in any case.<br/>
|
||||
* Once a process is fully aborted and thus finished, it's discarded along
|
||||
* with its child if any.
|
||||
* with its child, if any.
|
||||
*
|
||||
* @param immediately Requests an immediate operation.
|
||||
*/
|
||||
|
||||
@@ -134,6 +134,110 @@ TEST(DefaultRegistry, CreateDestroyEntities) {
|
||||
ASSERT_EQ(registry.current(pre), registry.current(post));
|
||||
}
|
||||
|
||||
TEST(DefaultRegistry, AttachRemoveTags) {
|
||||
entt::DefaultRegistry registry;
|
||||
const auto &cregistry = registry;
|
||||
|
||||
ASSERT_FALSE(registry.has<int>());
|
||||
|
||||
auto entity = registry.create();
|
||||
registry.attach<int>(entity, 42);
|
||||
|
||||
ASSERT_TRUE(registry.has<int>());
|
||||
ASSERT_EQ(registry.get<int>(), 42);
|
||||
ASSERT_EQ(cregistry.get<int>(), 42);
|
||||
ASSERT_EQ(registry.attachee<int>(), entity);
|
||||
|
||||
registry.remove<int>();
|
||||
|
||||
ASSERT_FALSE(registry.has<int>());
|
||||
|
||||
registry.attach<int>(entity, 42);
|
||||
registry.destroy(entity);
|
||||
|
||||
ASSERT_FALSE(registry.has<int>());
|
||||
}
|
||||
|
||||
TEST(DefaultRegistry, StandardViews) {
|
||||
entt::DefaultRegistry registry;
|
||||
auto mview = registry.view<int, char>();
|
||||
auto iview = registry.view<int>();
|
||||
auto cview = registry.view<char>();
|
||||
|
||||
registry.create(0, 'c');
|
||||
registry.create(0);
|
||||
registry.create(0, 'c');
|
||||
|
||||
ASSERT_EQ(iview.size(), decltype(iview)::size_type{3});
|
||||
ASSERT_EQ(cview.size(), decltype(cview)::size_type{2});
|
||||
|
||||
decltype(mview)::size_type cnt{0};
|
||||
mview.each([&cnt](auto...) { ++cnt; });
|
||||
|
||||
ASSERT_EQ(cnt, decltype(mview)::size_type{2});
|
||||
}
|
||||
|
||||
TEST(DefaultRegistry, PersistentViews) {
|
||||
entt::DefaultRegistry registry;
|
||||
auto view = registry.persistent<int, char>();
|
||||
|
||||
ASSERT_TRUE((registry.contains<int, char>()));
|
||||
ASSERT_FALSE((registry.contains<int, double>()));
|
||||
|
||||
registry.prepare<int, double>();
|
||||
|
||||
ASSERT_TRUE((registry.contains<int, double>()));
|
||||
|
||||
registry.discard<int, double>();
|
||||
|
||||
ASSERT_FALSE((registry.contains<int, double>()));
|
||||
|
||||
registry.create(0, 'c');
|
||||
registry.create(0);
|
||||
registry.create(0, 'c');
|
||||
|
||||
decltype(view)::size_type cnt{0};
|
||||
view.each([&cnt](auto...) { ++cnt; });
|
||||
|
||||
ASSERT_EQ(cnt, decltype(view)::size_type{2});
|
||||
}
|
||||
|
||||
TEST(DefaultRegistry, CleanStandardViewsAfterReset) {
|
||||
entt::DefaultRegistry registry;
|
||||
auto view = registry.view<int>();
|
||||
registry.create(0);
|
||||
|
||||
ASSERT_EQ(view.size(), entt::DefaultRegistry::size_type{1});
|
||||
|
||||
registry.reset();
|
||||
|
||||
ASSERT_EQ(view.size(), entt::DefaultRegistry::size_type{0});
|
||||
}
|
||||
|
||||
TEST(DefaultRegistry, CleanPersistentViewsAfterReset) {
|
||||
entt::DefaultRegistry registry;
|
||||
auto view = registry.persistent<int, char>();
|
||||
registry.create(0, 'c');
|
||||
|
||||
ASSERT_EQ(view.size(), entt::DefaultRegistry::size_type{1});
|
||||
|
||||
registry.reset();
|
||||
|
||||
ASSERT_EQ(view.size(), entt::DefaultRegistry::size_type{0});
|
||||
}
|
||||
|
||||
TEST(DefaultRegistry, CleanTagsAfterReset) {
|
||||
entt::DefaultRegistry registry;
|
||||
auto entity = registry.create();
|
||||
registry.attach<int>(entity);
|
||||
|
||||
ASSERT_TRUE(registry.has<int>());
|
||||
|
||||
registry.reset();
|
||||
|
||||
ASSERT_FALSE(registry.has<int>());
|
||||
}
|
||||
|
||||
TEST(DefaultRegistry, SortSingle) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user