Browse Source

added operator[] to sparse set and views

Michele Caini 7 years ago
parent
commit
f2ab94fa7f
5 changed files with 272 additions and 136 deletions
  1. 1 3
      TODO
  2. 65 42
      src/entt/entity/sparse_set.hpp
  3. 56 20
      src/entt/entity/view.hpp
  4. 73 47
      test/entt/entity/sparse_set.cpp
  5. 77 24
      test/entt/entity/view.cpp

+ 1 - 3
TODO

@@ -7,10 +7,8 @@
 * define systems as composable mixins (initializazion, reactive, update, whatever) with flexible auto-detected arguments (registry, views, etc)
 * create dedicated flat map based on types implementation (sort of "type map") for types to use within the registry and so on...
 * ease the assignment of tags as string (use a template class with a non-type template parameter behind the scene)
-* improve CMake interface, see mail from Malte
-* is registry/utility.hpp really required?
 * "singleton mode" for tags (see #66)
 * add a shortcut to destroy all the entities that have components X, Y, Z (view and registry?)
-* add operator[] to views if possible
+* make views copy/move constructible and copy/move assignable
 * C++17. That's all.
 * AOB

+ 65 - 42
src/entt/entity/sparse_set.hpp

@@ -63,14 +63,14 @@ class SparseSet<Entity> {
         friend class SparseSet<Entity>;
 
         using entity_type = Entity;
-        using pos_type = typename traits_type::difference_type;
+        using index_type = typename traits_type::difference_type;
 
-        Iterator(const entity_type *direct, pos_type pos) ENTT_NOEXCEPT
-            : direct{direct}, pos{pos}
+        Iterator(const entity_type *direct, index_type index) ENTT_NOEXCEPT
+            : direct{direct}, index{index}
         {}
 
     public:
-        using difference_type = pos_type;
+        using difference_type = index_type;
         using value_type = const entity_type;
         using pointer = value_type *;
         using reference = value_type &;
@@ -82,7 +82,7 @@ class SparseSet<Entity> {
         Iterator & operator=(const Iterator &) ENTT_NOEXCEPT = default;
 
         Iterator & operator++() ENTT_NOEXCEPT {
-            return --pos, *this;
+            return --index, *this;
         }
 
         Iterator operator++(int) ENTT_NOEXCEPT {
@@ -91,7 +91,7 @@ class SparseSet<Entity> {
         }
 
         Iterator & operator--() ENTT_NOEXCEPT {
-            return ++pos, *this;
+            return ++index, *this;
         }
 
         Iterator operator--(int) ENTT_NOEXCEPT {
@@ -100,12 +100,12 @@ class SparseSet<Entity> {
         }
 
         Iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
-            pos -= value;
+            index -= value;
             return *this;
         }
 
         Iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
-            return Iterator{direct, pos-value};
+            return Iterator{direct, index-value};
         }
 
         inline Iterator & operator-=(const difference_type value) ENTT_NOEXCEPT {
@@ -117,15 +117,15 @@ class SparseSet<Entity> {
         }
 
         difference_type operator-(const Iterator &other) const ENTT_NOEXCEPT {
-            return other.pos - pos;
+            return other.index - index;
         }
 
         reference operator[](const difference_type value) const ENTT_NOEXCEPT {
-            return direct[pos-value-1];
+            return direct[index-value-1];
         }
 
         bool operator==(const Iterator &other) const ENTT_NOEXCEPT {
-            return other.pos == pos;
+            return other.index == index;
         }
 
         inline bool operator!=(const Iterator &other) const ENTT_NOEXCEPT {
@@ -133,11 +133,11 @@ class SparseSet<Entity> {
         }
 
         bool operator<(const Iterator &other) const ENTT_NOEXCEPT {
-            return pos > other.pos;
+            return index > other.index;
         }
 
         bool operator>(const Iterator &other) const ENTT_NOEXCEPT {
-            return pos < other.pos;
+            return index < other.index;
         }
 
         inline bool operator<=(const Iterator &other) const ENTT_NOEXCEPT {
@@ -149,7 +149,7 @@ class SparseSet<Entity> {
         }
 
         pointer operator->() const ENTT_NOEXCEPT {
-            return (direct+pos-1);
+            return (direct+index-1);
         }
 
         inline reference operator*() const ENTT_NOEXCEPT {
@@ -158,7 +158,7 @@ class SparseSet<Entity> {
 
     private:
         pointer direct;
-        pos_type pos;
+        index_type index;
     };
 
     static constexpr auto pending = ~typename traits_type::entity_type{};
@@ -166,8 +166,6 @@ class SparseSet<Entity> {
 public:
     /*! @brief Underlying entity identifier. */
     using entity_type = Entity;
-    /*! @brief Entity dependent position type. */
-    using pos_type = entity_type;
     /*! @brief Unsigned integer type. */
     using size_type = std::size_t;
     /*! @brief Input iterator type. */
@@ -358,6 +356,15 @@ public:
         return cend();
     }
 
+    /**
+     * @brief Returns a reference to the element at the given position.
+     * @param pos Position of the element to return.
+     * @return A reference to the requested element.
+     */
+    inline const entity_type & operator[](const size_type pos) const ENTT_NOEXCEPT {
+        return cbegin()[pos];
+    }
+
     /**
      * @brief Checks if a sparse set contains an entity.
      * @param entity A valid entity identifier.
@@ -405,7 +412,7 @@ public:
      * @param entity A valid entity identifier.
      * @return The position of the entity in the sparse set.
      */
-    pos_type get(const entity_type entity) const ENTT_NOEXCEPT {
+    size_type get(const entity_type entity) const ENTT_NOEXCEPT {
         assert(has(entity));
         return reverse[entity & traits_type::entity_mask];
     }
@@ -430,7 +437,7 @@ public:
             reverse.resize(pos+1, value);
         }
 
-        reverse[pos] = pos_type(direct.size());
+        reverse[pos] = entity_type(direct.size());
         direct.push_back(entity);
     }
 
@@ -471,7 +478,7 @@ public:
      * @param lhs A valid position within the sparse set.
      * @param rhs A valid position within the sparse set.
      */
-    void swap(const pos_type lhs, const pos_type rhs) ENTT_NOEXCEPT {
+    void swap(const size_type lhs, const size_type rhs) ENTT_NOEXCEPT {
         assert(lhs < direct.size());
         assert(rhs < direct.size());
         auto &src = direct[lhs];
@@ -503,7 +510,7 @@ public:
         auto from = other.cbegin();
         auto to = other.cend();
 
-        pos_type pos = direct.size() - 1;
+        size_type pos = direct.size() - 1;
 
         while(pos && from != to) {
             if(has(*from)) {
@@ -527,7 +534,7 @@ public:
     }
 
 private:
-    std::vector<pos_type> reverse;
+    std::vector<entity_type> reverse;
     std::vector<entity_type> direct;
 };
 
@@ -564,14 +571,14 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
         friend class SparseSet<Entity, Type>;
 
         using instance_type = std::conditional_t<Const, const Type, Type>;
-        using pos_type = typename traits_type::difference_type;
+        using index_type = typename traits_type::difference_type;
 
-        Iterator(instance_type *instances, pos_type pos) ENTT_NOEXCEPT
-            : instances{instances}, pos{pos}
+        Iterator(instance_type *instances, index_type index) ENTT_NOEXCEPT
+            : instances{instances}, index{index}
         {}
 
     public:
-        using difference_type = pos_type;
+        using difference_type = index_type;
         using value_type = instance_type;
         using pointer = value_type *;
         using reference = value_type &;
@@ -583,7 +590,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
         Iterator & operator=(const Iterator &) ENTT_NOEXCEPT = default;
 
         Iterator & operator++() ENTT_NOEXCEPT {
-            return --pos, *this;
+            return --index, *this;
         }
 
         Iterator operator++(int) ENTT_NOEXCEPT {
@@ -592,7 +599,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
         }
 
         Iterator & operator--() ENTT_NOEXCEPT {
-            return ++pos, *this;
+            return ++index, *this;
         }
 
         Iterator operator--(int) ENTT_NOEXCEPT {
@@ -601,12 +608,12 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
         }
 
         Iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
-            pos -= value;
+            index -= value;
             return *this;
         }
 
         Iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
-            return Iterator{instances, pos-value};
+            return Iterator{instances, index-value};
         }
 
         inline Iterator & operator-=(const difference_type value) ENTT_NOEXCEPT {
@@ -618,15 +625,15 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
         }
 
         difference_type operator-(const Iterator &other) const ENTT_NOEXCEPT {
-            return other.pos - pos;
+            return other.index - index;
         }
 
         reference operator[](const difference_type value) const ENTT_NOEXCEPT {
-            return instances[pos-value-1];
+            return instances[index-value-1];
         }
 
         bool operator==(const Iterator &other) const ENTT_NOEXCEPT {
-            return other.pos == pos;
+            return other.index == index;
         }
 
         inline bool operator!=(const Iterator &other) const ENTT_NOEXCEPT {
@@ -634,11 +641,11 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
         }
 
         bool operator<(const Iterator &other) const ENTT_NOEXCEPT {
-            return pos > other.pos;
+            return index > other.index;
         }
 
         bool operator>(const Iterator &other) const ENTT_NOEXCEPT {
-            return pos < other.pos;
+            return index < other.index;
         }
 
         inline bool operator<=(const Iterator &other) const ENTT_NOEXCEPT {
@@ -650,7 +657,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
         }
 
         pointer operator->() const ENTT_NOEXCEPT {
-            return (instances+pos-1);
+            return (instances+index-1);
         }
 
         inline reference operator*() const ENTT_NOEXCEPT {
@@ -659,7 +666,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
 
     private:
         pointer instances;
-        difference_type pos;
+        index_type index;
     };
 
 public:
@@ -667,8 +674,6 @@ public:
     using object_type = Type;
     /*! @brief Underlying entity identifier. */
     using entity_type = typename underlying_type::entity_type;
-    /*! @brief Entity dependent position type. */
-    using pos_type = typename underlying_type::pos_type;
     /*! @brief Unsigned integer type. */
     using size_type = typename underlying_type::size_type;
     /*! @brief Input iterator type. */
@@ -844,6 +849,24 @@ public:
         return iterator_type{instances.data(), {}};
     }
 
+    /**
+     * @brief Returns a reference to the element at the given position.
+     * @param pos Position of the element to return.
+     * @return A reference to the requested element.
+     */
+    inline const object_type & operator[](const size_type pos) const ENTT_NOEXCEPT {
+        return cbegin()[pos];
+    }
+
+    /**
+     * @brief Returns a reference to the element at the given position.
+     * @param pos Position of the element to return.
+     * @return A reference to the requested element.
+     */
+    inline object_type & operator[](const size_type pos) ENTT_NOEXCEPT {
+        return const_cast<object_type &>(const_cast<const SparseSet *>(this)->operator[](pos));
+    }
+
     /**
      * @brief Returns the object associated to an entity.
      *
@@ -993,14 +1016,14 @@ public:
      */
     template<typename Compare, typename Sort = StdSort>
     void sort(Compare compare, Sort sort = Sort{}) {
-        std::vector<pos_type> copy(instances.size());
+        std::vector<size_type> copy(instances.size());
         std::iota(copy.begin(), copy.end(), 0);
 
         sort(copy.begin(), copy.end(), [this, compare = std::move(compare)](const auto lhs, const auto rhs) {
             return compare(const_cast<const object_type &>(instances[rhs]), const_cast<const object_type &>(instances[lhs]));
         });
 
-        for(pos_type pos = 0, last = copy.size(); pos < last; ++pos) {
+        for(size_type pos = 0, last = copy.size(); pos < last; ++pos) {
             auto curr = pos;
             auto next = copy[curr];
 
@@ -1043,7 +1066,7 @@ public:
         auto from = other.cbegin();
         auto to = other.cend();
 
-        pos_type pos = underlying_type::size() - 1;
+        size_type pos = underlying_type::size() - 1;
         const auto *local = underlying_type::data();
 
         while(pos && from != to) {

+ 56 - 20
src/entt/entity/view.hpp

@@ -83,14 +83,14 @@ class PersistentView final {
     {}
 
 public:
-    /*! @brief Input iterator type. */
-    using iterator_type = typename view_type::iterator_type;
-    /*! @brief Constant input iterator type. */
-    using const_iterator_type = typename view_type::const_iterator_type;
     /*! @brief Underlying entity identifier. */
     using entity_type = typename view_type::entity_type;
     /*! @brief Unsigned integer type. */
     using size_type = typename view_type::size_type;
+    /*! @brief Input iterator type. */
+    using iterator_type = typename view_type::iterator_type;
+    /*! @brief Constant input iterator type. */
+    using const_iterator_type = typename view_type::const_iterator_type;
 
     /**
      * @brief Returns the number of entities that have the given components.
@@ -235,6 +235,15 @@ public:
         return view.end();
     }
 
+    /**
+     * @brief Returns a reference to the element at the given position.
+     * @param pos Position of the element to return.
+     * @return A reference to the requested element.
+     */
+    const entity_type & operator[](const size_type pos) const ENTT_NOEXCEPT {
+        return view[pos];
+    }
+
     /**
      * @brief Checks if a view contains an entity.
      * @param entity A valid entity identifier.
@@ -608,14 +617,14 @@ class View final {
     }
 
 public:
-    /*! @brief Input iterator type. */
-    using iterator_type = Iterator;
-    /*! @brief Constant input iterator type. */
-    using const_iterator_type = Iterator;
     /*! @brief Underlying entity identifier. */
     using entity_type = typename view_type::entity_type;
     /*! @brief Unsigned integer type. */
     using size_type = typename view_type::size_type;
+    /*! @brief Input iterator type. */
+    using iterator_type = Iterator;
+    /*! @brief Constant input iterator type. */
+    using const_iterator_type = Iterator;
 
     /**
      * @brief Estimates the number of entities that have the given components.
@@ -952,16 +961,16 @@ class View<Entity, Component> final {
     {}
 
 public:
-    /*! @brief Input iterator type. */
-    using iterator_type = typename view_type::iterator_type;
-    /*! @brief Constant input iterator type. */
-    using const_iterator_type = typename view_type::const_iterator_type;
+    /*! @brief Type of component iterated by the view. */
+    using raw_type = typename pool_type::object_type;
     /*! @brief Underlying entity identifier. */
     using entity_type = typename pool_type::entity_type;
     /*! @brief Unsigned integer type. */
     using size_type = typename pool_type::size_type;
-    /*! @brief Type of component iterated by the view. */
-    using raw_type = typename pool_type::object_type;
+    /*! @brief Input iterator type. */
+    using iterator_type = typename view_type::iterator_type;
+    /*! @brief Constant input iterator type. */
+    using const_iterator_type = typename view_type::const_iterator_type;
 
     /**
      * @brief Returns the number of entities that have the given component.
@@ -1138,6 +1147,15 @@ public:
         return pool.view_type::end();
     }
 
+    /**
+     * @brief Returns a reference to the element at the given position.
+     * @param pos Position of the element to return.
+     * @return A reference to the requested element.
+     */
+    const entity_type & operator[](const size_type pos) const ENTT_NOEXCEPT {
+        return pool.view_type::operator[](pos);
+    }
+
     /**
      * @brief Checks if a view contains an entity.
      * @param entity A valid entity identifier.
@@ -1285,16 +1303,16 @@ class RawView final {
     {}
 
 public:
-    /*! @brief Input iterator type. */
-    using iterator_type = typename pool_type::iterator_type;
-    /*! @brief Constant input iterator type. */
-    using const_iterator_type = typename pool_type::const_iterator_type;
+    /*! @brief Type of component iterated by the view. */
+    using raw_type = typename pool_type::object_type;
     /*! @brief Underlying entity identifier. */
     using entity_type = typename pool_type::entity_type;
     /*! @brief Unsigned integer type. */
     using size_type = typename pool_type::size_type;
-    /*! @brief Type of component iterated by the view. */
-    using raw_type = typename pool_type::object_type;
+    /*! @brief Input iterator type. */
+    using iterator_type = typename pool_type::iterator_type;
+    /*! @brief Constant input iterator type. */
+    using const_iterator_type = typename pool_type::const_iterator_type;
 
     /**
      * @brief Returns the number of instances of the given type.
@@ -1465,6 +1483,24 @@ public:
         return pool.end();
     }
 
+    /**
+     * @brief Returns a reference to the element at the given position.
+     * @param pos Position of the element to return.
+     * @return A reference to the requested element.
+     */
+    const raw_type & operator[](const size_type pos) const ENTT_NOEXCEPT {
+        return pool[pos];
+    }
+
+    /**
+     * @brief Returns a reference to the element at the given position.
+     * @param pos Position of the element to return.
+     * @return A reference to the requested element.
+     */
+    inline raw_type & operator[](const size_type pos) ENTT_NOEXCEPT {
+        return const_cast<raw_type &>(const_cast<const RawView *>(this)->operator[](pos));
+    }
+
     /**
      * @brief Iterates components and applies the given function object to them.
      *

+ 73 - 47
test/entt/entity/sparse_set.cpp

@@ -2,12 +2,8 @@
 #include <gtest/gtest.h>
 #include <entt/entity/sparse_set.hpp>
 
-struct Type {
-    int value;
-};
-
 TEST(SparseSetNoType, Functionalities) {
-    entt::SparseSet<unsigned int> set;
+    entt::SparseSet<std::uint64_t> set;
     const auto &cset = set;
 
     ASSERT_NO_THROW(set.reserve(42));
@@ -53,15 +49,28 @@ TEST(SparseSetNoType, Functionalities) {
     ASSERT_FALSE(set.has(0));
     ASSERT_FALSE(set.has(42));
 
-    (void)entt::SparseSet<unsigned int>{std::move(set)};
-    entt::SparseSet<unsigned int> other;
+    (void)entt::SparseSet<std::uint64_t>{std::move(set)};
+    entt::SparseSet<std::uint64_t> other;
     other = std::move(set);
 }
 
+TEST(SparseSetNoType, ElementAccess) {
+    entt::SparseSet<std::uint64_t> set;
+    const auto &cset = set;
+
+    set.construct(42);
+    set.construct(3);
+
+    for(typename entt::SparseSet<std::uint64_t>::size_type i{}; i < set.size(); ++i) {
+        ASSERT_EQ(set[i], i ? 42 : 3);
+        ASSERT_EQ(cset[i], i ? 42 : 3);
+    }
+}
+
 TEST(SparseSetNoType, Iterator) {
-    using iterator_type = typename entt::SparseSet<unsigned int>::iterator_type;
+    using iterator_type = typename entt::SparseSet<std::uint64_t>::iterator_type;
 
-    entt::SparseSet<unsigned int> set;
+    entt::SparseSet<std::uint64_t> set;
     set.construct(3);
 
     iterator_type end{set.begin()};
@@ -104,9 +113,9 @@ TEST(SparseSetNoType, Iterator) {
 }
 
 TEST(SparseSetNoType, ConstIterator) {
-    using iterator_type = typename entt::SparseSet<unsigned int>::const_iterator_type;
+    using iterator_type = typename entt::SparseSet<std::uint64_t>::const_iterator_type;
 
-    entt::SparseSet<unsigned int> set;
+    entt::SparseSet<std::uint64_t> set;
     set.construct(3);
 
     iterator_type cend{set.cbegin()};
@@ -149,7 +158,7 @@ TEST(SparseSetNoType, ConstIterator) {
 }
 
 TEST(SparseSetNoType, Data) {
-    entt::SparseSet<unsigned int> set;
+    entt::SparseSet<std::uint64_t> set;
 
     set.construct(3);
     set.construct(12);
@@ -165,8 +174,8 @@ TEST(SparseSetNoType, Data) {
 }
 
 TEST(SparseSetNoType, RespectDisjoint) {
-    entt::SparseSet<unsigned int> lhs;
-    entt::SparseSet<unsigned int> rhs;
+    entt::SparseSet<std::uint64_t> lhs;
+    entt::SparseSet<std::uint64_t> rhs;
     const auto &clhs = lhs;
 
     lhs.construct(3);
@@ -185,8 +194,8 @@ TEST(SparseSetNoType, RespectDisjoint) {
 }
 
 TEST(SparseSetNoType, RespectOverlap) {
-    entt::SparseSet<unsigned int> lhs;
-    entt::SparseSet<unsigned int> rhs;
+    entt::SparseSet<std::uint64_t> lhs;
+    entt::SparseSet<std::uint64_t> rhs;
     const auto &clhs = lhs;
 
     lhs.construct(3);
@@ -207,8 +216,8 @@ TEST(SparseSetNoType, RespectOverlap) {
 }
 
 TEST(SparseSetNoType, RespectOrdered) {
-    entt::SparseSet<unsigned int> lhs;
-    entt::SparseSet<unsigned int> rhs;
+    entt::SparseSet<std::uint64_t> lhs;
+    entt::SparseSet<std::uint64_t> rhs;
 
     lhs.construct(1);
     lhs.construct(2);
@@ -247,8 +256,8 @@ TEST(SparseSetNoType, RespectOrdered) {
 }
 
 TEST(SparseSetNoType, RespectReverse) {
-    entt::SparseSet<unsigned int> lhs;
-    entt::SparseSet<unsigned int> rhs;
+    entt::SparseSet<std::uint64_t> lhs;
+    entt::SparseSet<std::uint64_t> rhs;
 
     lhs.construct(1);
     lhs.construct(2);
@@ -287,8 +296,8 @@ TEST(SparseSetNoType, RespectReverse) {
 }
 
 TEST(SparseSetNoType, RespectUnordered) {
-    entt::SparseSet<unsigned int> lhs;
-    entt::SparseSet<unsigned int> rhs;
+    entt::SparseSet<std::uint64_t> lhs;
+    entt::SparseSet<std::uint64_t> rhs;
 
     lhs.construct(1);
     lhs.construct(2);
@@ -327,7 +336,7 @@ TEST(SparseSetNoType, RespectUnordered) {
 }
 
 TEST(SparseSetWithType, Functionalities) {
-    entt::SparseSet<unsigned int, int> set;
+    entt::SparseSet<std::uint64_t, int> set;
     const auto &cset = set;
 
     ASSERT_NO_THROW(set.reserve(42));
@@ -371,28 +380,43 @@ TEST(SparseSetWithType, Functionalities) {
     ASSERT_FALSE(set.has(0));
     ASSERT_FALSE(set.has(42));
 
-    (void)entt::SparseSet<unsigned int>{std::move(set)};
-    entt::SparseSet<unsigned int> other;
+    (void)entt::SparseSet<std::uint64_t>{std::move(set)};
+    entt::SparseSet<std::uint64_t> other;
     other = std::move(set);
 }
 
+TEST(SparseSetWithType, ElementAccess) {
+    entt::SparseSet<std::uint64_t, int> set;
+    const auto &cset = set;
+
+    set.construct(42, 1);
+    set.construct(3, 0);
+
+    for(typename entt::SparseSet<std::uint64_t, int>::size_type i{}; i < set.size(); ++i) {
+        ASSERT_EQ(set[i], i);
+        ASSERT_EQ(cset[i], i);
+    }
+}
+
 TEST(SparseSetWithType, AggregatesMustWork) {
     struct AggregateType { int value; };
     // the goal of this test is to enforce the requirements for aggregate types
-    entt::SparseSet<unsigned int, AggregateType>{}.construct(0, 42);
+    entt::SparseSet<std::uint64_t, AggregateType>{}.construct(0, 42);
 }
 
 TEST(SparseSetWithType, TypesFromStandardTemplateLibraryMustWork) {
     // see #37 - this test shouldn't crash, that's all
-    entt::SparseSet<unsigned int, std::unordered_set<int>> set;
+    entt::SparseSet<std::uint64_t, std::unordered_set<int>> set;
     set.construct(0).insert(42);
     set.destroy(0);
 }
 
 TEST(SparseSetWithType, Iterator) {
-    using iterator_type = typename entt::SparseSet<unsigned int, Type>::iterator_type;
+    struct InternalType { int value; };
+
+    using iterator_type = typename entt::SparseSet<std::uint64_t, InternalType>::iterator_type;
 
-    entt::SparseSet<unsigned int, Type> set;
+    entt::SparseSet<std::uint64_t, InternalType> set;
     set.construct(3, 42);
 
     iterator_type end{set.begin()};
@@ -432,9 +456,11 @@ TEST(SparseSetWithType, Iterator) {
 }
 
 TEST(SparseSetWithType, ConstIterator) {
-    using iterator_type = typename entt::SparseSet<unsigned int, Type>::const_iterator_type;
+    struct InternalType { int value; };
+
+    using iterator_type = typename entt::SparseSet<std::uint64_t, InternalType>::const_iterator_type;
 
-    entt::SparseSet<unsigned int, Type> set;
+    entt::SparseSet<std::uint64_t, InternalType> set;
     set.construct(3, 42);
 
     iterator_type cend{set.cbegin()};
@@ -474,7 +500,7 @@ TEST(SparseSetWithType, ConstIterator) {
 }
 
 TEST(SparseSetWithType, Raw) {
-    entt::SparseSet<unsigned int, int> set;
+    entt::SparseSet<std::uint64_t, int> set;
 
     set.construct(3, 3);
     set.construct(12, 6);
@@ -490,7 +516,7 @@ TEST(SparseSetWithType, Raw) {
 }
 
 TEST(SparseSetWithType, SortOrdered) {
-    entt::SparseSet<unsigned int, int> set;
+    entt::SparseSet<std::uint64_t, int> set;
 
     set.construct(12, 12);
     set.construct(42, 9);
@@ -526,7 +552,7 @@ TEST(SparseSetWithType, SortOrdered) {
 }
 
 TEST(SparseSetWithType, SortReverse) {
-    entt::SparseSet<unsigned int, int> set;
+    entt::SparseSet<std::uint64_t, int> set;
 
     set.construct(12, 1);
     set.construct(42, 3);
@@ -562,7 +588,7 @@ TEST(SparseSetWithType, SortReverse) {
 }
 
 TEST(SparseSetWithType, SortUnordered) {
-    entt::SparseSet<unsigned int, int> set;
+    entt::SparseSet<std::uint64_t, int> set;
 
     set.construct(12, 6);
     set.construct(42, 3);
@@ -598,8 +624,8 @@ TEST(SparseSetWithType, SortUnordered) {
 }
 
 TEST(SparseSetWithType, RespectDisjoint) {
-    entt::SparseSet<unsigned int, int> lhs;
-    entt::SparseSet<unsigned int, int> rhs;
+    entt::SparseSet<std::uint64_t, int> lhs;
+    entt::SparseSet<std::uint64_t, int> rhs;
     const auto &clhs = lhs;
 
     lhs.construct(3, 3);
@@ -626,8 +652,8 @@ TEST(SparseSetWithType, RespectDisjoint) {
 }
 
 TEST(SparseSetWithType, RespectOverlap) {
-    entt::SparseSet<unsigned int, int> lhs;
-    entt::SparseSet<unsigned int, int> rhs;
+    entt::SparseSet<std::uint64_t, int> lhs;
+    entt::SparseSet<std::uint64_t, int> rhs;
     const auto &clhs = lhs;
 
     lhs.construct(3, 3);
@@ -656,8 +682,8 @@ TEST(SparseSetWithType, RespectOverlap) {
 }
 
 TEST(SparseSetWithType, RespectOrdered) {
-    entt::SparseSet<unsigned int, int> lhs;
-    entt::SparseSet<unsigned int, int> rhs;
+    entt::SparseSet<std::uint64_t, int> lhs;
+    entt::SparseSet<std::uint64_t, int> rhs;
 
     lhs.construct(1, 0);
     lhs.construct(2, 0);
@@ -702,8 +728,8 @@ TEST(SparseSetWithType, RespectOrdered) {
 }
 
 TEST(SparseSetWithType, RespectReverse) {
-    entt::SparseSet<unsigned int, int> lhs;
-    entt::SparseSet<unsigned int, int> rhs;
+    entt::SparseSet<std::uint64_t, int> lhs;
+    entt::SparseSet<std::uint64_t, int> rhs;
 
     lhs.construct(1, 0);
     lhs.construct(2, 0);
@@ -748,8 +774,8 @@ TEST(SparseSetWithType, RespectReverse) {
 }
 
 TEST(SparseSetWithType, RespectUnordered) {
-    entt::SparseSet<unsigned int, int> lhs;
-    entt::SparseSet<unsigned int, int> rhs;
+    entt::SparseSet<std::uint64_t, int> lhs;
+    entt::SparseSet<std::uint64_t, int> rhs;
 
     lhs.construct(1, 0);
     lhs.construct(2, 0);
@@ -796,7 +822,7 @@ TEST(SparseSetWithType, RespectUnordered) {
 TEST(SparseSetWithType, ReferencesGuaranteed) {
     struct InternalType { int value; };
 
-    entt::SparseSet<unsigned int, InternalType> set;
+    entt::SparseSet<std::uint64_t, InternalType> set;
 
     set.construct(0, 0);
     set.construct(1, 1);
@@ -834,6 +860,6 @@ TEST(SparseSetWithType, MoveOnlyComponent) {
     };
 
     // it's purpose is to ensure that move only components are always accepted
-    entt::SparseSet<unsigned int, MoveOnlyComponent> set;
+    entt::SparseSet<std::uint64_t, MoveOnlyComponent> set;
     (void)set;
 }

+ 77 - 24
test/entt/entity/view.cpp

@@ -4,7 +4,7 @@
 #include <entt/entity/view.hpp>
 
 TEST(SingleComponentView, Functionalities) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
     auto view = registry.view<char>();
     const auto &cview = view;
 
@@ -50,8 +50,25 @@ TEST(SingleComponentView, Functionalities) {
     ASSERT_TRUE(view.empty());
 }
 
+TEST(SingleComponentView, ElementAccess) {
+    entt::Registry<std::uint64_t> registry;
+    auto view = registry.view<int>();
+    const auto &cview = view;
+
+    const auto e0 = registry.create();
+    registry.assign<int>(e0);
+
+    const auto e1 = registry.create();
+    registry.assign<int>(e1);
+
+    for(typename decltype(view)::size_type i{}; i < view.size(); ++i) {
+        //ASSERT_EQ(view[i], i ? e0 : e1);
+        ASSERT_EQ(cview[i], i ? e0 : e1);
+    }
+}
+
 TEST(SingleComponentView, Contains) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
 
     const auto e0 = registry.create();
     registry.assign<int>(e0);
@@ -68,7 +85,7 @@ TEST(SingleComponentView, Contains) {
 }
 
 TEST(SingleComponentView, Empty) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
 
     const auto e0 = registry.create();
     registry.assign<char>(e0);
@@ -79,7 +96,7 @@ TEST(SingleComponentView, Empty) {
 
     auto view = registry.view<int>();
 
-    ASSERT_EQ(view.size(), entt::DefaultRegistry::size_type{0});
+    ASSERT_EQ(view.size(), entt::Registry<std::uint64_t>::size_type{0});
 
     for(auto entity: view) {
         (void)entity;
@@ -88,7 +105,7 @@ TEST(SingleComponentView, Empty) {
 }
 
 TEST(SingleComponentView, Each) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
 
     registry.assign<int>(registry.create());
     registry.assign<int>(registry.create());
@@ -107,7 +124,7 @@ TEST(SingleComponentView, Each) {
 }
 
 TEST(MultipleComponentView, Functionalities) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
     auto view = registry.view<int, char>();
     const auto &cview = view;
 
@@ -152,9 +169,9 @@ TEST(MultipleComponentView, Functionalities) {
 }
 
 TEST(MultipleComponentView, Iterator) {
-    using iterator_type = typename decltype(std::declval<entt::DefaultRegistry>().view<int, char>())::iterator_type;
+    using iterator_type = typename decltype(std::declval<entt::Registry<std::uint64_t>>().view<int, char>())::iterator_type;
 
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
     const auto entity = registry.create();
     registry.assign<int>(entity);
     registry.assign<char>(entity);
@@ -175,9 +192,9 @@ TEST(MultipleComponentView, Iterator) {
 }
 
 TEST(MultipleComponentView, ConstIterator) {
-    using iterator_type = typename decltype(std::declval<entt::DefaultRegistry>().view<int, char>())::const_iterator_type;
+    using iterator_type = typename decltype(std::declval<entt::Registry<std::uint64_t>>().view<int, char>())::const_iterator_type;
 
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
     const auto entity = registry.create();
     registry.assign<int>(entity);
     registry.assign<char>(entity);
@@ -198,7 +215,7 @@ TEST(MultipleComponentView, ConstIterator) {
 }
 
 TEST(MultipleComponentView, Contains) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
 
     const auto e0 = registry.create();
     registry.assign<int>(e0);
@@ -217,7 +234,7 @@ TEST(MultipleComponentView, Contains) {
 }
 
 TEST(MultipleComponentView, Empty) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
 
     const auto e0 = registry.create();
     registry.assign<double>(e0);
@@ -237,7 +254,7 @@ TEST(MultipleComponentView, Empty) {
 }
 
 TEST(MultipleComponentView, Each) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
 
     const auto e0 = registry.create();
     registry.assign<int>(e0);
@@ -261,7 +278,7 @@ TEST(MultipleComponentView, Each) {
 }
 
 TEST(MultipleComponentView, EachWithHoles) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
 
     const auto e0 = registry.create();
     const auto e1 = registry.create();
@@ -286,7 +303,7 @@ TEST(MultipleComponentView, EachWithHoles) {
 }
 
 TEST(PersistentView, Prepare) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
     registry.prepare<int, char>();
     auto view = registry.view<int, char>(entt::persistent_t{});
     const auto &cview = view;
@@ -338,7 +355,7 @@ TEST(PersistentView, Prepare) {
 }
 
 TEST(PersistentView, NoPrepare) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
     auto view = registry.view<int, char>(entt::persistent_t{});
 
     ASSERT_TRUE(view.empty());
@@ -386,8 +403,27 @@ TEST(PersistentView, NoPrepare) {
     ASSERT_TRUE(view.empty());
 }
 
+TEST(PersistentView, ElementAccess) {
+    entt::Registry<std::uint64_t> registry;
+    auto view = registry.view<int, char>(entt::persistent_t{});
+    const auto &cview = view;
+
+    const auto e0 = registry.create();
+    registry.assign<int>(e0);
+    registry.assign<char>(e0);
+
+    const auto e1 = registry.create();
+    registry.assign<int>(e1);
+    registry.assign<char>(e1);
+
+    for(typename decltype(view)::size_type i{}; i < view.size(); ++i) {
+        ASSERT_EQ(view[i], i ? e0 : e1);
+        ASSERT_EQ(cview[i], i ? e0 : e1);
+    }
+}
+
 TEST(PersistentView, Contains) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
 
     const auto e0 = registry.create();
     registry.assign<int>(e0);
@@ -406,7 +442,7 @@ TEST(PersistentView, Contains) {
 }
 
 TEST(PersistentView, Empty) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
 
     const auto e0 = registry.create();
     registry.assign<double>(e0);
@@ -429,7 +465,7 @@ TEST(PersistentView, Empty) {
 }
 
 TEST(PersistentView, Each) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
     registry.prepare<int, char>();
 
     const auto e0 = registry.create();
@@ -454,7 +490,7 @@ TEST(PersistentView, Each) {
 }
 
 TEST(PersistentView, Sort) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
     registry.prepare<int, unsigned int>();
 
     const auto e0 = registry.create();
@@ -489,7 +525,7 @@ TEST(PersistentView, Sort) {
 }
 
 TEST(RawView, Functionalities) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
     auto view = registry.view<char>(entt::raw_t{});
     const auto &cview = view;
 
@@ -543,8 +579,25 @@ TEST(RawView, Functionalities) {
     ASSERT_TRUE(view.empty());
 }
 
+TEST(RawView, ElementAccess) {
+    entt::Registry<std::uint64_t> registry;
+    auto view = registry.view<int>(entt::raw_t{});
+    const auto &cview = view;
+
+    const auto e0 = registry.create();
+    registry.assign<int>(e0, 42);
+
+    const auto e1 = registry.create();
+    registry.assign<int>(e1, 3);
+
+    for(typename decltype(view)::size_type i{}; i < view.size(); ++i) {
+        ASSERT_EQ(view[i], i ? 42 : 3);
+        ASSERT_EQ(cview[i], i ? 42 : 3);
+    }
+}
+
 TEST(RawView, Empty) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
 
     const auto e0 = registry.create();
     registry.assign<char>(e0);
@@ -555,7 +608,7 @@ TEST(RawView, Empty) {
 
     auto view = registry.view<int>(entt::raw_t{});
 
-    ASSERT_EQ(view.size(), entt::DefaultRegistry::size_type{0});
+    ASSERT_EQ(view.size(), entt::Registry<std::uint64_t>::size_type{0});
 
     for(auto &&component: view) {
         (void)component;
@@ -564,7 +617,7 @@ TEST(RawView, Empty) {
 }
 
 TEST(RawView, Each) {
-    entt::DefaultRegistry registry;
+    entt::Registry<std::uint64_t> registry;
 
     registry.assign<int>(registry.create(), 1);
     registry.assign<int>(registry.create(), 3);