Michele Caini 8 лет назад
Родитель
Сommit
ed98ae3e70
3 измененных файлов с 209 добавлено и 20 удалено
  1. 2 2
      src/registry.hpp
  2. 16 11
      src/sparse_set.hpp
  3. 191 7
      test/sparse_set.cpp

+ 2 - 2
src/registry.hpp

@@ -378,11 +378,11 @@ public:
         std::get<ident<Component...>.template get<Comp>()>(pool).sort(std::move(compare));
     }
 
-    template<typename To, typename From, typename Compare>
+    template<typename To, typename From>
     void sort() {
         auto &&to = std::get<ident<Component...>.template get<To>()>(pool);
         auto &&from = std::get<ident<Component...>.template get<From>()>(pool);
-        to.sort(from);
+        to.respect(from);
     }
 
     template<typename Comp>

+ 16 - 11
src/sparse_set.hpp

@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include <utility>
+#include <numeric>
 #include <vector>
 #include <cstddef>
 #include <cassert>
@@ -159,17 +160,21 @@ class SparseSet<Index, Type> final: public SparseSet<Index> {
         const auto *data = SparseSet<Index>::data();
         const auto size = SparseSet<Index>::size();
         std::vector<pos_type> copy(size);
-        pos_type pos = 0;
 
-        std::generate(copy.begin(), copy.end(), [&pos]() { return pos++; });
+        std::iota(copy.begin(), copy.end(), pos_type{});
         std::sort(copy.begin(), copy.end(), compare);
 
         for(pos_type i = 0; i < copy.size(); ++i) {
-            if(copy[i] != i) {
-                SparseSet<Index>::swap(*(data + copy[i]), *(data + i));
-                std::swap(instances[copy[i]], instances[i]);
-                std::swap(copy[copy[i]], copy[i]);
+            const auto target = i;
+            auto curr = i;
+
+            while(copy[curr] != target) {
+                SparseSet<Index>::swap(*(data + copy[curr]), *(data + curr));
+                std::swap(instances[copy[curr]], instances[curr]);
+                std::swap(copy[curr], curr);
             }
+
+            copy[curr] = curr;
         }
     }
 
@@ -230,12 +235,12 @@ public:
     }
 
     template<typename Idx>
-    void sort(const SparseSet<Index> &other) {
+    void respect(const SparseSet<Idx> &other) {
         const auto *data = SparseSet<Index>::data();
 
         arrange([data, &other](auto lhs, auto rhs) {
-            auto eLhs = data + lhs;
-            auto eRhs = data + rhs;
+            auto eLhs = *(data + lhs);
+            auto eRhs = *(data + rhs);
 
             bool bLhs = other.has(eLhs);
             bool bRhs = other.has(eRhs);
@@ -246,10 +251,10 @@ public:
             } else if(!bLhs && !bRhs) {
                 compare = eLhs < eRhs;
             } else {
-                compare = bLhs;
+                compare = bRhs;
             }
 
-            return !compare;
+            return compare;
         });
     }
 

+ 191 - 7
test/sparse_set.cpp

@@ -165,34 +165,218 @@ TEST(SparseSetWithType, Swap) {
     set.reset();
 }
 
-TEST(SparseSetWithType, SortBasic) {
+TEST(SparseSetWithType, SortOrdered) {
     using SparseSet = entt::SparseSet<unsigned int, int>;
 
     SparseSet set;
 
-    ASSERT_EQ(set.construct(12, 6), 6);
+    ASSERT_EQ(set.construct(12, 12), 12);
     ASSERT_EQ(set.construct(42, 9), 9);
+    ASSERT_EQ(set.construct(7, 6), 6);
     ASSERT_EQ(set.construct(3, 3), 3);
+    ASSERT_EQ(set.construct(9, 1), 1);
 
     set.sort([](auto lhs, auto rhs) {
         return lhs < rhs;
     });
 
-    ASSERT_EQ(*(set.raw() + 0u), 9);
-    ASSERT_EQ(*(set.raw() + 1u), 6);
-    ASSERT_EQ(*(set.raw() + 2u), 3);
+    ASSERT_EQ(*(set.raw() + 0u), 12);
+    ASSERT_EQ(*(set.raw() + 1u), 9);
+    ASSERT_EQ(*(set.raw() + 2u), 6);
+    ASSERT_EQ(*(set.raw() + 3u), 3);
+    ASSERT_EQ(*(set.raw() + 4u), 1);
 
     auto begin = set.begin();
     auto end = set.end();
 
+    ASSERT_EQ(set.get(*(begin++)), 1);
     ASSERT_EQ(set.get(*(begin++)), 3);
     ASSERT_EQ(set.get(*(begin++)), 6);
     ASSERT_EQ(set.get(*(begin++)), 9);
+    ASSERT_EQ(set.get(*(begin++)), 12);
     ASSERT_EQ(begin, end);
 
     set.reset();
 }
 
-TEST(SparseSetWithType, SortAccordingTo) {
-    // TODO
+TEST(SparseSetWithType, SortReverse) {
+    using SparseSet = entt::SparseSet<unsigned int, int>;
+
+    SparseSet set;
+
+    ASSERT_EQ(set.construct(12, 1), 1);
+    ASSERT_EQ(set.construct(42, 3), 3);
+    ASSERT_EQ(set.construct(7, 6), 6);
+    ASSERT_EQ(set.construct(3, 9), 9);
+    ASSERT_EQ(set.construct(9, 12), 12);
+
+    set.sort([](auto lhs, auto rhs) {
+        return lhs < rhs;
+    });
+
+    ASSERT_EQ(*(set.raw() + 0u), 12);
+    ASSERT_EQ(*(set.raw() + 1u), 9);
+    ASSERT_EQ(*(set.raw() + 2u), 6);
+    ASSERT_EQ(*(set.raw() + 3u), 3);
+    ASSERT_EQ(*(set.raw() + 4u), 1);
+
+    auto begin = set.begin();
+    auto end = set.end();
+
+    ASSERT_EQ(set.get(*(begin++)), 1);
+    ASSERT_EQ(set.get(*(begin++)), 3);
+    ASSERT_EQ(set.get(*(begin++)), 6);
+    ASSERT_EQ(set.get(*(begin++)), 9);
+    ASSERT_EQ(set.get(*(begin++)), 12);
+    ASSERT_EQ(begin, end);
+
+    set.reset();
+}
+
+TEST(SparseSetWithType, SortUnordered) {
+    using SparseSet = entt::SparseSet<unsigned int, int>;
+
+    SparseSet set;
+
+    ASSERT_EQ(set.construct(12, 6), 6);
+    ASSERT_EQ(set.construct(42, 3), 3);
+    ASSERT_EQ(set.construct(7, 1), 1);
+    ASSERT_EQ(set.construct(3, 9), 9);
+    ASSERT_EQ(set.construct(9, 12), 12);
+
+    set.sort([](auto lhs, auto rhs) {
+        return lhs < rhs;
+    });
+
+    ASSERT_EQ(*(set.raw() + 0u), 12);
+    ASSERT_EQ(*(set.raw() + 1u), 9);
+    ASSERT_EQ(*(set.raw() + 2u), 6);
+    ASSERT_EQ(*(set.raw() + 3u), 3);
+    ASSERT_EQ(*(set.raw() + 4u), 1);
+
+    auto begin = set.begin();
+    auto end = set.end();
+
+    ASSERT_EQ(set.get(*(begin++)), 1);
+    ASSERT_EQ(set.get(*(begin++)), 3);
+    ASSERT_EQ(set.get(*(begin++)), 6);
+    ASSERT_EQ(set.get(*(begin++)), 9);
+    ASSERT_EQ(set.get(*(begin++)), 12);
+    ASSERT_EQ(begin, end);
+
+    set.reset();
+}
+
+TEST(SparseSetWithType, RespectOrdered) {
+    using SparseSet = entt::SparseSet<unsigned int, int>;
+
+    SparseSet lhs;
+    SparseSet rhs;
+
+    ASSERT_EQ(lhs.construct(1, 0), 0);
+    ASSERT_EQ(lhs.construct(2, 0), 0);
+    ASSERT_EQ(lhs.construct(3, 0), 0);
+    ASSERT_EQ(lhs.construct(4, 0), 0);
+    ASSERT_EQ(lhs.construct(5, 0), 0);
+
+    ASSERT_EQ(rhs.construct(6, 0), 0);
+    ASSERT_EQ(rhs.construct(1, 0), 0);
+    ASSERT_EQ(rhs.construct(2, 0), 0);
+    ASSERT_EQ(rhs.construct(3, 0), 0);
+    ASSERT_EQ(rhs.construct(4, 0), 0);
+    ASSERT_EQ(rhs.construct(5, 0), 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);
+
+    lhs.reset();
+    rhs.reset();
+}
+
+TEST(SparseSetWithType, RespectReverse) {
+    using SparseSet = entt::SparseSet<unsigned int, int>;
+
+    SparseSet lhs;
+    SparseSet rhs;
+
+    ASSERT_EQ(lhs.construct(1, 0), 0);
+    ASSERT_EQ(lhs.construct(2, 0), 0);
+    ASSERT_EQ(lhs.construct(3, 0), 0);
+    ASSERT_EQ(lhs.construct(4, 0), 0);
+    ASSERT_EQ(lhs.construct(5, 0), 0);
+
+    ASSERT_EQ(rhs.construct(5, 0), 0);
+    ASSERT_EQ(rhs.construct(4, 0), 0);
+    ASSERT_EQ(rhs.construct(3, 0), 0);
+    ASSERT_EQ(rhs.construct(2, 0), 0);
+    ASSERT_EQ(rhs.construct(1, 0), 0);
+    ASSERT_EQ(rhs.construct(6, 0), 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);
+
+    lhs.reset();
+    rhs.reset();
+}
+
+TEST(SparseSetWithType, RespectUnordered) {
+    using SparseSet = entt::SparseSet<unsigned int, int>;
+
+    SparseSet lhs;
+    SparseSet rhs;
+
+    ASSERT_EQ(lhs.construct(1, 0), 0);
+    ASSERT_EQ(lhs.construct(2, 0), 0);
+    ASSERT_EQ(lhs.construct(3, 0), 0);
+    ASSERT_EQ(lhs.construct(4, 0), 0);
+    ASSERT_EQ(lhs.construct(5, 0), 0);
+
+    ASSERT_EQ(rhs.construct(3, 0), 0);
+    ASSERT_EQ(rhs.construct(2, 0), 0);
+    ASSERT_EQ(rhs.construct(6, 0), 0);
+    ASSERT_EQ(rhs.construct(1, 0), 0);
+    ASSERT_EQ(rhs.construct(4, 0), 0);
+    ASSERT_EQ(rhs.construct(5, 0), 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);
+
+    lhs.reset();
+    rhs.reset();
 }