Michele Caini il y a 7 ans
Parent
commit
15b9255a25
2 fichiers modifiés avec 49 ajouts et 17 suppressions
  1. 17 17
      src/entt/entity/sparse_set.hpp
  2. 32 0
      test/entt/entity/sparse_set.cpp

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

@@ -63,16 +63,16 @@ class SparseSet<Entity> {
     class Iterator final {
         friend class SparseSet<Entity>;
 
-        using entity_type = Entity;
+        using direct_type = const std::vector<Entity>;
         using index_type = typename traits_type::difference_type;
 
-        Iterator(const entity_type *direct, index_type index) ENTT_NOEXCEPT
+        Iterator(direct_type *direct, index_type index) ENTT_NOEXCEPT
             : direct{direct}, index{index}
         {}
 
     public:
         using difference_type = index_type;
-        using value_type = const entity_type;
+        using value_type = const Entity;
         using pointer = value_type *;
         using reference = value_type &;
         using iterator_category = std::random_access_iterator_tag;
@@ -122,7 +122,7 @@ class SparseSet<Entity> {
         }
 
         reference operator[](const difference_type value) const ENTT_NOEXCEPT {
-            return direct[index-value-1];
+            return (*direct)[index-value-1];
         }
 
         bool operator==(const Iterator &other) const ENTT_NOEXCEPT {
@@ -150,7 +150,7 @@ class SparseSet<Entity> {
         }
 
         pointer operator->() const ENTT_NOEXCEPT {
-            return (direct+index-1);
+            return &(*direct)[index-1];
         }
 
         inline reference operator*() const ENTT_NOEXCEPT {
@@ -158,7 +158,7 @@ class SparseSet<Entity> {
         }
 
     private:
-        pointer direct;
+        direct_type *direct;
         index_type index;
     };
 
@@ -278,7 +278,7 @@ public:
      */
     const_iterator_type cbegin() const ENTT_NOEXCEPT {
         const typename traits_type::difference_type pos = direct.size();
-        return const_iterator_type{direct.data(), pos};
+        return const_iterator_type{&direct, pos};
     }
 
     /**
@@ -327,7 +327,7 @@ public:
      * internal packed array.
      */
     const_iterator_type cend() const ENTT_NOEXCEPT {
-        return const_iterator_type{direct.data(), {}};
+        return const_iterator_type{&direct, {}};
     }
 
     /**
@@ -578,7 +578,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
     class Iterator final {
         friend class SparseSet<Entity, Type>;
 
-        using instance_type = std::conditional_t<Const, const Type, Type>;
+        using instance_type = std::conditional_t<Const, const std::vector<Type>, std::vector<Type>>;
         using index_type = typename traits_type::difference_type;
 
         Iterator(instance_type *instances, index_type index) ENTT_NOEXCEPT
@@ -587,7 +587,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
 
     public:
         using difference_type = index_type;
-        using value_type = instance_type;
+        using value_type = std::conditional_t<Const, const Type, Type>;
         using pointer = value_type *;
         using reference = value_type &;
         using iterator_category = std::random_access_iterator_tag;
@@ -637,7 +637,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
         }
 
         reference operator[](const difference_type value) const ENTT_NOEXCEPT {
-            return instances[index-value-1];
+            return (*instances)[index-value-1];
         }
 
         bool operator==(const Iterator &other) const ENTT_NOEXCEPT {
@@ -665,7 +665,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
         }
 
         pointer operator->() const ENTT_NOEXCEPT {
-            return (instances+index-1);
+            return &(*instances)[index-1];
         }
 
         inline reference operator*() const ENTT_NOEXCEPT {
@@ -673,7 +673,7 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
         }
 
     private:
-        pointer instances;
+        instance_type *instances;
         index_type index;
     };
 
@@ -767,7 +767,7 @@ public:
      */
     const_iterator_type cbegin() const ENTT_NOEXCEPT {
         const typename traits_type::difference_type pos = instances.size();
-        return const_iterator_type{instances.data(), pos};
+        return const_iterator_type{&instances, pos};
     }
 
     /**
@@ -800,7 +800,7 @@ public:
      */
     iterator_type begin() ENTT_NOEXCEPT {
         const typename traits_type::difference_type pos = instances.size();
-        return iterator_type{instances.data(), pos};
+        return iterator_type{&instances, pos};
     }
 
     /**
@@ -818,7 +818,7 @@ public:
      * given type.
      */
     const_iterator_type cend() const ENTT_NOEXCEPT {
-        return const_iterator_type{instances.data(), {}};
+        return const_iterator_type{&instances, {}};
     }
 
     /**
@@ -854,7 +854,7 @@ public:
      * given type.
      */
     iterator_type end() ENTT_NOEXCEPT {
-        return iterator_type{instances.data(), {}};
+        return iterator_type{&instances, {}};
     }
 
     /**

+ 32 - 0
test/entt/entity/sparse_set.cpp

@@ -337,6 +337,22 @@ TEST(SparseSetNoType, RespectUnordered) {
     ASSERT_EQ(rhs.get(5), 5u);
 }
 
+TEST(SparseSetNoType, CanModifyDuringIteration) {
+    entt::SparseSet<std::uint64_t> set;
+    set.construct(0);
+
+    ASSERT_EQ(set.capacity(), entt::SparseSet<std::uint64_t>::size_type{1});
+
+    const auto it = set.cbegin();
+    set.reserve(entt::SparseSet<std::uint64_t>::size_type{2});
+
+    ASSERT_EQ(set.capacity(), entt::SparseSet<std::uint64_t>::size_type{2});
+
+    // this should crash with asan enabled if we break the constraint
+    const auto entity = *it;
+    (void)entity;
+}
+
 TEST(SparseSetWithType, Functionalities) {
     entt::SparseSet<std::uint64_t, int> set;
     const auto &cset = set;
@@ -823,6 +839,22 @@ TEST(SparseSetWithType, RespectUnordered) {
     ASSERT_EQ(*(rhs.data() + 5u), 5u);
 }
 
+TEST(SparseSetWithType, CanModifyDuringIteration) {
+    entt::SparseSet<std::uint64_t, int> set;
+    set.construct(0, 42);
+
+    ASSERT_EQ(set.capacity(), entt::SparseSet<std::uint64_t>::size_type{1});
+
+    const auto it = set.cbegin();
+    set.reserve(entt::SparseSet<std::uint64_t>::size_type{2});
+
+    ASSERT_EQ(set.capacity(), entt::SparseSet<std::uint64_t>::size_type{2});
+
+    // this should crash with asan enabled if we break the constraint
+    const auto entity = *it;
+    (void)entity;
+}
+
 TEST(SparseSetWithType, ReferencesGuaranteed) {
     struct InternalType { int value; };