From 2466c7123e0484c1b94e115ce52f3e982fc346a7 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Wed, 11 Oct 2023 08:15:00 +0200 Subject: [PATCH] test: storage entity --- test/CMakeLists.txt | 1 + test/entt/entity/storage.cpp | 638 ---------------------------- test/entt/entity/storage_entity.cpp | 542 +++++++++++++++++++++++ 3 files changed, 543 insertions(+), 638 deletions(-) create mode 100644 test/entt/entity/storage_entity.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e642438884..878e3cce3f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -245,6 +245,7 @@ SETUP_BASIC_TEST(sigh_mixin entt/entity/sigh_mixin.cpp) SETUP_BASIC_TEST(snapshot entt/entity/snapshot.cpp) SETUP_BASIC_TEST(sparse_set entt/entity/sparse_set.cpp) SETUP_BASIC_TEST(storage entt/entity/storage.cpp) +SETUP_BASIC_TEST(storage_entity entt/entity/storage_entity.cpp) SETUP_BASIC_TEST(storage_no_instance entt/entity/storage_no_instance.cpp) SETUP_BASIC_TEST(storage_utility entt/entity/storage_utility.cpp) SETUP_BASIC_TEST(view entt/entity/view.cpp) diff --git a/test/entt/entity/storage.cpp b/test/entt/entity/storage.cpp index 0b19740ffb..afa43b9fbb 100644 --- a/test/entt/entity/storage.cpp +++ b/test/entt/entity/storage.cpp @@ -524,22 +524,6 @@ TEST(StoragePointerStable, Constructors) { // <<<<<<<<<<<< REWORK IN PROGRESS [stable/TODO] <<<<<<<<<<<< -TEST(StorageEntity, Constructors) { - entt::storage pool; - - ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_only); - ASSERT_NO_FATAL_FAILURE([[maybe_unused]] auto alloc = pool.get_allocator()); - ASSERT_EQ(pool.type(), entt::type_id()); - - pool = entt::storage{std::allocator{}}; - - ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_only); - ASSERT_NO_FATAL_FAILURE([[maybe_unused]] auto alloc = pool.get_allocator()); - ASSERT_EQ(pool.type(), entt::type_id()); -} - -// <<<<<<<<<<<< REWORK IN PROGRESS [entity/TODO] <<<<<<<<<<<< - // <<<<<<<<<<<< REWORK IN PROGRESS [non-copyable/non-movable/whatever/TODO] <<<<<<<<<<<< struct pinned_type { @@ -2128,625 +2112,3 @@ TEST_F(StorageOld, UsesAllocatorConstruction) { } #endif - -TEST(StorageEntity, TypeAndPolicy) { - entt::storage pool; - - ASSERT_EQ(pool.type(), entt::type_id()); - ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_only); -} - -TEST(StorageEntity, Functionalities) { - entt::entity entity[2u]{entt::entity{0}, entt::entity{1}}; - entt::storage pool; - - ASSERT_TRUE(pool.empty()); - ASSERT_EQ(pool.size(), 0u); - ASSERT_EQ(pool.in_use(), 0u); - - ASSERT_EQ(*pool.push(entt::null), entity[0u]); - ASSERT_EQ(*pool.push(entt::tombstone), entity[1u]); - - ASSERT_FALSE(pool.empty()); - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(pool.in_use(), 2u); - - pool.in_use(1u); - - ASSERT_FALSE(pool.empty()); - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(pool.in_use(), 1u); - - ASSERT_NO_THROW(pool.get(entity[0u])); - ASSERT_EQ(pool.get_as_tuple(entity[0u]), std::tuple<>{}); - - pool.erase(entity[0u]); - - ASSERT_FALSE(pool.empty()); - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(pool.in_use(), 0u); -} - -ENTT_DEBUG_TEST(StorageEntityDeathTest, Get) { - entt::storage pool; - pool.emplace(entt::entity{99}); - - ASSERT_DEATH(pool.get(entt::entity{3}), ""); - ASSERT_DEATH([[maybe_unused]] auto tup = pool.get_as_tuple(entt::entity{3}), ""); - - ASSERT_NO_THROW(pool.get(entt::entity{99})); - ASSERT_NO_THROW([[maybe_unused]] auto tup = pool.get_as_tuple(entt::entity{99})); - - pool.erase(entt::entity{99}); - - ASSERT_DEATH(pool.get(entt::entity{99}), ""); - ASSERT_DEATH([[maybe_unused]] auto tup = pool.get_as_tuple(entt::entity{99}), ""); -} - -TEST(StorageEntity, Move) { - entt::storage pool; - - pool.push(entt::entity{1}); - - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(pool.in_use(), 1u); - - ASSERT_TRUE(std::is_move_constructible_v); - ASSERT_TRUE(std::is_move_assignable_v); - - entt::storage other{std::move(pool)}; - - ASSERT_EQ(pool.size(), 0u); - ASSERT_EQ(other.size(), 2u); - ASSERT_EQ(pool.in_use(), 0u); - ASSERT_EQ(other.in_use(), 1u); - ASSERT_EQ(pool.at(0u), static_cast(entt::null)); - ASSERT_EQ(other.at(0u), entt::entity{1}); - - pool = std::move(other); - - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(other.size(), 0u); - ASSERT_EQ(pool.in_use(), 1u); - ASSERT_EQ(other.in_use(), 0u); - ASSERT_EQ(pool.at(0u), entt::entity{1}); - ASSERT_EQ(other.at(0u), static_cast(entt::null)); - - other = entt::storage{}; - - other.push(entt::entity{3}); - other = std::move(pool); - - ASSERT_EQ(pool.size(), 0u); - ASSERT_EQ(other.size(), 2u); - ASSERT_EQ(pool.in_use(), 0u); - ASSERT_EQ(other.in_use(), 1u); - ASSERT_EQ(pool.at(0u), static_cast(entt::null)); - ASSERT_EQ(other.at(0u), entt::entity{1}); - - other.clear(); - - ASSERT_EQ(other.size(), 0u); - ASSERT_EQ(other.in_use(), 0u); - - ASSERT_EQ(*other.push(entt::null), entt::entity{0}); -} - -TEST(StorageEntity, Swap) { - entt::storage pool; - entt::storage other; - - pool.push(entt::entity{1}); - - other.push(entt::entity{2}); - other.push(entt::entity{0}); - other.erase(entt::entity{2}); - - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(other.size(), 3u); - ASSERT_EQ(pool.in_use(), 1u); - ASSERT_EQ(other.in_use(), 1u); - - pool.swap(other); - - ASSERT_EQ(pool.size(), 3u); - ASSERT_EQ(other.size(), 2u); - ASSERT_EQ(pool.in_use(), 1u); - ASSERT_EQ(other.in_use(), 1u); - - ASSERT_EQ(pool.at(0u), entt::entity{0}); - ASSERT_EQ(other.at(0u), entt::entity{1}); - - pool.clear(); - other.clear(); - - ASSERT_EQ(pool.size(), 0u); - ASSERT_EQ(other.size(), 0u); - ASSERT_EQ(pool.in_use(), 0u); - ASSERT_EQ(other.in_use(), 0u); - - ASSERT_EQ(*other.push(entt::null), entt::entity{0}); -} - -TEST(StorageEntity, Push) { - using traits_type = entt::entt_traits; - - entt::storage pool; - - ASSERT_EQ(*pool.push(entt::null), entt::entity{0}); - ASSERT_EQ(*pool.push(entt::tombstone), entt::entity{1}); - ASSERT_EQ(*pool.push(entt::entity{0}), entt::entity{2}); - ASSERT_EQ(*pool.push(traits_type::construct(1, 1)), entt::entity{3}); - ASSERT_EQ(*pool.push(traits_type::construct(5, 3)), traits_type::construct(5, 3)); - - ASSERT_LT(pool.index(entt::entity{0}), pool.in_use()); - ASSERT_LT(pool.index(entt::entity{1}), pool.in_use()); - ASSERT_LT(pool.index(entt::entity{2}), pool.in_use()); - ASSERT_LT(pool.index(entt::entity{3}), pool.in_use()); - ASSERT_GE(pool.index(entt::entity{4}), pool.in_use()); - ASSERT_LT(pool.index(traits_type::construct(5, 3)), pool.in_use()); - - ASSERT_EQ(*pool.push(traits_type::construct(4, 42)), traits_type::construct(4, 42)); - ASSERT_EQ(*pool.push(traits_type::construct(4, 43)), entt::entity{6}); - - entt::entity entity[2u]{entt::entity{1}, traits_type::construct(5, 3)}; - - pool.erase(entity, entity + 2u); - pool.erase(entt::entity{2}); - - ASSERT_EQ(pool.current(entity[0u]), 1); - ASSERT_EQ(pool.current(entity[1u]), 4); - ASSERT_EQ(pool.current(entt::entity{2}), 1); - - ASSERT_LT(pool.index(entt::entity{0}), pool.in_use()); - ASSERT_GE(pool.index(traits_type::construct(1, 1)), pool.in_use()); - ASSERT_GE(pool.index(traits_type::construct(2, 1)), pool.in_use()); - ASSERT_LT(pool.index(entt::entity{3}), pool.in_use()); - ASSERT_LT(pool.index(traits_type::construct(4, 42)), pool.in_use()); - ASSERT_GE(pool.index(traits_type::construct(5, 4)), pool.in_use()); - - ASSERT_EQ(*pool.push(entt::null), traits_type::construct(2, 1)); - ASSERT_EQ(*pool.push(traits_type::construct(1, 3)), traits_type::construct(1, 3)); - ASSERT_EQ(*pool.push(entt::null), traits_type::construct(5, 4)); - ASSERT_EQ(*pool.push(entt::null), entt::entity{7}); -} - -TEST(StorageEntity, Emplace) { - using traits_type = entt::entt_traits; - - entt::storage pool; - entt::entity entity[2u]{}; - - ASSERT_EQ(pool.emplace(), entt::entity{0}); - ASSERT_EQ(pool.emplace(entt::null), entt::entity{1}); - ASSERT_EQ(pool.emplace(entt::tombstone), entt::entity{2}); - ASSERT_EQ(pool.emplace(entt::entity{0}), entt::entity{3}); - ASSERT_EQ(pool.emplace(traits_type::construct(1, 1)), entt::entity{4}); - ASSERT_EQ(pool.emplace(traits_type::construct(6, 3)), traits_type::construct(6, 3)); - - ASSERT_LT(pool.index(entt::entity{0}), pool.in_use()); - ASSERT_LT(pool.index(entt::entity{1}), pool.in_use()); - ASSERT_LT(pool.index(entt::entity{2}), pool.in_use()); - ASSERT_LT(pool.index(entt::entity{3}), pool.in_use()); - ASSERT_LT(pool.index(entt::entity{4}), pool.in_use()); - ASSERT_GE(pool.index(entt::entity{5}), pool.in_use()); - ASSERT_LT(pool.index(traits_type::construct(6, 3)), pool.in_use()); - - ASSERT_EQ(pool.emplace(traits_type::construct(5, 42)), traits_type::construct(5, 42)); - ASSERT_EQ(pool.emplace(traits_type::construct(5, 43)), entt::entity{7}); - - pool.erase(entt::entity{2}); - - ASSERT_EQ(pool.emplace(), traits_type::construct(2, 1)); - - pool.erase(traits_type::construct(2, 1)); - pool.insert(entity, entity + 2u); - - ASSERT_EQ(entity[0u], traits_type::construct(2, 2)); - ASSERT_EQ(entity[1u], entt::entity{8}); -} - -TEST(StorageEntity, Patch) { - entt::storage pool; - const auto entity = pool.emplace(); - - int counter = 0; - auto callback = [&counter]() { ++counter; }; - - ASSERT_EQ(counter, 0); - - pool.patch(entity); - pool.patch(entity, callback); - pool.patch(entity, callback, callback); - - ASSERT_EQ(counter, 3); -} - -ENTT_DEBUG_TEST(StorageEntityDeathTest, Patch) { - entt::storage pool; - - ASSERT_DEATH(pool.patch(entt::null), ""); -} - -TEST(StorageEntity, Insert) { - entt::storage pool; - entt::entity entity[2u]{}; - - pool.insert(std::begin(entity), std::end(entity)); - - ASSERT_TRUE(pool.contains(entity[0u])); - ASSERT_TRUE(pool.contains(entity[1u])); - - ASSERT_FALSE(pool.empty()); - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(pool.in_use(), 2u); - - pool.erase(std::begin(entity), std::end(entity)); - - ASSERT_FALSE(pool.empty()); - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(pool.in_use(), 0u); - - pool.insert(entity, entity + 1u); - - ASSERT_TRUE(pool.contains(entity[0u])); - ASSERT_FALSE(pool.contains(entity[1u])); - - ASSERT_FALSE(pool.empty()); - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(pool.in_use(), 1u); -} - -TEST(StorageEntity, Pack) { - entt::storage pool; - entt::entity entity[3u]{entt::entity{1}, entt::entity{3}, entt::entity{42}}; - - pool.push(entity, entity + 3u); - std::swap(entity[0u], entity[1u]); - - const auto len = pool.pack(entity + 1u, entity + 3u); - auto it = pool.each().cbegin().base(); - - ASSERT_NE(it, pool.cbegin()); - ASSERT_NE(it, pool.cend()); - - ASSERT_EQ(len, 2u); - ASSERT_NE(it + len, pool.cend()); - ASSERT_EQ(it + len + 1u, pool.cend()); - - ASSERT_EQ(*it++, entity[1u]); - ASSERT_EQ(*it++, entity[2u]); - - ASSERT_NE(it, pool.cend()); - ASSERT_EQ(*it++, entity[0u]); - ASSERT_EQ(it, pool.cend()); -} - -TEST(StorageEntity, Iterable) { - using iterator = typename entt::storage::iterable::iterator; - - testing::StaticAssertTypeEq>(); - testing::StaticAssertTypeEq>>(); - testing::StaticAssertTypeEq(); - - entt::storage pool; - - pool.emplace(entt::entity{1}); - pool.emplace(entt::entity{3}); - pool.emplace(entt::entity{42}); - - pool.erase(entt::entity{3}); - - auto iterable = pool.each(); - - iterator end{iterable.begin()}; - iterator begin{}; - begin = iterable.end(); - std::swap(begin, end); - - ASSERT_EQ(begin, iterable.begin()); - ASSERT_EQ(end, iterable.end()); - ASSERT_NE(begin, end); - - ASSERT_NE(begin.base(), pool.begin()); - ASSERT_EQ(begin.base(), pool.end() - pool.in_use()); - ASSERT_EQ(end.base(), pool.end()); - - ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{42}); - ASSERT_EQ(std::get<0>(*begin), entt::entity{42}); - - ASSERT_EQ(begin++, iterable.begin()); - ASSERT_EQ(begin.base(), pool.end() - 1); - ASSERT_EQ(++begin, iterable.end()); - ASSERT_EQ(begin.base(), pool.end()); - - for(auto [entity]: iterable) { - testing::StaticAssertTypeEq(); - ASSERT_TRUE(entity != entt::entity{3}); - } -} - -TEST(StorageEntity, ConstIterable) { - using iterator = typename entt::storage::const_iterable::iterator; - - testing::StaticAssertTypeEq>(); - testing::StaticAssertTypeEq>>(); - testing::StaticAssertTypeEq(); - - entt::storage pool; - - pool.emplace(entt::entity{1}); - pool.emplace(entt::entity{3}); - pool.emplace(entt::entity{42}); - - pool.erase(entt::entity{3}); - - auto iterable = std::as_const(pool).each(); - - iterator end{iterable.cbegin()}; - iterator begin{}; - begin = iterable.cend(); - std::swap(begin, end); - - ASSERT_EQ(begin, iterable.cbegin()); - ASSERT_EQ(end, iterable.cend()); - ASSERT_NE(begin, end); - - ASSERT_NE(begin.base(), pool.begin()); - ASSERT_EQ(begin.base(), pool.end() - pool.in_use()); - ASSERT_EQ(end.base(), pool.end()); - - ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{42}); - ASSERT_EQ(std::get<0>(*begin), entt::entity{42}); - - ASSERT_EQ(begin++, iterable.begin()); - ASSERT_EQ(begin.base(), pool.end() - 1); - ASSERT_EQ(++begin, iterable.end()); - ASSERT_EQ(begin.base(), pool.end()); - - for(auto [entity]: iterable) { - testing::StaticAssertTypeEq(); - ASSERT_TRUE(entity != entt::entity{3}); - } -} - -TEST(StorageEntity, IterableIteratorConversion) { - entt::storage pool; - pool.emplace(entt::entity{3}); - - typename entt::storage::iterable::iterator it = pool.each().begin(); - typename entt::storage::const_iterable::iterator cit = it; - - testing::StaticAssertTypeEq>(); - testing::StaticAssertTypeEq>(); - - ASSERT_EQ(it, cit); - ASSERT_NE(++cit, it); -} - -TEST(StorageEntity, IterableAlgorithmCompatibility) { - entt::storage pool; - pool.emplace(entt::entity{3}); - - const auto iterable = pool.each(); - const auto it = std::find_if(iterable.begin(), iterable.end(), [](auto args) { return std::get<0>(args) == entt::entity{3}; }); - - ASSERT_EQ(std::get<0>(*it), entt::entity{3}); -} - -TEST(StorageEntity, ReverseIterable) { - using iterator = typename entt::storage::reverse_iterable::iterator; - - testing::StaticAssertTypeEq>(); - testing::StaticAssertTypeEq>>(); - testing::StaticAssertTypeEq(); - - entt::storage pool; - - pool.emplace(entt::entity{1}); - pool.emplace(entt::entity{3}); - pool.emplace(entt::entity{42}); - - pool.erase(entt::entity{3}); - - auto iterable = pool.reach(); - - iterator end{iterable.begin()}; - iterator begin{}; - begin = iterable.end(); - std::swap(begin, end); - - ASSERT_EQ(begin, iterable.begin()); - ASSERT_EQ(end, iterable.end()); - ASSERT_NE(begin, end); - - ASSERT_EQ(begin.base(), pool.rbegin()); - ASSERT_EQ(end.base(), pool.rbegin() + pool.in_use()); - ASSERT_NE(end.base(), pool.rend()); - - ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{1}); - ASSERT_EQ(std::get<0>(*begin), entt::entity{1}); - - ASSERT_EQ(begin++, iterable.begin()); - ASSERT_EQ(begin.base(), pool.rbegin() + 1); - ASSERT_EQ(++begin, iterable.end()); - ASSERT_EQ(begin.base(), pool.rbegin() + 2); - - for(auto [entity]: iterable) { - testing::StaticAssertTypeEq(); - ASSERT_TRUE(entity != entt::entity{3}); - } -} - -TEST(StorageEntity, ReverseConstIterable) { - using iterator = typename entt::storage::const_reverse_iterable::iterator; - - testing::StaticAssertTypeEq>(); - testing::StaticAssertTypeEq>>(); - testing::StaticAssertTypeEq(); - - entt::storage pool; - - pool.emplace(entt::entity{1}); - pool.emplace(entt::entity{3}); - pool.emplace(entt::entity{42}); - - pool.erase(entt::entity{3}); - - auto iterable = std::as_const(pool).reach(); - - iterator end{iterable.cbegin()}; - iterator begin{}; - begin = iterable.cend(); - std::swap(begin, end); - - ASSERT_EQ(begin, iterable.cbegin()); - ASSERT_EQ(end, iterable.cend()); - ASSERT_NE(begin, end); - - ASSERT_EQ(begin.base(), pool.rbegin()); - ASSERT_EQ(end.base(), pool.rbegin() + pool.in_use()); - ASSERT_NE(end.base(), pool.rend()); - - ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{1}); - ASSERT_EQ(std::get<0>(*begin), entt::entity{1}); - - ASSERT_EQ(begin++, iterable.begin()); - ASSERT_EQ(begin.base(), pool.rbegin() + 1); - ASSERT_EQ(++begin, iterable.end()); - ASSERT_EQ(begin.base(), pool.rbegin() + 2); - - for(auto [entity]: iterable) { - testing::StaticAssertTypeEq(); - ASSERT_TRUE(entity != entt::entity{3}); - } -} - -TEST(StorageEntity, ReverseIterableIteratorConversion) { - entt::storage pool; - pool.emplace(entt::entity{3}); - - typename entt::storage::reverse_iterable::iterator it = pool.reach().begin(); - typename entt::storage::const_reverse_iterable::iterator cit = it; - - testing::StaticAssertTypeEq>(); - testing::StaticAssertTypeEq>(); - - ASSERT_EQ(it, cit); - ASSERT_NE(++cit, it); -} - -TEST(StorageEntity, ReverseIterableAlgorithmCompatibility) { - entt::storage pool; - pool.emplace(entt::entity{3}); - - const auto iterable = pool.reach(); - const auto it = std::find_if(iterable.begin(), iterable.end(), [](auto args) { return std::get<0>(args) == entt::entity{3}; }); - - ASSERT_EQ(std::get<0>(*it), entt::entity{3}); -} - -TEST(StorageEntity, SwapElements) { - entt::storage pool; - - pool.push(entt::entity{0}); - pool.push(entt::entity{1}); - - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(pool.in_use(), 2u); - ASSERT_TRUE(pool.contains(entt::entity{0})); - ASSERT_TRUE(pool.contains(entt::entity{1})); - - ASSERT_EQ(*pool.begin(), entt::entity{1}); - ASSERT_EQ(*++pool.begin(), entt::entity{0}); - - pool.swap_elements(entt::entity{0}, entt::entity{1}); - - ASSERT_EQ(*pool.begin(), entt::entity{0}); - ASSERT_EQ(*++pool.begin(), entt::entity{1}); -} - -ENTT_DEBUG_TEST(StorageEntityDeathTest, SwapElements) { - entt::storage pool; - - pool.push(entt::entity{1}); - - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(pool.in_use(), 1u); - ASSERT_TRUE(pool.contains(entt::entity{0})); - ASSERT_TRUE(pool.contains(entt::entity{1})); - - ASSERT_DEATH(pool.swap_elements(entt::entity{0}, entt::entity{1}), ""); -} - -ENTT_DEBUG_TEST(StorageEntityDeathTest, InUse) { - entt::storage pool; - - pool.push(entt::entity{0}); - pool.push(entt::entity{1}); - - ASSERT_DEATH(pool.in_use(3u), ""); -} - -ENTT_DEBUG_TEST(StorageEntityDeathTest, SortAndRespect) { - entt::storage pool; - entt::storage other; - - pool.push(entt::entity{1}); - pool.push(entt::entity{2}); - pool.erase(entt::entity{2}); - - other.push(entt::entity{2}); - - ASSERT_DEATH(pool.sort([](auto...) { return true; }), ""); - ASSERT_DEATH(pool.sort_as(other), ""); -} - -TEST(StorageEntity, CustomAllocator) { - test::throwing_allocator allocator{}; - entt::basic_storage> pool{allocator}; - - pool.reserve(1u); - - ASSERT_EQ(pool.size(), 0u); - ASSERT_EQ(pool.in_use(), 0u); - - pool.push(entt::entity{0}); - pool.push(entt::entity{1}); - - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(pool.in_use(), 2u); - - decltype(pool) other{std::move(pool), allocator}; - - ASSERT_TRUE(pool.empty()); - ASSERT_FALSE(other.empty()); - ASSERT_EQ(pool.size(), 0u); - ASSERT_EQ(other.size(), 2u); - ASSERT_EQ(pool.in_use(), 0u); - ASSERT_EQ(other.in_use(), 2u); - - pool = std::move(other); - - ASSERT_FALSE(pool.empty()); - ASSERT_TRUE(other.empty()); - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(other.size(), 0u); - ASSERT_EQ(pool.in_use(), 2u); - ASSERT_EQ(other.in_use(), 0u); - - pool.swap(other); - pool = std::move(other); - - ASSERT_FALSE(pool.empty()); - ASSERT_TRUE(other.empty()); - ASSERT_EQ(pool.size(), 2u); - ASSERT_EQ(other.size(), 0u); - ASSERT_EQ(pool.in_use(), 2u); - ASSERT_EQ(other.in_use(), 0u); - - pool.clear(); - - ASSERT_EQ(pool.size(), 0u); - ASSERT_EQ(pool.in_use(), 0u); -} diff --git a/test/entt/entity/storage_entity.cpp b/test/entt/entity/storage_entity.cpp new file mode 100644 index 0000000000..5c973de7cd --- /dev/null +++ b/test/entt/entity/storage_entity.cpp @@ -0,0 +1,542 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "../common/config.h" + +TEST(StorageEntity, Constructors) { + entt::storage pool; + + ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_only); + ASSERT_NO_FATAL_FAILURE([[maybe_unused]] auto alloc = pool.get_allocator()); + ASSERT_EQ(pool.type(), entt::type_id()); + + pool = entt::storage{std::allocator{}}; + + ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_only); + ASSERT_NO_FATAL_FAILURE([[maybe_unused]] auto alloc = pool.get_allocator()); + ASSERT_EQ(pool.type(), entt::type_id()); +} + +TEST(StorageEntity, Move) { + entt::storage pool; + + pool.emplace(entt::entity{3}); + + ASSERT_TRUE(std::is_move_constructible_v); + ASSERT_TRUE(std::is_move_assignable_v); + + entt::storage other{std::move(pool)}; + + ASSERT_TRUE(pool.empty()); + ASSERT_FALSE(other.empty()); + + ASSERT_EQ(pool.type(), entt::type_id()); + ASSERT_EQ(other.type(), entt::type_id()); + + ASSERT_EQ(pool.at(0u), static_cast(entt::null)); + ASSERT_EQ(other.at(0u), entt::entity{3}); + + entt::storage extended{std::move(other), std::allocator{}}; + + ASSERT_TRUE(other.empty()); + ASSERT_FALSE(extended.empty()); + + ASSERT_EQ(other.type(), entt::type_id()); + ASSERT_EQ(extended.type(), entt::type_id()); + + ASSERT_EQ(other.at(0u), static_cast(entt::null)); + ASSERT_EQ(extended.at(0u), entt::entity{3}); + + pool = std::move(extended); + + ASSERT_FALSE(pool.empty()); + ASSERT_TRUE(other.empty()); + ASSERT_TRUE(extended.empty()); + + ASSERT_EQ(pool.type(), entt::type_id()); + ASSERT_EQ(other.type(), entt::type_id()); + ASSERT_EQ(extended.type(), entt::type_id()); + + ASSERT_EQ(pool.at(0u), entt::entity{3}); + ASSERT_EQ(other.at(0u), static_cast(entt::null)); + ASSERT_EQ(extended.at(0u), static_cast(entt::null)); + + other = entt::storage{}; + other.emplace(entt::entity{42}); + other = std::move(pool); + + ASSERT_TRUE(pool.empty()); + ASSERT_FALSE(other.empty()); + + ASSERT_EQ(pool.type(), entt::type_id()); + ASSERT_EQ(other.type(), entt::type_id()); + + ASSERT_EQ(pool.at(0u), static_cast(entt::null)); + ASSERT_EQ(other.at(0u), entt::entity{3}); +} + +TEST(StorageEntity, Swap) { + entt::storage pool; + entt::storage other; + + ASSERT_EQ(pool.type(), entt::type_id()); + ASSERT_EQ(other.type(), entt::type_id()); + + pool.emplace(entt::entity{42}); + + other.emplace(entt::entity{9}); + other.emplace(entt::entity{3}); + other.erase(entt::entity{9}); + + ASSERT_EQ(pool.size(), 43u); + ASSERT_EQ(other.size(), 10u); + + pool.swap(other); + + ASSERT_EQ(pool.type(), entt::type_id()); + ASSERT_EQ(other.type(), entt::type_id()); + + ASSERT_EQ(pool.size(), 10u); + ASSERT_EQ(other.size(), 43u); + + ASSERT_EQ(pool.at(0u), entt::entity{3}); + ASSERT_EQ(other.at(0u), entt::entity{42}); +} + +TEST(StorageEntity, Getters) { + entt::storage pool; + + pool.emplace(entt::entity{41}); + + testing::StaticAssertTypeEq(); + testing::StaticAssertTypeEq(); + + testing::StaticAssertTypeEq>(); + testing::StaticAssertTypeEq>(); + + ASSERT_NO_FATAL_FAILURE(pool.get(entt::entity{41})); + ASSERT_NO_FATAL_FAILURE(std::as_const(pool).get(entt::entity{41})); + + ASSERT_EQ(pool.get_as_tuple(entt::entity{41}), std::make_tuple()); + ASSERT_EQ(std::as_const(pool).get_as_tuple(entt::entity{41}), std::make_tuple()); +} + +ENTT_DEBUG_TEST(StorageEntityDeathTest, Getters) { + entt::storage pool; + + ASSERT_DEATH(pool.get(entt::entity{41}), ""); + ASSERT_DEATH(std::as_const(pool).get(entt::entity{41}), ""); + + ASSERT_DEATH([[maybe_unused]] const auto value = pool.get_as_tuple(entt::entity{41}), ""); + ASSERT_DEATH([[maybe_unused]] const auto value = std::as_const(pool).get_as_tuple(entt::entity{41}), ""); +} + +TEST(StorageEntity, Emplace) { + using traits_type = entt::entt_traits; + + entt::storage pool; + entt::entity entity[2u]{}; + + ASSERT_EQ(pool.emplace(), entt::entity{0}); + ASSERT_EQ(pool.emplace(entt::null), entt::entity{1}); + ASSERT_EQ(pool.emplace(entt::tombstone), entt::entity{2}); + ASSERT_EQ(pool.emplace(entt::entity{0}), entt::entity{3}); + ASSERT_EQ(pool.emplace(traits_type::construct(1, 1)), entt::entity{4}); + ASSERT_EQ(pool.emplace(traits_type::construct(6, 3)), traits_type::construct(6, 3)); + + ASSERT_LT(pool.index(entt::entity{0}), pool.in_use()); + ASSERT_LT(pool.index(entt::entity{1}), pool.in_use()); + ASSERT_LT(pool.index(entt::entity{2}), pool.in_use()); + ASSERT_LT(pool.index(entt::entity{3}), pool.in_use()); + ASSERT_LT(pool.index(entt::entity{4}), pool.in_use()); + ASSERT_GE(pool.index(entt::entity{5}), pool.in_use()); + ASSERT_LT(pool.index(traits_type::construct(6, 3)), pool.in_use()); + + ASSERT_EQ(pool.emplace(traits_type::construct(5, 42)), traits_type::construct(5, 42)); + ASSERT_EQ(pool.emplace(traits_type::construct(5, 43)), entt::entity{7}); + + pool.erase(entt::entity{2}); + + ASSERT_EQ(pool.emplace(), traits_type::construct(2, 1)); + + pool.erase(traits_type::construct(2, 1)); + pool.insert(entity, entity + 2u); + + ASSERT_EQ(entity[0u], traits_type::construct(2, 2)); + ASSERT_EQ(entity[1u], entt::entity{8}); +} + +TEST(StorageEntity, TryEmplace) { + using traits_type = entt::entt_traits; + + entt::storage pool; + + ASSERT_EQ(*pool.push(entt::null), entt::entity{0}); + ASSERT_EQ(*pool.push(entt::tombstone), entt::entity{1}); + ASSERT_EQ(*pool.push(entt::entity{0}), entt::entity{2}); + ASSERT_EQ(*pool.push(traits_type::construct(1, 1)), entt::entity{3}); + ASSERT_EQ(*pool.push(traits_type::construct(5, 3)), traits_type::construct(5, 3)); + + ASSERT_LT(pool.index(entt::entity{0}), pool.in_use()); + ASSERT_LT(pool.index(entt::entity{1}), pool.in_use()); + ASSERT_LT(pool.index(entt::entity{2}), pool.in_use()); + ASSERT_LT(pool.index(entt::entity{3}), pool.in_use()); + ASSERT_GE(pool.index(entt::entity{4}), pool.in_use()); + ASSERT_LT(pool.index(traits_type::construct(5, 3)), pool.in_use()); + + ASSERT_EQ(*pool.push(traits_type::construct(4, 42)), traits_type::construct(4, 42)); + ASSERT_EQ(*pool.push(traits_type::construct(4, 43)), entt::entity{6}); + + entt::entity entity[2u]{entt::entity{1}, traits_type::construct(5, 3)}; + + pool.erase(entity, entity + 2u); + pool.erase(entt::entity{2}); + + ASSERT_EQ(pool.current(entity[0u]), 1); + ASSERT_EQ(pool.current(entity[1u]), 4); + ASSERT_EQ(pool.current(entt::entity{2}), 1); + + ASSERT_LT(pool.index(entt::entity{0}), pool.in_use()); + ASSERT_GE(pool.index(traits_type::construct(1, 1)), pool.in_use()); + ASSERT_GE(pool.index(traits_type::construct(2, 1)), pool.in_use()); + ASSERT_LT(pool.index(entt::entity{3}), pool.in_use()); + ASSERT_LT(pool.index(traits_type::construct(4, 42)), pool.in_use()); + ASSERT_GE(pool.index(traits_type::construct(5, 4)), pool.in_use()); + + ASSERT_EQ(*pool.push(entt::null), traits_type::construct(2, 1)); + ASSERT_EQ(*pool.push(traits_type::construct(1, 3)), traits_type::construct(1, 3)); + ASSERT_EQ(*pool.push(entt::null), traits_type::construct(5, 4)); + ASSERT_EQ(*pool.push(entt::null), entt::entity{7}); +} + +TEST(StorageEntity, Patch) { + entt::storage pool; + const auto entity = pool.emplace(); + + int counter = 0; + auto callback = [&counter]() { ++counter; }; + + ASSERT_EQ(counter, 0); + + pool.patch(entity); + pool.patch(entity, callback); + pool.patch(entity, callback, callback); + + ASSERT_EQ(counter, 3); +} + +ENTT_DEBUG_TEST(StorageEntityDeathTest, Patch) { + entt::storage pool; + + ASSERT_DEATH(pool.patch(entt::null), ""); +} + +TEST(StorageEntity, Insert) { + entt::storage pool; + entt::entity entity[2u]{}; + + pool.insert(std::begin(entity), std::end(entity)); + + ASSERT_TRUE(pool.contains(entity[0u])); + ASSERT_TRUE(pool.contains(entity[1u])); + + ASSERT_FALSE(pool.empty()); + ASSERT_EQ(pool.size(), 2u); + ASSERT_EQ(pool.in_use(), 2u); + + pool.erase(std::begin(entity), std::end(entity)); + + ASSERT_FALSE(pool.empty()); + ASSERT_EQ(pool.size(), 2u); + ASSERT_EQ(pool.in_use(), 0u); + + pool.insert(entity, entity + 1u); + + ASSERT_TRUE(pool.contains(entity[0u])); + ASSERT_FALSE(pool.contains(entity[1u])); + + ASSERT_FALSE(pool.empty()); + ASSERT_EQ(pool.size(), 2u); + ASSERT_EQ(pool.in_use(), 1u); +} + +TEST(StorageEntity, Pack) { + entt::storage pool; + entt::entity entity[3u]{entt::entity{1}, entt::entity{3}, entt::entity{42}}; + + pool.push(entity, entity + 3u); + std::swap(entity[0u], entity[1u]); + + const auto len = pool.pack(entity + 1u, entity + 3u); + auto it = pool.each().cbegin().base(); + + ASSERT_NE(it, pool.cbegin()); + ASSERT_NE(it, pool.cend()); + + ASSERT_EQ(len, 2u); + ASSERT_NE(it + len, pool.cend()); + ASSERT_EQ(it + len + 1u, pool.cend()); + + ASSERT_EQ(*it++, entity[1u]); + ASSERT_EQ(*it++, entity[2u]); + + ASSERT_NE(it, pool.cend()); + ASSERT_EQ(*it++, entity[0u]); + ASSERT_EQ(it, pool.cend()); +} + +TEST(StorageEntity, InUse) { + entt::storage pool; + + pool.emplace(entt::entity{0}); + + ASSERT_EQ(pool.in_use(), 1u); + ASSERT_EQ(pool.free_list(), 1u); + + pool.in_use(0u); + + ASSERT_EQ(pool.in_use(), 0u); + ASSERT_EQ(pool.free_list(), 0u); + + pool.in_use(1u); + + ASSERT_EQ(pool.in_use(), 1u); + ASSERT_EQ(pool.free_list(), 1u); +} + +ENTT_DEBUG_TEST(StorageEntityDeathTest, InUse) { + entt::storage pool; + + pool.emplace(entt::entity{0}); + + ASSERT_DEATH(pool.in_use(2u), ""); +} + +TEST(StorageEntity, Iterable) { + using iterator = typename entt::storage::iterable::iterator; + + testing::StaticAssertTypeEq>(); + testing::StaticAssertTypeEq>>(); + testing::StaticAssertTypeEq(); + + entt::storage pool; + + pool.emplace(entt::entity{1}); + pool.emplace(entt::entity{3}); + pool.emplace(entt::entity{42}); + + pool.erase(entt::entity{3}); + + auto iterable = pool.each(); + + iterator end{iterable.begin()}; + iterator begin{}; + begin = iterable.end(); + std::swap(begin, end); + + ASSERT_EQ(begin, iterable.begin()); + ASSERT_EQ(end, iterable.end()); + ASSERT_NE(begin, end); + + ASSERT_NE(begin.base(), pool.begin()); + ASSERT_EQ(begin.base(), pool.end() - pool.in_use()); + ASSERT_EQ(end.base(), pool.end()); + + ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{42}); + ASSERT_EQ(std::get<0>(*begin), entt::entity{42}); + + ASSERT_EQ(begin++, iterable.begin()); + ASSERT_EQ(begin.base(), pool.end() - 1); + ASSERT_EQ(++begin, iterable.end()); + ASSERT_EQ(begin.base(), pool.end()); + + for(auto [entity]: iterable) { + testing::StaticAssertTypeEq(); + ASSERT_TRUE(entity != entt::entity{3}); + } +} + +TEST(StorageEntity, ConstIterable) { + using iterator = typename entt::storage::const_iterable::iterator; + + testing::StaticAssertTypeEq>(); + testing::StaticAssertTypeEq>>(); + testing::StaticAssertTypeEq(); + + entt::storage pool; + + pool.emplace(entt::entity{1}); + pool.emplace(entt::entity{3}); + pool.emplace(entt::entity{42}); + + pool.erase(entt::entity{3}); + + auto iterable = std::as_const(pool).each(); + + iterator end{iterable.cbegin()}; + iterator begin{}; + begin = iterable.cend(); + std::swap(begin, end); + + ASSERT_EQ(begin, iterable.cbegin()); + ASSERT_EQ(end, iterable.cend()); + ASSERT_NE(begin, end); + + ASSERT_NE(begin.base(), pool.begin()); + ASSERT_EQ(begin.base(), pool.end() - pool.in_use()); + ASSERT_EQ(end.base(), pool.end()); + + ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{42}); + ASSERT_EQ(std::get<0>(*begin), entt::entity{42}); + + ASSERT_EQ(begin++, iterable.begin()); + ASSERT_EQ(begin.base(), pool.end() - 1); + ASSERT_EQ(++begin, iterable.end()); + ASSERT_EQ(begin.base(), pool.end()); + + for(auto [entity]: iterable) { + testing::StaticAssertTypeEq(); + ASSERT_TRUE(entity != entt::entity{3}); + } +} + +TEST(StorageEntity, IterableIteratorConversion) { + entt::storage pool; + pool.emplace(entt::entity{3}); + + typename entt::storage::iterable::iterator it = pool.each().begin(); + typename entt::storage::const_iterable::iterator cit = it; + + testing::StaticAssertTypeEq>(); + testing::StaticAssertTypeEq>(); + + ASSERT_EQ(it, cit); + ASSERT_NE(++cit, it); +} + +TEST(StorageEntity, IterableAlgorithmCompatibility) { + entt::storage pool; + pool.emplace(entt::entity{3}); + + const auto iterable = pool.each(); + const auto it = std::find_if(iterable.begin(), iterable.end(), [](auto args) { return std::get<0>(args) == entt::entity{3}; }); + + ASSERT_EQ(std::get<0>(*it), entt::entity{3}); +} + +TEST(StorageEntity, ReverseIterable) { + using iterator = typename entt::storage::reverse_iterable::iterator; + + testing::StaticAssertTypeEq>(); + testing::StaticAssertTypeEq>>(); + testing::StaticAssertTypeEq(); + + entt::storage pool; + + pool.emplace(entt::entity{1}); + pool.emplace(entt::entity{3}); + pool.emplace(entt::entity{42}); + + pool.erase(entt::entity{3}); + + auto iterable = pool.reach(); + + iterator end{iterable.begin()}; + iterator begin{}; + begin = iterable.end(); + std::swap(begin, end); + + ASSERT_EQ(begin, iterable.begin()); + ASSERT_EQ(end, iterable.end()); + ASSERT_NE(begin, end); + + ASSERT_EQ(begin.base(), pool.rbegin()); + ASSERT_EQ(end.base(), pool.rbegin() + pool.in_use()); + ASSERT_NE(end.base(), pool.rend()); + + ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{1}); + ASSERT_EQ(std::get<0>(*begin), entt::entity{1}); + + ASSERT_EQ(begin++, iterable.begin()); + ASSERT_EQ(begin.base(), pool.rbegin() + 1); + ASSERT_EQ(++begin, iterable.end()); + ASSERT_EQ(begin.base(), pool.rbegin() + 2); + + for(auto [entity]: iterable) { + testing::StaticAssertTypeEq(); + ASSERT_TRUE(entity != entt::entity{3}); + } +} + +TEST(StorageEntity, ReverseConstIterable) { + using iterator = typename entt::storage::const_reverse_iterable::iterator; + + testing::StaticAssertTypeEq>(); + testing::StaticAssertTypeEq>>(); + testing::StaticAssertTypeEq(); + + entt::storage pool; + + pool.emplace(entt::entity{1}); + pool.emplace(entt::entity{3}); + pool.emplace(entt::entity{42}); + + pool.erase(entt::entity{3}); + + auto iterable = std::as_const(pool).reach(); + + iterator end{iterable.cbegin()}; + iterator begin{}; + begin = iterable.cend(); + std::swap(begin, end); + + ASSERT_EQ(begin, iterable.cbegin()); + ASSERT_EQ(end, iterable.cend()); + ASSERT_NE(begin, end); + + ASSERT_EQ(begin.base(), pool.rbegin()); + ASSERT_EQ(end.base(), pool.rbegin() + pool.in_use()); + ASSERT_NE(end.base(), pool.rend()); + + ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{1}); + ASSERT_EQ(std::get<0>(*begin), entt::entity{1}); + + ASSERT_EQ(begin++, iterable.begin()); + ASSERT_EQ(begin.base(), pool.rbegin() + 1); + ASSERT_EQ(++begin, iterable.end()); + ASSERT_EQ(begin.base(), pool.rbegin() + 2); + + for(auto [entity]: iterable) { + testing::StaticAssertTypeEq(); + ASSERT_TRUE(entity != entt::entity{3}); + } +} + +TEST(StorageEntity, ReverseIterableIteratorConversion) { + entt::storage pool; + pool.emplace(entt::entity{3}); + + typename entt::storage::reverse_iterable::iterator it = pool.reach().begin(); + typename entt::storage::const_reverse_iterable::iterator cit = it; + + testing::StaticAssertTypeEq>(); + testing::StaticAssertTypeEq>(); + + ASSERT_EQ(it, cit); + ASSERT_NE(++cit, it); +} + +TEST(StorageEntity, ReverseIterableAlgorithmCompatibility) { + entt::storage pool; + pool.emplace(entt::entity{3}); + + const auto iterable = pool.reach(); + const auto it = std::find_if(iterable.begin(), iterable.end(), [](auto args) { return std::get<0>(args) == entt::entity{3}; }); + + ASSERT_EQ(std::get<0>(*it), entt::entity{3}); +}