Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8de85b961 | ||
|
|
90742a72b0 | ||
|
|
7bbd7d82b0 | ||
|
|
965c440d86 | ||
|
|
6b2aff821c | ||
|
|
84d9125ea1 | ||
|
|
9b969e762c | ||
|
|
2695d48ba7 | ||
|
|
aba2a6b17d | ||
|
|
7b87d17d22 |
1
AUTHORS
1
AUTHORS
@@ -11,6 +11,7 @@ ceeac
|
|||||||
ColinH
|
ColinH
|
||||||
corystegel
|
corystegel
|
||||||
Croydon
|
Croydon
|
||||||
|
cschreib
|
||||||
cugone
|
cugone
|
||||||
dbacchet
|
dbacchet
|
||||||
dBagrat
|
dBagrat
|
||||||
|
|||||||
7
TODO
7
TODO
@@ -8,16 +8,15 @@ EXAMPLES
|
|||||||
|
|
||||||
WIP:
|
WIP:
|
||||||
* view/group: no storage_traits dependency -> use storage instead of components for the definition
|
* view/group: no storage_traits dependency -> use storage instead of components for the definition
|
||||||
* resource<T>::operator</<=/>/>=
|
|
||||||
* simplify emitter (see uvw), runtime events
|
|
||||||
* basic_storage::bind for cross-registry setups
|
* basic_storage::bind for cross-registry setups
|
||||||
* uses-allocator construction: any (with allocator support), poly, ...
|
* uses-allocator construction: any (with allocator support), poly, ...
|
||||||
* process scheduler: reviews, use free lists internally
|
* process scheduler: reviews, use free lists internally
|
||||||
* iterator based try_emplace vs try_insert for perf reasons
|
* iterator based try_emplace vs try_insert for perf reasons
|
||||||
* dedicated entity storage, in-place O(1) release/destroy for non-orphaned entities, out-of-sync model
|
* dedicated entity storage, in-place O(1) release/destroy for non-orphaned entities, out-of-sync model
|
||||||
* entity-only and exclude-only views
|
* entity-only and exclude-only views
|
||||||
* custom allocators all over
|
* custom allocators all over (sigh storage mixin, registry, ...)
|
||||||
* use ENTT_NOEXCEPT_IF as appropriate (ie make compressed_pair conditionally noexcept)
|
* consider removing ENTT_NOEXCEPT, use ENTT_NOEXCEPT_IF (or noexcept(...)) as appropriate in any case (ie make compressed_pair conditionally noexcept)
|
||||||
|
* add test for maximum number of entities reached
|
||||||
|
|
||||||
WIP:
|
WIP:
|
||||||
* add user data to type_info
|
* add user data to type_info
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,19 +4,22 @@
|
|||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION)
|
#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION)
|
||||||
# define ENTT_NOEXCEPT noexcept
|
|
||||||
# define ENTT_NOEXCEPT_IF(expr) noexcept(expr)
|
|
||||||
# define ENTT_THROW throw
|
# define ENTT_THROW throw
|
||||||
# define ENTT_TRY try
|
# define ENTT_TRY try
|
||||||
# define ENTT_CATCH catch(...)
|
# define ENTT_CATCH catch(...)
|
||||||
#else
|
#else
|
||||||
# define ENTT_NOEXCEPT
|
|
||||||
# define ENTT_NOEXCEPT_IF(...)
|
|
||||||
# define ENTT_THROW
|
# define ENTT_THROW
|
||||||
# define ENTT_TRY if(true)
|
# define ENTT_TRY if(true)
|
||||||
# define ENTT_CATCH if(false)
|
# define ENTT_CATCH if(false)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef ENTT_NOEXCEPT
|
||||||
|
# define ENTT_NOEXCEPT noexcept
|
||||||
|
# define ENTT_NOEXCEPT_IF(expr) noexcept(expr)
|
||||||
|
# else
|
||||||
|
# define ENTT_NOEXCEPT_IF(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENTT_USE_ATOMIC
|
#ifdef ENTT_USE_ATOMIC
|
||||||
# include <atomic>
|
# include <atomic>
|
||||||
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
|
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#define ENTT_VERSION_MAJOR 3
|
#define ENTT_VERSION_MAJOR 3
|
||||||
#define ENTT_VERSION_MINOR 10
|
#define ENTT_VERSION_MINOR 10
|
||||||
#define ENTT_VERSION_PATCH 0
|
#define ENTT_VERSION_PATCH 2
|
||||||
|
|
||||||
#define ENTT_VERSION \
|
#define ENTT_VERSION \
|
||||||
ENTT_XSTR(ENTT_VERSION_MAJOR) \
|
ENTT_XSTR(ENTT_VERSION_MAJOR) \
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ class basic_registry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto generate_identifier(const std::size_t pos) ENTT_NOEXCEPT {
|
auto generate_identifier(const std::size_t pos) ENTT_NOEXCEPT {
|
||||||
ENTT_ASSERT(pos < entity_traits::to_integral(null), "No entities available");
|
ENTT_ASSERT(pos < entity_traits::to_entity(null), "No entities available");
|
||||||
return entity_traits::combine(static_cast<typename entity_traits::entity_type>(pos), {});
|
return entity_traits::combine(static_cast<typename entity_traits::entity_type>(pos), {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -240,12 +240,14 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual void swap_and_pop(basic_iterator first, basic_iterator last) {
|
virtual void swap_and_pop(basic_iterator first, basic_iterator last) {
|
||||||
for(; first != last; ++first) {
|
for(; first != last; ++first) {
|
||||||
sparse_ref(packed.back()) = entity_traits::combine(static_cast<typename entity_traits::entity_type>(first.index()), entity_traits::to_integral(packed.back()));
|
auto &self = sparse_ref(*first);
|
||||||
const auto entt = std::exchange(packed[first.index()], packed.back());
|
const auto entt = entity_traits::to_entity(self);
|
||||||
|
sparse_ref(packed.back()) = entity_traits::combine(entt, entity_traits::to_integral(packed.back()));
|
||||||
|
packed[static_cast<size_type>(entt)] = packed.back();
|
||||||
// unnecessary but it helps to detect nasty bugs
|
// unnecessary but it helps to detect nasty bugs
|
||||||
ENTT_ASSERT((packed.back() = tombstone, true), "");
|
ENTT_ASSERT((packed.back() = tombstone, true), "");
|
||||||
// lazy self-assignment guard
|
// lazy self-assignment guard
|
||||||
sparse_ref(entt) = null;
|
self = null;
|
||||||
packed.pop_back();
|
packed.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,8 +259,8 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual void in_place_pop(basic_iterator first, basic_iterator last) {
|
virtual void in_place_pop(basic_iterator first, basic_iterator last) {
|
||||||
for(; first != last; ++first) {
|
for(; first != last; ++first) {
|
||||||
sparse_ref(*first) = null;
|
const auto entt = entity_traits::to_entity(std::exchange(sparse_ref(*first), null));
|
||||||
packed[first.index()] = std::exchange(free_list, entity_traits::combine(static_cast<typename entity_traits::entity_type>(first.index()), entity_traits::reserved));
|
packed[static_cast<size_type>(entt)] = std::exchange(free_list, entity_traits::combine(entt, entity_traits::reserved));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,14 +55,12 @@ struct basic_meta_sequence_container_traits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static iterator iter(any &container, const bool as_end) {
|
[[nodiscard]] static iterator iter(any &container, const bool as_end) {
|
||||||
using std::begin;
|
|
||||||
|
|
||||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||||
return iterator{begin(*cont), static_cast<typename iterator::difference_type>(as_end * cont->size())};
|
return iterator{*cont, static_cast<typename iterator::difference_type>(as_end * cont->size())};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type &as_const = any_cast<const Type &>(container);
|
const Type &as_const = any_cast<const Type &>(container);
|
||||||
return iterator{begin(as_const), static_cast<typename iterator::difference_type>(as_end * as_const.size())};
|
return iterator{as_const, static_cast<typename iterator::difference_type>(as_end * as_const.size())};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static iterator insert([[maybe_unused]] any &container, [[maybe_unused]] const std::ptrdiff_t offset, [[maybe_unused]] meta_any &value) {
|
[[nodiscard]] static iterator insert([[maybe_unused]] any &container, [[maybe_unused]] const std::ptrdiff_t offset, [[maybe_unused]] meta_any &value) {
|
||||||
@@ -70,10 +68,9 @@ struct basic_meta_sequence_container_traits {
|
|||||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||||
// this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
|
// this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
|
||||||
if(value.allow_cast<typename Type::const_reference>() || value.allow_cast<typename Type::value_type>()) {
|
if(value.allow_cast<typename Type::const_reference>() || value.allow_cast<typename Type::value_type>()) {
|
||||||
using std::begin;
|
|
||||||
const auto *element = value.try_cast<std::remove_reference_t<typename Type::const_reference>>();
|
const auto *element = value.try_cast<std::remove_reference_t<typename Type::const_reference>>();
|
||||||
const auto curr = cont->insert(begin(*cont) + offset, element ? *element : value.cast<typename Type::value_type>());
|
const auto curr = cont->insert(cont->begin() + offset, element ? *element : value.cast<typename Type::value_type>());
|
||||||
return iterator{curr, curr - begin(*cont)};
|
return iterator{*cont, curr - cont->begin()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,9 +81,8 @@ struct basic_meta_sequence_container_traits {
|
|||||||
[[nodiscard]] static iterator erase([[maybe_unused]] any &container, [[maybe_unused]] const std::ptrdiff_t offset) {
|
[[nodiscard]] static iterator erase([[maybe_unused]] any &container, [[maybe_unused]] const std::ptrdiff_t offset) {
|
||||||
if constexpr(is_dynamic_sequence_container<Type>::value) {
|
if constexpr(is_dynamic_sequence_container<Type>::value) {
|
||||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||||
using std::begin;
|
const auto curr = cont->erase(cont->begin() + offset);
|
||||||
const auto curr = cont->erase(begin(*cont) + offset);
|
return iterator{*cont, curr - cont->begin()};
|
||||||
return iterator{curr, curr - begin(*cont)};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,15 +111,12 @@ struct basic_meta_associative_container_traits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static iterator iter(any &container, const bool as_end) {
|
[[nodiscard]] static iterator iter(any &container, const bool as_end) {
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
|
|
||||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||||
return iterator{std::integral_constant<bool, key_only>{}, as_end ? end(*cont) : begin(*cont)};
|
return iterator{std::integral_constant<bool, key_only>{}, as_end ? cont->end() : cont->begin()};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &as_const = any_cast<const Type &>(container);
|
const auto &as_const = any_cast<const Type &>(container);
|
||||||
return iterator{std::integral_constant<bool, key_only>{}, as_end ? end(as_const) : begin(as_const)};
|
return iterator{std::integral_constant<bool, key_only>{}, as_end ? as_const.end() : as_const.begin()};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] static bool insert(any &container, meta_any &key, [[maybe_unused]] meta_any &value) {
|
[[nodiscard]] static bool insert(any &container, meta_any &key, [[maybe_unused]] meta_any &value) {
|
||||||
|
|||||||
@@ -1070,6 +1070,15 @@ public:
|
|||||||
return !!(node->traits & internal::meta_traits::is_pointer);
|
return !!(node->traits & internal::meta_traits::is_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides the type for which the pointer is defined.
|
||||||
|
* @return The type for which the pointer is defined or this type if it
|
||||||
|
* doesn't refer to a pointer type.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] meta_type remove_pointer() const ENTT_NOEXCEPT {
|
||||||
|
return node->remove_pointer();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks whether a type is a pointer-like type or not.
|
* @brief Checks whether a type is a pointer-like type or not.
|
||||||
* @return True if the underlying type is a pointer-like one, false
|
* @return True if the underlying type is a pointer-like one, false
|
||||||
@@ -1464,11 +1473,11 @@ public:
|
|||||||
offset{},
|
offset{},
|
||||||
handle{} {}
|
handle{} {}
|
||||||
|
|
||||||
template<typename It>
|
template<typename Type>
|
||||||
explicit meta_iterator(It iter, const difference_type init) ENTT_NOEXCEPT
|
explicit meta_iterator(Type &cont, const difference_type init) ENTT_NOEXCEPT
|
||||||
: deref{&deref_fn<It>},
|
: deref{&deref_fn<decltype(cont.begin())>},
|
||||||
offset{init},
|
offset{init},
|
||||||
handle{std::move(iter)} {}
|
handle{cont.begin()} {}
|
||||||
|
|
||||||
meta_iterator &operator++() ENTT_NOEXCEPT {
|
meta_iterator &operator++() ENTT_NOEXCEPT {
|
||||||
return ++offset, *this;
|
return ++offset, *this;
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ struct meta_type_node {
|
|||||||
meta_type_node *next;
|
meta_type_node *next;
|
||||||
meta_prop_node *prop;
|
meta_prop_node *prop;
|
||||||
const size_type size_of;
|
const size_type size_of;
|
||||||
|
meta_type_node *(*const remove_pointer)() ENTT_NOEXCEPT;
|
||||||
meta_any (*const default_constructor)();
|
meta_any (*const default_constructor)();
|
||||||
double (*const conversion_helper)(void *, const void *);
|
double (*const conversion_helper)(void *, const void *);
|
||||||
const meta_template_node *const templ;
|
const meta_template_node *const templ;
|
||||||
@@ -180,6 +181,7 @@ public:
|
|||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
size_of_v<Type>,
|
size_of_v<Type>,
|
||||||
|
&meta_node<std::remove_cv_t<std::remove_reference_t<std::remove_pointer_t<Type>>>>::resolve,
|
||||||
meta_default_constructor(),
|
meta_default_constructor(),
|
||||||
meta_conversion_helper(),
|
meta_conversion_helper(),
|
||||||
meta_template_info()
|
meta_template_info()
|
||||||
|
|||||||
@@ -178,11 +178,65 @@ template<typename Res, typename Other>
|
|||||||
* @param rhs A valid handle.
|
* @param rhs A valid handle.
|
||||||
* @return False if both handles refer to the same registry, true otherwise.
|
* @return False if both handles refer to the same registry, true otherwise.
|
||||||
*/
|
*/
|
||||||
template<typename ILhs, typename IRhs>
|
template<typename Res, typename Other>
|
||||||
[[nodiscard]] bool operator!=(const resource<ILhs> &lhs, const resource<IRhs> &rhs) ENTT_NOEXCEPT {
|
[[nodiscard]] bool operator!=(const resource<Res> &lhs, const resource<Other> &rhs) ENTT_NOEXCEPT {
|
||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compares two handles.
|
||||||
|
* @tparam Res Type of resource managed by the first handle.
|
||||||
|
* @tparam Other Type of resource managed by the second handle.
|
||||||
|
* @param lhs A valid handle.
|
||||||
|
* @param rhs A valid handle.
|
||||||
|
* @return True if the first handle is less than the second, false otherwise.
|
||||||
|
*/
|
||||||
|
template<typename Res, typename Other>
|
||||||
|
[[nodiscard]] bool operator<(const resource<Res> &lhs, const resource<Other> &rhs) ENTT_NOEXCEPT {
|
||||||
|
return (std::addressof(*lhs) < std::addressof(*rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compares two handles.
|
||||||
|
* @tparam Res Type of resource managed by the first handle.
|
||||||
|
* @tparam Other Type of resource managed by the second handle.
|
||||||
|
* @param lhs A valid handle.
|
||||||
|
* @param rhs A valid handle.
|
||||||
|
* @return True if the first handle is greater than the second, false otherwise.
|
||||||
|
*/
|
||||||
|
template<typename Res, typename Other>
|
||||||
|
[[nodiscard]] bool operator>(const resource<Res> &lhs, const resource<Other> &rhs) ENTT_NOEXCEPT {
|
||||||
|
return (std::addressof(*lhs) > std::addressof(*rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compares two handles.
|
||||||
|
* @tparam Res Type of resource managed by the first handle.
|
||||||
|
* @tparam Other Type of resource managed by the second handle.
|
||||||
|
* @param lhs A valid handle.
|
||||||
|
* @param rhs A valid handle.
|
||||||
|
* @return True if the first handle is less than or equal to the second, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
template<typename Res, typename Other>
|
||||||
|
[[nodiscard]] bool operator<=(const resource<Res> &lhs, const resource<Other> &rhs) ENTT_NOEXCEPT {
|
||||||
|
return !(lhs > rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compares two handles.
|
||||||
|
* @tparam Res Type of resource managed by the first handle.
|
||||||
|
* @tparam Other Type of resource managed by the second handle.
|
||||||
|
* @param lhs A valid handle.
|
||||||
|
* @param rhs A valid handle.
|
||||||
|
* @return True if the first handle is greater than or equal to the second,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
template<typename Res, typename Other>
|
||||||
|
[[nodiscard]] bool operator>=(const resource<Res> &lhs, const resource<Other> &rhs) ENTT_NOEXCEPT {
|
||||||
|
return !(lhs < rhs);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace entt
|
} // namespace entt
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -428,6 +428,22 @@ TEST(SparseSetDeathTest, Erase) {
|
|||||||
ASSERT_DEATH(set.erase(entt::null), "");
|
ASSERT_DEATH(set.erase(entt::null), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SparseSet, CrossErase) {
|
||||||
|
using traits_type = entt::entt_traits<entt::entity>;
|
||||||
|
|
||||||
|
entt::sparse_set set;
|
||||||
|
entt::sparse_set other;
|
||||||
|
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||||
|
|
||||||
|
set.insert(std::begin(entities), std::end(entities));
|
||||||
|
other.emplace(entities[1u]);
|
||||||
|
set.erase(other.begin(), other.end());
|
||||||
|
|
||||||
|
ASSERT_TRUE(set.contains(entities[0u]));
|
||||||
|
ASSERT_FALSE(set.contains(entities[1u]));
|
||||||
|
ASSERT_EQ(set.data()[0u], entities[0u]);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(SparseSet, StableErase) {
|
TEST(SparseSet, StableErase) {
|
||||||
using traits_type = entt::entt_traits<entt::entity>;
|
using traits_type = entt::entt_traits<entt::entity>;
|
||||||
|
|
||||||
@@ -552,6 +568,22 @@ TEST(SparseSetDeathTest, StableErase) {
|
|||||||
ASSERT_DEATH(set.erase(entt::null), "");
|
ASSERT_DEATH(set.erase(entt::null), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SparseSet, CrossStableErase) {
|
||||||
|
using traits_type = entt::entt_traits<entt::entity>;
|
||||||
|
|
||||||
|
entt::sparse_set set{entt::deletion_policy::in_place};
|
||||||
|
entt::sparse_set other{entt::deletion_policy::in_place};
|
||||||
|
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||||
|
|
||||||
|
set.insert(std::begin(entities), std::end(entities));
|
||||||
|
other.emplace(entities[1u]);
|
||||||
|
set.erase(other.begin(), other.end());
|
||||||
|
|
||||||
|
ASSERT_TRUE(set.contains(entities[0u]));
|
||||||
|
ASSERT_FALSE(set.contains(entities[1u]));
|
||||||
|
ASSERT_EQ(set.data()[0u], entities[0u]);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(SparseSet, Remove) {
|
TEST(SparseSet, Remove) {
|
||||||
using traits_type = entt::entt_traits<entt::entity>;
|
using traits_type = entt::entt_traits<entt::entity>;
|
||||||
|
|
||||||
@@ -609,6 +641,22 @@ TEST(SparseSet, Remove) {
|
|||||||
ASSERT_EQ(set.remove(entt::null), 0u);
|
ASSERT_EQ(set.remove(entt::null), 0u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SparseSet, CrossRemove) {
|
||||||
|
using traits_type = entt::entt_traits<entt::entity>;
|
||||||
|
|
||||||
|
entt::sparse_set set;
|
||||||
|
entt::sparse_set other;
|
||||||
|
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||||
|
|
||||||
|
set.insert(std::begin(entities), std::end(entities));
|
||||||
|
other.emplace(entities[1u]);
|
||||||
|
set.remove(other.begin(), other.end());
|
||||||
|
|
||||||
|
ASSERT_TRUE(set.contains(entities[0u]));
|
||||||
|
ASSERT_FALSE(set.contains(entities[1u]));
|
||||||
|
ASSERT_EQ(set.data()[0u], entities[0u]);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(SparseSet, StableRemove) {
|
TEST(SparseSet, StableRemove) {
|
||||||
using traits_type = entt::entt_traits<entt::entity>;
|
using traits_type = entt::entt_traits<entt::entity>;
|
||||||
|
|
||||||
@@ -739,6 +787,22 @@ TEST(SparseSet, StableRemove) {
|
|||||||
ASSERT_EQ(set.remove(entt::null), 0u);
|
ASSERT_EQ(set.remove(entt::null), 0u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SparseSet, CrossStableRemove) {
|
||||||
|
using traits_type = entt::entt_traits<entt::entity>;
|
||||||
|
|
||||||
|
entt::sparse_set set{entt::deletion_policy::in_place};
|
||||||
|
entt::sparse_set other{entt::deletion_policy::in_place};
|
||||||
|
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||||
|
|
||||||
|
set.insert(std::begin(entities), std::end(entities));
|
||||||
|
other.emplace(entities[1u]);
|
||||||
|
set.remove(other.begin(), other.end());
|
||||||
|
|
||||||
|
ASSERT_TRUE(set.contains(entities[0u]));
|
||||||
|
ASSERT_FALSE(set.contains(entities[1u]));
|
||||||
|
ASSERT_EQ(set.data()[0u], entities[0u]);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(SparseSet, Compact) {
|
TEST(SparseSet, Compact) {
|
||||||
entt::sparse_set set{entt::deletion_policy::in_place};
|
entt::sparse_set set{entt::deletion_policy::in_place};
|
||||||
|
|
||||||
|
|||||||
@@ -147,11 +147,16 @@ TEST_F(MetaContainer, StdVector) {
|
|||||||
ASSERT_EQ(view.begin()->cast<int>(), 0);
|
ASSERT_EQ(view.begin()->cast<int>(), 0);
|
||||||
ASSERT_EQ((++view.begin())->cast<int>(), 1);
|
ASSERT_EQ((++view.begin())->cast<int>(), 1);
|
||||||
|
|
||||||
|
ret = view.insert(view.end(), 42);
|
||||||
|
|
||||||
|
ASSERT_TRUE(ret);
|
||||||
|
ASSERT_EQ(*ret, 42);
|
||||||
|
|
||||||
it = view.begin();
|
it = view.begin();
|
||||||
ret = view.erase(it);
|
ret = view.erase(it);
|
||||||
|
|
||||||
ASSERT_TRUE(ret);
|
ASSERT_TRUE(ret);
|
||||||
ASSERT_EQ(view.size(), 4u);
|
ASSERT_EQ(view.size(), 5u);
|
||||||
ASSERT_EQ(ret->cast<int>(), 1);
|
ASSERT_EQ(ret->cast<int>(), 1);
|
||||||
|
|
||||||
ASSERT_TRUE(view.clear());
|
ASSERT_TRUE(view.clear());
|
||||||
|
|||||||
@@ -261,6 +261,13 @@ TEST_F(MetaType, Traits) {
|
|||||||
ASSERT_FALSE(entt::resolve<std::vector<int>>().is_associative_container());
|
ASSERT_FALSE(entt::resolve<std::vector<int>>().is_associative_container());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(MetaType, RemovePointer) {
|
||||||
|
ASSERT_EQ(entt::resolve<void *>().remove_pointer(), entt::resolve<void>());
|
||||||
|
ASSERT_EQ(entt::resolve<char **>().remove_pointer(), entt::resolve<char *>());
|
||||||
|
ASSERT_EQ(entt::resolve<int (*)(char, double)>().remove_pointer(), entt::resolve<int(char, double)>());
|
||||||
|
ASSERT_EQ(entt::resolve<derived_t>().remove_pointer(), entt::resolve<derived_t>());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(MetaType, TemplateInfo) {
|
TEST_F(MetaType, TemplateInfo) {
|
||||||
ASSERT_FALSE(entt::resolve<int>().is_template_specialization());
|
ASSERT_FALSE(entt::resolve<int>().is_template_specialization());
|
||||||
ASSERT_EQ(entt::resolve<int>().template_arity(), 0u);
|
ASSERT_EQ(entt::resolve<int>().template_arity(), 0u);
|
||||||
|
|||||||
@@ -128,3 +128,17 @@ TEST(Resource, DynamicResourceHandleCast) {
|
|||||||
ASSERT_FALSE(cast);
|
ASSERT_FALSE(cast);
|
||||||
ASSERT_EQ(resource.use_count(), 1u);
|
ASSERT_EQ(resource.use_count(), 1u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Resource, Comparison) {
|
||||||
|
entt::resource<derived> resource{std::make_shared<derived>()};
|
||||||
|
entt::resource<const base> other = resource;
|
||||||
|
|
||||||
|
ASSERT_TRUE(resource == other);
|
||||||
|
ASSERT_FALSE(resource != other);
|
||||||
|
|
||||||
|
ASSERT_FALSE(resource < other);
|
||||||
|
ASSERT_FALSE(resource > other);
|
||||||
|
|
||||||
|
ASSERT_TRUE(resource <= other);
|
||||||
|
ASSERT_TRUE(resource >= other);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user