Files
entt/test/entt/entity/storage.cpp

688 lines
22 KiB
C++

#include <memory>
#include <utility>
#include <iterator>
#include <exception>
#include <type_traits>
#include <unordered_set>
#include <gtest/gtest.h>
#include <entt/entity/storage.hpp>
#include <entt/entity/fwd.hpp>
struct empty_type {};
struct boxed_int { int value; };
bool operator==(const boxed_int &lhs, const boxed_int &rhs) {
return lhs.value == rhs.value;
}
struct throwing_component {
struct constructor_exception: std::exception {};
[[noreturn]] throwing_component() { throw constructor_exception{}; }
// necessary to disable the empty type optimization
int data;
};
struct update_from_destructor {
~update_from_destructor() {
if(target != entt::null) {
storage->remove(target);
}
}
entt::storage<update_from_destructor> *storage{};
entt::entity target{entt::null};
};
TEST(Storage, Functionalities) {
entt::storage<int> pool;
pool.reserve(42);
ASSERT_EQ(pool.capacity(), 42u);
ASSERT_TRUE(pool.empty());
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(std::as_const(pool).begin(), std::as_const(pool).end());
ASSERT_EQ(pool.begin(), pool.end());
ASSERT_FALSE(pool.contains(entt::entity{0}));
ASSERT_FALSE(pool.contains(entt::entity{41}));
pool.emplace(entt::entity{41}, 3);
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 1u);
ASSERT_NE(std::as_const(pool).begin(), std::as_const(pool).end());
ASSERT_NE(pool.begin(), pool.end());
ASSERT_FALSE(pool.contains(entt::entity{0}));
ASSERT_TRUE(pool.contains(entt::entity{41}));
ASSERT_EQ(pool.get(entt::entity{41}), 3);
pool.remove(entt::entity{41});
ASSERT_TRUE(pool.empty());
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(std::as_const(pool).begin(), std::as_const(pool).end());
ASSERT_EQ(pool.begin(), pool.end());
ASSERT_FALSE(pool.contains(entt::entity{0}));
ASSERT_FALSE(pool.contains(entt::entity{41}));
pool.emplace(entt::entity{41}, 12);
ASSERT_EQ(pool.get(entt::entity{41}), 12);
pool.clear();
ASSERT_TRUE(pool.empty());
ASSERT_EQ(pool.size(), 0u);
ASSERT_EQ(std::as_const(pool).begin(), std::as_const(pool).end());
ASSERT_EQ(pool.begin(), pool.end());
ASSERT_FALSE(pool.contains(entt::entity{0}));
ASSERT_FALSE(pool.contains(entt::entity{41}));
ASSERT_EQ(pool.capacity(), 42u);
pool.shrink_to_fit();
ASSERT_EQ(pool.capacity(), 0u);
(void)entt::storage<int>{std::move(pool)};
entt::storage<int> other;
other = std::move(pool);
}
TEST(Storage, EmptyType) {
entt::storage<empty_type> pool;
pool.emplace(entt::entity{99});
ASSERT_TRUE(pool.contains(entt::entity{99}));
}
TEST(Storage, Insert) {
entt::storage<int> pool;
entt::entity entities[2];
entities[0] = entt::entity{3};
entities[1] = entt::entity{42};
pool.insert(std::begin(entities), std::end(entities), {});
ASSERT_TRUE(pool.contains(entities[0]));
ASSERT_TRUE(pool.contains(entities[1]));
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
ASSERT_EQ(pool.get(entities[0]), 0);
ASSERT_EQ(pool.get(entities[1]), 0);
}
TEST(Storage, InsertEmptyType) {
entt::storage<empty_type> pool;
entt::entity entities[2];
entities[0] = entt::entity{3};
entities[1] = entt::entity{42};
pool.insert(std::begin(entities), std::end(entities));
ASSERT_TRUE(pool.contains(entities[0]));
ASSERT_TRUE(pool.contains(entities[1]));
ASSERT_FALSE(pool.empty());
ASSERT_EQ(pool.size(), 2u);
}
TEST(Storage, Remove) {
entt::storage<int> pool;
entt::sparse_set &base = pool;
pool.emplace(entt::entity{3});
pool.emplace(entt::entity{42});
base.remove(base.begin(), base.end());
ASSERT_TRUE(pool.empty());
pool.emplace(entt::entity{3}, 3);
pool.emplace(entt::entity{42}, 42);
pool.emplace(entt::entity{9}, 9);
base.remove(base.rbegin(), base.rbegin() + 2u);
ASSERT_FALSE(pool.empty());
ASSERT_EQ(*pool.begin(), 9);
pool.clear();
pool.emplace(entt::entity{3}, 3);
pool.emplace(entt::entity{42}, 42);
pool.emplace(entt::entity{9}, 9);
entt::entity entities[2]{entt::entity{3}, entt::entity{9}};
base.remove(std::begin(entities), std::end(entities));
ASSERT_FALSE(pool.empty());
ASSERT_EQ(*pool.begin(), 42);
}
TEST(Storage, AggregatesMustWork) {
struct aggregate_type { int value; };
// the goal of this test is to enforce the requirements for aggregate types
entt::storage<aggregate_type>{}.emplace(entt::entity{0}, 42);
}
TEST(Storage, TypesFromStandardTemplateLibraryMustWork) {
// see #37 - this test shouldn't crash, that's all
entt::storage<std::unordered_set<int>> pool;
pool.emplace(entt::entity{0}).insert(42);
pool.remove(entt::entity{0});
}
TEST(Storage, Iterator) {
using iterator = typename entt::storage<boxed_int>::iterator;
entt::storage<boxed_int> pool;
pool.emplace(entt::entity{3}, 42);
iterator end{pool.begin()};
iterator begin{};
begin = pool.end();
std::swap(begin, end);
ASSERT_EQ(begin, pool.begin());
ASSERT_EQ(end, pool.end());
ASSERT_NE(begin, end);
ASSERT_EQ(begin++, pool.begin());
ASSERT_EQ(begin--, pool.end());
ASSERT_EQ(begin+1, pool.end());
ASSERT_EQ(end-1, pool.begin());
ASSERT_EQ(++begin, pool.end());
ASSERT_EQ(--begin, pool.begin());
ASSERT_EQ(begin += 1, pool.end());
ASSERT_EQ(begin -= 1, pool.begin());
ASSERT_EQ(begin + (end - begin), pool.end());
ASSERT_EQ(begin - (begin - end), pool.end());
ASSERT_EQ(end - (end - begin), pool.begin());
ASSERT_EQ(end + (begin - end), pool.begin());
ASSERT_EQ(begin[0].value, pool.begin()->value);
ASSERT_LT(begin, end);
ASSERT_LE(begin, pool.begin());
ASSERT_GT(end, begin);
ASSERT_GE(end, pool.end());
}
TEST(Storage, ConstIterator) {
using iterator = typename entt::storage<boxed_int>::const_iterator;
entt::storage<boxed_int> pool;
pool.emplace(entt::entity{3}, 42);
iterator cend{pool.cbegin()};
iterator cbegin{};
cbegin = pool.cend();
std::swap(cbegin, cend);
ASSERT_EQ(cbegin, pool.cbegin());
ASSERT_EQ(cend, pool.cend());
ASSERT_NE(cbegin, cend);
ASSERT_EQ(cbegin++, pool.cbegin());
ASSERT_EQ(cbegin--, pool.cend());
ASSERT_EQ(cbegin+1, pool.cend());
ASSERT_EQ(cend-1, pool.cbegin());
ASSERT_EQ(++cbegin, pool.cend());
ASSERT_EQ(--cbegin, pool.cbegin());
ASSERT_EQ(cbegin += 1, pool.cend());
ASSERT_EQ(cbegin -= 1, pool.cbegin());
ASSERT_EQ(cbegin + (cend - cbegin), pool.cend());
ASSERT_EQ(cbegin - (cbegin - cend), pool.cend());
ASSERT_EQ(cend - (cend - cbegin), pool.cbegin());
ASSERT_EQ(cend + (cbegin - cend), pool.cbegin());
ASSERT_EQ(cbegin[0].value, pool.cbegin()->value);
ASSERT_LT(cbegin, cend);
ASSERT_LE(cbegin, pool.cbegin());
ASSERT_GT(cend, cbegin);
ASSERT_GE(cend, pool.cend());
}
TEST(Storage, ReverseIterator) {
using reverse_iterator = typename entt::storage<boxed_int>::reverse_iterator;
entt::storage<boxed_int> pool;
pool.emplace(entt::entity{3}, 42);
reverse_iterator end{pool.rbegin()};
reverse_iterator begin{};
begin = pool.rend();
std::swap(begin, end);
ASSERT_EQ(begin, pool.rbegin());
ASSERT_EQ(end, pool.rend());
ASSERT_NE(begin, end);
ASSERT_EQ(begin++, pool.rbegin());
ASSERT_EQ(begin--, pool.rend());
ASSERT_EQ(begin+1, pool.rend());
ASSERT_EQ(end-1, pool.rbegin());
ASSERT_EQ(++begin, pool.rend());
ASSERT_EQ(--begin, pool.rbegin());
ASSERT_EQ(begin += 1, pool.rend());
ASSERT_EQ(begin -= 1, pool.rbegin());
ASSERT_EQ(begin + (end - begin), pool.rend());
ASSERT_EQ(begin - (begin - end), pool.rend());
ASSERT_EQ(end - (end - begin), pool.rbegin());
ASSERT_EQ(end + (begin - end), pool.rbegin());
ASSERT_EQ(begin[0].value, pool.rbegin()->value);
ASSERT_LT(begin, end);
ASSERT_LE(begin, pool.rbegin());
ASSERT_GT(end, begin);
ASSERT_GE(end, pool.rend());
}
TEST(Storage, ConstReverseIterator) {
using const_reverse_iterator = typename entt::storage<boxed_int>::const_reverse_iterator;
entt::storage<boxed_int> pool;
pool.emplace(entt::entity{3}, 42);
const_reverse_iterator cend{pool.crbegin()};
const_reverse_iterator cbegin{};
cbegin = pool.crend();
std::swap(cbegin, cend);
ASSERT_EQ(cbegin, pool.crbegin());
ASSERT_EQ(cend, pool.crend());
ASSERT_NE(cbegin, cend);
ASSERT_EQ(cbegin++, pool.crbegin());
ASSERT_EQ(cbegin--, pool.crend());
ASSERT_EQ(cbegin+1, pool.crend());
ASSERT_EQ(cend-1, pool.crbegin());
ASSERT_EQ(++cbegin, pool.crend());
ASSERT_EQ(--cbegin, pool.crbegin());
ASSERT_EQ(cbegin += 1, pool.crend());
ASSERT_EQ(cbegin -= 1, pool.crbegin());
ASSERT_EQ(cbegin + (cend - cbegin), pool.crend());
ASSERT_EQ(cbegin - (cbegin - cend), pool.crend());
ASSERT_EQ(cend - (cend - cbegin), pool.crbegin());
ASSERT_EQ(cend + (cbegin - cend), pool.crbegin());
ASSERT_EQ(cbegin[0].value, pool.crbegin()->value);
ASSERT_LT(cbegin, cend);
ASSERT_LE(cbegin, pool.crbegin());
ASSERT_GT(cend, cbegin);
ASSERT_GE(cend, pool.crend());
}
TEST(Storage, Raw) {
entt::storage<int> pool;
pool.emplace(entt::entity{3}, 3);
pool.emplace(entt::entity{12}, 6);
pool.emplace(entt::entity{42}, 9);
ASSERT_EQ(pool.get(entt::entity{3}), 3);
ASSERT_EQ(std::as_const(pool).get(entt::entity{12}), 6);
ASSERT_EQ(pool.get(entt::entity{42}), 9);
ASSERT_EQ(pool.raw()[0u], 3);
ASSERT_EQ(std::as_const(pool).raw()[1u], 6);
ASSERT_EQ(pool.raw()[2u], 9);
}
TEST(Storage, SortOrdered) {
entt::storage<boxed_int> pool;
entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
boxed_int values[5u]{{12}, {9}, {6}, {3}, {1}};
pool.insert(std::begin(entities), std::end(entities), std::begin(values), std::end(values));
pool.sort([](auto lhs, auto rhs) { return lhs.value < rhs.value; });
ASSERT_TRUE(std::equal(std::rbegin(entities), std::rend(entities), pool.entt::sparse_set::begin(), pool.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(values), std::rend(values), pool.begin(), pool.end()));
}
TEST(Storage, SortReverse) {
entt::storage<boxed_int> pool;
entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
boxed_int values[5u]{{1}, {3}, {6}, {9}, {12}};
pool.insert(std::begin(entities), std::end(entities), std::begin(values), std::end(values));
pool.sort([](auto lhs, auto rhs) { return lhs.value < rhs.value; });
ASSERT_TRUE(std::equal(std::begin(entities), std::end(entities), pool.entt::sparse_set::begin(), pool.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::begin(values), std::end(values), pool.begin(), pool.end()));
}
TEST(Storage, SortUnordered) {
entt::storage<boxed_int> pool;
entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
boxed_int values[5u]{{6}, {3}, {1}, {9}, {12}};
pool.insert(std::begin(entities), std::end(entities), std::begin(values), std::end(values));
pool.sort([](auto lhs, auto rhs) { return lhs.value < rhs.value; });
auto begin = pool.begin();
auto end = pool.end();
ASSERT_EQ(*(begin++), boxed_int{1});
ASSERT_EQ(*(begin++), boxed_int{3});
ASSERT_EQ(*(begin++), boxed_int{6});
ASSERT_EQ(*(begin++), boxed_int{9});
ASSERT_EQ(*(begin++), boxed_int{12});
ASSERT_EQ(begin, end);
ASSERT_EQ(pool.data()[0u], entt::entity{9});
ASSERT_EQ(pool.data()[1u], entt::entity{3});
ASSERT_EQ(pool.data()[2u], entt::entity{12});
ASSERT_EQ(pool.data()[3u], entt::entity{42});
ASSERT_EQ(pool.data()[4u], entt::entity{7});
}
TEST(Storage, SortRange) {
entt::storage<boxed_int> pool;
entt::entity entities[5u]{entt::entity{12}, entt::entity{42}, entt::entity{7}, entt::entity{3}, entt::entity{9}};
boxed_int values[5u]{{3}, {6}, {1}, {9}, {12}};
pool.insert(std::begin(entities), std::end(entities), std::begin(values), std::end(values));
pool.sort_n(0u, [](auto lhs, auto rhs) { return lhs.value < rhs.value; });
ASSERT_TRUE(std::equal(std::rbegin(entities), std::rend(entities), pool.entt::sparse_set::begin(), pool.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(values), std::rend(values), pool.begin(), pool.end()));
pool.sort_n(2u, [](auto lhs, auto rhs) { return lhs.value < rhs.value; });
ASSERT_EQ(pool.raw()[0u], boxed_int{6});
ASSERT_EQ(pool.raw()[1u], boxed_int{3});
ASSERT_EQ(pool.raw()[2u], boxed_int{1});
ASSERT_EQ(pool.data()[0u], entt::entity{42});
ASSERT_EQ(pool.data()[1u], entt::entity{12});
ASSERT_EQ(pool.data()[2u], entt::entity{7});
pool.sort_n(5u, [](auto lhs, auto rhs) { return lhs.value < rhs.value; });
auto begin = pool.begin();
auto end = pool.end();
ASSERT_EQ(*(begin++), boxed_int{1});
ASSERT_EQ(*(begin++), boxed_int{3});
ASSERT_EQ(*(begin++), boxed_int{6});
ASSERT_EQ(*(begin++), boxed_int{9});
ASSERT_EQ(*(begin++), boxed_int{12});
ASSERT_EQ(begin, end);
ASSERT_EQ(pool.data()[0u], entt::entity{9});
ASSERT_EQ(pool.data()[1u], entt::entity{3});
ASSERT_EQ(pool.data()[2u], entt::entity{42});
ASSERT_EQ(pool.data()[3u], entt::entity{12});
ASSERT_EQ(pool.data()[4u], entt::entity{7});
}
TEST(Storage, RespectDisjoint) {
entt::storage<int> lhs;
entt::storage<int> rhs;
entt::entity lhs_entities[3u]{entt::entity{3}, entt::entity{12}, entt::entity{42}};
int lhs_values[3u]{3, 6, 9};
lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), std::begin(lhs_values), std::end(lhs_values));
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
lhs.respect(rhs);
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
}
TEST(Storage, RespectOverlap) {
entt::storage<int> lhs;
entt::storage<int> rhs;
entt::entity lhs_entities[3u]{entt::entity{3}, entt::entity{12}, entt::entity{42}};
int lhs_values[3u]{3, 6, 9};
lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), std::begin(lhs_values), std::end(lhs_values));
entt::entity rhs_entities[1u]{entt::entity{12}};
int rhs_values[1u]{6};
rhs.insert(std::begin(rhs_entities), std::end(rhs_entities), std::begin(rhs_values), std::end(rhs_values));
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
lhs.respect(rhs);
auto begin = lhs.begin();
auto end = lhs.end();
ASSERT_EQ(*(begin++), 6);
ASSERT_EQ(*(begin++), 9);
ASSERT_EQ(*(begin++), 3);
ASSERT_EQ(begin, end);
ASSERT_EQ(lhs.data()[0u], entt::entity{3});
ASSERT_EQ(lhs.data()[1u], entt::entity{42});
ASSERT_EQ(lhs.data()[2u], entt::entity{12});
}
TEST(Storage, RespectOrdered) {
entt::storage<int> lhs;
entt::storage<int> rhs;
entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
int lhs_values[5u]{1, 2, 3, 4, 5};
lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), std::begin(lhs_values), std::end(lhs_values));
entt::entity rhs_entities[6u]{entt::entity{6}, entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
int rhs_values[6u]{6, 1, 2, 3, 4, 5};
rhs.insert(std::begin(rhs_entities), std::end(rhs_entities), std::begin(rhs_values), std::end(rhs_values));
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
rhs.respect(lhs);
ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
}
TEST(Storage, RespectReverse) {
entt::storage<int> lhs;
entt::storage<int> rhs;
entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
int lhs_values[5u]{1, 2, 3, 4, 5};
lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), std::begin(lhs_values), std::end(lhs_values));
entt::entity rhs_entities[6u]{entt::entity{5}, entt::entity{4}, entt::entity{3}, entt::entity{2}, entt::entity{1}, entt::entity{6}};
int rhs_values[6u]{5, 4, 3, 2, 1, 6};
rhs.insert(std::begin(rhs_entities), std::end(rhs_entities), std::begin(rhs_values), std::end(rhs_values));
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
rhs.respect(lhs);
auto begin = rhs.begin();
auto end = rhs.end();
ASSERT_EQ(*(begin++), 5);
ASSERT_EQ(*(begin++), 4);
ASSERT_EQ(*(begin++), 3);
ASSERT_EQ(*(begin++), 2);
ASSERT_EQ(*(begin++), 1);
ASSERT_EQ(*(begin++), 6);
ASSERT_EQ(begin, end);
ASSERT_EQ(rhs.data()[0u], entt::entity{6});
ASSERT_EQ(rhs.data()[1u], entt::entity{1});
ASSERT_EQ(rhs.data()[2u], entt::entity{2});
ASSERT_EQ(rhs.data()[3u], entt::entity{3});
ASSERT_EQ(rhs.data()[4u], entt::entity{4});
ASSERT_EQ(rhs.data()[5u], entt::entity{5});
}
TEST(Storage, RespectUnordered) {
entt::storage<int> lhs;
entt::storage<int> rhs;
entt::entity lhs_entities[5u]{entt::entity{1}, entt::entity{2}, entt::entity{3}, entt::entity{4}, entt::entity{5}};
int lhs_values[5u]{1, 2, 3, 4, 5};
lhs.insert(std::begin(lhs_entities), std::end(lhs_entities), std::begin(lhs_values), std::end(lhs_values));
entt::entity rhs_entities[6u]{entt::entity{3}, entt::entity{2}, entt::entity{6}, entt::entity{1}, entt::entity{4}, entt::entity{5}};
int rhs_values[6u]{3, 2, 6, 1, 4, 5};
rhs.insert(std::begin(rhs_entities), std::end(rhs_entities), std::begin(rhs_values), std::end(rhs_values));
ASSERT_TRUE(std::equal(std::rbegin(lhs_entities), std::rend(lhs_entities), lhs.entt::sparse_set::begin(), lhs.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(lhs_values), std::rend(lhs_values), lhs.begin(), lhs.end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_entities), std::rend(rhs_entities), rhs.entt::sparse_set::begin(), rhs.entt::sparse_set::end()));
ASSERT_TRUE(std::equal(std::rbegin(rhs_values), std::rend(rhs_values), rhs.begin(), rhs.end()));
rhs.respect(lhs);
auto begin = rhs.begin();
auto end = rhs.end();
ASSERT_EQ(*(begin++), 5);
ASSERT_EQ(*(begin++), 4);
ASSERT_EQ(*(begin++), 3);
ASSERT_EQ(*(begin++), 2);
ASSERT_EQ(*(begin++), 1);
ASSERT_EQ(*(begin++), 6);
ASSERT_EQ(begin, end);
ASSERT_EQ(rhs.data()[0u], entt::entity{6});
ASSERT_EQ(rhs.data()[1u], entt::entity{1});
ASSERT_EQ(rhs.data()[2u], entt::entity{2});
ASSERT_EQ(rhs.data()[3u], entt::entity{3});
ASSERT_EQ(rhs.data()[4u], entt::entity{4});
ASSERT_EQ(rhs.data()[5u], entt::entity{5});
}
TEST(Storage, CanModifyDuringIteration) {
entt::storage<int> pool;
pool.emplace(entt::entity{0}, 42);
ASSERT_EQ(pool.capacity(), 1u);
const auto it = pool.cbegin();
pool.reserve(2u);
ASSERT_EQ(pool.capacity(), 2u);
// this should crash with asan enabled if we break the constraint
const auto entity = *it;
(void)entity;
}
TEST(Storage, ReferencesGuaranteed) {
entt::storage<boxed_int> pool;
pool.emplace(entt::entity{0}, 0);
pool.emplace(entt::entity{1}, 1);
ASSERT_EQ(pool.get(entt::entity{0}).value, 0);
ASSERT_EQ(pool.get(entt::entity{1}).value, 1);
for(auto &&type: pool) {
if(type.value) {
type.value = 42;
}
}
ASSERT_EQ(pool.get(entt::entity{0}).value, 0);
ASSERT_EQ(pool.get(entt::entity{1}).value, 42);
auto begin = pool.begin();
while(begin != pool.end()) {
(begin++)->value = 3;
}
ASSERT_EQ(pool.get(entt::entity{0}).value, 3);
ASSERT_EQ(pool.get(entt::entity{1}).value, 3);
}
TEST(Storage, MoveOnlyComponent) {
// the purpose is to ensure that move only components are always accepted
entt::storage<std::unique_ptr<int>> pool;
(void)pool;
}
TEST(Storage, ConstructorExceptionDoesNotAddToStorage) {
entt::storage<throwing_component> pool;
try {
pool.emplace(entt::entity{0});
} catch (const throwing_component::constructor_exception &) {
ASSERT_TRUE(pool.empty());
}
ASSERT_TRUE(pool.empty());
}
TEST(Storage, UpdateFromDestructor) {
static constexpr auto size = 10u;
auto test = [](const auto target) {
entt::storage<update_from_destructor> pool;
for(std::size_t next{}; next < size; ++next) {
pool.emplace(entt::entity(next), &pool);
}
for(std::size_t next{}; next < size; ++next) {
ASSERT_EQ(pool.get(entt::entity(next)).target, entt::entity{entt::null});
}
pool.get(entt::entity(size/2)).target = target;
pool.remove(entt::entity(size/2));
ASSERT_EQ(pool.size(), size - 1u - (target != entt::null));
};
test(entt::null);
test(entt::entity(size - 1u));
test(entt::entity{0u});
}