Просмотр исходного кода

entity identifiers as enum classes (close #256)

Michele Caini 6 лет назад
Родитель
Сommit
11d18fa1af

+ 7 - 5
docs/md/entity.md

@@ -137,9 +137,9 @@ use as-is and store around if needed. Do not try to inspect an entity
 identifier, its format can change in future and a registry offers all the
 functionalities to query them out-of-the-box. The underlying type of an entity
 (either `std::uint16_t`, `std::uint32_t` or `std::uint64_t`) can be specified
-when defining a registry (actually `entt::registry` is nothing more than an
-alias for `entt::basic_registry<entt::entity>` and `entt::entity` is an alias
-for `std::uint32_t`).<br/>
+when defining a registry. In fact, an `entt::registry` is nothing more than an
+alias for `entt::basic_registry<entt::entity>` and `entt::entity` is a distinct
+type that implements the concept of _entity identifier_.<br/>
 Components (the _C_ of an _ECS_) should be plain old data structures or more
 complex and movable data structures with a proper constructor. Actually, the
 sole requirement of a component type is that it must be both move constructible
@@ -162,12 +162,14 @@ A registry can store and manage entities, as well as create views and groups to
 iterate the underlying data structures.<br/>
 The class template `basic_registry` lets users decide what's the preferred type
 to represent an entity. Because `std::uint32_t` is large enough for almost all
-the cases, there exists also the alias `entt::entity` for it, as well as the
+the cases, there exists also the type `entt::entity` for it, as well as the
 alias `entt::registry` for `entt::basic_registry<entt::entity>`.
 
 Entities are represented by _entity identifiers_. An entity identifier is an
 opaque type that users should not inspect or modify in any way. It carries
-information about the entity itself and its version.
+information about the entity itself and its version.<br/>
+User defined identifiers can be introduced by means of the `ENTT_ENTITY_TYPE`
+macro if needed.
 
 A registry can be used both to construct and to destroy entities:
 

+ 1 - 1
src/entt/entity/actor.hpp

@@ -184,7 +184,7 @@ struct basic_actor {
 
 private:
     registry_type *reg;
-    Entity entt;
+    entity_type entt;
 };
 
 

+ 17 - 2
src/entt/entity/entity.hpp

@@ -3,6 +3,7 @@
 
 
 #include <cstdint>
+#include <type_traits>
 #include "../config/config.h"
 
 
@@ -109,8 +110,8 @@ namespace internal {
 struct null {
     template<typename Entity>
     constexpr operator Entity() const ENTT_NOEXCEPT {
-        using traits_type = entt_traits<Entity>;
-        return traits_type::entity_mask | (traits_type::version_mask << traits_type::entity_shift);
+        using traits_type = entt_traits<std::underlying_type_t<Entity>>;
+        return Entity{traits_type::entity_mask | (traits_type::version_mask << traits_type::entity_shift)};
     }
 
     constexpr bool operator==(null) const ENTT_NOEXCEPT {
@@ -164,6 +165,20 @@ constexpr bool operator!=(const Entity entity, null other) ENTT_NOEXCEPT {
 constexpr auto null = internal::null{};
 
 
+/**
+ * @brief Defines an enum class to use for entity identifiers and a dedicate
+ * `to_integer` function to convert the identifiers to their underlying type.
+ * @param clazz The name to use for the enum class.
+ * @param type The underlying type for the enum class.
+ */
+#define ENTT_ENTITY_TYPE(clazz, type)\
+    enum class clazz: type {};\
+    constexpr auto to_integer(const clazz entt) ENTT_NOEXCEPT {\
+        using traits_type = entt_traits<std::underlying_type_t<clazz>>;\
+        return typename traits_type::entity_type(entt);\
+    }
+
+
 }
 
 

+ 2 - 1
src/entt/entity/fwd.hpp

@@ -4,6 +4,7 @@
 
 #include <cstdint>
 #include "../config/config.h"
+#include "entity.hpp"
 
 
 namespace entt {
@@ -49,7 +50,7 @@ template<typename>
 class basic_continuous_loader;
 
 /*! @brief Alias declaration for the most common use case. */
-using entity = std::uint32_t;
+ENTT_ENTITY_TYPE(entity, std::uint32_t)
 
 /*! @brief Alias declaration for the most common use case. */
 using registry = basic_registry<entity>;

+ 2 - 3
src/entt/entity/observer.hpp

@@ -165,7 +165,6 @@ constexpr basic_collector<> collector{};
  */
 template<typename Entity>
 class basic_observer {
-    using traits_type = entt_traits<Entity>;
     using payload_type = std::uint32_t;
 
     template<typename>
@@ -257,7 +256,7 @@ class basic_observer {
 
 public:
     /*! @brief Underlying entity identifier. */
-    using entity_type = typename traits_type::entity_type;
+    using entity_type = Entity;
     /*! @brief Unsigned integer type. */
     using size_type = typename sparse_set<Entity>::size_type;
     /*! @brief Input iterator type. */
@@ -428,7 +427,7 @@ public:
 
 private:
     basic_registry<entity_type> *target;
-    void(* release)(basic_observer &, basic_registry<Entity> &);
+    void(* release)(basic_observer &, basic_registry<entity_type> &);
     storage<entity_type, payload_type> view;
 };
 

+ 39 - 35
src/entt/entity/registry.hpp

@@ -7,7 +7,6 @@
 #include <memory>
 #include <utility>
 #include <cstddef>
-#include <numeric>
 #include <iterator>
 #include <algorithm>
 #include <type_traits>
@@ -44,7 +43,7 @@ template<typename Entity>
 class basic_registry {
     using context_family = family<struct internal_registry_context_family>;
     using component_family = family<struct internal_registry_component_family>;
-    using traits_type = entt_traits<Entity>;
+    using traits_type = entt_traits<std::underlying_type_t<Entity>>;
 
     template<typename Component>
     struct pool_handler: storage<Entity, Component> {
@@ -214,11 +213,11 @@ class basic_registry {
 
     void release(const Entity entity) {
         // lengthens the implicit list of destroyed entities
-        const auto entt = entity & traits_type::entity_mask;
-        const auto version = ((entity >> traits_type::entity_shift) + 1) << traits_type::entity_shift;
-        const auto node = (available ? next : ((entt + 1) & traits_type::entity_mask)) | version;
-        entities[entt] = node;
-        next = entt;
+        const auto entt = to_integer(entity) & traits_type::entity_mask;
+        const auto version = ((to_integer(entity) >> traits_type::entity_shift) + 1) << traits_type::entity_shift;
+        const auto node = (available ? to_integer(next) : ((entt + 1) & traits_type::entity_mask)) | version;
+        entities[entt] = Entity{node};
+        next = Entity{entt};
         ++available;
     }
 
@@ -284,7 +283,7 @@ class basic_registry {
 
 public:
     /*! @brief Underlying entity identifier. */
-    using entity_type = typename traits_type::entity_type;
+    using entity_type = Entity;
     /*! @brief Underlying version type. */
     using version_type = typename traits_type::version_type;
     /*! @brief Unsigned integer type. */
@@ -473,7 +472,7 @@ public:
      * @return True if the identifier is valid, false otherwise.
      */
     bool valid(const entity_type entity) const ENTT_NOEXCEPT {
-        const auto pos = size_type(entity & traits_type::entity_mask);
+        const auto pos = size_type(to_integer(entity) & traits_type::entity_mask);
         return (pos < entities.size() && entities[pos] == entity);
     }
 
@@ -483,7 +482,7 @@ public:
      * @return The entity identifier without the version.
      */
     static entity_type entity(const entity_type entity) ENTT_NOEXCEPT {
-        return entity & traits_type::entity_mask;
+        return entity_type{to_integer(entity) & traits_type::entity_mask};
     }
 
     /**
@@ -492,7 +491,7 @@ public:
      * @return The version stored along with the given entity identifier.
      */
     static version_type version(const entity_type entity) ENTT_NOEXCEPT {
-        return version_type(entity >> traits_type::entity_shift);
+        return version_type(to_integer(entity) >> traits_type::entity_shift);
     }
 
     /**
@@ -509,9 +508,9 @@ public:
      * @return Actual version for the given entity identifier.
      */
     version_type current(const entity_type entity) const ENTT_NOEXCEPT {
-        const auto pos = size_type(entity & traits_type::entity_mask);
+        const auto pos = size_type(to_integer(entity) & traits_type::entity_mask);
         ENTT_ASSERT(pos < entities.size());
-        return version_type(entities[pos] >> traits_type::entity_shift);
+        return version_type(to_integer(entities[pos]) >> traits_type::entity_shift);
     }
 
     /**
@@ -541,16 +540,16 @@ public:
         entity_type entity;
 
         if(available) {
-            const auto entt = next;
-            const auto version = entities[entt] & (traits_type::version_mask << traits_type::entity_shift);
-            next = entities[entt] & traits_type::entity_mask;
-            entity = entt | version;
+            const auto entt = to_integer(next);
+            const auto version = to_integer(entities[entt]) & (traits_type::version_mask << traits_type::entity_shift);
+            next = entity_type{to_integer(entities[entt]) & traits_type::entity_mask};
+            entity = entity_type{entt | version};
             entities[entt] = entity;
             --available;
         } else {
             entity = entities.emplace_back(entity_type(entities.size()));
             // traits_type::entity_mask is reserved to allow for null identifiers
-            ENTT_ASSERT(entity < traits_type::entity_mask);
+            ENTT_ASSERT(to_integer(entity) < traits_type::entity_mask);
         }
 
         if constexpr(sizeof...(Component) == 0) {
@@ -584,16 +583,16 @@ public:
 
         const auto tail = std::generate_n(first, sz, [&candidate, this]() mutable {
             if constexpr(sizeof...(Component) > 0) {
-                candidate = std::max(candidate, next);
+                candidate = entity_type{std::max(candidate, next)};
             } else {
                 // suppress warnings
                 (void)candidate;
             }
 
-            const auto entt = next;
-            const auto version = entities[entt] & (traits_type::version_mask << traits_type::entity_shift);
-            next = entities[entt] & traits_type::entity_mask;
-            return (entities[entt] = entt | version);
+            const auto entt = to_integer(next);
+            const auto version = to_integer(entities[entt]) & (traits_type::version_mask << traits_type::entity_shift);
+            next = entity_type{to_integer(entities[entt]) & traits_type::entity_mask};
+            return (entities[entt] = entity_type{entt | version});
         });
 
         std::generate(tail, last, [this]() {
@@ -1145,8 +1144,8 @@ public:
         if(available) {
             for(auto pos = entities.size(); pos; --pos) {
                 const auto curr = entity_type(pos - 1);
-                const auto entity = entities[curr];
-                const auto entt = entity & traits_type::entity_mask;
+                const auto entity = entities[to_integer(curr)];
+                const auto entt = entity_type{to_integer(entity) & traits_type::entity_mask};
 
                 if(curr == entt) {
                     func(entity);
@@ -1486,13 +1485,17 @@ public:
      */
     entt::basic_snapshot<Entity> snapshot() const ENTT_NOEXCEPT {
         using follow_fn_type = entity_type(const basic_registry &, const entity_type);
-        const entity_type seed = available ? (next | (entities[next] & (traits_type::version_mask << traits_type::entity_shift))) : next;
+
+        const auto head = to_integer(next);
+        const entity_type seed = available
+                ? entity_type{head | (to_integer(entities[head]) & (traits_type::version_mask << traits_type::entity_shift))}
+                : next;
 
         follow_fn_type *follow = [](const basic_registry &reg, const entity_type entity) -> entity_type {
             const auto &others = reg.entities;
-            const auto entt = entity & traits_type::entity_mask;
-            const auto curr = others[entt] & traits_type::entity_mask;
-            return (curr | (others[curr] & (traits_type::version_mask << traits_type::entity_shift)));
+            const auto entt = to_integer(entity) & traits_type::entity_mask;
+            const auto curr = to_integer(others[entt]) & traits_type::entity_mask;
+            return entity_type{curr | (to_integer(others[curr]) & (traits_type::version_mask << traits_type::entity_shift))};
         };
 
         return { this, seed, follow };
@@ -1517,23 +1520,24 @@ public:
         using force_fn_type = void(basic_registry &, const entity_type, const bool);
 
         force_fn_type *force = [](basic_registry &reg, const entity_type entity, const bool destroyed) {
-            using promotion_type = std::conditional_t<sizeof(size_type) >= sizeof(entity_type), size_type, entity_type>;
-            // explicit promotion to avoid warnings with std::uint16_t
-            const auto entt = promotion_type{entity} & traits_type::entity_mask;
+            const auto entt = to_integer(entity) & traits_type::entity_mask;
             auto &others = reg.entities;
 
             if(!(entt < others.size())) {
                 auto curr = others.size();
                 others.resize(entt + 1);
-                std::iota(others.data() + curr, others.data() + entt, entity_type(curr));
+
+                std::generate(others.data() + curr, others.data() + entt, [curr]() mutable {
+                    return entity_type(curr++);
+                });
             }
 
             others[entt] = entity;
 
             if(destroyed) {
                 reg.destroy(entity);
-                const auto version = entity & (traits_type::version_mask << traits_type::entity_shift);
-                others[entt] = ((others[entt] & traits_type::entity_mask) | version);
+                const auto version = to_integer(entity) & (traits_type::version_mask << traits_type::entity_shift);
+                others[entt] = entity_type{(to_integer(others[entt]) & traits_type::entity_mask) | version};
             }
         };
 

+ 3 - 2
src/entt/entity/runtime_view.hpp

@@ -7,6 +7,7 @@
 #include <vector>
 #include <utility>
 #include <algorithm>
+#include <type_traits>
 #include "../config/config.h"
 #include "sparse_set.hpp"
 #include "entity.hpp"
@@ -61,7 +62,7 @@ class basic_runtime_view {
 
     using underlying_iterator_type = typename sparse_set<Entity>::iterator_type;
     using extent_type = typename sparse_set<Entity>::size_type;
-    using traits_type = entt_traits<Entity>;
+    using traits_type = entt_traits<std::underlying_type_t<Entity>>;
 
     class iterator {
         friend class basic_runtime_view<Entity>;
@@ -80,7 +81,7 @@ class basic_runtime_view {
 
         bool valid() const ENTT_NOEXCEPT {
             const auto entt = *begin;
-            const auto sz = size_type(entt & traits_type::entity_mask);
+            const auto sz = size_type(to_integer(entt) & traits_type::entity_mask);
 
             return sz < extent && std::all_of(from, to, [entt](const auto *view) {
                 return view->has(entt);

+ 13 - 11
src/entt/entity/snapshot.hpp

@@ -32,6 +32,7 @@ class basic_snapshot {
     friend class basic_registry<Entity>;
 
     using follow_fn_type = Entity(const basic_registry<Entity> &, const Entity);
+    using traits_type = entt_traits<std::underlying_type_t<Entity>>;
 
     basic_snapshot(const basic_registry<Entity> *source, Entity init, follow_fn_type *fn) ENTT_NOEXCEPT
         : reg{source},
@@ -41,7 +42,7 @@ class basic_snapshot {
 
     template<typename Component, typename Archive, typename It>
     void get(Archive &archive, std::size_t sz, It first, It last) const {
-        archive(static_cast<Entity>(sz));
+        archive(typename traits_type::entity_type(sz));
 
         while(first != last) {
             const auto entt = *(first++);
@@ -88,7 +89,7 @@ public:
      */
     template<typename Archive>
     const basic_snapshot & entities(Archive &archive) const {
-        archive(static_cast<Entity>(reg->alive()));
+        archive(typename traits_type::entity_type(reg->alive()));
         reg->each([&archive](const auto entt) { archive(entt); });
         return *this;
     }
@@ -106,7 +107,7 @@ public:
     template<typename Archive>
     const basic_snapshot & destroyed(Archive &archive) const {
         auto size = reg->size() - reg->alive();
-        archive(static_cast<Entity>(size));
+        archive(typename traits_type::entity_type(size));
 
         if(size) {
             auto curr = seed;
@@ -138,7 +139,7 @@ public:
             const auto sz = reg->template size<Component...>();
             const auto *entities = reg->template data<Component...>();
 
-            archive(static_cast<Entity>(sz));
+            archive(typename traits_type::entity_type(sz));
 
             for(std::remove_const_t<decltype(sz)> pos{}; pos < sz; ++pos) {
                 const auto entt = entities[pos];
@@ -199,6 +200,7 @@ class basic_snapshot_loader {
     friend class basic_registry<Entity>;
 
     using force_fn_type = void(basic_registry<Entity> &, const Entity, const bool);
+    using traits_type = entt_traits<std::underlying_type_t<Entity>>;
 
     basic_snapshot_loader(basic_registry<Entity> *source, force_fn_type *fn) ENTT_NOEXCEPT
         : reg{source},
@@ -210,7 +212,7 @@ class basic_snapshot_loader {
 
     template<typename Archive>
     void assure(Archive &archive, bool destroyed) const {
-        Entity length{};
+        typename traits_type::entity_type length{};
         archive(length);
 
         while(length--) {
@@ -222,7 +224,7 @@ class basic_snapshot_loader {
 
     template<typename Type, typename Archive, typename... Args>
     void assign(Archive &archive, Args... args) const {
-        Entity length{};
+        typename traits_type::entity_type length{};
         archive(length);
 
         while(length--) {
@@ -344,7 +346,7 @@ private:
  */
 template<typename Entity>
 class basic_continuous_loader {
-    using traits_type = entt_traits<Entity>;
+    using traits_type = entt_traits<std::underlying_type_t<Entity>>;
 
     void destroy(Entity entt) {
         const auto it = remloc.find(entt);
@@ -385,7 +387,7 @@ class basic_continuous_loader {
 
     template<typename Archive>
     void assure(Archive &archive, void(basic_continuous_loader:: *member)(Entity)) {
-        Entity length{};
+        typename traits_type::entity_type length{};
         archive(length);
 
         while(length--) {
@@ -408,7 +410,7 @@ class basic_continuous_loader {
 
     template<typename Other, typename Archive, typename... Type, typename... Member>
     void assign(Archive &archive, [[maybe_unused]] Member Type:: *... member) {
-        Entity length{};
+        typename traits_type::entity_type length{};
         archive(length);
 
         while(length--) {
@@ -578,8 +580,8 @@ public:
     }
 
 private:
-    std::unordered_map<Entity, std::pair<Entity, bool>> remloc;
-    basic_registry<Entity> *reg;
+    std::unordered_map<entity_type, std::pair<entity_type, bool>> remloc;
+    basic_registry<entity_type> *reg;
 };
 
 

+ 7 - 5
src/entt/entity/sparse_set.hpp

@@ -8,8 +8,10 @@
 #include <vector>
 #include <memory>
 #include <cstddef>
+#include <type_traits>
 #include "../config/config.h"
 #include "entity.hpp"
+#include "fwd.hpp"
 
 
 namespace entt {
@@ -44,7 +46,7 @@ namespace entt {
  */
 template<typename Entity>
 class sparse_set {
-    using traits_type = entt_traits<Entity>;
+    using traits_type = entt_traits<std::underlying_type_t<Entity>>;
 
     static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0));
     static constexpr auto entt_per_page = ENTT_PAGE_SIZE / sizeof(typename traits_type::entity_type);
@@ -163,7 +165,7 @@ class sparse_set {
     }
 
     auto index(const Entity entt) const ENTT_NOEXCEPT {
-        const auto identifier = entt & traits_type::entity_mask;
+        const auto identifier = to_integer(entt) & traits_type::entity_mask;
         const auto page = size_type(identifier / entt_per_page);
         const auto offset = size_type(identifier & (entt_per_page - 1));
         return std::make_pair(page, offset);
@@ -413,11 +415,11 @@ public:
      */
     template<typename It>
     void batch(It first, It last) {
-        std::for_each(first, last, [next = entity_type(direct.size()), this](const auto entt) mutable {
+        std::for_each(first, last, [next = direct.size(), this](const auto entt) mutable {
             ENTT_ASSERT(!has(entt));
             auto [page, offset] = index(entt);
             assure(page);
-            reverse[page][offset] = next++;
+            reverse[page][offset] = entity_type(next++);
         });
 
         direct.insert(direct.end(), first, last);
@@ -438,7 +440,7 @@ public:
         ENTT_ASSERT(has(entt));
         auto [from_page, from_offset] = index(entt);
         auto [to_page, to_offset] = index(direct.back());
-        direct[size_type(reverse[from_page][from_offset])] = direct.back();
+        direct[size_type(reverse[from_page][from_offset])] = entity_type(direct.back());
         reverse[to_page][to_offset] = reverse[from_page][from_offset];
         reverse[from_page][from_offset] = null;
         direct.pop_back();

+ 2 - 2
src/entt/entity/storage.hpp

@@ -49,7 +49,7 @@ namespace entt {
 template<typename Entity, typename Type, typename = std::void_t<>>
 class basic_storage: public sparse_set<Entity> {
     using underlying_type = sparse_set<Entity>;
-    using traits_type = entt_traits<Entity>;
+    using traits_type = entt_traits<std::underlying_type_t<Entity>>;
 
     template<bool Const>
     class iterator {
@@ -530,8 +530,8 @@ private:
 /*! @copydoc basic_storage */
 template<typename Entity, typename Type>
 class basic_storage<Entity, Type, std::enable_if_t<std::is_empty_v<Type>>>: public sparse_set<Entity> {
+    using traits_type = entt_traits<std::underlying_type_t<Entity>>;
     using underlying_type = sparse_set<Entity>;
-    using traits_type = entt_traits<Entity>;
 
     class iterator {
         friend class basic_storage<Entity, Type>;

+ 2 - 2
src/entt/entity/view.hpp

@@ -71,7 +71,7 @@ class basic_view {
 
     using underlying_iterator_type = typename sparse_set<Entity>::iterator_type;
     using unchecked_type = std::array<const sparse_set<Entity> *, (sizeof...(Component) - 1)>;
-    using traits_type = entt_traits<Entity>;
+    using traits_type = entt_traits<std::underlying_type_t<Entity>>;
 
     class iterator {
         friend class basic_view<Entity, Component...>;
@@ -96,7 +96,7 @@ class basic_view {
 
         bool valid() const ENTT_NOEXCEPT {
             const auto entt = *begin;
-            const auto sz = size_type(entt& traits_type::entity_mask);
+            const auto sz = size_type(to_integer(entt) & traits_type::entity_mask);
 
             return sz < extent && std::all_of(unchecked.cbegin(), unchecked.cend(), [entt](const sparse_set<Entity> *view) {
                 return view->has(entt);

+ 5 - 2
test/entt/entity/entity.cpp

@@ -1,15 +1,18 @@
 #include <functional>
+#include <type_traits>
 #include <gtest/gtest.h>
 #include <entt/entity/entity.hpp>
 #include <entt/entity/registry.hpp>
 
 TEST(Traits, Null) {
-    entt::registry registry{};
+    using traits_type = entt::entt_traits<std::underlying_type_t<entt::entity>>;
 
+    entt::registry registry{};
     const auto entity = registry.create();
+
     registry.assign<int>(entity, 42);
 
-    ASSERT_TRUE(~entt::entity{} == entt::null);
+    ASSERT_TRUE(entt::entity{~traits_type::entity_type{}} == entt::null);
 
     ASSERT_TRUE(entt::null == entt::null);
     ASSERT_FALSE(entt::null != entt::null);

+ 8 - 8
test/entt/entity/group.cpp

@@ -242,9 +242,9 @@ TEST(NonOwningGroup, ConstNonConstAndAllInBetween) {
 
     ASSERT_EQ(group.size(), decltype(group.size()){1});
 
-    ASSERT_TRUE((std::is_same_v<decltype(group.get<int>(0)), int &>));
-    ASSERT_TRUE((std::is_same_v<decltype(group.get<const char>(0)), const char &>));
-    ASSERT_TRUE((std::is_same_v<decltype(group.get<int, const char>(0)), std::tuple<int &, const char &>>));
+    ASSERT_TRUE((std::is_same_v<decltype(group.get<int>(entt::entity{0})), int &>));
+    ASSERT_TRUE((std::is_same_v<decltype(group.get<const char>(entt::entity{0})), const char &>));
+    ASSERT_TRUE((std::is_same_v<decltype(group.get<int, const char>(entt::entity{0})), std::tuple<int &, const char &>>));
     ASSERT_TRUE((std::is_same_v<decltype(group.raw<const char>()), const char *>));
     ASSERT_TRUE((std::is_same_v<decltype(group.raw<int>()), int *>));
 
@@ -761,11 +761,11 @@ TEST(OwningGroup, ConstNonConstAndAllInBetween) {
 
     ASSERT_EQ(group.size(), decltype(group.size()){1});
 
-    ASSERT_TRUE((std::is_same_v<decltype(group.get<int>(0)), int &>));
-    ASSERT_TRUE((std::is_same_v<decltype(group.get<const char>(0)), const char &>));
-    ASSERT_TRUE((std::is_same_v<decltype(group.get<double>(0)), double &>));
-    ASSERT_TRUE((std::is_same_v<decltype(group.get<const float>(0)), const float &>));
-    ASSERT_TRUE((std::is_same_v<decltype(group.get<int, const char, double, const float>(0)), std::tuple<int &, const char &, double &, const float &>>));
+    ASSERT_TRUE((std::is_same_v<decltype(group.get<int>(entt::entity{0})), int &>));
+    ASSERT_TRUE((std::is_same_v<decltype(group.get<const char>(entt::entity{0})), const char &>));
+    ASSERT_TRUE((std::is_same_v<decltype(group.get<double>(entt::entity{0})), double &>));
+    ASSERT_TRUE((std::is_same_v<decltype(group.get<const float>(entt::entity{0})), const float &>));
+    ASSERT_TRUE((std::is_same_v<decltype(group.get<int, const char, double, const float>(entt::entity{0})), std::tuple<int &, const char &, double &, const float &>>));
     ASSERT_TRUE((std::is_same_v<decltype(group.raw<const float>()), const float *>));
     ASSERT_TRUE((std::is_same_v<decltype(group.raw<double>()), double *>));
     ASSERT_TRUE((std::is_same_v<decltype(group.raw<const char>()), const char *>));

+ 1 - 1
test/entt/entity/registry.cpp

@@ -311,7 +311,7 @@ TEST(Registry, VersionOverflow) {
 
     ASSERT_EQ(registry.version(entity), entt::registry::version_type{});
 
-    for(auto i = entt::entt_traits<entt::entity>::version_mask; i; --i) {
+    for(auto i = entt::entt_traits<std::underlying_type_t<entt::entity>>::version_mask; i; --i) {
         ASSERT_NE(registry.current(entity), registry.version(entity));
         registry.destroy(registry.create());
     }

+ 23 - 2
test/entt/entity/snapshot.cpp

@@ -1,6 +1,7 @@
 #include <tuple>
 #include <queue>
 #include <vector>
+#include <type_traits>
 #include <gtest/gtest.h>
 #include <entt/entity/registry.hpp>
 #include <entt/entity/entity.hpp>
@@ -54,6 +55,8 @@ struct what_a_component {
 };
 
 TEST(Snapshot, Dump) {
+    using traits_type = entt::entt_traits<std::underlying_type_t<entt::entity>>;
+
     entt::registry registry;
 
     const auto e0 = registry.create();
@@ -74,6 +77,7 @@ TEST(Snapshot, Dump) {
     auto v1 = registry.current(e1);
 
     using storage_type = std::tuple<
+        std::queue<typename traits_type::entity_type>,
         std::queue<entt::entity>,
         std::queue<int>,
         std::queue<char>,
@@ -125,6 +129,8 @@ TEST(Snapshot, Dump) {
 }
 
 TEST(Snapshot, Partial) {
+    using traits_type = entt::entt_traits<std::underlying_type_t<entt::entity>>;
+
     entt::registry registry;
 
     const auto e0 = registry.create();
@@ -144,6 +150,7 @@ TEST(Snapshot, Partial) {
     auto v1 = registry.current(e1);
 
     using storage_type = std::tuple<
+        std::queue<typename traits_type::entity_type>,
         std::queue<entt::entity>,
         std::queue<int>,
         std::queue<char>,
@@ -206,6 +213,8 @@ TEST(Snapshot, Partial) {
 }
 
 TEST(Snapshot, Iterator) {
+    using traits_type = entt::entt_traits<std::underlying_type_t<entt::entity>>;
+
     entt::registry registry;
 
     for(auto i = 0; i < 50; ++i) {
@@ -218,6 +227,7 @@ TEST(Snapshot, Iterator) {
     }
 
     using storage_type = std::tuple<
+        std::queue<typename traits_type::entity_type>,
         std::queue<entt::entity>,
         std::queue<another_component>
     >;
@@ -236,11 +246,13 @@ TEST(Snapshot, Iterator) {
     ASSERT_EQ(registry.view<another_component>().size(), size);
 
     registry.view<another_component>().each([](const auto entity, const auto &) {
-        ASSERT_TRUE(entity % 2);
+        ASSERT_TRUE(entt::to_integer(entity) % 2);
     });
 }
 
 TEST(Snapshot, Continuous) {
+    using traits_type = entt::entt_traits<std::underlying_type_t<entt::entity>>;
+
     entt::registry src;
     entt::registry dst;
 
@@ -250,6 +262,7 @@ TEST(Snapshot, Continuous) {
     entt::entity entity;
 
     using storage_type = std::tuple<
+        std::queue<typename traits_type::entity_type>,
         std::queue<entt::entity>,
         std::queue<another_component>,
         std::queue<what_a_component>,
@@ -429,12 +442,17 @@ TEST(Snapshot, Continuous) {
 }
 
 TEST(Snapshot, MoreOnShrink) {
+    using traits_type = entt::entt_traits<std::underlying_type_t<entt::entity>>;
+
     entt::registry src;
     entt::registry dst;
 
     entt::continuous_loader loader{dst};
 
-    using storage_type = std::tuple<std::queue<entt::entity>>;
+    using storage_type = std::tuple<
+        std::queue<typename traits_type::entity_type>,
+        std::queue<entt::entity>
+    >;
 
     storage_type storage;
     output_archive<storage_type> output{storage};
@@ -452,12 +470,15 @@ TEST(Snapshot, MoreOnShrink) {
 }
 
 TEST(Snapshot, SyncDataMembers) {
+    using traits_type = entt::entt_traits<std::underlying_type_t<entt::entity>>;
+
     entt::registry src;
     entt::registry dst;
 
     entt::continuous_loader loader{dst};
 
     using storage_type = std::tuple<
+        std::queue<typename traits_type::entity_type>,
         std::queue<entt::entity>,
         std::queue<what_a_component>
     >;

+ 205 - 204
test/entt/entity/sparse_set.cpp

@@ -4,12 +4,13 @@
 #include <type_traits>
 #include <gtest/gtest.h>
 #include <entt/entity/sparse_set.hpp>
+#include <entt/entity/fwd.hpp>
 
 struct empty_type {};
 struct boxed_int { int value; };
 
 TEST(SparseSet, Functionalities) {
-    entt::sparse_set<std::uint64_t> set;
+    entt::sparse_set<entt::entity> set;
 
     set.reserve(42);
 
@@ -18,54 +19,54 @@ TEST(SparseSet, Functionalities) {
     ASSERT_EQ(set.size(), 0u);
     ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end());
     ASSERT_EQ(set.begin(), set.end());
-    ASSERT_FALSE(set.has(0));
-    ASSERT_FALSE(set.has(42));
+    ASSERT_FALSE(set.has(entt::entity{0}));
+    ASSERT_FALSE(set.has(entt::entity{42}));
 
-    set.construct(42);
+    set.construct(entt::entity{42});
 
-    ASSERT_EQ(set.get(42), 0u);
+    ASSERT_EQ(set.get(entt::entity{42}), 0u);
 
     ASSERT_FALSE(set.empty());
     ASSERT_EQ(set.size(), 1u);
     ASSERT_NE(std::as_const(set).begin(), std::as_const(set).end());
     ASSERT_NE(set.begin(), set.end());
-    ASSERT_FALSE(set.has(0));
-    ASSERT_TRUE(set.has(42));
-    ASSERT_EQ(set.get(42), 0u);
+    ASSERT_FALSE(set.has(entt::entity{0}));
+    ASSERT_TRUE(set.has(entt::entity{42}));
+    ASSERT_EQ(set.get(entt::entity{42}), 0u);
 
-    set.destroy(42);
+    set.destroy(entt::entity{42});
 
     ASSERT_TRUE(set.empty());
     ASSERT_EQ(set.size(), 0u);
     ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end());
     ASSERT_EQ(set.begin(), set.end());
-    ASSERT_FALSE(set.has(0));
-    ASSERT_FALSE(set.has(42));
+    ASSERT_FALSE(set.has(entt::entity{0}));
+    ASSERT_FALSE(set.has(entt::entity{42}));
 
-    set.construct(42);
+    set.construct(entt::entity{42});
 
     ASSERT_FALSE(set.empty());
-    ASSERT_EQ(set.get(42), 0u);
+    ASSERT_EQ(set.get(entt::entity{42}), 0u);
 
     ASSERT_TRUE(std::is_move_constructible_v<decltype(set)>);
     ASSERT_TRUE(std::is_move_assignable_v<decltype(set)>);
 
-    entt::sparse_set<std::uint64_t> cpy{set};
+    entt::sparse_set<entt::entity> cpy{set};
     set = cpy;
 
     ASSERT_FALSE(set.empty());
     ASSERT_FALSE(cpy.empty());
-    ASSERT_EQ(set.get(42), 0u);
-    ASSERT_EQ(cpy.get(42), 0u);
+    ASSERT_EQ(set.get(entt::entity{42}), 0u);
+    ASSERT_EQ(cpy.get(entt::entity{42}), 0u);
 
-    entt::sparse_set<std::uint64_t> other{std::move(set)};
+    entt::sparse_set<entt::entity> other{std::move(set)};
 
     set = std::move(other);
     other = std::move(set);
 
     ASSERT_TRUE(set.empty());
     ASSERT_FALSE(other.empty());
-    ASSERT_EQ(other.get(42), 0u);
+    ASSERT_EQ(other.get(entt::entity{42}), 0u);
 
     other.reset();
 
@@ -73,40 +74,40 @@ TEST(SparseSet, Functionalities) {
     ASSERT_EQ(other.size(), 0u);
     ASSERT_EQ(std::as_const(other).begin(), std::as_const(other).end());
     ASSERT_EQ(other.begin(), other.end());
-    ASSERT_FALSE(other.has(0));
-    ASSERT_FALSE(other.has(42));
+    ASSERT_FALSE(other.has(entt::entity{0}));
+    ASSERT_FALSE(other.has(entt::entity{42}));
 }
 
 TEST(SparseSet, Pagination) {
-    entt::sparse_set<std::uint64_t> set;
-    constexpr auto entt_per_page = ENTT_PAGE_SIZE / sizeof(std::uint64_t);
+    entt::sparse_set<entt::entity> set;
+    constexpr auto entt_per_page = ENTT_PAGE_SIZE / sizeof(std::underlying_type_t<entt::entity>);
 
     ASSERT_EQ(set.extent(), 0);
 
-    set.construct(entt_per_page-1);
+    set.construct(entt::entity{entt_per_page-1});
 
     ASSERT_EQ(set.extent(), entt_per_page);
-    ASSERT_TRUE(set.has(entt_per_page-1));
+    ASSERT_TRUE(set.has(entt::entity{entt_per_page-1}));
 
-    set.construct(entt_per_page);
+    set.construct(entt::entity{entt_per_page});
 
     ASSERT_EQ(set.extent(), 2 * entt_per_page);
-    ASSERT_TRUE(set.has(entt_per_page-1));
-    ASSERT_TRUE(set.has(entt_per_page));
-    ASSERT_FALSE(set.has(entt_per_page+1));
+    ASSERT_TRUE(set.has(entt::entity{entt_per_page-1}));
+    ASSERT_TRUE(set.has(entt::entity{entt_per_page}));
+    ASSERT_FALSE(set.has(entt::entity{entt_per_page+1}));
 
-    set.destroy(entt_per_page-1);
+    set.destroy(entt::entity{entt_per_page-1});
 
     ASSERT_EQ(set.extent(), 2 * entt_per_page);
-    ASSERT_FALSE(set.has(entt_per_page-1));
-    ASSERT_TRUE(set.has(entt_per_page));
+    ASSERT_FALSE(set.has(entt::entity{entt_per_page-1}));
+    ASSERT_TRUE(set.has(entt::entity{entt_per_page}));
 
     set.shrink_to_fit();
-    set.destroy(entt_per_page);
+    set.destroy(entt::entity{entt_per_page});
 
     ASSERT_EQ(set.extent(), 2 * entt_per_page);
-    ASSERT_FALSE(set.has(entt_per_page-1));
-    ASSERT_FALSE(set.has(entt_per_page));
+    ASSERT_FALSE(set.has(entt::entity{entt_per_page-1}));
+    ASSERT_FALSE(set.has(entt::entity{entt_per_page}));
 
     set.shrink_to_fit();
 
@@ -114,36 +115,36 @@ TEST(SparseSet, Pagination) {
 }
 
 TEST(SparseSet, BatchAdd) {
-    entt::sparse_set<std::uint64_t> set;
-    entt::sparse_set<std::uint64_t>::entity_type entities[2];
+    entt::sparse_set<entt::entity> set;
+    entt::sparse_set<entt::entity>::entity_type entities[2];
 
-    entities[0] = 3;
-    entities[1] = 42;
+    entities[0] = entt::entity{3};
+    entities[1] = entt::entity{42};
 
-    set.construct(12);
+    set.construct(entt::entity{12});
     set.batch(std::begin(entities), std::end(entities));
-    set.construct(24);
+    set.construct(entt::entity{24});
 
     ASSERT_TRUE(set.has(entities[0]));
     ASSERT_TRUE(set.has(entities[1]));
-    ASSERT_FALSE(set.has(0));
-    ASSERT_FALSE(set.has(9));
-    ASSERT_TRUE(set.has(12));
-    ASSERT_TRUE(set.has(24));
+    ASSERT_FALSE(set.has(entt::entity{0}));
+    ASSERT_FALSE(set.has(entt::entity{9}));
+    ASSERT_TRUE(set.has(entt::entity{12}));
+    ASSERT_TRUE(set.has(entt::entity{24}));
 
     ASSERT_FALSE(set.empty());
     ASSERT_EQ(set.size(), 4u);
-    ASSERT_EQ(set.get(12), 0u);
+    ASSERT_EQ(set.get(entt::entity{12}), 0u);
     ASSERT_EQ(set.get(entities[0]), 1u);
     ASSERT_EQ(set.get(entities[1]), 2u);
-    ASSERT_EQ(set.get(24), 3u);
+    ASSERT_EQ(set.get(entt::entity{24}), 3u);
 }
 
 TEST(SparseSet, Iterator) {
-    using iterator_type = typename entt::sparse_set<std::uint64_t>::iterator_type;
+    using iterator_type = typename entt::sparse_set<entt::entity>::iterator_type;
 
-    entt::sparse_set<std::uint64_t> set;
-    set.construct(3);
+    entt::sparse_set<entt::entity> set;
+    set.construct(entt::entity{3});
 
     iterator_type end{set.begin()};
     iterator_type begin{};
@@ -180,216 +181,216 @@ TEST(SparseSet, Iterator) {
     ASSERT_GT(end, begin);
     ASSERT_GE(end, set.end());
 
-    ASSERT_EQ(*begin, 3);
-    ASSERT_EQ(*begin.operator->(), 3);
+    ASSERT_EQ(*begin, entt::entity{3});
+    ASSERT_EQ(*begin.operator->(), entt::entity{3});
 }
 
 TEST(SparseSet, Find) {
-    entt::sparse_set<std::uint64_t> set;
-    set.construct(3);
-    set.construct(42);
-    set.construct(99);
+    entt::sparse_set<entt::entity> set;
+    set.construct(entt::entity{3});
+    set.construct(entt::entity{42});
+    set.construct(entt::entity{99});
 
-    ASSERT_NE(set.find(3), set.end());
-    ASSERT_NE(set.find(42), set.end());
-    ASSERT_NE(set.find(99), set.end());
-    ASSERT_EQ(set.find(0), set.end());
+    ASSERT_NE(set.find(entt::entity{3}), set.end());
+    ASSERT_NE(set.find(entt::entity{42}), set.end());
+    ASSERT_NE(set.find(entt::entity{99}), set.end());
+    ASSERT_EQ(set.find(entt::entity{0}), set.end());
 
-    auto it = set.find(99);
+    auto it = set.find(entt::entity{99});
 
-    ASSERT_EQ(*it, 99);
-    ASSERT_EQ(*(++it), 42);
-    ASSERT_EQ(*(++it), 3);
+    ASSERT_EQ(*it, entt::entity{99});
+    ASSERT_EQ(*(++it), entt::entity{42});
+    ASSERT_EQ(*(++it), entt::entity{3});
     ASSERT_EQ(++it, set.end());
-    ASSERT_EQ(++set.find(3), set.end());
+    ASSERT_EQ(++set.find(entt::entity{3}), set.end());
 }
 
 TEST(SparseSet, Data) {
-    entt::sparse_set<std::uint64_t> set;
+    entt::sparse_set<entt::entity> set;
 
-    set.construct(3);
-    set.construct(12);
-    set.construct(42);
+    set.construct(entt::entity{3});
+    set.construct(entt::entity{12});
+    set.construct(entt::entity{42});
 
-    ASSERT_EQ(set.get(3), 0u);
-    ASSERT_EQ(set.get(12), 1u);
-    ASSERT_EQ(set.get(42), 2u);
+    ASSERT_EQ(set.get(entt::entity{3}), 0u);
+    ASSERT_EQ(set.get(entt::entity{12}), 1u);
+    ASSERT_EQ(set.get(entt::entity{42}), 2u);
 
-    ASSERT_EQ(*(set.data() + 0u), 3u);
-    ASSERT_EQ(*(set.data() + 1u), 12u);
-    ASSERT_EQ(*(set.data() + 2u), 42u);
+    ASSERT_EQ(*(set.data() + 0u), entt::entity{3});
+    ASSERT_EQ(*(set.data() + 1u), entt::entity{12});
+    ASSERT_EQ(*(set.data() + 2u), entt::entity{42});
 }
 
 TEST(SparseSet, RespectDisjoint) {
-    entt::sparse_set<std::uint64_t> lhs;
-    entt::sparse_set<std::uint64_t> rhs;
+    entt::sparse_set<entt::entity> lhs;
+    entt::sparse_set<entt::entity> rhs;
 
-    lhs.construct(3);
-    lhs.construct(12);
-    lhs.construct(42);
+    lhs.construct(entt::entity{3});
+    lhs.construct(entt::entity{12});
+    lhs.construct(entt::entity{42});
 
-    ASSERT_EQ(lhs.get(3), 0u);
-    ASSERT_EQ(lhs.get(12), 1u);
-    ASSERT_EQ(lhs.get(42), 2u);
+    ASSERT_EQ(lhs.get(entt::entity{3}), 0u);
+    ASSERT_EQ(lhs.get(entt::entity{12}), 1u);
+    ASSERT_EQ(lhs.get(entt::entity{42}), 2u);
 
     lhs.respect(rhs);
 
-    ASSERT_EQ(std::as_const(lhs).get(3), 0u);
-    ASSERT_EQ(std::as_const(lhs).get(12), 1u);
-    ASSERT_EQ(std::as_const(lhs).get(42), 2u);
+    ASSERT_EQ(std::as_const(lhs).get(entt::entity{3}), 0u);
+    ASSERT_EQ(std::as_const(lhs).get(entt::entity{12}), 1u);
+    ASSERT_EQ(std::as_const(lhs).get(entt::entity{42}), 2u);
 }
 
 TEST(SparseSet, RespectOverlap) {
-    entt::sparse_set<std::uint64_t> lhs;
-    entt::sparse_set<std::uint64_t> rhs;
+    entt::sparse_set<entt::entity> lhs;
+    entt::sparse_set<entt::entity> rhs;
 
-    lhs.construct(3);
-    lhs.construct(12);
-    lhs.construct(42);
+    lhs.construct(entt::entity{3});
+    lhs.construct(entt::entity{12});
+    lhs.construct(entt::entity{42});
 
-    rhs.construct(12);
+    rhs.construct(entt::entity{12});
 
-    ASSERT_EQ(lhs.get(3), 0u);
-    ASSERT_EQ(lhs.get(12), 1u);
-    ASSERT_EQ(lhs.get(42), 2u);
+    ASSERT_EQ(lhs.get(entt::entity{3}), 0u);
+    ASSERT_EQ(lhs.get(entt::entity{12}), 1u);
+    ASSERT_EQ(lhs.get(entt::entity{42}), 2u);
 
     lhs.respect(rhs);
 
-    ASSERT_EQ(std::as_const(lhs).get(3), 0u);
-    ASSERT_EQ(std::as_const(lhs).get(12), 2u);
-    ASSERT_EQ(std::as_const(lhs).get(42), 1u);
+    ASSERT_EQ(std::as_const(lhs).get(entt::entity{3}), 0u);
+    ASSERT_EQ(std::as_const(lhs).get(entt::entity{12}), 2u);
+    ASSERT_EQ(std::as_const(lhs).get(entt::entity{42}), 1u);
 }
 
 TEST(SparseSet, RespectOrdered) {
-    entt::sparse_set<std::uint64_t> lhs;
-    entt::sparse_set<std::uint64_t> rhs;
-
-    lhs.construct(1);
-    lhs.construct(2);
-    lhs.construct(3);
-    lhs.construct(4);
-    lhs.construct(5);
-
-    ASSERT_EQ(lhs.get(1), 0u);
-    ASSERT_EQ(lhs.get(2), 1u);
-    ASSERT_EQ(lhs.get(3), 2u);
-    ASSERT_EQ(lhs.get(4), 3u);
-    ASSERT_EQ(lhs.get(5), 4u);
-
-    rhs.construct(6);
-    rhs.construct(1);
-    rhs.construct(2);
-    rhs.construct(3);
-    rhs.construct(4);
-    rhs.construct(5);
-
-    ASSERT_EQ(rhs.get(6), 0u);
-    ASSERT_EQ(rhs.get(1), 1u);
-    ASSERT_EQ(rhs.get(2), 2u);
-    ASSERT_EQ(rhs.get(3), 3u);
-    ASSERT_EQ(rhs.get(4), 4u);
-    ASSERT_EQ(rhs.get(5), 5u);
+    entt::sparse_set<entt::entity> lhs;
+    entt::sparse_set<entt::entity> rhs;
+
+    lhs.construct(entt::entity{1});
+    lhs.construct(entt::entity{2});
+    lhs.construct(entt::entity{3});
+    lhs.construct(entt::entity{4});
+    lhs.construct(entt::entity{5});
+
+    ASSERT_EQ(lhs.get(entt::entity{1}), 0u);
+    ASSERT_EQ(lhs.get(entt::entity{2}), 1u);
+    ASSERT_EQ(lhs.get(entt::entity{3}), 2u);
+    ASSERT_EQ(lhs.get(entt::entity{4}), 3u);
+    ASSERT_EQ(lhs.get(entt::entity{5}), 4u);
+
+    rhs.construct(entt::entity{6});
+    rhs.construct(entt::entity{1});
+    rhs.construct(entt::entity{2});
+    rhs.construct(entt::entity{3});
+    rhs.construct(entt::entity{4});
+    rhs.construct(entt::entity{5});
+
+    ASSERT_EQ(rhs.get(entt::entity{6}), 0u);
+    ASSERT_EQ(rhs.get(entt::entity{1}), 1u);
+    ASSERT_EQ(rhs.get(entt::entity{2}), 2u);
+    ASSERT_EQ(rhs.get(entt::entity{3}), 3u);
+    ASSERT_EQ(rhs.get(entt::entity{4}), 4u);
+    ASSERT_EQ(rhs.get(entt::entity{5}), 5u);
 
     rhs.respect(lhs);
 
-    ASSERT_EQ(rhs.get(6), 0u);
-    ASSERT_EQ(rhs.get(1), 1u);
-    ASSERT_EQ(rhs.get(2), 2u);
-    ASSERT_EQ(rhs.get(3), 3u);
-    ASSERT_EQ(rhs.get(4), 4u);
-    ASSERT_EQ(rhs.get(5), 5u);
+    ASSERT_EQ(rhs.get(entt::entity{6}), 0u);
+    ASSERT_EQ(rhs.get(entt::entity{1}), 1u);
+    ASSERT_EQ(rhs.get(entt::entity{2}), 2u);
+    ASSERT_EQ(rhs.get(entt::entity{3}), 3u);
+    ASSERT_EQ(rhs.get(entt::entity{4}), 4u);
+    ASSERT_EQ(rhs.get(entt::entity{5}), 5u);
 }
 
 TEST(SparseSet, RespectReverse) {
-    entt::sparse_set<std::uint64_t> lhs;
-    entt::sparse_set<std::uint64_t> rhs;
-
-    lhs.construct(1);
-    lhs.construct(2);
-    lhs.construct(3);
-    lhs.construct(4);
-    lhs.construct(5);
-
-    ASSERT_EQ(lhs.get(1), 0u);
-    ASSERT_EQ(lhs.get(2), 1u);
-    ASSERT_EQ(lhs.get(3), 2u);
-    ASSERT_EQ(lhs.get(4), 3u);
-    ASSERT_EQ(lhs.get(5), 4u);
-
-    rhs.construct(5);
-    rhs.construct(4);
-    rhs.construct(3);
-    rhs.construct(2);
-    rhs.construct(1);
-    rhs.construct(6);
-
-    ASSERT_EQ(rhs.get(5), 0u);
-    ASSERT_EQ(rhs.get(4), 1u);
-    ASSERT_EQ(rhs.get(3), 2u);
-    ASSERT_EQ(rhs.get(2), 3u);
-    ASSERT_EQ(rhs.get(1), 4u);
-    ASSERT_EQ(rhs.get(6), 5u);
+    entt::sparse_set<entt::entity> lhs;
+    entt::sparse_set<entt::entity> rhs;
+
+    lhs.construct(entt::entity{1});
+    lhs.construct(entt::entity{2});
+    lhs.construct(entt::entity{3});
+    lhs.construct(entt::entity{4});
+    lhs.construct(entt::entity{5});
+
+    ASSERT_EQ(lhs.get(entt::entity{1}), 0u);
+    ASSERT_EQ(lhs.get(entt::entity{2}), 1u);
+    ASSERT_EQ(lhs.get(entt::entity{3}), 2u);
+    ASSERT_EQ(lhs.get(entt::entity{4}), 3u);
+    ASSERT_EQ(lhs.get(entt::entity{5}), 4u);
+
+    rhs.construct(entt::entity{5});
+    rhs.construct(entt::entity{4});
+    rhs.construct(entt::entity{3});
+    rhs.construct(entt::entity{2});
+    rhs.construct(entt::entity{1});
+    rhs.construct(entt::entity{6});
+
+    ASSERT_EQ(rhs.get(entt::entity{5}), 0u);
+    ASSERT_EQ(rhs.get(entt::entity{4}), 1u);
+    ASSERT_EQ(rhs.get(entt::entity{3}), 2u);
+    ASSERT_EQ(rhs.get(entt::entity{2}), 3u);
+    ASSERT_EQ(rhs.get(entt::entity{1}), 4u);
+    ASSERT_EQ(rhs.get(entt::entity{6}), 5u);
 
     rhs.respect(lhs);
 
-    ASSERT_EQ(rhs.get(6), 0u);
-    ASSERT_EQ(rhs.get(1), 1u);
-    ASSERT_EQ(rhs.get(2), 2u);
-    ASSERT_EQ(rhs.get(3), 3u);
-    ASSERT_EQ(rhs.get(4), 4u);
-    ASSERT_EQ(rhs.get(5), 5u);
+    ASSERT_EQ(rhs.get(entt::entity{6}), 0u);
+    ASSERT_EQ(rhs.get(entt::entity{1}), 1u);
+    ASSERT_EQ(rhs.get(entt::entity{2}), 2u);
+    ASSERT_EQ(rhs.get(entt::entity{3}), 3u);
+    ASSERT_EQ(rhs.get(entt::entity{4}), 4u);
+    ASSERT_EQ(rhs.get(entt::entity{5}), 5u);
 }
 
 TEST(SparseSet, RespectUnordered) {
-    entt::sparse_set<std::uint64_t> lhs;
-    entt::sparse_set<std::uint64_t> rhs;
-
-    lhs.construct(1);
-    lhs.construct(2);
-    lhs.construct(3);
-    lhs.construct(4);
-    lhs.construct(5);
-
-    ASSERT_EQ(lhs.get(1), 0u);
-    ASSERT_EQ(lhs.get(2), 1u);
-    ASSERT_EQ(lhs.get(3), 2u);
-    ASSERT_EQ(lhs.get(4), 3u);
-    ASSERT_EQ(lhs.get(5), 4u);
-
-    rhs.construct(3);
-    rhs.construct(2);
-    rhs.construct(6);
-    rhs.construct(1);
-    rhs.construct(4);
-    rhs.construct(5);
-
-    ASSERT_EQ(rhs.get(3), 0u);
-    ASSERT_EQ(rhs.get(2), 1u);
-    ASSERT_EQ(rhs.get(6), 2u);
-    ASSERT_EQ(rhs.get(1), 3u);
-    ASSERT_EQ(rhs.get(4), 4u);
-    ASSERT_EQ(rhs.get(5), 5u);
+    entt::sparse_set<entt::entity> lhs;
+    entt::sparse_set<entt::entity> rhs;
+
+    lhs.construct(entt::entity{1});
+    lhs.construct(entt::entity{2});
+    lhs.construct(entt::entity{3});
+    lhs.construct(entt::entity{4});
+    lhs.construct(entt::entity{5});
+
+    ASSERT_EQ(lhs.get(entt::entity{1}), 0u);
+    ASSERT_EQ(lhs.get(entt::entity{2}), 1u);
+    ASSERT_EQ(lhs.get(entt::entity{3}), 2u);
+    ASSERT_EQ(lhs.get(entt::entity{4}), 3u);
+    ASSERT_EQ(lhs.get(entt::entity{5}), 4u);
+
+    rhs.construct(entt::entity{3});
+    rhs.construct(entt::entity{2});
+    rhs.construct(entt::entity{6});
+    rhs.construct(entt::entity{1});
+    rhs.construct(entt::entity{4});
+    rhs.construct(entt::entity{5});
+
+    ASSERT_EQ(rhs.get(entt::entity{3}), 0u);
+    ASSERT_EQ(rhs.get(entt::entity{2}), 1u);
+    ASSERT_EQ(rhs.get(entt::entity{6}), 2u);
+    ASSERT_EQ(rhs.get(entt::entity{1}), 3u);
+    ASSERT_EQ(rhs.get(entt::entity{4}), 4u);
+    ASSERT_EQ(rhs.get(entt::entity{5}), 5u);
 
     rhs.respect(lhs);
 
-    ASSERT_EQ(rhs.get(6), 0u);
-    ASSERT_EQ(rhs.get(1), 1u);
-    ASSERT_EQ(rhs.get(2), 2u);
-    ASSERT_EQ(rhs.get(3), 3u);
-    ASSERT_EQ(rhs.get(4), 4u);
-    ASSERT_EQ(rhs.get(5), 5u);
+    ASSERT_EQ(rhs.get(entt::entity{6}), 0u);
+    ASSERT_EQ(rhs.get(entt::entity{1}), 1u);
+    ASSERT_EQ(rhs.get(entt::entity{2}), 2u);
+    ASSERT_EQ(rhs.get(entt::entity{3}), 3u);
+    ASSERT_EQ(rhs.get(entt::entity{4}), 4u);
+    ASSERT_EQ(rhs.get(entt::entity{5}), 5u);
 }
 
 TEST(SparseSet, CanModifyDuringIteration) {
-    entt::sparse_set<std::uint64_t> set;
-    set.construct(0);
+    entt::sparse_set<entt::entity> set;
+    set.construct(entt::entity{0});
 
-    ASSERT_EQ(set.capacity(), entt::sparse_set<std::uint64_t>::size_type{1});
+    ASSERT_EQ(set.capacity(), entt::sparse_set<entt::entity>::size_type{1});
 
     const auto it = set.begin();
-    set.reserve(entt::sparse_set<std::uint64_t>::size_type{2});
+    set.reserve(entt::sparse_set<entt::entity>::size_type{2});
 
-    ASSERT_EQ(set.capacity(), entt::sparse_set<std::uint64_t>::size_type{2});
+    ASSERT_EQ(set.capacity(), entt::sparse_set<entt::entity>::size_type{2});
 
     // this should crash with asan enabled if we break the constraint
     const auto entity = *it;

+ 271 - 270
test/entt/entity/storage.cpp

@@ -6,6 +6,7 @@
 #include <unordered_set>
 #include <gtest/gtest.h>
 #include <entt/entity/storage.hpp>
+#include <entt/entity/fwd.hpp>
 
 struct empty_type {};
 struct boxed_int { int value; };
@@ -20,7 +21,7 @@ struct throwing_component {
 };
 
 TEST(Storage, Functionalities) {
-    entt::storage<std::uint64_t, int> set;
+    entt::storage<entt::entity, int> set;
 
     set.reserve(42);
 
@@ -29,35 +30,35 @@ TEST(Storage, Functionalities) {
     ASSERT_EQ(set.size(), 0u);
     ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end());
     ASSERT_EQ(set.begin(), set.end());
-    ASSERT_FALSE(set.has(0));
-    ASSERT_FALSE(set.has(41));
+    ASSERT_FALSE(set.has(entt::entity{0}));
+    ASSERT_FALSE(set.has(entt::entity{41}));
 
-    set.construct(41, 3);
+    set.construct(entt::entity{41}, 3);
 
     ASSERT_FALSE(set.empty());
     ASSERT_EQ(set.size(), 1u);
     ASSERT_NE(std::as_const(set).begin(), std::as_const(set).end());
     ASSERT_NE(set.begin(), set.end());
-    ASSERT_FALSE(set.has(0));
-    ASSERT_TRUE(set.has(41));
-    ASSERT_EQ(set.get(41), 3);
-    ASSERT_EQ(*set.try_get(41), 3);
-    ASSERT_EQ(set.try_get(99), nullptr);
+    ASSERT_FALSE(set.has(entt::entity{0}));
+    ASSERT_TRUE(set.has(entt::entity{41}));
+    ASSERT_EQ(set.get(entt::entity{41}), 3);
+    ASSERT_EQ(*set.try_get(entt::entity{41}), 3);
+    ASSERT_EQ(set.try_get(entt::entity{99}), nullptr);
 
-    set.destroy(41);
+    set.destroy(entt::entity{41});
 
     ASSERT_TRUE(set.empty());
     ASSERT_EQ(set.size(), 0u);
     ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end());
     ASSERT_EQ(set.begin(), set.end());
-    ASSERT_FALSE(set.has(0));
-    ASSERT_FALSE(set.has(41));
+    ASSERT_FALSE(set.has(entt::entity{0}));
+    ASSERT_FALSE(set.has(entt::entity{41}));
 
-    set.construct(41, 12);
+    set.construct(entt::entity{41}, 12);
 
-    ASSERT_EQ(set.get(41), 12);
-    ASSERT_EQ(*set.try_get(41), 12);
-    ASSERT_EQ(set.try_get(99), nullptr);
+    ASSERT_EQ(set.get(entt::entity{41}), 12);
+    ASSERT_EQ(*set.try_get(entt::entity{41}), 12);
+    ASSERT_EQ(set.try_get(entt::entity{99}), nullptr);
 
     set.reset();
 
@@ -65,8 +66,8 @@ TEST(Storage, Functionalities) {
     ASSERT_EQ(set.size(), 0u);
     ASSERT_EQ(std::as_const(set).begin(), std::as_const(set).end());
     ASSERT_EQ(set.begin(), set.end());
-    ASSERT_FALSE(set.has(0));
-    ASSERT_FALSE(set.has(41));
+    ASSERT_FALSE(set.has(entt::entity{0}));
+    ASSERT_FALSE(set.has(entt::entity{41}));
 
     ASSERT_EQ(set.capacity(), 42);
 
@@ -74,50 +75,50 @@ TEST(Storage, Functionalities) {
 
     ASSERT_EQ(set.capacity(), 0);
 
-    (void)entt::storage<std::uint64_t, int>{std::move(set)};
-    entt::storage<std::uint64_t, int> other;
+    (void)entt::storage<entt::entity, int>{std::move(set)};
+    entt::storage<entt::entity, int> other;
     other = std::move(set);
 }
 
 TEST(Storage, EmptyType) {
-    entt::storage<std::uint64_t, empty_type> set;
+    entt::storage<entt::entity, empty_type> set;
 
-    set.construct(42);
-    set.construct(99);
+    set.construct(entt::entity{42});
+    set.construct(entt::entity{99});
 
-    ASSERT_TRUE(set.has(42));
-    ASSERT_TRUE(set.has(99));
+    ASSERT_TRUE(set.has(entt::entity{42}));
+    ASSERT_TRUE(set.has(entt::entity{99}));
 
-    auto &&component = set.get(42);
+    auto &&component = set.get(entt::entity{42});
 
     ASSERT_TRUE((std::is_same_v<decltype(component), empty_type &&>));
 }
 
 TEST(Storage, BatchAdd) {
-    entt::storage<std::uint64_t, int> set;
-    entt::storage<std::uint64_t, int>::entity_type entities[2];
+    entt::storage<entt::entity, int> set;
+    entt::storage<entt::entity, int>::entity_type entities[2];
 
-    entities[0] = 3;
-    entities[1] = 42;
+    entities[0] = entt::entity{3};
+    entities[1] = entt::entity{42};
 
     set.reserve(4);
-    set.construct(12, 21);
+    set.construct(entt::entity{12}, 21);
     auto *component = set.batch(std::begin(entities), std::end(entities));
-    set.construct(24, 42);
+    set.construct(entt::entity{24}, 42);
 
     ASSERT_TRUE(set.has(entities[0]));
     ASSERT_TRUE(set.has(entities[1]));
-    ASSERT_FALSE(set.has(0));
-    ASSERT_FALSE(set.has(9));
-    ASSERT_TRUE(set.has(12));
-    ASSERT_TRUE(set.has(24));
+    ASSERT_FALSE(set.has(entt::entity{0}));
+    ASSERT_FALSE(set.has(entt::entity{9}));
+    ASSERT_TRUE(set.has(entt::entity{12}));
+    ASSERT_TRUE(set.has(entt::entity{24}));
 
     ASSERT_FALSE(set.empty());
     ASSERT_EQ(set.size(), 4u);
-    ASSERT_EQ(set.get(12), 21);
+    ASSERT_EQ(set.get(entt::entity{12}), 21);
     ASSERT_EQ(set.get(entities[0]), 0);
     ASSERT_EQ(set.get(entities[1]), 0);
-    ASSERT_EQ(set.get(24), 42);
+    ASSERT_EQ(set.get(entt::entity{24}), 42);
 
     component[0] = 1;
     component[1] = 2;
@@ -127,23 +128,23 @@ TEST(Storage, BatchAdd) {
 }
 
 TEST(Storage, BatchAddEmptyType) {
-    entt::storage<std::uint64_t, empty_type> set;
-    entt::storage<std::uint64_t, empty_type>::entity_type entities[2];
+    entt::storage<entt::entity, empty_type> set;
+    entt::storage<entt::entity, empty_type>::entity_type entities[2];
 
-    entities[0] = 3;
-    entities[1] = 42;
+    entities[0] = entt::entity{3};
+    entities[1] = entt::entity{42};
 
     set.reserve(4);
-    set.construct(12);
+    set.construct(entt::entity{12});
     set.batch(std::begin(entities), std::end(entities));
-    set.construct(24);
+    set.construct(entt::entity{24});
 
     ASSERT_TRUE(set.has(entities[0]));
     ASSERT_TRUE(set.has(entities[1]));
-    ASSERT_FALSE(set.has(0));
-    ASSERT_FALSE(set.has(9));
-    ASSERT_TRUE(set.has(12));
-    ASSERT_TRUE(set.has(24));
+    ASSERT_FALSE(set.has(entt::entity{0}));
+    ASSERT_FALSE(set.has(entt::entity{9}));
+    ASSERT_TRUE(set.has(entt::entity{12}));
+    ASSERT_TRUE(set.has(entt::entity{24}));
 
     ASSERT_FALSE(set.empty());
     ASSERT_EQ(set.size(), 4u);
@@ -156,21 +157,21 @@ TEST(Storage, BatchAddEmptyType) {
 TEST(Storage, AggregatesMustWork) {
     struct aggregate_type { int value; };
     // the goal of this test is to enforce the requirements for aggregate types
-    entt::storage<std::uint64_t, aggregate_type>{}.construct(0, 42);
+    entt::storage<entt::entity, aggregate_type>{}.construct(entt::entity{0}, 42);
 }
 
 TEST(Storage, TypesFromStandardTemplateLibraryMustWork) {
     // see #37 - this test shouldn't crash, that's all
-    entt::storage<std::uint64_t, std::unordered_set<int>> set;
-    set.construct(0).insert(42);
-    set.destroy(0);
+    entt::storage<entt::entity, std::unordered_set<int>> set;
+    set.construct(entt::entity{0}).insert(42);
+    set.destroy(entt::entity{0});
 }
 
 TEST(Storage, Iterator) {
-    using iterator_type = typename entt::storage<std::uint64_t, boxed_int>::iterator_type;
+    using iterator_type = typename entt::storage<entt::entity, boxed_int>::iterator_type;
 
-    entt::storage<std::uint64_t, boxed_int> set;
-    set.construct(3, 42);
+    entt::storage<entt::entity, boxed_int> set;
+    set.construct(entt::entity{3}, 42);
 
     iterator_type end{set.begin()};
     iterator_type begin{};
@@ -209,10 +210,10 @@ TEST(Storage, Iterator) {
 }
 
 TEST(Storage, ConstIterator) {
-    using iterator_type = typename entt::storage<std::uint64_t, boxed_int>::const_iterator_type;
+    using iterator_type = typename entt::storage<entt::entity, boxed_int>::const_iterator_type;
 
-    entt::storage<std::uint64_t, boxed_int> set;
-    set.construct(3, 42);
+    entt::storage<entt::entity, boxed_int> set;
+    set.construct(entt::entity{3}, 42);
 
     iterator_type cend{set.cbegin()};
     iterator_type cbegin{};
@@ -251,9 +252,9 @@ TEST(Storage, ConstIterator) {
 }
 
 TEST(Storage, IteratorEmptyType) {
-    using iterator_type = typename entt::storage<std::uint64_t, empty_type>::iterator_type;
-    entt::storage<std::uint64_t, empty_type> set;
-    set.construct(3);
+    using iterator_type = typename entt::storage<entt::entity, empty_type>::iterator_type;
+    entt::storage<entt::entity, empty_type> set;
+    set.construct(entt::entity{3});
 
     iterator_type end{set.begin()};
     iterator_type begin{};
@@ -290,22 +291,22 @@ TEST(Storage, IteratorEmptyType) {
     ASSERT_GT(end, begin);
     ASSERT_GE(end, set.end());
 
-    set.construct(33);
+    set.construct(entt::entity{33});
     auto &&component = *begin;
 
     ASSERT_TRUE((std::is_same_v<decltype(component), empty_type &&>));
 }
 
 TEST(Storage, Raw) {
-    entt::storage<std::uint64_t, int> set;
+    entt::storage<entt::entity, int> set;
 
-    set.construct(3, 3);
-    set.construct(12, 6);
-    set.construct(42, 9);
+    set.construct(entt::entity{3}, 3);
+    set.construct(entt::entity{12}, 6);
+    set.construct(entt::entity{42}, 9);
 
-    ASSERT_EQ(set.get(3), 3);
-    ASSERT_EQ(std::as_const(set).get(12), 6);
-    ASSERT_EQ(set.get(42), 9);
+    ASSERT_EQ(set.get(entt::entity{3}), 3);
+    ASSERT_EQ(std::as_const(set).get(entt::entity{12}), 6);
+    ASSERT_EQ(set.get(entt::entity{42}), 9);
 
     ASSERT_EQ(*(set.raw() + 0u), 3);
     ASSERT_EQ(*(std::as_const(set).raw() + 1u), 6);
@@ -313,19 +314,19 @@ TEST(Storage, Raw) {
 }
 
 TEST(Storage, SortOrdered) {
-    entt::storage<std::uint64_t, boxed_int> set;
+    entt::storage<entt::entity, boxed_int> set;
 
-    set.construct(12, boxed_int{12});
-    set.construct(42, boxed_int{9});
-    set.construct(7, boxed_int{6});
-    set.construct(3, boxed_int{3});
-    set.construct(9, boxed_int{1});
+    set.construct(entt::entity{12}, boxed_int{12});
+    set.construct(entt::entity{42}, boxed_int{9});
+    set.construct(entt::entity{7}, boxed_int{6});
+    set.construct(entt::entity{3}, boxed_int{3});
+    set.construct(entt::entity{9}, boxed_int{1});
 
-    ASSERT_EQ(set.get(12).value, 12);
-    ASSERT_EQ(set.get(42).value, 9);
-    ASSERT_EQ(set.get(7).value, 6);
-    ASSERT_EQ(set.get(3).value, 3);
-    ASSERT_EQ(set.get(9).value, 1);
+    ASSERT_EQ(set.get(entt::entity{12}).value, 12);
+    ASSERT_EQ(set.get(entt::entity{42}).value, 9);
+    ASSERT_EQ(set.get(entt::entity{7}).value, 6);
+    ASSERT_EQ(set.get(entt::entity{3}).value, 3);
+    ASSERT_EQ(set.get(entt::entity{9}).value, 1);
 
     set.sort([](auto lhs, auto rhs) {
         return lhs.value < rhs.value;
@@ -349,21 +350,21 @@ TEST(Storage, SortOrdered) {
 }
 
 TEST(Storage, SortReverse) {
-    entt::storage<std::uint64_t, boxed_int> set;
+    entt::storage<entt::entity, boxed_int> set;
 
-    set.construct(12, boxed_int{1});
-    set.construct(42, boxed_int{3});
-    set.construct(7, boxed_int{6});
-    set.construct(3, boxed_int{9});
-    set.construct(9, boxed_int{12});
+    set.construct(entt::entity{12}, boxed_int{1});
+    set.construct(entt::entity{42}, boxed_int{3});
+    set.construct(entt::entity{7}, boxed_int{6});
+    set.construct(entt::entity{3}, boxed_int{9});
+    set.construct(entt::entity{9}, boxed_int{12});
 
-    ASSERT_EQ(set.get(12).value, 1);
-    ASSERT_EQ(set.get(42).value, 3);
-    ASSERT_EQ(set.get(7).value, 6);
-    ASSERT_EQ(set.get(3).value, 9);
-    ASSERT_EQ(set.get(9).value, 12);
+    ASSERT_EQ(set.get(entt::entity{12}).value, 1);
+    ASSERT_EQ(set.get(entt::entity{42}).value, 3);
+    ASSERT_EQ(set.get(entt::entity{7}).value, 6);
+    ASSERT_EQ(set.get(entt::entity{3}).value, 9);
+    ASSERT_EQ(set.get(entt::entity{9}).value, 12);
 
-    set.sort([&set](std::uint64_t lhs, std::uint64_t rhs) {
+    set.sort([&set](entt::entity lhs, entt::entity rhs) {
         return set.get(lhs).value < set.get(rhs).value;
     });
 
@@ -385,19 +386,19 @@ TEST(Storage, SortReverse) {
 }
 
 TEST(Storage, SortUnordered) {
-    entt::storage<std::uint64_t, boxed_int> set;
+    entt::storage<entt::entity, boxed_int> set;
 
-    set.construct(12, boxed_int{6});
-    set.construct(42, boxed_int{3});
-    set.construct(7, boxed_int{1});
-    set.construct(3, boxed_int{9});
-    set.construct(9, boxed_int{12});
+    set.construct(entt::entity{12}, boxed_int{6});
+    set.construct(entt::entity{42}, boxed_int{3});
+    set.construct(entt::entity{7}, boxed_int{1});
+    set.construct(entt::entity{3}, boxed_int{9});
+    set.construct(entt::entity{9}, boxed_int{12});
 
-    ASSERT_EQ(set.get(12).value, 6);
-    ASSERT_EQ(set.get(42).value, 3);
-    ASSERT_EQ(set.get(7).value, 1);
-    ASSERT_EQ(set.get(3).value, 9);
-    ASSERT_EQ(set.get(9).value, 12);
+    ASSERT_EQ(set.get(entt::entity{12}).value, 6);
+    ASSERT_EQ(set.get(entt::entity{42}).value, 3);
+    ASSERT_EQ(set.get(entt::entity{7}).value, 1);
+    ASSERT_EQ(set.get(entt::entity{3}).value, 9);
+    ASSERT_EQ(set.get(entt::entity{9}).value, 12);
 
     set.sort([](auto lhs, auto rhs) {
         return lhs.value < rhs.value;
@@ -421,16 +422,16 @@ TEST(Storage, SortUnordered) {
 }
 
 TEST(Storage, RespectDisjoint) {
-    entt::storage<std::uint64_t, int> lhs;
-    entt::storage<std::uint64_t, int> rhs;
+    entt::storage<entt::entity, int> lhs;
+    entt::storage<entt::entity, int> rhs;
 
-    lhs.construct(3, 3);
-    lhs.construct(12, 6);
-    lhs.construct(42, 9);
+    lhs.construct(entt::entity{3}, 3);
+    lhs.construct(entt::entity{12}, 6);
+    lhs.construct(entt::entity{42}, 9);
 
-    ASSERT_EQ(std::as_const(lhs).get(3), 3);
-    ASSERT_EQ(std::as_const(lhs).get(12), 6);
-    ASSERT_EQ(std::as_const(lhs).get(42), 9);
+    ASSERT_EQ(std::as_const(lhs).get(entt::entity{3}), 3);
+    ASSERT_EQ(std::as_const(lhs).get(entt::entity{12}), 6);
+    ASSERT_EQ(std::as_const(lhs).get(entt::entity{42}), 9);
 
     lhs.respect(rhs);
 
@@ -448,18 +449,18 @@ TEST(Storage, RespectDisjoint) {
 }
 
 TEST(Storage, RespectOverlap) {
-    entt::storage<std::uint64_t, int> lhs;
-    entt::storage<std::uint64_t, int> rhs;
+    entt::storage<entt::entity, int> lhs;
+    entt::storage<entt::entity, int> rhs;
 
-    lhs.construct(3, 3);
-    lhs.construct(12, 6);
-    lhs.construct(42, 9);
-    rhs.construct(12, 6);
+    lhs.construct(entt::entity{3}, 3);
+    lhs.construct(entt::entity{12}, 6);
+    lhs.construct(entt::entity{42}, 9);
+    rhs.construct(entt::entity{12}, 6);
 
-    ASSERT_EQ(std::as_const(lhs).get(3), 3);
-    ASSERT_EQ(std::as_const(lhs).get(12), 6);
-    ASSERT_EQ(std::as_const(lhs).get(42), 9);
-    ASSERT_EQ(rhs.get(12), 6);
+    ASSERT_EQ(std::as_const(lhs).get(entt::entity{3}), 3);
+    ASSERT_EQ(std::as_const(lhs).get(entt::entity{12}), 6);
+    ASSERT_EQ(std::as_const(lhs).get(entt::entity{42}), 9);
+    ASSERT_EQ(rhs.get(entt::entity{12}), 6);
 
     lhs.respect(rhs);
 
@@ -477,174 +478,174 @@ TEST(Storage, RespectOverlap) {
 }
 
 TEST(Storage, RespectOrdered) {
-    entt::storage<std::uint64_t, int> lhs;
-    entt::storage<std::uint64_t, int> rhs;
-
-    lhs.construct(1, 0);
-    lhs.construct(2, 0);
-    lhs.construct(3, 0);
-    lhs.construct(4, 0);
-    lhs.construct(5, 0);
-
-    ASSERT_EQ(lhs.get(1), 0);
-    ASSERT_EQ(lhs.get(2), 0);
-    ASSERT_EQ(lhs.get(3), 0);
-    ASSERT_EQ(lhs.get(4), 0);
-    ASSERT_EQ(lhs.get(5), 0);
-
-    rhs.construct(6, 0);
-    rhs.construct(1, 0);
-    rhs.construct(2, 0);
-    rhs.construct(3, 0);
-    rhs.construct(4, 0);
-    rhs.construct(5, 0);
-
-    ASSERT_EQ(rhs.get(6), 0);
-    ASSERT_EQ(rhs.get(1), 0);
-    ASSERT_EQ(rhs.get(2), 0);
-    ASSERT_EQ(rhs.get(3), 0);
-    ASSERT_EQ(rhs.get(4), 0);
-    ASSERT_EQ(rhs.get(5), 0);
+    entt::storage<entt::entity, int> lhs;
+    entt::storage<entt::entity, int> rhs;
+
+    lhs.construct(entt::entity{1}, 0);
+    lhs.construct(entt::entity{2}, 0);
+    lhs.construct(entt::entity{3}, 0);
+    lhs.construct(entt::entity{4}, 0);
+    lhs.construct(entt::entity{5}, 0);
+
+    ASSERT_EQ(lhs.get(entt::entity{1}), 0);
+    ASSERT_EQ(lhs.get(entt::entity{2}), 0);
+    ASSERT_EQ(lhs.get(entt::entity{3}), 0);
+    ASSERT_EQ(lhs.get(entt::entity{4}), 0);
+    ASSERT_EQ(lhs.get(entt::entity{5}), 0);
+
+    rhs.construct(entt::entity{6}, 0);
+    rhs.construct(entt::entity{1}, 0);
+    rhs.construct(entt::entity{2}, 0);
+    rhs.construct(entt::entity{3}, 0);
+    rhs.construct(entt::entity{4}, 0);
+    rhs.construct(entt::entity{5}, 0);
+
+    ASSERT_EQ(rhs.get(entt::entity{6}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{1}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{2}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{3}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{4}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{5}), 0);
 
     rhs.respect(lhs);
 
-    ASSERT_EQ(*(lhs.data() + 0u), 1u);
-    ASSERT_EQ(*(lhs.data() + 1u), 2u);
-    ASSERT_EQ(*(lhs.data() + 2u), 3u);
-    ASSERT_EQ(*(lhs.data() + 3u), 4u);
-    ASSERT_EQ(*(lhs.data() + 4u), 5u);
-
-    ASSERT_EQ(*(rhs.data() + 0u), 6u);
-    ASSERT_EQ(*(rhs.data() + 1u), 1u);
-    ASSERT_EQ(*(rhs.data() + 2u), 2u);
-    ASSERT_EQ(*(rhs.data() + 3u), 3u);
-    ASSERT_EQ(*(rhs.data() + 4u), 4u);
-    ASSERT_EQ(*(rhs.data() + 5u), 5u);
+    ASSERT_EQ(*(lhs.data() + 0u), entt::entity{1});
+    ASSERT_EQ(*(lhs.data() + 1u), entt::entity{2});
+    ASSERT_EQ(*(lhs.data() + 2u), entt::entity{3});
+    ASSERT_EQ(*(lhs.data() + 3u), entt::entity{4});
+    ASSERT_EQ(*(lhs.data() + 4u), entt::entity{5});
+
+    ASSERT_EQ(*(rhs.data() + 0u), entt::entity{6});
+    ASSERT_EQ(*(rhs.data() + 1u), entt::entity{1});
+    ASSERT_EQ(*(rhs.data() + 2u), entt::entity{2});
+    ASSERT_EQ(*(rhs.data() + 3u), entt::entity{3});
+    ASSERT_EQ(*(rhs.data() + 4u), entt::entity{4});
+    ASSERT_EQ(*(rhs.data() + 5u), entt::entity{5});
 }
 
 TEST(Storage, RespectReverse) {
-    entt::storage<std::uint64_t, int> lhs;
-    entt::storage<std::uint64_t, int> rhs;
-
-    lhs.construct(1, 0);
-    lhs.construct(2, 0);
-    lhs.construct(3, 0);
-    lhs.construct(4, 0);
-    lhs.construct(5, 0);
-
-    ASSERT_EQ(lhs.get(1), 0);
-    ASSERT_EQ(lhs.get(2), 0);
-    ASSERT_EQ(lhs.get(3), 0);
-    ASSERT_EQ(lhs.get(4), 0);
-    ASSERT_EQ(lhs.get(5), 0);
-
-    rhs.construct(5, 0);
-    rhs.construct(4, 0);
-    rhs.construct(3, 0);
-    rhs.construct(2, 0);
-    rhs.construct(1, 0);
-    rhs.construct(6, 0);
-
-    ASSERT_EQ(rhs.get(5), 0);
-    ASSERT_EQ(rhs.get(4), 0);
-    ASSERT_EQ(rhs.get(3), 0);
-    ASSERT_EQ(rhs.get(2), 0);
-    ASSERT_EQ(rhs.get(1), 0);
-    ASSERT_EQ(rhs.get(6), 0);
+    entt::storage<entt::entity, int> lhs;
+    entt::storage<entt::entity, int> rhs;
+
+    lhs.construct(entt::entity{1}, 0);
+    lhs.construct(entt::entity{2}, 0);
+    lhs.construct(entt::entity{3}, 0);
+    lhs.construct(entt::entity{4}, 0);
+    lhs.construct(entt::entity{5}, 0);
+
+    ASSERT_EQ(lhs.get(entt::entity{1}), 0);
+    ASSERT_EQ(lhs.get(entt::entity{2}), 0);
+    ASSERT_EQ(lhs.get(entt::entity{3}), 0);
+    ASSERT_EQ(lhs.get(entt::entity{4}), 0);
+    ASSERT_EQ(lhs.get(entt::entity{5}), 0);
+
+    rhs.construct(entt::entity{5}, 0);
+    rhs.construct(entt::entity{4}, 0);
+    rhs.construct(entt::entity{3}, 0);
+    rhs.construct(entt::entity{2}, 0);
+    rhs.construct(entt::entity{1}, 0);
+    rhs.construct(entt::entity{6}, 0);
+
+    ASSERT_EQ(rhs.get(entt::entity{5}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{4}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{3}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{2}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{1}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{6}), 0);
 
     rhs.respect(lhs);
 
-    ASSERT_EQ(*(lhs.data() + 0u), 1u);
-    ASSERT_EQ(*(lhs.data() + 1u), 2u);
-    ASSERT_EQ(*(lhs.data() + 2u), 3u);
-    ASSERT_EQ(*(lhs.data() + 3u), 4u);
-    ASSERT_EQ(*(lhs.data() + 4u), 5u);
-
-    ASSERT_EQ(*(rhs.data() + 0u), 6u);
-    ASSERT_EQ(*(rhs.data() + 1u), 1u);
-    ASSERT_EQ(*(rhs.data() + 2u), 2u);
-    ASSERT_EQ(*(rhs.data() + 3u), 3u);
-    ASSERT_EQ(*(rhs.data() + 4u), 4u);
-    ASSERT_EQ(*(rhs.data() + 5u), 5u);
+    ASSERT_EQ(*(lhs.data() + 0u), entt::entity{1});
+    ASSERT_EQ(*(lhs.data() + 1u), entt::entity{2});
+    ASSERT_EQ(*(lhs.data() + 2u), entt::entity{3});
+    ASSERT_EQ(*(lhs.data() + 3u), entt::entity{4});
+    ASSERT_EQ(*(lhs.data() + 4u), entt::entity{5});
+
+    ASSERT_EQ(*(rhs.data() + 0u), entt::entity{6});
+    ASSERT_EQ(*(rhs.data() + 1u), entt::entity{1});
+    ASSERT_EQ(*(rhs.data() + 2u), entt::entity{2});
+    ASSERT_EQ(*(rhs.data() + 3u), entt::entity{3});
+    ASSERT_EQ(*(rhs.data() + 4u), entt::entity{4});
+    ASSERT_EQ(*(rhs.data() + 5u), entt::entity{5});
 }
 
 TEST(Storage, RespectUnordered) {
-    entt::storage<std::uint64_t, int> lhs;
-    entt::storage<std::uint64_t, int> rhs;
-
-    lhs.construct(1, 0);
-    lhs.construct(2, 0);
-    lhs.construct(3, 0);
-    lhs.construct(4, 0);
-    lhs.construct(5, 0);
-
-    ASSERT_EQ(lhs.get(1), 0);
-    ASSERT_EQ(lhs.get(2), 0);
-    ASSERT_EQ(lhs.get(3), 0);
-    ASSERT_EQ(lhs.get(4), 0);
-    ASSERT_EQ(lhs.get(5), 0);
-
-    rhs.construct(3, 0);
-    rhs.construct(2, 0);
-    rhs.construct(6, 0);
-    rhs.construct(1, 0);
-    rhs.construct(4, 0);
-    rhs.construct(5, 0);
-
-    ASSERT_EQ(rhs.get(3), 0);
-    ASSERT_EQ(rhs.get(2), 0);
-    ASSERT_EQ(rhs.get(6), 0);
-    ASSERT_EQ(rhs.get(1), 0);
-    ASSERT_EQ(rhs.get(4), 0);
-    ASSERT_EQ(rhs.get(5), 0);
+    entt::storage<entt::entity, int> lhs;
+    entt::storage<entt::entity, int> rhs;
+
+    lhs.construct(entt::entity{1}, 0);
+    lhs.construct(entt::entity{2}, 0);
+    lhs.construct(entt::entity{3}, 0);
+    lhs.construct(entt::entity{4}, 0);
+    lhs.construct(entt::entity{5}, 0);
+
+    ASSERT_EQ(lhs.get(entt::entity{1}), 0);
+    ASSERT_EQ(lhs.get(entt::entity{2}), 0);
+    ASSERT_EQ(lhs.get(entt::entity{3}), 0);
+    ASSERT_EQ(lhs.get(entt::entity{4}), 0);
+    ASSERT_EQ(lhs.get(entt::entity{5}), 0);
+
+    rhs.construct(entt::entity{3}, 0);
+    rhs.construct(entt::entity{2}, 0);
+    rhs.construct(entt::entity{6}, 0);
+    rhs.construct(entt::entity{1}, 0);
+    rhs.construct(entt::entity{4}, 0);
+    rhs.construct(entt::entity{5}, 0);
+
+    ASSERT_EQ(rhs.get(entt::entity{3}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{2}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{6}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{1}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{4}), 0);
+    ASSERT_EQ(rhs.get(entt::entity{5}), 0);
 
     rhs.respect(lhs);
 
-    ASSERT_EQ(*(lhs.data() + 0u), 1u);
-    ASSERT_EQ(*(lhs.data() + 1u), 2u);
-    ASSERT_EQ(*(lhs.data() + 2u), 3u);
-    ASSERT_EQ(*(lhs.data() + 3u), 4u);
-    ASSERT_EQ(*(lhs.data() + 4u), 5u);
-
-    ASSERT_EQ(*(rhs.data() + 0u), 6u);
-    ASSERT_EQ(*(rhs.data() + 1u), 1u);
-    ASSERT_EQ(*(rhs.data() + 2u), 2u);
-    ASSERT_EQ(*(rhs.data() + 3u), 3u);
-    ASSERT_EQ(*(rhs.data() + 4u), 4u);
-    ASSERT_EQ(*(rhs.data() + 5u), 5u);
+    ASSERT_EQ(*(lhs.data() + 0u), entt::entity{1});
+    ASSERT_EQ(*(lhs.data() + 1u), entt::entity{2});
+    ASSERT_EQ(*(lhs.data() + 2u), entt::entity{3});
+    ASSERT_EQ(*(lhs.data() + 3u), entt::entity{4});
+    ASSERT_EQ(*(lhs.data() + 4u), entt::entity{5});
+
+    ASSERT_EQ(*(rhs.data() + 0u), entt::entity{6});
+    ASSERT_EQ(*(rhs.data() + 1u), entt::entity{1});
+    ASSERT_EQ(*(rhs.data() + 2u), entt::entity{2});
+    ASSERT_EQ(*(rhs.data() + 3u), entt::entity{3});
+    ASSERT_EQ(*(rhs.data() + 4u), entt::entity{4});
+    ASSERT_EQ(*(rhs.data() + 5u), entt::entity{5});
 }
 
 TEST(Storage, RespectOverlapEmptyType) {
-    entt::storage<std::uint64_t, empty_type> lhs;
-    entt::storage<std::uint64_t, empty_type> rhs;
+    entt::storage<entt::entity, empty_type> lhs;
+    entt::storage<entt::entity, empty_type> rhs;
 
-    lhs.construct(3);
-    lhs.construct(12);
-    lhs.construct(42);
+    lhs.construct(entt::entity{3});
+    lhs.construct(entt::entity{12});
+    lhs.construct(entt::entity{42});
 
-    rhs.construct(12);
+    rhs.construct(entt::entity{12});
 
-    ASSERT_EQ(lhs.sparse_set<std::uint64_t>::get(3), 0u);
-    ASSERT_EQ(lhs.sparse_set<std::uint64_t>::get(12), 1u);
-    ASSERT_EQ(lhs.sparse_set<std::uint64_t>::get(42), 2u);
+    ASSERT_EQ(lhs.sparse_set<entt::entity>::get(entt::entity{3}), 0u);
+    ASSERT_EQ(lhs.sparse_set<entt::entity>::get(entt::entity{12}), 1u);
+    ASSERT_EQ(lhs.sparse_set<entt::entity>::get(entt::entity{42}), 2u);
 
     lhs.respect(rhs);
 
-    ASSERT_EQ(std::as_const(lhs).sparse_set<std::uint64_t>::get(3), 0u);
-    ASSERT_EQ(std::as_const(lhs).sparse_set<std::uint64_t>::get(12), 2u);
-    ASSERT_EQ(std::as_const(lhs).sparse_set<std::uint64_t>::get(42), 1u);
+    ASSERT_EQ(std::as_const(lhs).sparse_set<entt::entity>::get(entt::entity{3}), 0u);
+    ASSERT_EQ(std::as_const(lhs).sparse_set<entt::entity>::get(entt::entity{12}), 2u);
+    ASSERT_EQ(std::as_const(lhs).sparse_set<entt::entity>::get(entt::entity{42}), 1u);
 }
 
 TEST(Storage, CanModifyDuringIteration) {
-    entt::storage<std::uint64_t, int> set;
-    set.construct(0, 42);
+    entt::storage<entt::entity, int> set;
+    set.construct(entt::entity{0}, 42);
 
-    ASSERT_EQ(set.capacity(), (entt::storage<std::uint64_t, int>::size_type{1}));
+    ASSERT_EQ(set.capacity(), (entt::storage<entt::entity, int>::size_type{1}));
 
     const auto it = set.cbegin();
-    set.reserve(entt::storage<std::uint64_t, int>::size_type{2});
+    set.reserve(entt::storage<entt::entity, int>::size_type{2});
 
-    ASSERT_EQ(set.capacity(), (entt::storage<std::uint64_t, int>::size_type{2}));
+    ASSERT_EQ(set.capacity(), (entt::storage<entt::entity, int>::size_type{2}));
 
     // this should crash with asan enabled if we break the constraint
     const auto entity = *it;
@@ -652,13 +653,13 @@ TEST(Storage, CanModifyDuringIteration) {
 }
 
 TEST(Storage, ReferencesGuaranteed) {
-    entt::storage<std::uint64_t, boxed_int> set;
+    entt::storage<entt::entity, boxed_int> set;
 
-    set.construct(0, 0);
-    set.construct(1, 1);
+    set.construct(entt::entity{0}, 0);
+    set.construct(entt::entity{1}, 1);
 
-    ASSERT_EQ(set.get(0).value, 0);
-    ASSERT_EQ(set.get(1).value, 1);
+    ASSERT_EQ(set.get(entt::entity{0}).value, 0);
+    ASSERT_EQ(set.get(entt::entity{1}).value, 1);
 
     for(auto &&type: set) {
         if(type.value) {
@@ -666,8 +667,8 @@ TEST(Storage, ReferencesGuaranteed) {
         }
     }
 
-    ASSERT_EQ(set.get(0).value, 0);
-    ASSERT_EQ(set.get(1).value, 42);
+    ASSERT_EQ(set.get(entt::entity{0}).value, 0);
+    ASSERT_EQ(set.get(entt::entity{1}).value, 42);
 
     auto begin = set.begin();
 
@@ -675,21 +676,21 @@ TEST(Storage, ReferencesGuaranteed) {
         (begin++)->value = 3;
     }
 
-    ASSERT_EQ(set.get(0).value, 3);
-    ASSERT_EQ(set.get(1).value, 3);
+    ASSERT_EQ(set.get(entt::entity{0}).value, 3);
+    ASSERT_EQ(set.get(entt::entity{1}).value, 3);
 }
 
 TEST(Storage, MoveOnlyComponent) {
     // the purpose is to ensure that move only components are always accepted
-    entt::storage<std::uint64_t, std::unique_ptr<int>> set;
+    entt::storage<entt::entity, std::unique_ptr<int>> set;
     (void)set;
 }
 
 TEST(Storage, ConstructorExceptionDoesNotAddToSet) {
-    entt::storage<std::uint64_t, throwing_component> set;
+    entt::storage<entt::entity, throwing_component> set;
 
     try {
-        set.construct(0);
+        set.construct(entt::entity{0});
         FAIL() << "Expected constructor_exception to be thrown";
     } catch (const throwing_component::constructor_exception &) {
         ASSERT_TRUE(set.empty());

+ 5 - 5
test/entt/entity/view.cpp

@@ -136,9 +136,9 @@ TEST(SingleComponentView, ConstNonConstAndAllInBetween) {
     ASSERT_TRUE((std::is_same_v<typename decltype(view)::raw_type, int>));
     ASSERT_TRUE((std::is_same_v<typename decltype(cview)::raw_type, const int>));
 
-    ASSERT_TRUE((std::is_same_v<decltype(view.get(0)), int &>));
+    ASSERT_TRUE((std::is_same_v<decltype(view.get(entt::entity{0})), int &>));
     ASSERT_TRUE((std::is_same_v<decltype(view.raw()), int *>));
-    ASSERT_TRUE((std::is_same_v<decltype(cview.get(0)), const int &>));
+    ASSERT_TRUE((std::is_same_v<decltype(cview.get(entt::entity{0})), const int &>));
     ASSERT_TRUE((std::is_same_v<decltype(cview.raw()), const int *>));
 
     view.each([](auto, auto &&i) {
@@ -416,9 +416,9 @@ TEST(MultipleComponentView, ConstNonConstAndAllInBetween) {
 
     ASSERT_EQ(view.size(), decltype(view.size()){1});
 
-    ASSERT_TRUE((std::is_same_v<decltype(view.get<int>(0)), int &>));
-    ASSERT_TRUE((std::is_same_v<decltype(view.get<const char>(0)), const char &>));
-    ASSERT_TRUE((std::is_same_v<decltype(view.get<int, const char>(0)), std::tuple<int &, const char &>>));
+    ASSERT_TRUE((std::is_same_v<decltype(view.get<int>(entt::entity{0})), int &>));
+    ASSERT_TRUE((std::is_same_v<decltype(view.get<const char>(entt::entity{0})), const char &>));
+    ASSERT_TRUE((std::is_same_v<decltype(view.get<int, const char>(entt::entity{0})), std::tuple<int &, const char &>>));
     ASSERT_TRUE((std::is_same_v<decltype(view.raw<const char>()), const char *>));
     ASSERT_TRUE((std::is_same_v<decltype(view.raw<int>()), int *>));
 

+ 4 - 3
test/lib/lib.cpp

@@ -1,7 +1,8 @@
+#include <gtest/gtest.h>
+#include <entt/entity/entity.hpp>
 #include <entt/entity/registry.hpp>
 #include <entt/signal/dispatcher.hpp>
 #include <entt/signal/emitter.hpp>
-#include <gtest/gtest.h>
 #include "types.h"
 
 extern typename entt::registry::component_type a_module_int_type();
@@ -58,8 +59,8 @@ TEST(Lib, Registry) {
     update_position(1, registry);
 
     registry.view<position>().each([](auto entity, auto &position) {
-        ASSERT_EQ(position.x, entity + 2);
-        ASSERT_EQ(position.y, entity + 3);
+        ASSERT_EQ(position.x, entt::to_integer(entity) + 2);
+        ASSERT_EQ(position.y, entt::to_integer(entity) + 3);
     });
 }
 

+ 9 - 8
test/mod/mod.cpp

@@ -1,9 +1,9 @@
-#include <gtest/gtest.h>
 #include <type_traits>
 #include <cassert>
 #include <map>
 #include <string>
 #include <duktape.h>
+#include <gtest/gtest.h>
 #include <entt/entity/registry.hpp>
 
 template<typename Type>
@@ -22,7 +22,7 @@ struct duktape_runtime {
 
 template<typename Comp>
 duk_ret_t set(duk_context *ctx, entt::registry &registry) {
-    const auto entity = duk_require_uint(ctx, 0);
+    const entt::entity entity{duk_require_uint(ctx, 0)};
 
     if constexpr(std::is_same_v<Comp, position>) {
         const auto x = duk_require_number(ctx, 2);
@@ -49,7 +49,7 @@ duk_ret_t set(duk_context *ctx, entt::registry &registry) {
 
 template<typename Comp>
 duk_ret_t unset(duk_context *ctx, entt::registry &registry) {
-    const auto entity = duk_require_uint(ctx, 0);
+    const entt::entity entity{duk_require_uint(ctx, 0)};
 
     if constexpr(std::is_same_v<Comp, duktape_runtime>) {
         const auto type = duk_require_uint(ctx, 1);
@@ -70,7 +70,7 @@ duk_ret_t unset(duk_context *ctx, entt::registry &registry) {
 
 template<typename Comp>
 duk_ret_t has(duk_context *ctx, entt::registry &registry) {
-    const auto entity = duk_require_uint(ctx, 0);
+    const entt::entity entity{duk_require_uint(ctx, 0)};
 
     if constexpr(std::is_same_v<Comp, duktape_runtime>) {
         duk_push_boolean(ctx, registry.has<duktape_runtime>(entity));
@@ -91,7 +91,7 @@ duk_ret_t has(duk_context *ctx, entt::registry &registry) {
 
 template<typename Comp>
 duk_ret_t get(duk_context *ctx, entt::registry &registry) {
-    [[maybe_unused]] const auto entity = duk_require_uint(ctx, 0);
+    [[maybe_unused]] const entt::entity entity{duk_require_uint(ctx, 0)};
 
     if constexpr(std::is_same_v<Comp, position>) {
         const auto &pos = registry.get<position>(entity);
@@ -186,7 +186,8 @@ public:
 
     static duk_ret_t create(duk_context *ctx) {
         auto &dreg = instance(ctx);
-        duk_push_uint(ctx, dreg.registry.create());
+        const auto entity = dreg.registry.create();
+        duk_push_uint(ctx, static_cast<std::underlying_type_t<entt::entity>>(entity));
         return 1;
     }
 
@@ -234,7 +235,7 @@ public:
 
         for(const auto entity: view) {
             if(runtime.empty()) {
-                duk_push_uint(ctx, entity);
+                duk_push_uint(ctx, static_cast<std::underlying_type_t<entt::entity>>(entity));
                 duk_put_prop_index(ctx, -2, pos++);
             } else {
                 const auto &others = dreg.registry.get<duktape_runtime>(entity).components;
@@ -243,7 +244,7 @@ public:
                 });
 
                 if(match) {
-                    duk_push_uint(ctx, entity);
+                    duk_push_uint(ctx, static_cast<std::underlying_type_t<entt::entity>>(entity));
                     duk_put_prop_index(ctx, -2, pos++);
                 }
             }