diff --git a/TODO b/TODO index 823598635..0681e1a2d 100644 --- a/TODO +++ b/TODO @@ -25,5 +25,4 @@ TODO * registry::sort also for types that are part of a group (untracked items only) * add sort by type to the non-owning group -* add test for range sort to storage * custom (decoupled) pools ==> double buffering, shared components, multi-model diff --git a/src/entt/entity/storage.hpp b/src/entt/entity/storage.hpp index a930c31ca..261198689 100644 --- a/src/entt/entity/storage.hpp +++ b/src/entt/entity/storage.hpp @@ -444,17 +444,18 @@ public: ENTT_ASSERT(!(first > last)); std::vector copy(last - first); - std::iota(copy.begin(), copy.end(), std::distance(last, end())); + const auto offset = std::distance(last, end()); + std::iota(copy.begin(), copy.end(), size_type{}); if constexpr(std::is_invocable_v) { static_assert(!std::is_empty_v); - algo(copy.rbegin(), copy.rend(), [this, compare = std::move(compare)](const auto lhs, const auto rhs) { - return compare(std::as_const(instances[lhs]), std::as_const(instances[rhs])); + algo(copy.rbegin(), copy.rend(), [this, offset, compare = std::move(compare)](const auto lhs, const auto rhs) { + return compare(std::as_const(instances[lhs+offset]), std::as_const(instances[rhs+offset])); }, std::forward(args)...); } else { - algo(copy.rbegin(), copy.rend(), [compare = std::move(compare), data = underlying_type::data()](const auto lhs, const auto rhs) { - return compare(std::as_const(data[lhs]), std::as_const(data[rhs])); + algo(copy.rbegin(), copy.rend(), [offset, compare = std::move(compare), data = underlying_type::data()](const auto lhs, const auto rhs) { + return compare(std::as_const(data[lhs+offset]), std::as_const(data[rhs+offset])); }, std::forward(args)...); } @@ -463,7 +464,7 @@ public: auto next = copy[curr]; while(curr != next) { - swap(copy[curr], copy[next]); + swap(copy[curr]+offset, copy[next]+offset); copy[curr] = curr; curr = next; next = copy[curr]; diff --git a/test/entt/entity/storage.cpp b/test/entt/entity/storage.cpp index d7f3e7508..840cc13e9 100644 --- a/test/entt/entity/storage.cpp +++ b/test/entt/entity/storage.cpp @@ -421,6 +421,72 @@ TEST(Storage, SortUnordered) { ASSERT_EQ(begin, end); } +TEST(Storage, SortRange) { + entt::storage set; + + 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(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(set.end(), set.end(), [](auto lhs, auto rhs) { + return lhs.value < rhs.value; + }); + + 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(set.begin(), set.begin(), [](auto lhs, auto rhs) { + return lhs.value < rhs.value; + }); + + 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(set.begin()+2, set.begin()+3, [](auto lhs, auto rhs) { + return lhs.value < rhs.value; + }); + + 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(++set.begin(), --set.end(), [](auto lhs, auto rhs) { + return lhs.value < rhs.value; + }); + + ASSERT_EQ((set.raw() + 0u)->value, 6); + ASSERT_EQ((set.raw() + 1u)->value, 9); + ASSERT_EQ((set.raw() + 2u)->value, 3); + ASSERT_EQ((set.raw() + 3u)->value, 1); + ASSERT_EQ((set.raw() + 4u)->value, 12); + + auto begin = set.begin(); + auto end = set.end(); + + ASSERT_EQ((begin++)->value, 12); + ASSERT_EQ((begin++)->value, 1); + ASSERT_EQ((begin++)->value, 3); + ASSERT_EQ((begin++)->value, 9); + ASSERT_EQ((begin++)->value, 6); + ASSERT_EQ(begin, end); +} + TEST(Storage, RespectDisjoint) { entt::storage lhs; entt::storage rhs;