diff --git a/README.md b/README.md
index a95f3e798..d6b60184d 100644
--- a/README.md
+++ b/README.md
@@ -578,7 +578,8 @@ data structures or more complex and movable data structures with a proper
constructor.
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.
+their own types. In some cases, the `tag_type_t` must also be used in order to
+disambiguate overloads of member functions.
Attaching tags to entities and removing them is trivial:
@@ -587,10 +588,10 @@ auto player = registry.create();
auto camera = registry.create();
// attaches a default-initialized tag to an entity
-registry.attach(player);
+registry.assign(entt::tag_type_t{}, player);
// attaches a tag to an entity and initializes it
-registry.attach(camera, player);
+registry.assign(entt::tag_type_t{}, camera, player);
// removes tags from their owners
registry.remove();
@@ -598,12 +599,12 @@ registry.remove();
```
In case a tag already has an owner, its content can be updated by means of the
-`set` member function template and the ownership of the tag can be transferred
-to another entity using the `move` member function template:
+`replace` member function template and the ownership of the tag can be
+transferred to another entity using the `move` member function template:
```
// replaces the content of the given tag
-Point &point = registry.set(1.f, 1.f);
+Point &point = registry.replace(entt::tag_type_t{}, 1.f, 1.f);
// transfers the ownership of the tag to another entity
entity_type prev = registry.move(next);
diff --git a/TODO b/TODO
index 8848d63bb..ae8f9a1b7 100644
--- a/TODO
+++ b/TODO
@@ -5,6 +5,5 @@
* define a macro for the noexcept policy, so as to provide users with an easy way to disable exception handling
* define basic reactive systems (track entities to which component is attached, track entities from which component is removed, and so on)
* blueprint registry - kind of factory to create entitites template for initialization (use signals, it's trivial this way)
-* use tag dispatching to disambiguate between standard components and single instance components, then provide users with an common API
* remove Actor::update (it's application dependent), allow tag instead
* AOB
diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp
index 78ad9c780..be6760734 100644
--- a/src/entt/entity/registry.hpp
+++ b/src/entt/entity/registry.hpp
@@ -16,6 +16,7 @@
#include "entt_traits.hpp"
#include "snapshot.hpp"
#include "sparse_set.hpp"
+#include "utility.hpp"
#include "view.hpp"
@@ -182,7 +183,7 @@ public:
* @return Runtime numeric identifier of the given type of tag.
*/
template
- tag_type tag() const noexcept {
+ tag_type type(tag_type_t) const noexcept {
return tag_family::type();
}
@@ -199,7 +200,7 @@ public:
* @return Runtime numeric identifier of the given type of component.
*/
template
- component_type component() const noexcept {
+ component_type type() const noexcept {
return component_family::type();
}
@@ -430,7 +431,7 @@ public:
* @return A reference to the newly created tag.
*/
template
- Tag & attach(entity_type entity, Args &&... args) {
+ Tag & assign(tag_type_t, entity_type entity, Args &&... args) {
assert(valid(entity));
assert(!has());
const auto ttype = tag_family::type();
@@ -444,6 +445,32 @@ public:
return static_cast *>(tags[ttype].get())->tag;
}
+ /**
+ * @brief Assigns the given component to an entity.
+ *
+ * A new instance of the given component is created and initialized with the
+ * arguments provided (the component must have a proper constructor or be of
+ * aggregate type). Then the component is assigned to the given entity.
+ *
+ * @warning
+ * Attempting to use an invalid entity or to assign a component to an entity
+ * that already owns it results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of
+ * invalid entity or if the entity already owns an instance of the given
+ * component.
+ *
+ * @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.
+ * @return A reference to the newly created component.
+ */
+ template
+ Component & assign(entity_type entity, Args &&... args) {
+ assert(valid(entity));
+ return assure().construct(entity, std::forward(args)...);
+ }
+
/**
* @brief Removes the given tag from its owner, if any.
* @tparam Tag Type of tag to remove.
@@ -455,6 +482,25 @@ public:
}
}
+ /**
+ * @brief Removes the given component from an entity.
+ *
+ * @warning
+ * Attempting to use an invalid entity or to remove a component from an
+ * entity that doesn't own it results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of
+ * invalid entity or if the entity doesn't own an instance of the given
+ * component.
+ *
+ * @tparam Component Type of component to remove.
+ * @param entity A valid entity identifier.
+ */
+ template
+ void remove(entity_type entity) {
+ assert(valid(entity));
+ pool().destroy(entity);
+ }
+
/**
* @brief Checks if the given tag has an owner.
* @tparam Tag Type of tag for which to perform the check.
@@ -470,6 +516,28 @@ public:
tags[ttype]->entity == (entities[tags[ttype]->entity & traits_type::entity_mask]));
}
+ /**
+ * @brief Checks if an entity has all the given components.
+ *
+ * @warning
+ * Attempting to use an invalid entity results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of
+ * invalid entity.
+ *
+ * @tparam Component Components for which to perform the check.
+ * @param entity A valid entity identifier.
+ * @return True if the entity has all the components, false otherwise.
+ */
+ template
+ bool has(entity_type entity) const noexcept {
+ assert(valid(entity));
+ using accumulator_type = bool[];
+ bool all = true;
+ accumulator_type accumulator = { all, (all = all && managed() && pool().has(entity))... };
+ (void)accumulator;
+ return all;
+ }
+
/**
* @brief Returns a reference to the given tag.
*
@@ -505,140 +573,6 @@ public:
return const_cast(const_cast(this)->get());
}
- /**
- * @brief Replaces the given tag.
- *
- * A new instance of the given tag is created and initialized with the
- * arguments provided (the tag must have a proper constructor or be of
- * aggregate type).
- *
- * @warning
- * Attempting to replace a tag that hasn't an owner results in undefined
- * behavior.
- * 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 replace.
- * @tparam Args Types of arguments to use to construct the tag.
- * @param args Parameters to use to initialize the tag.
- * @return A reference to the tag.
- */
- template
- Tag & set(Args &&... args) {
- return get() = Tag{std::forward(args)...};
- }
-
- /**
- * @brief Changes the owner of the given tag.
- *
- * The ownership of the tag is transferred from one entity to another.
- *
- * @warning
- * Attempting to use an invalid entity or to transfer the ownership of a tag
- * that hasn't an owner results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of
- * invalid entity or if the tag hasn't been previously attached to an
- * entity.
- *
- * @tparam Tag Type of tag of which to transfer the ownership.
- * @param entity A valid entity identifier.
- * @return A valid entity identifier.
- */
- template
- entity_type move(entity_type entity) {
- assert(valid(entity));
- assert(has());
- const auto ttype = tag_family::type();
- const auto owner = tags[ttype]->entity;
- tags[ttype]->entity = entity;
- return owner;
- }
-
- /**
- * @brief Gets the owner of the given 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.
- * 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
- entity_type attachee() const noexcept {
- assert(has());
- return tags[tag_family::type()]->entity;
- }
-
- /**
- * @brief Assigns the given component to an entity.
- *
- * A new instance of the given component is created and initialized with the
- * arguments provided (the component must have a proper constructor or be of
- * aggregate type). Then the component is assigned to the given entity.
- *
- * @warning
- * Attempting to use an invalid entity or to assign a component to an entity
- * that already owns it results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of
- * invalid entity or if the entity already owns an instance of the given
- * component.
- *
- * @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.
- * @return A reference to the newly created component.
- */
- template
- Component & assign(entity_type entity, Args &&... args) {
- assert(valid(entity));
- return assure().construct(entity, std::forward(args)...);
- }
-
- /**
- * @brief Removes the given component from an entity.
- *
- * @warning
- * Attempting to use an invalid entity or to remove a component from an
- * entity that doesn't own it results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of
- * invalid entity or if the entity doesn't own an instance of the given
- * component.
- *
- * @tparam Component Type of component to remove.
- * @param entity A valid entity identifier.
- */
- template
- void remove(entity_type entity) {
- assert(valid(entity));
- pool().destroy(entity);
- }
-
- /**
- * @brief Checks if an entity has all the given components.
- *
- * @warning
- * Attempting to use an invalid entity results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of
- * invalid entity.
- *
- * @tparam Component Components for which to perform the check.
- * @param entity A valid entity identifier.
- * @return True if the entity has all the components, false otherwise.
- */
- template
- bool has(entity_type entity) const noexcept {
- assert(valid(entity));
- using accumulator_type = bool[];
- bool all = true;
- accumulator_type accumulator = { all, (all = all && managed() && pool().has(entity))... };
- (void)accumulator;
- return all;
- }
-
/**
* @brief Returns a reference to the given component for an entity.
*
@@ -718,6 +652,29 @@ public:
return std::tuple{get(entity)...};
}
+ /**
+ * @brief Replaces the given tag.
+ *
+ * A new instance of the given tag is created and initialized with the
+ * arguments provided (the tag must have a proper constructor or be of
+ * aggregate type).
+ *
+ * @warning
+ * Attempting to replace a tag that hasn't an owner results in undefined
+ * behavior.
+ * 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 replace.
+ * @tparam Args Types of arguments to use to construct the tag.
+ * @param args Parameters to use to initialize the tag.
+ * @return A reference to the tag.
+ */
+ template
+ Tag & replace(tag_type_t, Args &&... args) {
+ return get() = Tag{std::forward(args)...};
+ }
+
/**
* @brief Replaces the given component for an entity.
*
@@ -743,6 +700,50 @@ public:
return (get(entity) = Component{std::forward(args)...});
}
+ /**
+ * @brief Changes the owner of the given tag.
+ *
+ * The ownership of the tag is transferred from one entity to another.
+ *
+ * @warning
+ * Attempting to use an invalid entity or to transfer the ownership of a tag
+ * that hasn't an owner results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of
+ * invalid entity or if the tag hasn't been previously attached to an
+ * entity.
+ *
+ * @tparam Tag Type of tag of which to transfer the ownership.
+ * @param entity A valid entity identifier.
+ * @return A valid entity identifier.
+ */
+ template
+ entity_type move(entity_type entity) {
+ assert(valid(entity));
+ assert(has());
+ const auto ttype = tag_family::type();
+ const auto owner = tags[ttype]->entity;
+ tags[ttype]->entity = entity;
+ return owner;
+ }
+
+ /**
+ * @brief Gets the owner of the given 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.
+ * 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
+ entity_type attachee() const noexcept {
+ assert(has());
+ return tags[tag_family::type()]->entity;
+ }
+
/**
* @brief Assigns or replaces the given component for an entity.
*
diff --git a/src/entt/entity/snapshot.hpp b/src/entt/entity/snapshot.hpp
index 57d2fa3f6..342d2940e 100644
--- a/src/entt/entity/snapshot.hpp
+++ b/src/entt/entity/snapshot.hpp
@@ -10,6 +10,7 @@
#include
#include
#include "entt_traits.hpp"
+#include "utility.hpp"
namespace entt {
@@ -50,7 +51,7 @@ class Snapshot final {
template
void get(Archive &archive, const Registry ®istry) {
- const auto component = registry.template component();
+ const auto component = registry.template type();
const auto sz = registry.template size();
const auto *entities = raw(registry, component);
@@ -216,21 +217,12 @@ class SnapshotLoader final {
}
}
- template
- void assign(Archive &archive) {
- each(archive, [&archive, this](auto entity) {
+ template
+ void assign(Archive &archive, Args... args) {
+ each(archive, [&archive, this, args...](auto entity) {
static constexpr auto destroyed = false;
assure_fn(registry, entity, destroyed);
- archive(registry.template assign(entity));
- });
- }
-
- template
- void attach(Archive &archive) {
- each(archive, [&archive, this](auto entity) {
- static constexpr auto destroyed = false;
- assure_fn(registry, entity, destroyed);
- archive(registry.template attach(entity));
+ archive(registry.template assign(args..., entity));
});
}
@@ -322,7 +314,7 @@ public:
template
SnapshotLoader & tag(Archive &archive) {
using accumulator_type = int[];
- accumulator_type accumulator = { 0, (attach(archive), 0)... };
+ accumulator_type accumulator = { 0, (assign(archive, tag_type_t{}), 0)... };
(void)accumulator;
return *this;
}
@@ -471,7 +463,7 @@ class ContinuousLoader final {
each(archive, [&archive, this](auto entity) {
entity = restore(entity);
- archive(registry.template attach(entity));
+ archive(registry.template assign(tag_type_t{}, entity));
});
}
diff --git a/src/entt/entity/utility.hpp b/src/entt/entity/utility.hpp
new file mode 100644
index 000000000..2e056a3b9
--- /dev/null
+++ b/src/entt/entity/utility.hpp
@@ -0,0 +1,20 @@
+#ifndef ENTT_ENTITY_UTILITY_HPP
+#define ENTT_ENTITY_UTILITY_HPP
+
+
+namespace entt {
+
+
+/**
+ * @brief Tag class type.
+ *
+ * An empty class type used to disambiguate the overloads of some member
+ * functions of the registry.
+ */
+struct tag_type_t final {};
+
+
+}
+
+
+#endif // ENTT_ENTITY_UTILITY_HPP
diff --git a/src/entt/entt.hpp b/src/entt/entt.hpp
index ca0547686..86475e9e4 100644
--- a/src/entt/entt.hpp
+++ b/src/entt/entt.hpp
@@ -6,6 +6,7 @@
#include "entity/registry.hpp"
#include "entity/snapshot.hpp"
#include "entity/sparse_set.hpp"
+#include "entity/utility.hpp"
#include "entity/view.hpp"
#include "locator/locator.hpp"
#include "process/process.hpp"
diff --git a/test/entt/entity/registry.cpp b/test/entt/entity/registry.cpp
index 61ab54042..e66bfe5ea 100644
--- a/test/entt/entity/registry.cpp
+++ b/test/entt/entity/registry.cpp
@@ -253,7 +253,7 @@ TEST(DefaultRegistry, Orphans) {
registry.create();
registry.assign(registry.create());
registry.create();
- registry.attach(registry.create());
+ registry.assign(entt::tag_type_t{}, registry.create());
registry.orphans([&](auto) { ++tot; });
ASSERT_EQ(tot, 2u);
@@ -272,11 +272,11 @@ TEST(DefaultRegistry, Orphans) {
TEST(DefaultRegistry, Types) {
entt::DefaultRegistry registry;
- ASSERT_EQ(registry.tag(), registry.tag());
- ASSERT_EQ(registry.component(), registry.component());
+ ASSERT_EQ(registry.type(entt::tag_type_t{}), registry.type(entt::tag_type_t{}));
+ ASSERT_EQ(registry.type(), registry.type());
- ASSERT_NE(registry.tag(), registry.tag());
- ASSERT_NE(registry.component(), registry.component());
+ ASSERT_NE(registry.type(entt::tag_type_t{}), registry.type(entt::tag_type_t{}));
+ ASSERT_NE(registry.type(), registry.type(entt::tag_type_t{}));
}
TEST(DefaultRegistry, CreateDestroyEntities) {
@@ -317,14 +317,14 @@ TEST(DefaultRegistry, AttachSetRemoveTags) {
ASSERT_FALSE(registry.has());
const auto entity = registry.create();
- registry.attach(entity, 42);
+ registry.assign(entt::tag_type_t{}, entity, 42);
ASSERT_TRUE(registry.has());
ASSERT_EQ(registry.get(), 42);
ASSERT_EQ(cregistry.get(), 42);
ASSERT_EQ(registry.attachee(), entity);
- registry.set(3);
+ registry.replace(entt::tag_type_t{}, 3);
ASSERT_TRUE(registry.has());
ASSERT_EQ(registry.get(), 3);
@@ -343,7 +343,7 @@ TEST(DefaultRegistry, AttachSetRemoveTags) {
ASSERT_FALSE(registry.has());
- registry.attach(entity, 42);
+ registry.assign(entt::tag_type_t{}, entity, 42);
registry.destroy(entity);
ASSERT_FALSE(registry.has());
@@ -437,7 +437,7 @@ TEST(DefaultRegistry, CleanPersistentViewsAfterReset) {
TEST(DefaultRegistry, CleanTagsAfterReset) {
entt::DefaultRegistry registry;
const auto entity = registry.create();
- registry.attach(entity);
+ registry.assign(entt::tag_type_t{}, entity);
ASSERT_TRUE(registry.has());
diff --git a/test/entt/entity/snapshot.cpp b/test/entt/entity/snapshot.cpp
index 67cd168f1..f2518955f 100644
--- a/test/entt/entity/snapshot.cpp
+++ b/test/entt/entity/snapshot.cpp
@@ -63,10 +63,10 @@ TEST(Snapshot, Dump) {
const auto e3 = registry.create();
registry.assign(e3, '0');
- registry.attach(e3, .3f);
+ registry.assign(entt::tag_type_t{}, e3, .3f);
const auto e4 = registry.create();
- registry.attach(e4);
+ registry.assign(entt::tag_type_t{}, e4);
registry.destroy(e1);
auto v1 = registry.current(e1);
@@ -152,10 +152,10 @@ TEST(Snapshot, Partial) {
const auto e3 = registry.create();
registry.assign(e3, '0');
- registry.attach(e3, .3f);
+ registry.assign(entt::tag_type_t{}, e3, .3f);
const auto e4 = registry.create();
- registry.attach(e4);
+ registry.assign(entt::tag_type_t{}, e4);
registry.destroy(e1);
auto v1 = registry.current(e1);
@@ -281,7 +281,7 @@ TEST(Snapshot, Continuous) {
if(i % 2) {
src.assign(entity, entity);
} else if(i == 2) {
- src.attach(entity, .3);
+ src.assign(entt::tag_type_t{}, entity, .3);
}
}
diff --git a/test/mod/mod.cpp b/test/mod/mod.cpp
index 0a4c47101..cd0777035 100644
--- a/test/mod/mod.cpp
+++ b/test/mod/mod.cpp
@@ -157,7 +157,7 @@ class DuktapeRegistry {
template
void reg() {
using accumulator_type = int[];
- accumulator_type acc = { (func[registry.component()] = {
+ accumulator_type acc = { (func[registry.type()] = {
&::set,
&::unset,
&::has,
@@ -186,7 +186,7 @@ class DuktapeRegistry {
auto type = duk_require_uint(ctx, 1);
if(type >= udef) {
- type = registry.component();
+ type = registry.type();
}
assert(func.find(type) != func.cend());
@@ -248,7 +248,7 @@ public:
assert(func.find(type) != func.cend());
match = (registry.*func[type].test)(entity);
} else {
- const auto ctype = registry.component();
+ const auto ctype = registry.type();
assert(func.find(ctype) != func.cend());
match = (registry.*func[ctype].test)(entity);
@@ -287,7 +287,7 @@ const duk_function_list_entry js_DuktapeRegistry_methods[] = {
void exportTypes(duk_context *ctx, entt::DefaultRegistry ®istry) {
auto exportType = [](auto *ctx, auto ®istry, auto idx, auto type, const auto *name) {
duk_push_string(ctx, name);
- duk_push_uint(ctx, registry.template component());
+ duk_push_uint(ctx, registry.template type());
duk_def_prop(ctx, idx, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_CLEAR_WRITABLE);
};