handle: full review with test coverage - close #1129
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "entity.hpp"
|
||||
@@ -95,6 +96,11 @@ template<typename ILhs, typename IRhs>
|
||||
*/
|
||||
template<typename Registry, typename... Scope>
|
||||
class basic_handle {
|
||||
auto &owner_or_assert() const noexcept {
|
||||
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
|
||||
return static_cast<Registry &>(*owner);
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Type of registry accepted by the handle. */
|
||||
using registry_type = Registry;
|
||||
@@ -132,30 +138,13 @@ public:
|
||||
* @return An iterable object to use to _visit_ the handle.
|
||||
*/
|
||||
[[nodiscard]] iterable storage() const noexcept {
|
||||
auto underlying = owner->storage();
|
||||
auto underlying = owner_or_assert().storage();
|
||||
return iterable{{entt, underlying.begin(), underlying.end()}, {entt, underlying.end(), underlying.end()}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a const handle from a non-const one.
|
||||
* @tparam Other A valid entity type.
|
||||
* @tparam Args Scope of the handle to construct.
|
||||
* @return A const handle referring to the same registry and the same
|
||||
* entity.
|
||||
*/
|
||||
template<typename Other, typename... Args>
|
||||
operator basic_handle<Other, Args...>() const noexcept {
|
||||
static_assert(std::is_same_v<Other, Registry> || std::is_same_v<std::remove_const_t<Other>, Registry>, "Invalid conversion between different handles");
|
||||
static_assert((sizeof...(Scope) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Scope)) && ... && (type_list_contains_v<type_list<Scope...>, Args>))), "Invalid conversion between different handles");
|
||||
return owner ? basic_handle<Other, Args...>{*owner, entt} : basic_handle<Other, Args...>{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a handle to its underlying entity.
|
||||
* @return The contained identifier.
|
||||
*/
|
||||
[[nodiscard]] operator entity_type() const noexcept {
|
||||
return entity();
|
||||
/*! @copydoc valid */
|
||||
[[nodiscard]] explicit operator bool() const noexcept {
|
||||
return owner && owner->valid(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,16 +152,8 @@ public:
|
||||
* @return True if the handle refers to non-null registry and entity, false
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] explicit operator bool() const noexcept {
|
||||
return owner && owner->valid(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a handle refers to a valid entity or not.
|
||||
* @return True if the handle refers to a valid entity, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool valid() const {
|
||||
return owner->valid(entt);
|
||||
return static_cast<bool>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,9 +172,14 @@ public:
|
||||
return entt;
|
||||
}
|
||||
|
||||
/*! @copydoc entity */
|
||||
[[nodiscard]] operator entity_type() const noexcept {
|
||||
return entity();
|
||||
}
|
||||
|
||||
/*! @brief Destroys the entity associated with a handle. */
|
||||
void destroy() {
|
||||
owner->destroy(std::exchange(entt, null));
|
||||
owner_or_assert().destroy(std::exchange(entt, null));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,7 +187,7 @@ public:
|
||||
* @param version A desired version upon destruction.
|
||||
*/
|
||||
void destroy(const version_type version) {
|
||||
owner->destroy(std::exchange(entt, null), version);
|
||||
owner_or_assert().destroy(std::exchange(entt, null), version);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,7 +200,7 @@ public:
|
||||
template<typename Type, typename... Args>
|
||||
decltype(auto) emplace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner->template emplace<Type>(entt, std::forward<Args>(args)...);
|
||||
return owner_or_assert().template emplace<Type>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,7 +213,7 @@ public:
|
||||
template<typename Type, typename... Args>
|
||||
decltype(auto) emplace_or_replace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner->template emplace_or_replace<Type>(entt, std::forward<Args>(args)...);
|
||||
return owner_or_assert().template emplace_or_replace<Type>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,7 +226,7 @@ public:
|
||||
template<typename Type, typename... Func>
|
||||
decltype(auto) patch(Func &&...func) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner->template patch<Type>(entt, std::forward<Func>(func)...);
|
||||
return owner_or_assert().template patch<Type>(entt, std::forward<Func>(func)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,7 +239,7 @@ public:
|
||||
template<typename Type, typename... Args>
|
||||
decltype(auto) replace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner->template replace<Type>(entt, std::forward<Args>(args)...);
|
||||
return owner_or_assert().template replace<Type>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,7 +250,7 @@ public:
|
||||
template<typename... Type>
|
||||
size_type remove() const {
|
||||
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Type> && ...), "Invalid type");
|
||||
return owner->template remove<Type...>(entt);
|
||||
return owner_or_assert().template remove<Type...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,7 +260,7 @@ public:
|
||||
template<typename... Type>
|
||||
void erase() const {
|
||||
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Type> && ...), "Invalid type");
|
||||
owner->template erase<Type...>(entt);
|
||||
owner_or_assert().template erase<Type...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,7 +270,7 @@ public:
|
||||
*/
|
||||
template<typename... Type>
|
||||
[[nodiscard]] decltype(auto) all_of() const {
|
||||
return owner->template all_of<Type...>(entt);
|
||||
return owner_or_assert().template all_of<Type...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,7 +281,7 @@ public:
|
||||
*/
|
||||
template<typename... Type>
|
||||
[[nodiscard]] decltype(auto) any_of() const {
|
||||
return owner->template any_of<Type...>(entt);
|
||||
return owner_or_assert().template any_of<Type...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -306,7 +292,7 @@ public:
|
||||
template<typename... Type>
|
||||
[[nodiscard]] decltype(auto) get() const {
|
||||
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Type> && ...), "Invalid type");
|
||||
return owner->template get<Type...>(entt);
|
||||
return owner_or_assert().template get<Type...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,7 +305,7 @@ public:
|
||||
template<typename Type, typename... Args>
|
||||
[[nodiscard]] decltype(auto) get_or_emplace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner->template get_or_emplace<Type>(entt, std::forward<Args>(args)...);
|
||||
return owner_or_assert().template get_or_emplace<Type>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -330,7 +316,7 @@ public:
|
||||
template<typename... Type>
|
||||
[[nodiscard]] auto try_get() const {
|
||||
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Type> && ...), "Invalid type");
|
||||
return owner->template try_get<Type...>(entt);
|
||||
return owner_or_assert().template try_get<Type...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,7 +324,21 @@ public:
|
||||
* @return True if the handle has no elements assigned, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool orphan() const {
|
||||
return owner->orphan(entt);
|
||||
return owner_or_assert().orphan(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a const handle from a non-const one.
|
||||
* @tparam Other A valid entity type.
|
||||
* @tparam Args Scope of the handle to construct.
|
||||
* @return A const handle referring to the same registry and the same
|
||||
* entity.
|
||||
*/
|
||||
template<typename Other, typename... Args>
|
||||
[[nodiscard]] operator basic_handle<Other, Args...>() const noexcept {
|
||||
static_assert(std::is_same_v<Other, Registry> || std::is_same_v<std::remove_const_t<Other>, Registry>, "Invalid conversion between different handles");
|
||||
static_assert((sizeof...(Scope) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Scope)) && ... && (type_list_contains_v<type_list<Scope...>, Args>))), "Invalid conversion between different handles");
|
||||
return owner ? basic_handle<Other, Args...>{*owner, entt} : basic_handle<Other, Args...>{};
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -8,15 +8,20 @@
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/handle.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include "../../common/config.h"
|
||||
|
||||
template<typename Type>
|
||||
struct BasicHandle: testing::Test {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using BasicHandleDeathTest = BasicHandle<Type>;
|
||||
|
||||
using BasicHandleTypes = ::testing::Types<entt::handle, entt::const_handle>;
|
||||
|
||||
TYPED_TEST_SUITE(BasicHandle, BasicHandleTypes, );
|
||||
TYPED_TEST_SUITE(BasicHandleDeathTest, BasicHandleTypes, );
|
||||
|
||||
TYPED_TEST(BasicHandle, Assumptions) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
@@ -36,41 +41,113 @@ TYPED_TEST(BasicHandle, Construction) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
const handle_type handle{registry, entity};
|
||||
handle_type handle{};
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_FALSE(handle.valid());
|
||||
|
||||
ASSERT_TRUE(handle == entt::null);
|
||||
ASSERT_EQ(handle.registry(), nullptr);
|
||||
|
||||
ASSERT_NE(handle, (entt::handle{registry, entity}));
|
||||
ASSERT_NE(handle, (entt::const_handle{registry, entity}));
|
||||
|
||||
handle = handle_type{registry, entity};
|
||||
|
||||
ASSERT_FALSE(entt::null == handle.entity());
|
||||
ASSERT_EQ(entity, handle);
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_TRUE(handle.valid());
|
||||
|
||||
ASSERT_FALSE(handle == entt::null);
|
||||
ASSERT_EQ(handle.registry(), ®istry);
|
||||
|
||||
ASSERT_EQ(handle, (entt::handle{registry, entity}));
|
||||
ASSERT_EQ(handle, (entt::const_handle{registry, entity}));
|
||||
|
||||
testing::StaticAssertTypeEq<typename handle_type::registry_type *, decltype(handle.registry())>();
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Invalidation) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
handle_type handle;
|
||||
handle = {};
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_FALSE(handle.valid());
|
||||
|
||||
ASSERT_TRUE(handle == entt::null);
|
||||
ASSERT_EQ(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entt::entity{entt::null});
|
||||
|
||||
ASSERT_NE(handle, (entt::handle{registry, entity}));
|
||||
ASSERT_NE(handle, (entt::const_handle{registry, entity}));
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Storage) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const handle_type handle{registry, entity};
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(*handle.storage().begin()), std::pair<entt::id_type, entt::constness_as_t<entt::sparse_set, typename handle_type::registry_type> &>>();
|
||||
|
||||
ASSERT_EQ(handle.storage().begin(), handle.storage().end());
|
||||
|
||||
registry.storage<double>();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_NE(handle.storage().begin(), handle.storage().end());
|
||||
ASSERT_EQ(++handle.storage().begin(), handle.storage().end());
|
||||
ASSERT_EQ(handle.storage().begin()->second.type(), entt::type_id<int>());
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(BasicHandleDeathTest, Storage) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
const handle_type handle{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] auto iterable = handle.storage(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, HandleStorageIterator) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
handle = {registry, entity};
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<double>(entity);
|
||||
// required to test the find-first initialization step
|
||||
registry.storage<entt::entity>().erase(entity);
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_NE(handle.entity(), entt::entity{entt::null});
|
||||
|
||||
handle = {};
|
||||
const handle_type handle{registry, entity};
|
||||
auto iterable = handle.storage();
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity));
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_EQ(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entt::entity{entt::null});
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Entity) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
handle_type handle{};
|
||||
|
||||
ASSERT_TRUE(handle == entt::null);
|
||||
ASSERT_NE(handle.entity(), entity);
|
||||
ASSERT_NE(handle, entity);
|
||||
|
||||
handle = handle_type{registry, entity};
|
||||
|
||||
ASSERT_FALSE(handle == entt::null);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
ASSERT_EQ(handle, entity);
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Destruction) {
|
||||
@@ -81,34 +158,351 @@ TEST(BasicHandle, Destruction) {
|
||||
entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_TRUE(handle.valid());
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.registry(), ®istry);
|
||||
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(registry.current(entity), typename entt::registry::version_type{});
|
||||
ASSERT_EQ(handle.registry(), ®istry);
|
||||
ASSERT_EQ(handle.entity(), entt::entity{entt::null});
|
||||
ASSERT_EQ(registry.current(entity), traits_type::to_version(entity));
|
||||
|
||||
handle = entt::handle{registry, registry.create()};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_TRUE(handle.valid());
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.registry(), ®istry);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
|
||||
handle.destroy();
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_FALSE(handle.valid());
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_NE(registry.current(entity), typename entt::registry::version_type{});
|
||||
ASSERT_NE(registry.current(entity), traits_type::to_version(entity));
|
||||
ASSERT_EQ(handle.entity(), entt::entity{entt::null});
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, Destruction) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.destroy(0u);, "");
|
||||
ASSERT_DEATH(handle.destroy();, "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Emplace) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_FALSE(registry.all_of<int>(entity));
|
||||
|
||||
ASSERT_EQ(handle.emplace<int>(3), 3);
|
||||
|
||||
ASSERT_TRUE(registry.all_of<int>(entity));
|
||||
ASSERT_EQ(registry.get<int>(entity), 3);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, Emplace) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.emplace<int>(3);, "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, EmplaceOrReplace) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_FALSE(registry.all_of<int>(entity));
|
||||
|
||||
ASSERT_EQ(handle.emplace_or_replace<int>(3), 3);
|
||||
|
||||
ASSERT_TRUE(registry.all_of<int>(entity));
|
||||
ASSERT_EQ(registry.get<int>(entity), 3);
|
||||
|
||||
ASSERT_EQ(handle.emplace_or_replace<int>(1), 1);
|
||||
|
||||
ASSERT_EQ(registry.get<int>(entity), 1);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, EmplaceOrReplace) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.emplace_or_replace<int>(3);, "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Patch) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
registry.emplace<int>(entity, 3);
|
||||
|
||||
ASSERT_TRUE(handle.all_of<int>());
|
||||
ASSERT_EQ(handle.patch<int>([](auto &comp) { comp = 1; }), 1);
|
||||
|
||||
ASSERT_EQ(registry.get<int>(entity), 1);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, Patch) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.patch<int>([](auto &comp) { comp = 1; });, "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Replace) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
registry.emplace<int>(entity, 3);
|
||||
|
||||
ASSERT_TRUE(handle.all_of<int>());
|
||||
ASSERT_EQ(handle.replace<int>(1), 1);
|
||||
|
||||
ASSERT_EQ(registry.get<int>(entity), 1);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, Replace) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.replace<int>(3);, "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Remove) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_FALSE(handle.all_of<int>());
|
||||
ASSERT_EQ(handle.remove<int>(), 0u);
|
||||
|
||||
registry.emplace<int>(entity, 3);
|
||||
|
||||
ASSERT_TRUE(handle.all_of<int>());
|
||||
ASSERT_EQ(handle.remove<int>(), 1u);
|
||||
|
||||
ASSERT_FALSE(handle.all_of<int>());
|
||||
ASSERT_EQ(handle.remove<int>(), 0u);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, Remove) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.remove<int>();, "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Erase) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
registry.emplace<int>(entity, 3);
|
||||
|
||||
ASSERT_TRUE(handle.all_of<int>());
|
||||
|
||||
handle.erase<int>();
|
||||
|
||||
ASSERT_FALSE(handle.all_of<int>());
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, Erase) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.erase<int>();, "");
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, AllAnyOf) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_FALSE((handle.all_of<int, char>()));
|
||||
ASSERT_FALSE((handle.any_of<int, char>()));
|
||||
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_FALSE((handle.all_of<int, char>()));
|
||||
ASSERT_TRUE((handle.any_of<int, char>()));
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_TRUE((handle.all_of<int, char>()));
|
||||
ASSERT_TRUE((handle.any_of<int, char>()));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(BasicHandleDeathTest, AllAnyOf) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
const handle_type handle{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const auto all_of = handle.template all_of<int>(), "");
|
||||
ASSERT_DEATH([[maybe_unused]] const auto any_of = handle.template any_of<int>(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Get) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
registry.emplace<int>(entity, 3);
|
||||
registry.emplace<char>(entity, 'c');
|
||||
|
||||
ASSERT_EQ(handle.get<int>(), 3);
|
||||
ASSERT_EQ((handle.get<int, const char>()), (std::make_tuple(3, 'c')));
|
||||
|
||||
std::get<0>(handle.get<int, char>()) = 1;
|
||||
std::get<1>(handle.get<int, char>()) = '\0';
|
||||
|
||||
ASSERT_EQ(registry.get<int>(entity), 1);
|
||||
ASSERT_EQ(registry.get<char>(entity), '\0');
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(BasicHandleDeathTest, Get) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
const handle_type handle{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const auto &elem = handle.template get<int>(), "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, GetOrEmplace) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_FALSE(registry.all_of<int>(entity));
|
||||
|
||||
ASSERT_EQ(handle.get_or_emplace<int>(3), 3);
|
||||
|
||||
ASSERT_TRUE(registry.all_of<int>(entity));
|
||||
ASSERT_EQ(registry.get<int>(entity), 3);
|
||||
|
||||
ASSERT_EQ(handle.get_or_emplace<int>(1), 3);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, GetOrEmplace) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] auto &&elem = handle.template get_or_emplace<int>(3), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, TryGet) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_EQ((handle.try_get<int, const char>()), (std::make_tuple(nullptr, nullptr)));
|
||||
|
||||
registry.emplace<int>(entity, 3);
|
||||
|
||||
ASSERT_NE(handle.try_get<int>(), nullptr);
|
||||
ASSERT_EQ(handle.try_get<char>(), nullptr);
|
||||
|
||||
ASSERT_EQ((*std::get<0>(handle.try_get<int, const char>())), 3);
|
||||
ASSERT_EQ((std::get<1>(handle.try_get<int, const char>())), nullptr);
|
||||
|
||||
*std::get<0>(handle.try_get<int, const char>()) = 1;
|
||||
|
||||
ASSERT_EQ(registry.get<int>(entity), 1);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(BasicHandleDeathTest, TryGet) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
const handle_type handle{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const auto *elem = handle.template try_get<int>(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Orphan) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_TRUE(handle.orphan());
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_FALSE(handle.orphan());
|
||||
|
||||
registry.erase<char>(entity);
|
||||
|
||||
ASSERT_FALSE(handle.orphan());
|
||||
|
||||
registry.erase<int>(entity);
|
||||
|
||||
ASSERT_TRUE(handle.orphan());
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(BasicHandleDeathTest, Orphan) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
const handle_type handle{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const auto result = handle.orphan(), "");
|
||||
}
|
||||
|
||||
/*
|
||||
TEST(BasicHandle, Component) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const 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 = 2; });
|
||||
|
||||
ASSERT_EQ(2, patched);
|
||||
ASSERT_EQ('a', handle.replace<char>('a'));
|
||||
ASSERT_TRUE((handle.all_of<int, char, double>()));
|
||||
ASSERT_EQ((std::make_tuple(2, '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(2, handle.get_or_emplace<int>(2));
|
||||
ASSERT_EQ(2, handle.get_or_emplace<int>(1));
|
||||
ASSERT_EQ(2, handle.get<int>());
|
||||
|
||||
ASSERT_EQ(2, *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, ImplicitConversion) {
|
||||
entt::registry registry;
|
||||
const entt::handle handle{registry, registry.create()};
|
||||
const entt::const_handle const_handle = handle;
|
||||
const entt::handle_view<int, char> handle_view = handle;
|
||||
const entt::const_handle_view<int> const_handle_view = handle_view;
|
||||
|
||||
handle.emplace<int>(2);
|
||||
|
||||
ASSERT_EQ(handle.get<int>(), const_handle.get<int>());
|
||||
ASSERT_EQ(const_handle.get<int>(), handle_view.get<int>());
|
||||
ASSERT_EQ(handle_view.get<int>(), const_handle_view.get<int>());
|
||||
ASSERT_EQ(const_handle_view.get<int>(), 2);
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Comparison) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
@@ -155,48 +549,37 @@ TYPED_TEST(BasicHandle, Comparison) {
|
||||
ASSERT_NE(handle.registry(), other.registry());
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Component) {
|
||||
TYPED_TEST(BasicHandle, Null) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
handle_type handle{};
|
||||
|
||||
ASSERT_TRUE(handle == entt::null);
|
||||
ASSERT_TRUE(entt::null == handle);
|
||||
|
||||
ASSERT_FALSE(handle != entt::null);
|
||||
ASSERT_FALSE(entt::null != handle);
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const 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));
|
||||
handle = handle_type{registry, entity};
|
||||
|
||||
const auto &patched = handle.patch<int>([](auto &comp) { comp = 2; });
|
||||
ASSERT_FALSE(handle == entt::null);
|
||||
ASSERT_FALSE(entt::null == handle);
|
||||
|
||||
ASSERT_EQ(2, patched);
|
||||
ASSERT_EQ('a', handle.replace<char>('a'));
|
||||
ASSERT_TRUE((handle.all_of<int, char, double>()));
|
||||
ASSERT_EQ((std::make_tuple(2, 'a', .3)), (handle.get<int, char, double>()));
|
||||
ASSERT_TRUE(handle != entt::null);
|
||||
ASSERT_TRUE(entt::null != handle);
|
||||
|
||||
handle.erase<char, double>();
|
||||
if constexpr(!std::is_const_v<typename handle_type::registry_type>) {
|
||||
handle.destroy();
|
||||
|
||||
ASSERT_TRUE(registry.storage<char>().empty());
|
||||
ASSERT_TRUE(registry.storage<double>().empty());
|
||||
ASSERT_EQ(0u, (handle.remove<char, double>()));
|
||||
ASSERT_TRUE(handle == entt::null);
|
||||
ASSERT_TRUE(entt::null == handle);
|
||||
|
||||
for(auto [id, pool]: handle.storage()) {
|
||||
ASSERT_EQ(id, entt::type_id<int>().hash());
|
||||
ASSERT_TRUE(pool.contains(handle.entity()));
|
||||
ASSERT_FALSE(handle != entt::null);
|
||||
ASSERT_FALSE(entt::null != handle);
|
||||
}
|
||||
|
||||
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(2, handle.get_or_emplace<int>(2));
|
||||
ASSERT_EQ(2, handle.get_or_emplace<int>(1));
|
||||
ASSERT_EQ(2, handle.get<int>());
|
||||
|
||||
ASSERT_EQ(2, *handle.try_get<int>());
|
||||
ASSERT_EQ(nullptr, handle.try_get<char>());
|
||||
ASSERT_EQ(nullptr, std::get<1>(handle.try_get<int, char, double>()));
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, FromEntity) {
|
||||
@@ -235,100 +618,3 @@ TEST(BasicHandle, Lifetime) {
|
||||
ASSERT_FALSE(registry.storage<int>().empty());
|
||||
ASSERT_NE(registry.storage<entt::entity>().free_list(), 0u);
|
||||
}
|
||||
|
||||
TEST(BasicHandle, ImplicitConversions) {
|
||||
entt::registry registry;
|
||||
const entt::handle handle{registry, registry.create()};
|
||||
const entt::const_handle const_handle = handle;
|
||||
const entt::handle_view<int, char> handle_view = handle;
|
||||
const entt::const_handle_view<int> const_handle_view = handle_view;
|
||||
|
||||
handle.emplace<int>(2);
|
||||
|
||||
ASSERT_EQ(handle.get<int>(), const_handle.get<int>());
|
||||
ASSERT_EQ(const_handle.get<int>(), handle_view.get<int>());
|
||||
ASSERT_EQ(handle_view.get<int>(), const_handle_view.get<int>());
|
||||
ASSERT_EQ(const_handle_view.get<int>(), 2);
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Storage) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const handle_type handle{registry, entity};
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(*handle.storage().begin()), std::pair<entt::id_type, entt::constness_as_t<entt::sparse_set, typename handle_type::registry_type> &>>();
|
||||
|
||||
ASSERT_EQ(handle.storage().begin(), handle.storage().end());
|
||||
|
||||
registry.storage<double>();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_NE(handle.storage().begin(), handle.storage().end());
|
||||
ASSERT_EQ(++handle.storage().begin(), handle.storage().end());
|
||||
ASSERT_EQ(handle.storage().begin()->second.type(), entt::type_id<int>());
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, HandleStorageIterator) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<double>(entity);
|
||||
// required to test the find-first initialization step
|
||||
registry.storage<entt::entity>().erase(entity);
|
||||
|
||||
const handle_type handle{registry, entity};
|
||||
auto iterable = handle.storage();
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity));
|
||||
ASSERT_FALSE(handle);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Null) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
handle_type handle{};
|
||||
|
||||
ASSERT_TRUE(handle == entt::null);
|
||||
ASSERT_TRUE(entt::null == handle);
|
||||
|
||||
ASSERT_FALSE(handle != entt::null);
|
||||
ASSERT_FALSE(entt::null != handle);
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
handle = handle_type{registry, entity};
|
||||
|
||||
ASSERT_FALSE(handle == entt::null);
|
||||
ASSERT_FALSE(entt::null == handle);
|
||||
|
||||
ASSERT_TRUE(handle != entt::null);
|
||||
ASSERT_TRUE(entt::null != handle);
|
||||
|
||||
if constexpr(!std::is_const_v<typename handle_type::registry_type>) {
|
||||
handle.destroy();
|
||||
|
||||
ASSERT_TRUE(handle == entt::null);
|
||||
ASSERT_TRUE(entt::null == handle);
|
||||
|
||||
ASSERT_FALSE(handle != entt::null);
|
||||
ASSERT_FALSE(entt::null != handle);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user