Squashed 'external/entt/entt/' content from commit fef92113
git-subtree-dir: external/entt/entt git-subtree-split: fef921132cae7588213d0f9bcd2fb9c8ffd8b7fc
This commit is contained in:
79
test/entt/entity/component.cpp
Normal file
79
test/entt/entity/component.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/config/config.h>
|
||||
#include <entt/entity/component.hpp>
|
||||
|
||||
struct empty {};
|
||||
|
||||
struct non_empty {
|
||||
int value;
|
||||
};
|
||||
|
||||
struct non_movable {
|
||||
non_movable() = default;
|
||||
non_movable(const non_movable &) = delete;
|
||||
non_movable &operator=(const non_movable &) = delete;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct self_contained {
|
||||
static constexpr auto in_place_delete = true;
|
||||
static constexpr auto page_size = 4u;
|
||||
};
|
||||
|
||||
struct traits_based {};
|
||||
|
||||
template<>
|
||||
struct entt::component_traits<traits_based> {
|
||||
using type = traits_based;
|
||||
static constexpr auto in_place_delete = false;
|
||||
static constexpr auto page_size = 8u;
|
||||
};
|
||||
|
||||
TEST(Component, VoidType) {
|
||||
using traits = entt::component_traits<void>;
|
||||
|
||||
static_assert(traits::in_place_delete);
|
||||
static_assert(entt::ignore_as_empty_v<typename traits::type>);
|
||||
// we don't really care about this thanks to ignore_as_empty_v
|
||||
static_assert(traits::page_size != 0u);
|
||||
}
|
||||
|
||||
TEST(Component, Empty) {
|
||||
using traits = entt::component_traits<empty>;
|
||||
|
||||
static_assert(!traits::in_place_delete);
|
||||
static_assert(entt::ignore_as_empty_v<typename traits::type>);
|
||||
static_assert(traits::page_size == 0u);
|
||||
}
|
||||
|
||||
TEST(Component, NonEmpty) {
|
||||
using traits = entt::component_traits<non_empty>;
|
||||
|
||||
static_assert(!traits::in_place_delete);
|
||||
static_assert(!entt::ignore_as_empty_v<typename traits::type>);
|
||||
static_assert(traits::page_size == ENTT_PACKED_PAGE);
|
||||
}
|
||||
|
||||
TEST(Component, NonMovable) {
|
||||
using traits = entt::component_traits<non_movable>;
|
||||
|
||||
static_assert(traits::in_place_delete);
|
||||
static_assert(!entt::ignore_as_empty_v<typename traits::type>);
|
||||
static_assert(traits::page_size == ENTT_PACKED_PAGE);
|
||||
}
|
||||
|
||||
TEST(Component, SelfContained) {
|
||||
using traits = entt::component_traits<self_contained>;
|
||||
|
||||
static_assert(traits::in_place_delete);
|
||||
static_assert(!entt::ignore_as_empty_v<typename traits::type>);
|
||||
static_assert(traits::page_size == 4u);
|
||||
}
|
||||
|
||||
TEST(Component, TraitsBased) {
|
||||
using traits = entt::component_traits<traits_based>;
|
||||
|
||||
static_assert(!traits::in_place_delete);
|
||||
static_assert(!entt::ignore_as_empty_v<typename traits::type>);
|
||||
static_assert(traits::page_size == 8u);
|
||||
}
|
92
test/entt/entity/entity.cpp
Normal file
92
test/entt/entity/entity.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
TEST(Entity, Traits) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
constexpr entt::entity tombstone = entt::tombstone;
|
||||
constexpr entt::entity null = entt::null;
|
||||
entt::registry registry{};
|
||||
|
||||
registry.destroy(registry.create());
|
||||
const auto entity = registry.create();
|
||||
const auto other = registry.create();
|
||||
|
||||
ASSERT_EQ(entt::to_integral(entity), entt::to_integral(entity));
|
||||
ASSERT_NE(entt::to_integral(entity), entt::to_integral<entt::entity>(entt::null));
|
||||
ASSERT_NE(entt::to_integral(entity), entt::to_integral(entt::entity{}));
|
||||
|
||||
ASSERT_EQ(entt::to_entity(entity), 0u);
|
||||
ASSERT_EQ(entt::to_version(entity), 1u);
|
||||
ASSERT_EQ(entt::to_entity(other), 1u);
|
||||
ASSERT_EQ(entt::to_version(other), 0u);
|
||||
|
||||
ASSERT_EQ(traits_type::construct(entt::to_entity(entity), entt::to_version(entity)), entity);
|
||||
ASSERT_EQ(traits_type::construct(entt::to_entity(other), entt::to_version(other)), other);
|
||||
ASSERT_NE(traits_type::construct(entt::to_entity(entity), {}), entity);
|
||||
|
||||
ASSERT_EQ(traits_type::construct(entt::to_entity(other), entt::to_version(entity)), traits_type::combine(entt::to_integral(other), entt::to_integral(entity)));
|
||||
|
||||
ASSERT_EQ(traits_type::combine(entt::tombstone, entt::null), tombstone);
|
||||
ASSERT_EQ(traits_type::combine(entt::null, entt::tombstone), null);
|
||||
}
|
||||
|
||||
TEST(Entity, Null) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
constexpr entt::entity null = entt::null;
|
||||
|
||||
ASSERT_FALSE(entt::entity{} == entt::null);
|
||||
ASSERT_TRUE(entt::null == entt::null);
|
||||
ASSERT_FALSE(entt::null != entt::null);
|
||||
|
||||
entt::registry registry{};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_EQ(traits_type::combine(entt::null, entt::to_integral(entity)), (traits_type::construct(entt::to_entity(null), entt::to_version(entity))));
|
||||
ASSERT_EQ(traits_type::combine(entt::null, entt::to_integral(null)), null);
|
||||
ASSERT_EQ(traits_type::combine(entt::null, entt::tombstone), null);
|
||||
|
||||
registry.emplace<int>(entity, 42);
|
||||
|
||||
ASSERT_FALSE(entity == entt::null);
|
||||
ASSERT_FALSE(entt::null == entity);
|
||||
|
||||
ASSERT_TRUE(entity != entt::null);
|
||||
ASSERT_TRUE(entt::null != entity);
|
||||
|
||||
const entt::entity other = entt::null;
|
||||
|
||||
ASSERT_FALSE(registry.valid(other));
|
||||
ASSERT_NE(registry.create(other), other);
|
||||
}
|
||||
|
||||
TEST(Entity, Tombstone) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
constexpr entt::entity tombstone = entt::tombstone;
|
||||
|
||||
ASSERT_FALSE(entt::entity{} == entt::tombstone);
|
||||
ASSERT_TRUE(entt::tombstone == entt::tombstone);
|
||||
ASSERT_FALSE(entt::tombstone != entt::tombstone);
|
||||
|
||||
entt::registry registry{};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_EQ(traits_type::combine(entt::to_integral(entity), entt::tombstone), (traits_type::construct(entt::to_entity(entity), entt::to_version(tombstone))));
|
||||
ASSERT_EQ(traits_type::combine(entt::tombstone, entt::to_integral(tombstone)), tombstone);
|
||||
ASSERT_EQ(traits_type::combine(entt::tombstone, entt::null), tombstone);
|
||||
|
||||
registry.emplace<int>(entity, 42);
|
||||
|
||||
ASSERT_FALSE(entity == entt::tombstone);
|
||||
ASSERT_FALSE(entt::tombstone == entity);
|
||||
|
||||
ASSERT_TRUE(entity != entt::tombstone);
|
||||
ASSERT_TRUE(entt::tombstone != entity);
|
||||
|
||||
constexpr auto vers = entt::to_version(tombstone);
|
||||
const auto other = traits_type::construct(entt::to_entity(entity), vers);
|
||||
|
||||
ASSERT_FALSE(registry.valid(entt::tombstone));
|
||||
ASSERT_NE(registry.destroy(entity, vers), vers);
|
||||
ASSERT_NE(registry.create(other), other);
|
||||
}
|
1468
test/entt/entity/group.cpp
Normal file
1468
test/entt/entity/group.cpp
Normal file
File diff suppressed because it is too large
Load Diff
295
test/entt/entity/handle.cpp
Normal file
295
test/entt/entity/handle.cpp
Normal file
@ -0,0 +1,295 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/handle.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
TEST(BasicHandle, Assumptions) {
|
||||
static_assert(std::is_trivially_copyable_v<entt::handle>);
|
||||
static_assert(std::is_trivially_assignable_v<entt::handle, entt::handle>);
|
||||
static_assert(std::is_trivially_destructible_v<entt::handle>);
|
||||
|
||||
static_assert(std::is_trivially_copyable_v<entt::const_handle>);
|
||||
static_assert(std::is_trivially_assignable_v<entt::const_handle, entt::const_handle>);
|
||||
static_assert(std::is_trivially_destructible_v<entt::const_handle>);
|
||||
}
|
||||
|
||||
TEST(BasicHandle, DeductionGuide) {
|
||||
static_assert(std::is_same_v<decltype(entt::basic_handle{std::declval<entt::registry &>(), {}}), entt::basic_handle<entt::registry>>);
|
||||
static_assert(std::is_same_v<decltype(entt::basic_handle{std::declval<const entt::registry &>(), {}}), entt::basic_handle<const entt::registry>>);
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Construction) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
entt::handle handle{registry, entity};
|
||||
entt::const_handle chandle{std::as_const(registry), entity};
|
||||
|
||||
ASSERT_FALSE(entt::null == handle.entity());
|
||||
ASSERT_EQ(entity, handle);
|
||||
ASSERT_TRUE(handle);
|
||||
|
||||
ASSERT_FALSE(entt::null == chandle.entity());
|
||||
ASSERT_EQ(entity, chandle);
|
||||
ASSERT_TRUE(chandle);
|
||||
|
||||
ASSERT_EQ(handle, chandle);
|
||||
|
||||
static_assert(std::is_same_v<entt::registry *, decltype(handle.registry())>);
|
||||
static_assert(std::is_same_v<const entt::registry *, decltype(chandle.registry())>);
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Invalidation) {
|
||||
entt::handle handle;
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_EQ(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entt::entity{entt::null});
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
handle = {registry, entity};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_NE(handle.entity(), entt::entity{entt::null});
|
||||
|
||||
handle = {};
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_EQ(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entt::entity{entt::null});
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Destruction) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_TRUE(handle.valid());
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
|
||||
handle.destroy(traits_type::to_version(entity));
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_FALSE(handle.valid());
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
ASSERT_EQ(registry.current(entity), typename entt::registry::version_type{});
|
||||
|
||||
handle = entt::handle{registry, registry.create()};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_TRUE(handle.valid());
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
|
||||
handle.destroy();
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_FALSE(handle.valid());
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
ASSERT_NE(registry.current(entity), typename entt::registry::version_type{});
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Comparison) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
entt::handle handle{registry, entity};
|
||||
entt::const_handle chandle = handle;
|
||||
|
||||
ASSERT_NE(handle, entt::handle{});
|
||||
ASSERT_FALSE(handle == entt::handle{});
|
||||
ASSERT_TRUE(handle != entt::handle{});
|
||||
|
||||
ASSERT_NE(chandle, entt::const_handle{});
|
||||
ASSERT_FALSE(chandle == entt::const_handle{});
|
||||
ASSERT_TRUE(chandle != entt::const_handle{});
|
||||
|
||||
ASSERT_EQ(handle, chandle);
|
||||
ASSERT_TRUE(handle == chandle);
|
||||
ASSERT_FALSE(handle != chandle);
|
||||
|
||||
ASSERT_EQ(entt::handle{}, entt::const_handle{});
|
||||
ASSERT_TRUE(entt::handle{} == entt::const_handle{});
|
||||
ASSERT_FALSE(entt::handle{} != entt::const_handle{});
|
||||
|
||||
handle = {};
|
||||
chandle = {};
|
||||
|
||||
ASSERT_EQ(handle, entt::handle{});
|
||||
ASSERT_TRUE(handle == entt::handle{});
|
||||
ASSERT_FALSE(handle != entt::handle{});
|
||||
|
||||
ASSERT_EQ(chandle, entt::const_handle{});
|
||||
ASSERT_TRUE(chandle == entt::const_handle{});
|
||||
ASSERT_FALSE(chandle != entt::const_handle{});
|
||||
|
||||
entt::registry other;
|
||||
const auto entt = other.create();
|
||||
|
||||
handle = {registry, entity};
|
||||
chandle = {other, entt};
|
||||
|
||||
ASSERT_NE(handle, chandle);
|
||||
ASSERT_FALSE(chandle == handle);
|
||||
ASSERT_TRUE(chandle != handle);
|
||||
ASSERT_EQ(handle.entity(), chandle.entity());
|
||||
ASSERT_NE(handle.registry(), chandle.registry());
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Component) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
entt::handle_view<int, char, double> handle{registry, entity};
|
||||
|
||||
ASSERT_EQ(3, handle.emplace<int>(3));
|
||||
ASSERT_EQ('c', handle.emplace_or_replace<char>('c'));
|
||||
ASSERT_EQ(.3, handle.emplace_or_replace<double>(.3));
|
||||
|
||||
const auto &patched = handle.patch<int>([](auto &comp) { comp = 42; });
|
||||
|
||||
ASSERT_EQ(42, patched);
|
||||
ASSERT_EQ('a', handle.replace<char>('a'));
|
||||
ASSERT_TRUE((handle.all_of<int, char, double>()));
|
||||
ASSERT_EQ((std::make_tuple(42, 'a', .3)), (handle.get<int, char, double>()));
|
||||
|
||||
handle.erase<char, double>();
|
||||
|
||||
ASSERT_TRUE(registry.storage<char>().empty());
|
||||
ASSERT_TRUE(registry.storage<double>().empty());
|
||||
ASSERT_EQ(0u, (handle.remove<char, double>()));
|
||||
|
||||
for(auto [id, pool]: handle.storage()) {
|
||||
ASSERT_EQ(id, entt::type_id<int>().hash());
|
||||
ASSERT_TRUE(pool.contains(handle.entity()));
|
||||
}
|
||||
|
||||
ASSERT_TRUE((handle.any_of<int, char, double>()));
|
||||
ASSERT_FALSE((handle.all_of<int, char, double>()));
|
||||
ASSERT_FALSE(handle.orphan());
|
||||
|
||||
ASSERT_EQ(1u, (handle.remove<int>()));
|
||||
ASSERT_TRUE(registry.storage<int>().empty());
|
||||
ASSERT_TRUE(handle.orphan());
|
||||
|
||||
ASSERT_EQ(42, handle.get_or_emplace<int>(42));
|
||||
ASSERT_EQ(42, handle.get_or_emplace<int>(1));
|
||||
ASSERT_EQ(42, handle.get<int>());
|
||||
|
||||
ASSERT_EQ(42, *handle.try_get<int>());
|
||||
ASSERT_EQ(nullptr, handle.try_get<char>());
|
||||
ASSERT_EQ(nullptr, std::get<1>(handle.try_get<int, char, double>()));
|
||||
}
|
||||
|
||||
TEST(BasicHandle, FromEntity) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity, 42);
|
||||
registry.emplace<char>(entity, 'c');
|
||||
|
||||
entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_EQ(entity, handle.entity());
|
||||
ASSERT_TRUE((handle.all_of<int, char>()));
|
||||
ASSERT_EQ(handle.get<int>(), 42);
|
||||
ASSERT_EQ(handle.get<char>(), 'c');
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Lifetime) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
auto *handle = new entt::handle{registry, entity};
|
||||
handle->emplace<int>();
|
||||
|
||||
ASSERT_FALSE(registry.storage<int>().empty());
|
||||
ASSERT_FALSE(registry.empty());
|
||||
|
||||
registry.each([handle](const auto e) {
|
||||
ASSERT_EQ(handle->entity(), e);
|
||||
});
|
||||
|
||||
delete handle;
|
||||
|
||||
ASSERT_FALSE(registry.storage<int>().empty());
|
||||
ASSERT_FALSE(registry.empty());
|
||||
}
|
||||
|
||||
TEST(BasicHandle, ImplicitConversions) {
|
||||
entt::registry registry;
|
||||
const entt::handle handle{registry, registry.create()};
|
||||
const entt::const_handle chandle = handle;
|
||||
const entt::handle_view<int, char> vhandle = handle;
|
||||
const entt::const_handle_view<int> cvhandle = vhandle;
|
||||
|
||||
handle.emplace<int>(42);
|
||||
|
||||
ASSERT_EQ(handle.get<int>(), chandle.get<int>());
|
||||
ASSERT_EQ(chandle.get<int>(), vhandle.get<int>());
|
||||
ASSERT_EQ(vhandle.get<int>(), cvhandle.get<int>());
|
||||
ASSERT_EQ(cvhandle.get<int>(), 42);
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Storage) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
entt::handle handle{registry, entity};
|
||||
entt::const_handle chandle{std::as_const(registry), entity};
|
||||
|
||||
static_assert(std::is_same_v<decltype(*handle.storage().begin()), std::pair<entt::id_type, entt::sparse_set &>>);
|
||||
static_assert(std::is_same_v<decltype(*chandle.storage().begin()), std::pair<entt::id_type, const entt::sparse_set &>>);
|
||||
|
||||
ASSERT_EQ(handle.storage().begin(), handle.storage().end());
|
||||
ASSERT_EQ(chandle.storage().begin(), chandle.storage().end());
|
||||
|
||||
registry.storage<double>();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_NE(handle.storage().begin(), handle.storage().end());
|
||||
ASSERT_NE(chandle.storage().begin(), chandle.storage().end());
|
||||
|
||||
ASSERT_EQ(++handle.storage().begin(), handle.storage().end());
|
||||
ASSERT_EQ(++chandle.storage().begin(), chandle.storage().end());
|
||||
|
||||
ASSERT_EQ(handle.storage().begin()->second.type(), entt::type_id<int>());
|
||||
ASSERT_EQ(chandle.storage().begin()->second.type(), entt::type_id<int>());
|
||||
}
|
||||
|
||||
TEST(BasicHandle, HandleStorageIterator) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<double>(entity);
|
||||
|
||||
auto test = [](auto iterable) {
|
||||
auto end{iterable.begin()};
|
||||
decltype(end) begin{};
|
||||
begin = iterable.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, iterable.cbegin());
|
||||
ASSERT_EQ(end, iterable.cend());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
};
|
||||
|
||||
test(entt::handle{registry, entity}.storage());
|
||||
test(entt::const_handle{std::as_const(registry), entity}.storage());
|
||||
}
|
126
test/entt/entity/helper.cpp
Normal file
126
test/entt/entity/helper.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/helper.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
struct clazz {
|
||||
void func(entt::registry &, entt::entity curr) {
|
||||
entt = curr;
|
||||
}
|
||||
|
||||
entt::entity entt{entt::null};
|
||||
};
|
||||
|
||||
struct stable_type {
|
||||
static constexpr auto in_place_delete = true;
|
||||
int value;
|
||||
};
|
||||
|
||||
TEST(Helper, AsView) {
|
||||
entt::registry registry;
|
||||
const entt::registry cregistry;
|
||||
|
||||
([](entt::view<entt::get_t<int>>) {})(entt::as_view{registry});
|
||||
([](entt::view<entt::get_t<char, double>, entt::exclude_t<int>>) {})(entt::as_view{registry});
|
||||
([](entt::view<entt::get_t<const char, double>, entt::exclude_t<const int>>) {})(entt::as_view{registry});
|
||||
([](entt::view<entt::get_t<const char, const double>, entt::exclude_t<const int>>) {})(entt::as_view{cregistry});
|
||||
}
|
||||
|
||||
TEST(Helper, AsGroup) {
|
||||
entt::registry registry;
|
||||
const entt::registry cregistry;
|
||||
|
||||
([](entt::group<entt::owned_t<double>, entt::get_t<char>, entt::exclude_t<int>>) {})(entt::as_group{registry});
|
||||
([](entt::group<entt::owned_t<double>, entt::get_t<const char>, entt::exclude_t<const int>>) {})(entt::as_group{registry});
|
||||
([](entt::group<entt::owned_t<const double>, entt::get_t<const char>, entt::exclude_t<const int>>) {})(entt::as_group{cregistry});
|
||||
}
|
||||
|
||||
TEST(Helper, Invoke) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.on_construct<clazz>().connect<entt::invoke<&clazz::func>>();
|
||||
registry.emplace<clazz>(entity);
|
||||
|
||||
ASSERT_EQ(entity, registry.get<clazz>(entity).entt);
|
||||
}
|
||||
|
||||
TEST(Helper, ToEntity) {
|
||||
entt::registry registry;
|
||||
const entt::entity null = entt::null;
|
||||
constexpr auto page_size = entt::component_traits<int>::page_size;
|
||||
const int value = 42;
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, 42), null);
|
||||
ASSERT_EQ(entt::to_entity(registry, value), null);
|
||||
|
||||
const auto entity = registry.create();
|
||||
auto &&storage = registry.storage<int>();
|
||||
storage.emplace(entity);
|
||||
|
||||
while(storage.size() < (page_size - 1u)) {
|
||||
storage.emplace(registry.create(), value);
|
||||
}
|
||||
|
||||
const auto other = registry.create();
|
||||
const auto next = registry.create();
|
||||
|
||||
registry.emplace<int>(other);
|
||||
registry.emplace<int>(next);
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(entity)), entity);
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(other)), other);
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(next)), next);
|
||||
|
||||
ASSERT_EQ(®istry.get<int>(entity) + page_size - 1u, ®istry.get<int>(other));
|
||||
|
||||
registry.destroy(other);
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(entity)), entity);
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(next)), next);
|
||||
|
||||
ASSERT_EQ(®istry.get<int>(entity) + page_size - 1u, ®istry.get<int>(next));
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, 42), null);
|
||||
ASSERT_EQ(entt::to_entity(registry, value), null);
|
||||
}
|
||||
|
||||
TEST(Helper, ToEntityStableType) {
|
||||
entt::registry registry;
|
||||
const entt::entity null = entt::null;
|
||||
constexpr auto page_size = entt::component_traits<stable_type>::page_size;
|
||||
const stable_type value{42};
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, stable_type{42}), null);
|
||||
ASSERT_EQ(entt::to_entity(registry, value), null);
|
||||
|
||||
const auto entity = registry.create();
|
||||
auto &&storage = registry.storage<stable_type>();
|
||||
registry.emplace<stable_type>(entity);
|
||||
|
||||
while(storage.size() < (page_size - 2u)) {
|
||||
storage.emplace(registry.create(), value);
|
||||
}
|
||||
|
||||
const auto other = registry.create();
|
||||
const auto next = registry.create();
|
||||
|
||||
registry.emplace<stable_type>(other);
|
||||
registry.emplace<stable_type>(next);
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(entity)), entity);
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(other)), other);
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(next)), next);
|
||||
|
||||
ASSERT_EQ(®istry.get<stable_type>(entity) + page_size - 2u, ®istry.get<stable_type>(other));
|
||||
|
||||
registry.destroy(other);
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(entity)), entity);
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(next)), next);
|
||||
|
||||
ASSERT_EQ(®istry.get<stable_type>(entity) + page_size - 1u, ®istry.get<stable_type>(next));
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, stable_type{42}), null);
|
||||
ASSERT_EQ(entt::to_entity(registry, value), null);
|
||||
}
|
371
test/entt/entity/observer.cpp
Normal file
371
test/entt/entity/observer.cpp
Normal file
@ -0,0 +1,371 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/observer.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
TEST(Observer, Functionalities) {
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, entt::collector.group<int>()};
|
||||
|
||||
ASSERT_EQ(observer.size(), 0u);
|
||||
ASSERT_TRUE(observer.empty());
|
||||
ASSERT_EQ(observer.begin(), observer.end());
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
ASSERT_NE(observer.begin(), observer.end());
|
||||
ASSERT_EQ(++observer.begin(), observer.end());
|
||||
ASSERT_EQ(*observer.begin(), entity);
|
||||
|
||||
observer.clear();
|
||||
|
||||
ASSERT_EQ(observer.size(), 0u);
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
observer.disconnect();
|
||||
registry.erase<int>(entity);
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 0u);
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, AllOf) {
|
||||
constexpr auto collector =
|
||||
entt::collector
|
||||
.group<int, char>(entt::exclude<float>)
|
||||
.group<int, double>();
|
||||
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, collector};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
registry.emplace<double>(entity);
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
|
||||
registry.erase<int>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<float>(entity);
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
|
||||
registry.erase<double>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<double>(entity);
|
||||
observer.clear();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
observer.disconnect();
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
registry.emplace_or_replace<char>(entity);
|
||||
registry.erase<float>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, AllOfFiltered) {
|
||||
constexpr auto collector =
|
||||
entt::collector
|
||||
.group<int>()
|
||||
.where<char>(entt::exclude<double>);
|
||||
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, collector};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 0u);
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.erase<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
registry.emplace<double>(entity);
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.erase<int>(entity);
|
||||
registry.erase<double>(entity);
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
registry.emplace<double>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.erase<double>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
observer.disconnect();
|
||||
registry.erase<int>(entity);
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, Observe) {
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, entt::collector.update<int>().update<char>()};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
observer.clear();
|
||||
registry.replace<char>(entity);
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
|
||||
observer.clear();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
observer.disconnect();
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
registry.emplace_or_replace<char>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, ObserveFiltered) {
|
||||
constexpr auto collector =
|
||||
entt::collector
|
||||
.update<int>()
|
||||
.where<char>(entt::exclude<double>);
|
||||
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, collector};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.replace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 0u);
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<char>(entity);
|
||||
registry.emplace<double>(entity);
|
||||
registry.replace<int>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.erase<double>(entity);
|
||||
registry.replace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
registry.emplace<double>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.erase<double>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
observer.disconnect();
|
||||
registry.replace<int>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, AllOfObserve) {
|
||||
entt::registry registry;
|
||||
entt::observer observer{};
|
||||
const auto entity = registry.create();
|
||||
|
||||
observer.connect(registry, entt::collector.group<int>().update<char>());
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
registry.replace<char>(entity);
|
||||
registry.erase<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
registry.erase<char>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.replace<char>(entity);
|
||||
observer.clear();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
observer.disconnect();
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
registry.emplace_or_replace<char>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, CrossRulesCornerCase) {
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, entt::collector.group<int>().group<char>()};
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
observer.clear();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<char>(entity);
|
||||
registry.erase<int>(entity);
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, Each) {
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, entt::collector.group<int>()};
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
|
||||
std::as_const(observer).each([entity](const auto entt) {
|
||||
ASSERT_EQ(entity, entt);
|
||||
});
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
|
||||
observer.each([entity](const auto entt) {
|
||||
ASSERT_EQ(entity, entt);
|
||||
});
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
ASSERT_EQ(observer.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Observer, MultipleFilters) {
|
||||
constexpr auto collector =
|
||||
entt::collector
|
||||
.update<int>()
|
||||
.where<char>()
|
||||
.update<double>()
|
||||
.where<float>();
|
||||
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, collector};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
observer.clear();
|
||||
registry.emplace<double>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace_or_replace<double>(entity);
|
||||
registry.emplace<float>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace_or_replace<double>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
registry.erase<float>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
observer.clear();
|
||||
observer.disconnect();
|
||||
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, GroupCornerCase) {
|
||||
constexpr auto add_collector = entt::collector.group<int>(entt::exclude<char>);
|
||||
constexpr auto remove_collector = entt::collector.group<int, char>();
|
||||
|
||||
entt::registry registry;
|
||||
entt::observer add_observer{registry, add_collector};
|
||||
entt::observer remove_observer{registry, remove_collector};
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_FALSE(add_observer.empty());
|
||||
ASSERT_TRUE(remove_observer.empty());
|
||||
|
||||
add_observer.clear();
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_TRUE(add_observer.empty());
|
||||
ASSERT_FALSE(remove_observer.empty());
|
||||
|
||||
remove_observer.clear();
|
||||
registry.erase<char>(entity);
|
||||
|
||||
ASSERT_FALSE(add_observer.empty());
|
||||
ASSERT_TRUE(remove_observer.empty());
|
||||
}
|
432
test/entt/entity/organizer.cpp
Normal file
432
test/entt/entity/organizer.cpp
Normal file
@ -0,0 +1,432 @@
|
||||
#include <cstddef>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/organizer.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
void ro_int_rw_char_double(entt::view<entt::get_t<const int, char>>, double &) {}
|
||||
void ro_char_rw_int(entt::view<entt::get_t<int, const char>>) {}
|
||||
void ro_char_rw_double(entt::view<entt::get_t<const char>>, double &) {}
|
||||
void ro_int_double(entt::view<entt::get_t<const int>>, const double &) {}
|
||||
void sync_point(entt::registry &, entt::view<entt::get_t<const int>>) {}
|
||||
|
||||
struct clazz {
|
||||
void ro_int_char_double(entt::view<entt::get_t<const int, const char>>, const double &) {}
|
||||
void rw_int(entt::view<entt::get_t<int>>) {}
|
||||
void rw_int_char(entt::view<entt::get_t<int, char>>) {}
|
||||
void rw_int_char_double(entt::view<entt::get_t<int, char>>, double &) {}
|
||||
|
||||
static void ro_int_with_payload(const clazz &, entt::view<entt::get_t<const int>>) {}
|
||||
static void ro_char_with_payload(const clazz &, entt::view<entt::get_t<const char>>) {}
|
||||
static void ro_int_char_with_payload(clazz &, entt::view<entt::get_t<const int, const char>>) {}
|
||||
};
|
||||
|
||||
void to_args_integrity(entt::view<entt::get_t<int>> view, std::size_t &value, entt::registry ®istry) {
|
||||
value = view.size();
|
||||
}
|
||||
|
||||
TEST(Organizer, EmplaceFreeFunction) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
|
||||
organizer.emplace<&ro_int_rw_char_double>("t1");
|
||||
organizer.emplace<&ro_char_rw_int>("t2");
|
||||
organizer.emplace<&ro_char_rw_double>("t3");
|
||||
organizer.emplace<&ro_int_double>("t4");
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_EQ(graph.size(), 4u);
|
||||
|
||||
ASSERT_STREQ(graph[0u].name(), "t1");
|
||||
ASSERT_STREQ(graph[1u].name(), "t2");
|
||||
ASSERT_STREQ(graph[2u].name(), "t3");
|
||||
ASSERT_STREQ(graph[3u].name(), "t4");
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[1u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[2u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[3u].ro_count(), 2u);
|
||||
|
||||
ASSERT_EQ(graph[0u].rw_count(), 2u);
|
||||
ASSERT_EQ(graph[1u].rw_count(), 1u);
|
||||
ASSERT_EQ(graph[2u].rw_count(), 1u);
|
||||
ASSERT_EQ(graph[3u].rw_count(), 0u);
|
||||
|
||||
ASSERT_NE(graph[0u].info(), graph[1u].info());
|
||||
ASSERT_NE(graph[1u].info(), graph[2u].info());
|
||||
ASSERT_NE(graph[2u].info(), graph[3u].info());
|
||||
|
||||
ASSERT_TRUE(graph[0u].top_level());
|
||||
ASSERT_FALSE(graph[1u].top_level());
|
||||
ASSERT_FALSE(graph[2u].top_level());
|
||||
ASSERT_FALSE(graph[3u].top_level());
|
||||
|
||||
ASSERT_EQ(graph[0u].children().size(), 2u);
|
||||
ASSERT_EQ(graph[1u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].children().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].children()[0u], 1u);
|
||||
ASSERT_EQ(graph[0u].children()[1u], 2u);
|
||||
ASSERT_EQ(graph[1u].children()[0u], 3u);
|
||||
ASSERT_EQ(graph[2u].children()[0u], 3u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
ASSERT_NO_FATAL_FAILURE(vertex.callback()(vertex.data(), registry));
|
||||
}
|
||||
|
||||
organizer.clear();
|
||||
|
||||
ASSERT_EQ(organizer.graph().size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Organizer, EmplaceMemberFunction) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
clazz instance;
|
||||
|
||||
organizer.emplace<&clazz::ro_int_char_double>(instance, "t1");
|
||||
organizer.emplace<&clazz::rw_int>(instance, "t2");
|
||||
organizer.emplace<&clazz::rw_int_char>(instance, "t3");
|
||||
organizer.emplace<&clazz::rw_int_char_double>(instance, "t4");
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_EQ(graph.size(), 4u);
|
||||
|
||||
ASSERT_STREQ(graph[0u].name(), "t1");
|
||||
ASSERT_STREQ(graph[1u].name(), "t2");
|
||||
ASSERT_STREQ(graph[2u].name(), "t3");
|
||||
ASSERT_STREQ(graph[3u].name(), "t4");
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_count(), 3u);
|
||||
ASSERT_EQ(graph[1u].ro_count(), 0u);
|
||||
ASSERT_EQ(graph[2u].ro_count(), 0u);
|
||||
ASSERT_EQ(graph[3u].ro_count(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].rw_count(), 0u);
|
||||
ASSERT_EQ(graph[1u].rw_count(), 1u);
|
||||
ASSERT_EQ(graph[2u].rw_count(), 2u);
|
||||
ASSERT_EQ(graph[3u].rw_count(), 3u);
|
||||
|
||||
ASSERT_NE(graph[0u].info(), graph[1u].info());
|
||||
ASSERT_NE(graph[1u].info(), graph[2u].info());
|
||||
ASSERT_NE(graph[2u].info(), graph[3u].info());
|
||||
|
||||
ASSERT_TRUE(graph[0u].top_level());
|
||||
ASSERT_FALSE(graph[1u].top_level());
|
||||
ASSERT_FALSE(graph[2u].top_level());
|
||||
ASSERT_FALSE(graph[3u].top_level());
|
||||
|
||||
ASSERT_EQ(graph[0u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].children().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].children()[0u], 1u);
|
||||
ASSERT_EQ(graph[1u].children()[0u], 2u);
|
||||
ASSERT_EQ(graph[2u].children()[0u], 3u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
ASSERT_NO_FATAL_FAILURE(vertex.callback()(vertex.data(), registry));
|
||||
}
|
||||
|
||||
organizer.clear();
|
||||
|
||||
ASSERT_EQ(organizer.graph().size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Organizer, EmplaceFreeFunctionWithPayload) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
clazz instance;
|
||||
|
||||
organizer.emplace<&clazz::ro_int_char_double>(instance, "t1");
|
||||
organizer.emplace<&clazz::ro_int_with_payload>(instance, "t2");
|
||||
organizer.emplace<&clazz::ro_char_with_payload, const clazz>(instance, "t3");
|
||||
organizer.emplace<&clazz::ro_int_char_with_payload, clazz>(instance, "t4");
|
||||
organizer.emplace<&clazz::rw_int_char>(instance, "t5");
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_EQ(graph.size(), 5u);
|
||||
|
||||
ASSERT_STREQ(graph[0u].name(), "t1");
|
||||
ASSERT_STREQ(graph[1u].name(), "t2");
|
||||
ASSERT_STREQ(graph[2u].name(), "t3");
|
||||
ASSERT_STREQ(graph[3u].name(), "t4");
|
||||
ASSERT_STREQ(graph[4u].name(), "t5");
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_count(), 3u);
|
||||
ASSERT_EQ(graph[1u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[2u].ro_count(), 2u);
|
||||
ASSERT_EQ(graph[3u].ro_count(), 2u);
|
||||
ASSERT_EQ(graph[4u].ro_count(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].rw_count(), 0u);
|
||||
ASSERT_EQ(graph[1u].rw_count(), 0u);
|
||||
ASSERT_EQ(graph[2u].rw_count(), 0u);
|
||||
ASSERT_EQ(graph[3u].rw_count(), 1u);
|
||||
ASSERT_EQ(graph[4u].rw_count(), 2u);
|
||||
|
||||
ASSERT_NE(graph[0u].info(), graph[1u].info());
|
||||
ASSERT_NE(graph[1u].info(), graph[2u].info());
|
||||
ASSERT_NE(graph[2u].info(), graph[3u].info());
|
||||
ASSERT_NE(graph[3u].info(), graph[4u].info());
|
||||
|
||||
ASSERT_TRUE(graph[0u].top_level());
|
||||
ASSERT_TRUE(graph[1u].top_level());
|
||||
ASSERT_TRUE(graph[2u].top_level());
|
||||
ASSERT_FALSE(graph[3u].top_level());
|
||||
ASSERT_FALSE(graph[4u].top_level());
|
||||
|
||||
ASSERT_EQ(graph[0u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[4u].children().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].children()[0u], 4u);
|
||||
ASSERT_EQ(graph[1u].children()[0u], 4u);
|
||||
ASSERT_EQ(graph[2u].children()[0u], 3u);
|
||||
ASSERT_EQ(graph[3u].children()[0u], 4u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
ASSERT_NO_FATAL_FAILURE(vertex.callback()(vertex.data(), registry));
|
||||
}
|
||||
|
||||
organizer.clear();
|
||||
|
||||
ASSERT_EQ(organizer.graph().size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Organizer, EmplaceDirectFunction) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
clazz instance;
|
||||
|
||||
// no aggressive comdat
|
||||
auto t1 = +[](const void *, entt::registry ®) { reg.clear<int>(); };
|
||||
auto t2 = +[](const void *, entt::registry ®) { reg.clear<char>(); };
|
||||
auto t3 = +[](const void *, entt::registry ®) { reg.clear<double>(); };
|
||||
auto t4 = +[](const void *, entt::registry ®) { reg.clear(); };
|
||||
|
||||
organizer.emplace<int>(t1, nullptr, "t1");
|
||||
organizer.emplace<const int>(t2, &instance, "t2");
|
||||
organizer.emplace<const int, char>(t3, nullptr, "t3");
|
||||
organizer.emplace<int, char, double>(t4, &instance, "t4");
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_EQ(graph.size(), 4u);
|
||||
|
||||
ASSERT_STREQ(graph[0u].name(), "t1");
|
||||
ASSERT_STREQ(graph[1u].name(), "t2");
|
||||
ASSERT_STREQ(graph[2u].name(), "t3");
|
||||
ASSERT_STREQ(graph[3u].name(), "t4");
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_count(), 0u);
|
||||
ASSERT_EQ(graph[1u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[2u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[3u].ro_count(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].rw_count(), 1u);
|
||||
ASSERT_EQ(graph[1u].rw_count(), 0u);
|
||||
ASSERT_EQ(graph[2u].rw_count(), 1u);
|
||||
ASSERT_EQ(graph[3u].rw_count(), 3u);
|
||||
|
||||
ASSERT_TRUE(graph[0u].callback() == t1);
|
||||
ASSERT_TRUE(graph[1u].callback() == t2);
|
||||
ASSERT_TRUE(graph[2u].callback() == t3);
|
||||
ASSERT_TRUE(graph[3u].callback() == t4);
|
||||
|
||||
ASSERT_EQ(graph[0u].data(), nullptr);
|
||||
ASSERT_EQ(graph[1u].data(), &instance);
|
||||
ASSERT_EQ(graph[2u].data(), nullptr);
|
||||
ASSERT_EQ(graph[3u].data(), &instance);
|
||||
|
||||
ASSERT_EQ(graph[0u].info(), entt::type_id<void>());
|
||||
ASSERT_EQ(graph[1u].info(), entt::type_id<void>());
|
||||
ASSERT_EQ(graph[2u].info(), entt::type_id<void>());
|
||||
ASSERT_EQ(graph[3u].info(), entt::type_id<void>());
|
||||
|
||||
ASSERT_TRUE(graph[0u].top_level());
|
||||
ASSERT_FALSE(graph[1u].top_level());
|
||||
ASSERT_FALSE(graph[2u].top_level());
|
||||
ASSERT_FALSE(graph[3u].top_level());
|
||||
|
||||
ASSERT_EQ(graph[0u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].children().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].children()[0u], 1u);
|
||||
ASSERT_EQ(graph[1u].children()[0u], 2u);
|
||||
ASSERT_EQ(graph[2u].children()[0u], 3u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
ASSERT_NO_FATAL_FAILURE(vertex.callback()(vertex.data(), registry));
|
||||
}
|
||||
|
||||
organizer.clear();
|
||||
|
||||
ASSERT_EQ(organizer.graph().size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Organizer, SyncPoint) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
clazz instance;
|
||||
|
||||
organizer.emplace<&ro_int_double>("before");
|
||||
organizer.emplace<&sync_point>("sync_1");
|
||||
organizer.emplace<&clazz::ro_int_char_double>(instance, "mid_1");
|
||||
organizer.emplace<&ro_int_double>("mid_2");
|
||||
organizer.emplace<&sync_point>("sync_2");
|
||||
organizer.emplace<&ro_int_double>("after");
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_EQ(graph.size(), 6u);
|
||||
|
||||
ASSERT_STREQ(graph[0u].name(), "before");
|
||||
ASSERT_STREQ(graph[1u].name(), "sync_1");
|
||||
ASSERT_STREQ(graph[2u].name(), "mid_1");
|
||||
ASSERT_STREQ(graph[3u].name(), "mid_2");
|
||||
ASSERT_STREQ(graph[4u].name(), "sync_2");
|
||||
ASSERT_STREQ(graph[5u].name(), "after");
|
||||
|
||||
ASSERT_TRUE(graph[0u].top_level());
|
||||
ASSERT_FALSE(graph[1u].top_level());
|
||||
ASSERT_FALSE(graph[2u].top_level());
|
||||
ASSERT_FALSE(graph[3u].top_level());
|
||||
ASSERT_FALSE(graph[4u].top_level());
|
||||
ASSERT_FALSE(graph[5u].top_level());
|
||||
|
||||
ASSERT_EQ(graph[0u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].children().size(), 2u);
|
||||
ASSERT_EQ(graph[2u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[4u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[5u].children().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].children()[0u], 1u);
|
||||
ASSERT_EQ(graph[1u].children()[0u], 2u);
|
||||
ASSERT_EQ(graph[1u].children()[1u], 3u);
|
||||
ASSERT_EQ(graph[2u].children()[0u], 4u);
|
||||
ASSERT_EQ(graph[3u].children()[0u], 4u);
|
||||
ASSERT_EQ(graph[4u].children()[0u], 5u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
ASSERT_NO_FATAL_FAILURE(vertex.callback()(vertex.data(), registry));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Organizer, Override) {
|
||||
entt::organizer organizer;
|
||||
|
||||
organizer.emplace<&ro_int_rw_char_double, const char, const double>("t1");
|
||||
organizer.emplace<&ro_char_rw_double, const double>("t2");
|
||||
organizer.emplace<&ro_int_double, double>("t3");
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_EQ(graph.size(), 3u);
|
||||
|
||||
ASSERT_STREQ(graph[0u].name(), "t1");
|
||||
ASSERT_STREQ(graph[1u].name(), "t2");
|
||||
ASSERT_STREQ(graph[2u].name(), "t3");
|
||||
|
||||
ASSERT_TRUE(graph[0u].top_level());
|
||||
ASSERT_TRUE(graph[1u].top_level());
|
||||
ASSERT_FALSE(graph[2u].top_level());
|
||||
|
||||
ASSERT_EQ(graph[0u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].children().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].children()[0u], 2u);
|
||||
ASSERT_EQ(graph[1u].children()[0u], 2u);
|
||||
}
|
||||
|
||||
TEST(Organizer, Prepare) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
clazz instance;
|
||||
|
||||
organizer.emplace<&ro_int_double>();
|
||||
organizer.emplace<&clazz::rw_int_char>(instance);
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_FALSE(registry.ctx().contains<int>());
|
||||
ASSERT_FALSE(registry.ctx().contains<char>());
|
||||
ASSERT_FALSE(registry.ctx().contains<double>());
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
vertex.prepare(registry);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(registry.ctx().contains<int>());
|
||||
ASSERT_FALSE(registry.ctx().contains<char>());
|
||||
ASSERT_TRUE(registry.ctx().contains<double>());
|
||||
}
|
||||
|
||||
TEST(Organizer, Dependencies) {
|
||||
entt::organizer organizer;
|
||||
clazz instance;
|
||||
|
||||
organizer.emplace<&ro_int_double>();
|
||||
organizer.emplace<&clazz::rw_int_char>(instance);
|
||||
organizer.emplace<char, const double>(+[](const void *, entt::registry &) {});
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
const entt::type_info *buffer[5u]{};
|
||||
|
||||
ASSERT_EQ(graph.size(), 3u);
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_count(), 2u);
|
||||
ASSERT_EQ(graph[0u].rw_count(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_dependency(buffer, 0u), 0u);
|
||||
ASSERT_EQ(graph[0u].rw_dependency(buffer, 2u), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_dependency(buffer, 5u), 2u);
|
||||
ASSERT_EQ(*buffer[0u], entt::type_id<int>());
|
||||
ASSERT_EQ(*buffer[1u], entt::type_id<double>());
|
||||
|
||||
ASSERT_EQ(graph[1u].ro_count(), 0u);
|
||||
ASSERT_EQ(graph[1u].rw_count(), 2u);
|
||||
|
||||
ASSERT_EQ(graph[1u].ro_dependency(buffer, 2u), 0u);
|
||||
ASSERT_EQ(graph[1u].rw_dependency(buffer, 0u), 0u);
|
||||
|
||||
ASSERT_EQ(graph[1u].rw_dependency(buffer, 5u), 2u);
|
||||
ASSERT_EQ(*buffer[0u], entt::type_id<int>());
|
||||
ASSERT_EQ(*buffer[1u], entt::type_id<char>());
|
||||
|
||||
ASSERT_EQ(graph[2u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[2u].rw_count(), 1u);
|
||||
|
||||
ASSERT_EQ(graph[2u].ro_dependency(buffer, 2u), 1u);
|
||||
ASSERT_EQ(graph[2u].rw_dependency(buffer, 0u), 0u);
|
||||
|
||||
ASSERT_EQ(graph[2u].ro_dependency(buffer, 5u), 1u);
|
||||
ASSERT_EQ(*buffer[0u], entt::type_id<double>());
|
||||
|
||||
ASSERT_EQ(graph[2u].rw_dependency(buffer, 5u), 1u);
|
||||
ASSERT_EQ(*buffer[0u], entt::type_id<char>());
|
||||
}
|
||||
|
||||
TEST(Organizer, ToArgsIntegrity) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
|
||||
organizer.emplace<&to_args_integrity>();
|
||||
registry.ctx().emplace<std::size_t>(42u);
|
||||
|
||||
auto graph = organizer.graph();
|
||||
graph[0u].callback()(graph[0u].data(), registry);
|
||||
|
||||
ASSERT_EQ(registry.ctx().at<std::size_t>(), 0u);
|
||||
}
|
2206
test/entt/entity/registry.cpp
Normal file
2206
test/entt/entity/registry.cpp
Normal file
File diff suppressed because it is too large
Load Diff
409
test/entt/entity/runtime_view.cpp
Normal file
409
test/entt/entity/runtime_view.cpp
Normal file
@ -0,0 +1,409 @@
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/runtime_view.hpp>
|
||||
|
||||
struct stable_type {
|
||||
static constexpr auto in_place_delete = true;
|
||||
int value;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct RuntimeView: testing::Test {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
using RuntimeViewTypes = ::testing::Types<entt::runtime_view, entt::const_runtime_view>;
|
||||
|
||||
TYPED_TEST_SUITE(RuntimeView, RuntimeViewTypes, );
|
||||
|
||||
TYPED_TEST(RuntimeView, Functionalities) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_FALSE(view.contains(e0));
|
||||
ASSERT_FALSE(view.contains(e1));
|
||||
|
||||
// forces the creation of the pools
|
||||
static_cast<void>(registry.storage<int>());
|
||||
static_cast<void>(registry.storage<char>());
|
||||
|
||||
view.iterate(registry.storage<int>()).iterate(registry.storage<char>());
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 0u);
|
||||
|
||||
registry.emplace<char>(e0);
|
||||
registry.emplace<int>(e1);
|
||||
|
||||
ASSERT_NE(view.size_hint(), 0u);
|
||||
|
||||
registry.emplace<char>(e1);
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 1u);
|
||||
|
||||
auto it = view.begin();
|
||||
|
||||
ASSERT_EQ(*it, e1);
|
||||
ASSERT_EQ(++it, (view.end()));
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE((view.begin()++));
|
||||
ASSERT_NO_FATAL_FAILURE((++view.begin()));
|
||||
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_EQ(view.size_hint(), 1u);
|
||||
|
||||
registry.get<char>(e0) = '1';
|
||||
registry.get<char>(e1) = '2';
|
||||
registry.get<int>(e1) = 42;
|
||||
|
||||
for(auto entity: view) {
|
||||
ASSERT_EQ(registry.get<int>(entity), 42);
|
||||
ASSERT_EQ(registry.get<char>(entity), '2');
|
||||
}
|
||||
|
||||
view.clear();
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Constructors) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
view = runtime_view_type{std::allocator<int>{}};
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
|
||||
runtime_view_type temp{view, view.get_allocator()};
|
||||
runtime_view_type other{std::move(temp), view.get_allocator()};
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_FALSE(temp.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Copy) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
|
||||
runtime_view_type other{view};
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
|
||||
other.iterate(registry.storage<int>()).exclude(registry.storage<char>());
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_FALSE(other.contains(entity));
|
||||
|
||||
other = view;
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Move) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
|
||||
runtime_view_type other{std::move(view)};
|
||||
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
|
||||
view = other;
|
||||
other.iterate(registry.storage<int>()).exclude(registry.storage<char>());
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_FALSE(other.contains(entity));
|
||||
|
||||
other = std::move(view);
|
||||
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Swap) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
runtime_view_type other{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 1u);
|
||||
ASSERT_EQ(other.size_hint(), 0u);
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_FALSE(other.contains(entity));
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_EQ(other.begin(), other.end());
|
||||
|
||||
view.swap(other);
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 0u);
|
||||
ASSERT_EQ(other.size_hint(), 1u);
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_NE(other.begin(), other.end());
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Iterator) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
using iterator = typename runtime_view_type::iterator;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
iterator end{view.begin()};
|
||||
iterator begin{};
|
||||
begin = view.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, view.begin());
|
||||
ASSERT_EQ(end, view.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin++, view.begin());
|
||||
ASSERT_EQ(begin--, view.end());
|
||||
|
||||
ASSERT_EQ(++begin, view.end());
|
||||
ASSERT_EQ(--begin, view.begin());
|
||||
|
||||
ASSERT_EQ(*begin, entity);
|
||||
ASSERT_EQ(*begin.operator->(), entity);
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Contains) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
const auto other = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<int>(other);
|
||||
|
||||
registry.destroy(entity);
|
||||
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_TRUE(view.contains(other));
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Empty) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
const auto other = registry.create();
|
||||
|
||||
registry.emplace<double>(entity);
|
||||
registry.emplace<float>(other);
|
||||
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_FALSE(view.contains(other));
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_EQ((std::find(view.begin(), view.end(), entity)), view.end());
|
||||
ASSERT_EQ((std::find(view.begin(), view.end(), other)), view.end());
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Each) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
const auto other = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
registry.emplace<char>(other);
|
||||
|
||||
view.iterate(registry.storage<int>()).iterate(registry.storage<char>());
|
||||
|
||||
view.each([entity](const auto entt) {
|
||||
ASSERT_EQ(entt, entity);
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, EachWithHoles) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
const auto e2 = registry.create();
|
||||
|
||||
registry.emplace<char>(e0, '0');
|
||||
registry.emplace<char>(e1, '1');
|
||||
|
||||
registry.emplace<int>(e0, 0);
|
||||
registry.emplace<int>(e2, 2);
|
||||
|
||||
view.iterate(registry.storage<int>()).iterate(registry.storage<char>());
|
||||
|
||||
view.each([e0](auto entt) {
|
||||
ASSERT_EQ(e0, entt);
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, ExcludedComponents) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.emplace<int>(e0);
|
||||
|
||||
const auto e1 = registry.create();
|
||||
registry.emplace<int>(e1);
|
||||
registry.emplace<char>(e1);
|
||||
|
||||
view.iterate(registry.storage<int>())
|
||||
.exclude(registry.storage<char>());
|
||||
|
||||
ASSERT_TRUE(view.contains(e0));
|
||||
ASSERT_FALSE(view.contains(e1));
|
||||
|
||||
view.each([e0](auto entt) {
|
||||
ASSERT_EQ(e0, entt);
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, StableType) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
const auto e2 = registry.create();
|
||||
|
||||
registry.emplace<int>(e0);
|
||||
registry.emplace<int>(e1);
|
||||
registry.emplace<int>(e2);
|
||||
|
||||
registry.emplace<stable_type>(e0);
|
||||
registry.emplace<stable_type>(e1);
|
||||
|
||||
registry.remove<stable_type>(e1);
|
||||
|
||||
view.iterate(registry.storage<int>()).iterate(registry.storage<stable_type>());
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 2u);
|
||||
ASSERT_TRUE(view.contains(e0));
|
||||
ASSERT_FALSE(view.contains(e1));
|
||||
|
||||
ASSERT_EQ(*view.begin(), e0);
|
||||
ASSERT_EQ(++view.begin(), view.end());
|
||||
|
||||
view.each([e0](const auto entt) {
|
||||
ASSERT_EQ(e0, entt);
|
||||
});
|
||||
|
||||
for(auto entt: view) {
|
||||
static_assert(std::is_same_v<decltype(entt), entt::entity>);
|
||||
ASSERT_EQ(e0, entt);
|
||||
}
|
||||
|
||||
registry.compact();
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 1u);
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, StableTypeWithExcludedComponent) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
const auto other = registry.create();
|
||||
|
||||
registry.emplace<stable_type>(entity, 0);
|
||||
registry.emplace<stable_type>(other, 42);
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
view.iterate(registry.storage<stable_type>()).exclude(registry.storage<int>());
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 2u);
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_TRUE(view.contains(other));
|
||||
|
||||
registry.destroy(entity);
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 2u);
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_TRUE(view.contains(other));
|
||||
|
||||
for(auto entt: view) {
|
||||
constexpr entt::entity tombstone = entt::tombstone;
|
||||
ASSERT_NE(entt, tombstone);
|
||||
ASSERT_EQ(entt, other);
|
||||
}
|
||||
|
||||
view.each([other](const auto entt) {
|
||||
constexpr entt::entity tombstone = entt::tombstone;
|
||||
ASSERT_NE(entt, tombstone);
|
||||
ASSERT_EQ(entt, other);
|
||||
});
|
||||
}
|
593
test/entt/entity/snapshot.cpp
Normal file
593
test/entt/entity/snapshot.cpp
Normal file
@ -0,0 +1,593 @@
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/snapshot.hpp>
|
||||
|
||||
struct noncopyable_component {
|
||||
noncopyable_component()
|
||||
: value{} {}
|
||||
|
||||
explicit noncopyable_component(int v)
|
||||
: value{v} {}
|
||||
|
||||
noncopyable_component(const noncopyable_component &) = delete;
|
||||
noncopyable_component(noncopyable_component &&) = default;
|
||||
|
||||
noncopyable_component &operator=(const noncopyable_component &) = delete;
|
||||
noncopyable_component &operator=(noncopyable_component &&) = default;
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
template<typename Storage>
|
||||
struct output_archive {
|
||||
output_archive(Storage &instance)
|
||||
: storage{instance} {}
|
||||
|
||||
template<typename... Value>
|
||||
void operator()(const Value &...value) {
|
||||
(std::get<std::queue<Value>>(storage).push(value), ...);
|
||||
}
|
||||
|
||||
void operator()(const entt::entity &entity, const noncopyable_component &instance) {
|
||||
(*this)(entity, instance.value);
|
||||
}
|
||||
|
||||
private:
|
||||
Storage &storage;
|
||||
};
|
||||
|
||||
template<typename Storage>
|
||||
struct input_archive {
|
||||
input_archive(Storage &instance)
|
||||
: storage{instance} {}
|
||||
|
||||
template<typename... Value>
|
||||
void operator()(Value &...value) {
|
||||
auto assign = [this](auto &val) {
|
||||
auto &queue = std::get<std::queue<std::decay_t<decltype(val)>>>(storage);
|
||||
val = queue.front();
|
||||
queue.pop();
|
||||
};
|
||||
|
||||
(assign(value), ...);
|
||||
}
|
||||
|
||||
void operator()(entt::entity &entity, noncopyable_component &instance) {
|
||||
(*this)(entity, instance.value);
|
||||
}
|
||||
|
||||
private:
|
||||
Storage &storage;
|
||||
};
|
||||
|
||||
struct a_component {};
|
||||
|
||||
struct another_component {
|
||||
int key;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct what_a_component {
|
||||
entt::entity bar;
|
||||
std::vector<entt::entity> quux;
|
||||
};
|
||||
|
||||
struct map_component {
|
||||
std::map<entt::entity, int> keys;
|
||||
std::map<int, entt::entity> values;
|
||||
std::map<entt::entity, entt::entity> both;
|
||||
};
|
||||
|
||||
TEST(Snapshot, Dump) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.emplace<int>(e0, 42);
|
||||
registry.emplace<char>(e0, 'c');
|
||||
registry.emplace<double>(e0, .1);
|
||||
|
||||
const auto e1 = registry.create();
|
||||
|
||||
const auto e2 = registry.create();
|
||||
registry.emplace<int>(e2, 3);
|
||||
|
||||
const auto e3 = registry.create();
|
||||
registry.emplace<a_component>(e3);
|
||||
registry.emplace<char>(e3, '0');
|
||||
|
||||
registry.destroy(e1);
|
||||
auto v1 = registry.current(e1);
|
||||
|
||||
using storage_type = std::tuple<
|
||||
std::queue<typename traits_type::entity_type>,
|
||||
std::queue<entt::entity>,
|
||||
std::queue<int>,
|
||||
std::queue<char>,
|
||||
std::queue<double>,
|
||||
std::queue<a_component>,
|
||||
std::queue<another_component>>;
|
||||
|
||||
storage_type storage;
|
||||
output_archive<storage_type> output{storage};
|
||||
input_archive<storage_type> input{storage};
|
||||
|
||||
entt::snapshot{registry}.entities(output).component<int, char, double, a_component, another_component>(output);
|
||||
registry.clear();
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_FALSE(registry.valid(e2));
|
||||
ASSERT_FALSE(registry.valid(e3));
|
||||
|
||||
entt::snapshot_loader{registry}.entities(input).component<int, char, double, a_component, another_component>(input).orphans();
|
||||
|
||||
ASSERT_TRUE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_TRUE(registry.valid(e2));
|
||||
ASSERT_TRUE(registry.valid(e3));
|
||||
|
||||
ASSERT_FALSE(registry.orphan(e0));
|
||||
ASSERT_FALSE(registry.orphan(e2));
|
||||
ASSERT_FALSE(registry.orphan(e3));
|
||||
|
||||
ASSERT_EQ(registry.get<int>(e0), 42);
|
||||
ASSERT_EQ(registry.get<char>(e0), 'c');
|
||||
ASSERT_EQ(registry.get<double>(e0), .1);
|
||||
ASSERT_EQ(registry.current(e1), v1);
|
||||
ASSERT_EQ(registry.get<int>(e2), 3);
|
||||
ASSERT_EQ(registry.get<char>(e3), '0');
|
||||
ASSERT_TRUE(registry.all_of<a_component>(e3));
|
||||
|
||||
ASSERT_TRUE(registry.storage<another_component>().empty());
|
||||
}
|
||||
|
||||
TEST(Snapshot, Partial) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.emplace<int>(e0, 42);
|
||||
registry.emplace<char>(e0, 'c');
|
||||
registry.emplace<double>(e0, .1);
|
||||
|
||||
const auto e1 = registry.create();
|
||||
|
||||
const auto e2 = registry.create();
|
||||
registry.emplace<int>(e2, 3);
|
||||
|
||||
const auto e3 = registry.create();
|
||||
registry.emplace<char>(e3, '0');
|
||||
|
||||
registry.destroy(e1);
|
||||
auto v1 = registry.current(e1);
|
||||
|
||||
using storage_type = std::tuple<
|
||||
std::queue<typename traits_type::entity_type>,
|
||||
std::queue<entt::entity>,
|
||||
std::queue<int>,
|
||||
std::queue<char>,
|
||||
std::queue<double>>;
|
||||
|
||||
storage_type storage;
|
||||
output_archive<storage_type> output{storage};
|
||||
input_archive<storage_type> input{storage};
|
||||
|
||||
entt::snapshot{registry}.entities(output).component<char, int>(output);
|
||||
registry.clear();
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_FALSE(registry.valid(e2));
|
||||
ASSERT_FALSE(registry.valid(e3));
|
||||
|
||||
entt::snapshot_loader{registry}.entities(input).component<char, int>(input);
|
||||
|
||||
ASSERT_TRUE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_TRUE(registry.valid(e2));
|
||||
ASSERT_TRUE(registry.valid(e3));
|
||||
|
||||
ASSERT_EQ(registry.get<int>(e0), 42);
|
||||
ASSERT_EQ(registry.get<char>(e0), 'c');
|
||||
ASSERT_FALSE(registry.all_of<double>(e0));
|
||||
ASSERT_EQ(registry.current(e1), v1);
|
||||
ASSERT_EQ(registry.get<int>(e2), 3);
|
||||
ASSERT_EQ(registry.get<char>(e3), '0');
|
||||
|
||||
entt::snapshot{registry}.entities(output);
|
||||
registry.clear();
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_FALSE(registry.valid(e2));
|
||||
ASSERT_FALSE(registry.valid(e3));
|
||||
|
||||
entt::snapshot_loader{registry}.entities(input).orphans();
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_FALSE(registry.valid(e2));
|
||||
ASSERT_FALSE(registry.valid(e3));
|
||||
}
|
||||
|
||||
TEST(Snapshot, Iterator) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
|
||||
for(auto i = 0; i < 50; ++i) {
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<another_component>(entity, i, i);
|
||||
registry.emplace<noncopyable_component>(entity, i);
|
||||
|
||||
if(i % 2) {
|
||||
registry.emplace<a_component>(entity);
|
||||
}
|
||||
}
|
||||
|
||||
using storage_type = std::tuple<
|
||||
std::queue<typename traits_type::entity_type>,
|
||||
std::queue<entt::entity>,
|
||||
std::queue<another_component>,
|
||||
std::queue<int>>;
|
||||
|
||||
storage_type storage;
|
||||
output_archive<storage_type> output{storage};
|
||||
input_archive<storage_type> input{storage};
|
||||
|
||||
const auto view = registry.view<a_component>();
|
||||
const auto size = view.size();
|
||||
|
||||
entt::snapshot{registry}.component<another_component, noncopyable_component>(output, view.begin(), view.end());
|
||||
registry.clear();
|
||||
entt::snapshot_loader{registry}.component<another_component, noncopyable_component>(input);
|
||||
|
||||
ASSERT_EQ(registry.view<another_component>().size(), size);
|
||||
|
||||
registry.view<another_component>().each([](const auto entity, const auto &) {
|
||||
ASSERT_NE(entt::to_integral(entity) % 2u, 0u);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(Snapshot, Continuous) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry src;
|
||||
entt::registry dst;
|
||||
|
||||
entt::continuous_loader loader{dst};
|
||||
|
||||
std::vector<entt::entity> entities;
|
||||
entt::entity entity;
|
||||
|
||||
using storage_type = std::tuple<
|
||||
std::queue<typename traits_type::entity_type>,
|
||||
std::queue<entt::entity>,
|
||||
std::queue<another_component>,
|
||||
std::queue<what_a_component>,
|
||||
std::queue<map_component>,
|
||||
std::queue<int>,
|
||||
std::queue<double>>;
|
||||
|
||||
storage_type storage;
|
||||
output_archive<storage_type> output{storage};
|
||||
input_archive<storage_type> input{storage};
|
||||
|
||||
for(int i = 0; i < 10; ++i) {
|
||||
static_cast<void>(src.create());
|
||||
}
|
||||
|
||||
src.clear();
|
||||
|
||||
for(int i = 0; i < 5; ++i) {
|
||||
entity = src.create();
|
||||
entities.push_back(entity);
|
||||
|
||||
src.emplace<a_component>(entity);
|
||||
src.emplace<another_component>(entity, i, i);
|
||||
src.emplace<noncopyable_component>(entity, i);
|
||||
|
||||
if(i % 2) {
|
||||
src.emplace<what_a_component>(entity, entity);
|
||||
} else {
|
||||
src.emplace<map_component>(entity);
|
||||
}
|
||||
}
|
||||
|
||||
src.view<what_a_component>().each([&entities](auto, auto &what_a_component) {
|
||||
what_a_component.quux.insert(what_a_component.quux.begin(), entities.begin(), entities.end());
|
||||
});
|
||||
|
||||
src.view<map_component>().each([&entities](auto, auto &map_component) {
|
||||
for(std::size_t i = 0; i < entities.size(); ++i) {
|
||||
map_component.keys.insert({entities[i], int(i)});
|
||||
map_component.values.insert({int(i), entities[i]});
|
||||
map_component.both.insert({entities[entities.size() - i - 1], entities[i]});
|
||||
}
|
||||
});
|
||||
|
||||
entity = dst.create();
|
||||
dst.emplace<a_component>(entity);
|
||||
dst.emplace<another_component>(entity, -1, -1);
|
||||
dst.emplace<noncopyable_component>(entity, -1);
|
||||
|
||||
entt::snapshot{src}.entities(output).component<a_component, another_component, what_a_component, map_component, noncopyable_component>(output);
|
||||
|
||||
loader.entities(input)
|
||||
.component<a_component, another_component, what_a_component, map_component, noncopyable_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both)
|
||||
.orphans();
|
||||
|
||||
decltype(dst.size()) a_component_cnt{};
|
||||
decltype(dst.size()) another_component_cnt{};
|
||||
decltype(dst.size()) what_a_component_cnt{};
|
||||
decltype(dst.size()) map_component_cnt{};
|
||||
decltype(dst.size()) noncopyable_component_cnt{};
|
||||
|
||||
dst.each([&dst, &a_component_cnt](auto entt) {
|
||||
ASSERT_TRUE(dst.all_of<a_component>(entt));
|
||||
++a_component_cnt;
|
||||
});
|
||||
|
||||
dst.view<another_component>().each([&another_component_cnt](auto, const auto &component) {
|
||||
ASSERT_EQ(component.value, component.key < 0 ? -1 : component.key);
|
||||
++another_component_cnt;
|
||||
});
|
||||
|
||||
dst.view<what_a_component>().each([&dst, &what_a_component_cnt](auto entt, const auto &component) {
|
||||
ASSERT_EQ(entt, component.bar);
|
||||
|
||||
for(auto child: component.quux) {
|
||||
ASSERT_TRUE(dst.valid(child));
|
||||
}
|
||||
|
||||
++what_a_component_cnt;
|
||||
});
|
||||
|
||||
dst.view<map_component>().each([&dst, &map_component_cnt](const auto &component) {
|
||||
for(auto child: component.keys) {
|
||||
ASSERT_TRUE(dst.valid(child.first));
|
||||
}
|
||||
|
||||
for(auto child: component.values) {
|
||||
ASSERT_TRUE(dst.valid(child.second));
|
||||
}
|
||||
|
||||
for(auto child: component.both) {
|
||||
ASSERT_TRUE(dst.valid(child.first));
|
||||
ASSERT_TRUE(dst.valid(child.second));
|
||||
}
|
||||
|
||||
++map_component_cnt;
|
||||
});
|
||||
|
||||
dst.view<noncopyable_component>().each([&dst, &noncopyable_component_cnt](auto, const auto &component) {
|
||||
++noncopyable_component_cnt;
|
||||
ASSERT_EQ(component.value, static_cast<int>(dst.storage<noncopyable_component>().size() - noncopyable_component_cnt - 1u));
|
||||
});
|
||||
|
||||
src.view<another_component>().each([](auto, auto &component) {
|
||||
component.value = 2 * component.key;
|
||||
});
|
||||
|
||||
auto size = dst.size();
|
||||
|
||||
entt::snapshot{src}.entities(output).component<a_component, what_a_component, map_component, another_component>(output);
|
||||
|
||||
loader.entities(input)
|
||||
.component<a_component, what_a_component, map_component, another_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both)
|
||||
.orphans();
|
||||
|
||||
ASSERT_EQ(size, dst.size());
|
||||
|
||||
ASSERT_EQ(dst.storage<a_component>().size(), a_component_cnt);
|
||||
ASSERT_EQ(dst.storage<another_component>().size(), another_component_cnt);
|
||||
ASSERT_EQ(dst.storage<what_a_component>().size(), what_a_component_cnt);
|
||||
ASSERT_EQ(dst.storage<map_component>().size(), map_component_cnt);
|
||||
ASSERT_EQ(dst.storage<noncopyable_component>().size(), noncopyable_component_cnt);
|
||||
|
||||
dst.view<another_component>().each([](auto, auto &component) {
|
||||
ASSERT_EQ(component.value, component.key < 0 ? -1 : (2 * component.key));
|
||||
});
|
||||
|
||||
entity = src.create();
|
||||
|
||||
src.view<what_a_component>().each([entity](auto, auto &component) {
|
||||
component.bar = entity;
|
||||
});
|
||||
|
||||
entt::snapshot{src}.entities(output).component<what_a_component, map_component, a_component, another_component>(output);
|
||||
|
||||
loader.entities(input)
|
||||
.component<what_a_component, map_component, a_component, another_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both)
|
||||
.orphans();
|
||||
|
||||
dst.view<what_a_component>().each([&loader, entity](auto, auto &component) {
|
||||
ASSERT_EQ(component.bar, loader.map(entity));
|
||||
});
|
||||
|
||||
entities.clear();
|
||||
for(auto entt: src.view<a_component>()) {
|
||||
entities.push_back(entt);
|
||||
}
|
||||
|
||||
src.destroy(entity);
|
||||
loader.shrink();
|
||||
|
||||
entt::snapshot{src}.entities(output).component<a_component, another_component, what_a_component, map_component>(output);
|
||||
|
||||
loader.entities(input)
|
||||
.component<a_component, another_component, what_a_component, map_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both)
|
||||
.orphans()
|
||||
.shrink();
|
||||
|
||||
dst.view<what_a_component>().each([&dst](auto, auto &component) {
|
||||
ASSERT_FALSE(dst.valid(component.bar));
|
||||
});
|
||||
|
||||
ASSERT_FALSE(loader.contains(entity));
|
||||
|
||||
entity = src.create();
|
||||
|
||||
src.view<what_a_component>().each([entity](auto, auto &component) {
|
||||
component.bar = entity;
|
||||
});
|
||||
|
||||
dst.clear<a_component>();
|
||||
a_component_cnt = src.storage<a_component>().size();
|
||||
|
||||
entt::snapshot{src}.entities(output).component<a_component, what_a_component, map_component, another_component>(output);
|
||||
|
||||
loader.entities(input)
|
||||
.component<a_component, what_a_component, map_component, another_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both)
|
||||
.orphans();
|
||||
|
||||
ASSERT_EQ(dst.storage<a_component>().size(), a_component_cnt);
|
||||
|
||||
src.clear<a_component>();
|
||||
a_component_cnt = {};
|
||||
|
||||
entt::snapshot{src}.entities(output).component<what_a_component, map_component, a_component, another_component>(output);
|
||||
|
||||
loader.entities(input)
|
||||
.component<what_a_component, map_component, a_component, another_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both)
|
||||
.orphans();
|
||||
|
||||
ASSERT_EQ(dst.storage<a_component>().size(), a_component_cnt);
|
||||
}
|
||||
|
||||
TEST(Snapshot, MoreOnShrink) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry src;
|
||||
entt::registry dst;
|
||||
|
||||
entt::continuous_loader loader{dst};
|
||||
|
||||
using storage_type = std::tuple<
|
||||
std::queue<typename traits_type::entity_type>,
|
||||
std::queue<entt::entity>>;
|
||||
|
||||
storage_type storage;
|
||||
output_archive<storage_type> output{storage};
|
||||
input_archive<storage_type> input{storage};
|
||||
|
||||
auto entity = src.create();
|
||||
entt::snapshot{src}.entities(output);
|
||||
loader.entities(input).shrink();
|
||||
|
||||
ASSERT_TRUE(dst.valid(entity));
|
||||
|
||||
loader.shrink();
|
||||
|
||||
ASSERT_FALSE(dst.valid(entity));
|
||||
}
|
||||
|
||||
TEST(Snapshot, SyncDataMembers) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry src;
|
||||
entt::registry dst;
|
||||
|
||||
entt::continuous_loader loader{dst};
|
||||
|
||||
using storage_type = std::tuple<
|
||||
std::queue<typename traits_type::entity_type>,
|
||||
std::queue<entt::entity>,
|
||||
std::queue<what_a_component>,
|
||||
std::queue<map_component>>;
|
||||
|
||||
storage_type storage;
|
||||
output_archive<storage_type> output{storage};
|
||||
input_archive<storage_type> input{storage};
|
||||
|
||||
static_cast<void>(src.create());
|
||||
static_cast<void>(src.create());
|
||||
|
||||
src.clear();
|
||||
|
||||
auto parent = src.create();
|
||||
auto child = src.create();
|
||||
|
||||
src.emplace<what_a_component>(parent, entt::null);
|
||||
src.emplace<what_a_component>(child, parent).quux.push_back(child);
|
||||
|
||||
src.emplace<map_component>(
|
||||
child,
|
||||
decltype(map_component::keys){{{child, 10}}},
|
||||
decltype(map_component::values){{{10, child}}},
|
||||
decltype(map_component::both){{{child, child}}});
|
||||
|
||||
entt::snapshot{src}.entities(output).component<what_a_component, map_component>(output);
|
||||
|
||||
loader.entities(input).component<what_a_component, map_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both);
|
||||
|
||||
ASSERT_FALSE(dst.valid(parent));
|
||||
ASSERT_FALSE(dst.valid(child));
|
||||
|
||||
ASSERT_TRUE(dst.all_of<what_a_component>(loader.map(parent)));
|
||||
ASSERT_TRUE(dst.all_of<what_a_component>(loader.map(child)));
|
||||
|
||||
ASSERT_EQ(dst.get<what_a_component>(loader.map(parent)).bar, static_cast<entt::entity>(entt::null));
|
||||
|
||||
const auto &component = dst.get<what_a_component>(loader.map(child));
|
||||
|
||||
ASSERT_EQ(component.bar, loader.map(parent));
|
||||
ASSERT_EQ(component.quux[0], loader.map(child));
|
||||
|
||||
const auto &foobar = dst.get<map_component>(loader.map(child));
|
||||
ASSERT_EQ(foobar.keys.at(loader.map(child)), 10);
|
||||
ASSERT_EQ(foobar.values.at(10), loader.map(child));
|
||||
ASSERT_EQ(foobar.both.at(loader.map(child)), loader.map(child));
|
||||
}
|
1426
test/entt/entity/sparse_set.cpp
Normal file
1426
test/entt/entity/sparse_set.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1933
test/entt/entity/storage.cpp
Normal file
1933
test/entt/entity/storage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
613
test/entt/entity/storage_mixin.cpp
Normal file
613
test/entt/entity/storage_mixin.cpp
Normal file
@ -0,0 +1,613 @@
|
||||
#include <iterator>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/storage.hpp>
|
||||
#include "../common/throwing_allocator.hpp"
|
||||
#include "../common/throwing_type.hpp"
|
||||
|
||||
struct empty_type {};
|
||||
|
||||
struct stable_type {
|
||||
static constexpr auto in_place_delete = true;
|
||||
int value{};
|
||||
};
|
||||
|
||||
struct non_default_constructible {
|
||||
non_default_constructible() = delete;
|
||||
|
||||
non_default_constructible(int v)
|
||||
: value{v} {}
|
||||
|
||||
int value{};
|
||||
};
|
||||
|
||||
struct counter {
|
||||
int value{};
|
||||
};
|
||||
|
||||
template<typename Registry>
|
||||
void listener(counter &counter, Registry &, typename Registry::entity_type) {
|
||||
++counter.value;
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, GenericType) {
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
entt::sigh_storage_mixin<entt::storage<int>> pool;
|
||||
entt::sparse_set &base = pool;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
ASSERT_NE(base.emplace(entities[0u]), base.end());
|
||||
|
||||
pool.emplace(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 0);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]), 0);
|
||||
ASSERT_EQ(pool.get(entities[1u]), 0);
|
||||
|
||||
base.erase(entities[0u]);
|
||||
pool.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 2);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
ASSERT_NE(base.insert(std::begin(entities), std::end(entities)), base.end());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]), 0);
|
||||
ASSERT_EQ(pool.get(entities[1u]), 0);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
base.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 4);
|
||||
ASSERT_EQ(on_destroy.value, 3);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
base.erase(entities[0u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 4);
|
||||
ASSERT_EQ(on_destroy.value, 4);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
pool.insert(std::begin(entities), std::end(entities), 3);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 4);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]), 3);
|
||||
ASSERT_EQ(pool.get(entities[1u]), 3);
|
||||
|
||||
pool.erase(std::begin(entities), std::end(entities));
|
||||
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 6);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, StableType) {
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
entt::sigh_storage_mixin<entt::storage<stable_type>> pool;
|
||||
entt::sparse_set &base = pool;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
ASSERT_NE(base.emplace(entities[0u]), base.end());
|
||||
|
||||
pool.emplace(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 0);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]).value, 0);
|
||||
ASSERT_EQ(pool.get(entities[1u]).value, 0);
|
||||
|
||||
base.erase(entities[0u]);
|
||||
pool.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 2);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_NE(base.insert(std::begin(entities), std::end(entities)), base.end());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]).value, 0);
|
||||
ASSERT_EQ(pool.get(entities[1u]).value, 0);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
base.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 4);
|
||||
ASSERT_EQ(on_destroy.value, 3);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
base.erase(entities[0u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 4);
|
||||
ASSERT_EQ(on_destroy.value, 4);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
pool.insert(std::begin(entities), std::end(entities), stable_type{3});
|
||||
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 4);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]).value, 3);
|
||||
ASSERT_EQ(pool.get(entities[1u]).value, 3);
|
||||
|
||||
pool.erase(std::begin(entities), std::end(entities));
|
||||
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 6);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, EmptyType) {
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
entt::sigh_storage_mixin<entt::storage<empty_type>> pool;
|
||||
entt::sparse_set &base = pool;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
ASSERT_NE(base.emplace(entities[0u]), base.end());
|
||||
|
||||
pool.emplace(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 0);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_TRUE(pool.contains(entities[0u]));
|
||||
ASSERT_TRUE(pool.contains(entities[1u]));
|
||||
|
||||
base.erase(entities[0u]);
|
||||
pool.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 2);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
ASSERT_NE(base.insert(std::begin(entities), std::end(entities)), base.end());
|
||||
|
||||
ASSERT_TRUE(pool.contains(entities[0u]));
|
||||
ASSERT_TRUE(pool.contains(entities[1u]));
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
base.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 4);
|
||||
ASSERT_EQ(on_destroy.value, 3);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
base.erase(entities[0u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 4);
|
||||
ASSERT_EQ(on_destroy.value, 4);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
pool.insert(std::begin(entities), std::end(entities));
|
||||
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 4);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_TRUE(pool.contains(entities[0u]));
|
||||
ASSERT_TRUE(pool.contains(entities[1u]));
|
||||
|
||||
pool.erase(std::begin(entities), std::end(entities));
|
||||
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 6);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, NonDefaultConstructibleType) {
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
entt::sigh_storage_mixin<entt::storage<non_default_constructible>> pool;
|
||||
entt::sparse_set &base = pool;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
ASSERT_EQ(base.emplace(entities[0u]), base.end());
|
||||
|
||||
pool.emplace(entities[1u], 3);
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 0);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_FALSE(pool.contains(entities[0u]));
|
||||
ASSERT_EQ(pool.get(entities[1u]).value, 3);
|
||||
|
||||
base.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 1);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
ASSERT_EQ(base.insert(std::begin(entities), std::end(entities)), base.end());
|
||||
|
||||
ASSERT_FALSE(pool.contains(entities[0u]));
|
||||
ASSERT_FALSE(pool.contains(entities[1u]));
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
pool.insert(std::begin(entities), std::end(entities), 3);
|
||||
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 1);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]).value, 3);
|
||||
ASSERT_EQ(pool.get(entities[1u]).value, 3);
|
||||
|
||||
pool.erase(std::begin(entities), std::end(entities));
|
||||
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 3);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, VoidType) {
|
||||
entt::sigh_storage_mixin<entt::storage<void>> pool;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
pool.emplace(entt::entity{99});
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<void>());
|
||||
ASSERT_TRUE(pool.contains(entt::entity{99}));
|
||||
|
||||
entt::sigh_storage_mixin<entt::storage<void>> other{std::move(pool)};
|
||||
|
||||
ASSERT_FALSE(pool.contains(entt::entity{99}));
|
||||
ASSERT_TRUE(other.contains(entt::entity{99}));
|
||||
|
||||
pool = std::move(other);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entt::entity{99}));
|
||||
ASSERT_FALSE(other.contains(entt::entity{99}));
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_EQ(on_construct.value, 1);
|
||||
ASSERT_EQ(on_destroy.value, 1);
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, Move) {
|
||||
entt::sigh_storage_mixin<entt::storage<int>> pool;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
pool.emplace(entt::entity{3}, 3);
|
||||
|
||||
ASSERT_TRUE(std::is_move_constructible_v<decltype(pool)>);
|
||||
ASSERT_TRUE(std::is_move_assignable_v<decltype(pool)>);
|
||||
ASSERT_EQ(pool.type(), entt::type_id<int>());
|
||||
|
||||
entt::sigh_storage_mixin<entt::storage<int>> other{std::move(pool)};
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_EQ(other.type(), entt::type_id<int>());
|
||||
ASSERT_EQ(pool.at(0u), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_EQ(other.at(0u), entt::entity{3});
|
||||
ASSERT_EQ(other.get(entt::entity{3}), 3);
|
||||
|
||||
pool = std::move(other);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_EQ(pool.at(0u), entt::entity{3});
|
||||
ASSERT_EQ(pool.get(entt::entity{3}), 3);
|
||||
ASSERT_EQ(other.at(0u), static_cast<entt::entity>(entt::null));
|
||||
|
||||
other = entt::sigh_storage_mixin<entt::storage<int>>{};
|
||||
other.bind(entt::forward_as_any(registry));
|
||||
|
||||
other.emplace(entt::entity{42}, 42);
|
||||
other = std::move(pool);
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_EQ(pool.at(0u), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_EQ(other.at(0u), entt::entity{3});
|
||||
ASSERT_EQ(other.get(entt::entity{3}), 3);
|
||||
|
||||
other.clear();
|
||||
|
||||
ASSERT_EQ(on_construct.value, 1);
|
||||
ASSERT_EQ(on_destroy.value, 1);
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, Swap) {
|
||||
entt::sigh_storage_mixin<entt::storage<int>> pool;
|
||||
entt::sigh_storage_mixin<entt::storage<int>> other;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
other.bind(entt::forward_as_any(registry));
|
||||
other.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
other.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
pool.emplace(entt::entity{42}, 41);
|
||||
|
||||
other.emplace(entt::entity{9}, 8);
|
||||
other.emplace(entt::entity{3}, 2);
|
||||
other.erase(entt::entity{9});
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
pool.swap(other);
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<int>());
|
||||
ASSERT_EQ(other.type(), entt::type_id<int>());
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
ASSERT_EQ(pool.at(0u), entt::entity{3});
|
||||
ASSERT_EQ(pool.get(entt::entity{3}), 2);
|
||||
|
||||
ASSERT_EQ(other.at(0u), entt::entity{42});
|
||||
ASSERT_EQ(other.get(entt::entity{42}), 41);
|
||||
|
||||
pool.clear();
|
||||
other.clear();
|
||||
|
||||
ASSERT_EQ(on_construct.value, 3);
|
||||
ASSERT_EQ(on_destroy.value, 3);
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, CustomAllocator) {
|
||||
auto test = [](auto pool, auto alloc) {
|
||||
using registry_type = typename decltype(pool)::registry_type;
|
||||
registry_type registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().template connect<&listener<registry_type>>(on_construct);
|
||||
pool.on_destroy().template connect<&listener<registry_type>>(on_destroy);
|
||||
|
||||
pool.reserve(1u);
|
||||
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
|
||||
pool.emplace(entt::entity{0});
|
||||
pool.emplace(entt::entity{1});
|
||||
|
||||
decltype(pool) other{std::move(pool), alloc};
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_EQ(pool.capacity(), 0u);
|
||||
ASSERT_NE(other.capacity(), 0u);
|
||||
ASSERT_EQ(other.size(), 2u);
|
||||
|
||||
pool = std::move(other);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_EQ(other.capacity(), 0u);
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
|
||||
pool.swap(other);
|
||||
pool = std::move(other);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_EQ(other.capacity(), 0u);
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 2);
|
||||
};
|
||||
|
||||
test::throwing_allocator<entt::entity> allocator{};
|
||||
|
||||
test(entt::sigh_storage_mixin<entt::basic_storage<int, entt::entity, test::throwing_allocator<int>>>{allocator}, allocator);
|
||||
test(entt::sigh_storage_mixin<entt::basic_storage<std::true_type, entt::entity, test::throwing_allocator<std::true_type>>>{allocator}, allocator);
|
||||
test(entt::sigh_storage_mixin<entt::basic_storage<stable_type, entt::entity, test::throwing_allocator<stable_type>>>{allocator}, allocator);
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, ThrowingAllocator) {
|
||||
auto test = [](auto pool) {
|
||||
using pool_allocator_type = typename decltype(pool)::allocator_type;
|
||||
using value_type = typename decltype(pool)::value_type;
|
||||
using registry_type = typename decltype(pool)::registry_type;
|
||||
|
||||
typename std::decay_t<decltype(pool)>::base_type &base = pool;
|
||||
constexpr auto packed_page_size = entt::component_traits<typename decltype(pool)::value_type>::page_size;
|
||||
constexpr auto sparse_page_size = entt::entt_traits<typename decltype(pool)::entity_type>::page_size;
|
||||
registry_type registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().template connect<&listener<registry_type>>(on_construct);
|
||||
pool.on_destroy().template connect<&listener<registry_type>>(on_destroy);
|
||||
|
||||
pool_allocator_type::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(pool.reserve(1u), typename pool_allocator_type::exception_type);
|
||||
ASSERT_EQ(pool.capacity(), 0u);
|
||||
|
||||
pool_allocator_type::trigger_after_allocate = true;
|
||||
|
||||
ASSERT_THROW(pool.reserve(2 * packed_page_size), typename pool_allocator_type::exception_type);
|
||||
ASSERT_EQ(pool.capacity(), packed_page_size);
|
||||
|
||||
pool.shrink_to_fit();
|
||||
|
||||
ASSERT_EQ(pool.capacity(), 0u);
|
||||
|
||||
test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(pool.emplace(entt::entity{0}, 0), test::throwing_allocator<entt::entity>::exception_type);
|
||||
ASSERT_FALSE(pool.contains(entt::entity{0}));
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(base.emplace(entt::entity{0}), test::throwing_allocator<entt::entity>::exception_type);
|
||||
ASSERT_FALSE(base.contains(entt::entity{0}));
|
||||
ASSERT_TRUE(base.empty());
|
||||
|
||||
pool_allocator_type::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(pool.emplace(entt::entity{0}, 0), typename pool_allocator_type::exception_type);
|
||||
ASSERT_FALSE(pool.contains(entt::entity{0}));
|
||||
ASSERT_NO_FATAL_FAILURE(pool.compact());
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
pool.emplace(entt::entity{0}, 0);
|
||||
const entt::entity entities[2u]{entt::entity{1}, entt::entity{sparse_page_size}};
|
||||
test::throwing_allocator<entt::entity>::trigger_after_allocate = true;
|
||||
|
||||
ASSERT_THROW(pool.insert(std::begin(entities), std::end(entities), value_type{0}), test::throwing_allocator<entt::entity>::exception_type);
|
||||
ASSERT_TRUE(pool.contains(entt::entity{1}));
|
||||
ASSERT_FALSE(pool.contains(entt::entity{sparse_page_size}));
|
||||
|
||||
pool.erase(entt::entity{1});
|
||||
const value_type components[2u]{value_type{1}, value_type{sparse_page_size}};
|
||||
test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
|
||||
pool.compact();
|
||||
|
||||
ASSERT_THROW(pool.insert(std::begin(entities), std::end(entities), std::begin(components)), test::throwing_allocator<entt::entity>::exception_type);
|
||||
ASSERT_TRUE(pool.contains(entt::entity{1}));
|
||||
ASSERT_FALSE(pool.contains(entt::entity{sparse_page_size}));
|
||||
|
||||
ASSERT_EQ(on_construct.value, 1);
|
||||
ASSERT_EQ(on_destroy.value, 1);
|
||||
};
|
||||
|
||||
test(entt::sigh_storage_mixin<entt::basic_storage<int, entt::entity, test::throwing_allocator<int>>>{});
|
||||
test(entt::sigh_storage_mixin<entt::basic_storage<stable_type, entt::entity, test::throwing_allocator<stable_type>>>{});
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, ThrowingComponent) {
|
||||
entt::sigh_storage_mixin<entt::storage<test::throwing_type>> pool;
|
||||
using registry_type = typename decltype(pool)::registry_type;
|
||||
registry_type registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<registry_type>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<registry_type>>(on_destroy);
|
||||
|
||||
test::throwing_type::trigger_on_value = 42;
|
||||
|
||||
// strong exception safety
|
||||
ASSERT_THROW(pool.emplace(entt::entity{0}, test::throwing_type{42}), typename test::throwing_type::exception_type);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
const entt::entity entities[2u]{entt::entity{42}, entt::entity{1}};
|
||||
const test::throwing_type components[2u]{42, 1};
|
||||
|
||||
// basic exception safety
|
||||
ASSERT_THROW(pool.insert(std::begin(entities), std::end(entities), test::throwing_type{42}), typename test::throwing_type::exception_type);
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_FALSE(pool.contains(entt::entity{1}));
|
||||
|
||||
// basic exception safety
|
||||
ASSERT_THROW(pool.insert(std::begin(entities), std::end(entities), std::begin(components)), typename test::throwing_type::exception_type);
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_FALSE(pool.contains(entt::entity{1}));
|
||||
|
||||
// basic exception safety
|
||||
ASSERT_THROW(pool.insert(std::rbegin(entities), std::rend(entities), std::rbegin(components)), typename test::throwing_type::exception_type);
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_TRUE(pool.contains(entt::entity{1}));
|
||||
ASSERT_EQ(pool.get(entt::entity{1}), 1);
|
||||
|
||||
pool.clear();
|
||||
pool.emplace(entt::entity{1}, 1);
|
||||
pool.emplace(entt::entity{42}, 42);
|
||||
|
||||
// basic exception safety
|
||||
ASSERT_THROW(pool.erase(entt::entity{1}), typename test::throwing_type::exception_type);
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_TRUE(pool.contains(entt::entity{42}));
|
||||
ASSERT_TRUE(pool.contains(entt::entity{1}));
|
||||
ASSERT_EQ(pool.at(0u), entt::entity{1});
|
||||
ASSERT_EQ(pool.at(1u), entt::entity{42});
|
||||
ASSERT_EQ(pool.get(entt::entity{42}), 42);
|
||||
// the element may have been moved but it's still there
|
||||
ASSERT_EQ(pool.get(entt::entity{1}), test::throwing_type::moved_from_value);
|
||||
|
||||
test::throwing_type::trigger_on_value = 99;
|
||||
pool.erase(entt::entity{1});
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_TRUE(pool.contains(entt::entity{42}));
|
||||
ASSERT_FALSE(pool.contains(entt::entity{1}));
|
||||
ASSERT_EQ(pool.at(0u), entt::entity{42});
|
||||
ASSERT_EQ(pool.get(entt::entity{42}), 42);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 3);
|
||||
}
|
1290
test/entt/entity/view.cpp
Normal file
1290
test/entt/entity/view.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user