From dc4e5ddc3cee8268c99d55788c7327b76cd88593 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Fri, 8 Jun 2018 22:30:50 +0200 Subject: [PATCH] review: iterators (sparse set/view) --- TODO | 3 + src/entt/entity/entt_traits.hpp | 16 ++- src/entt/entity/sparse_set.hpp | 170 ++++++++++++++++++++---- src/entt/entity/view.hpp | 76 ++++++----- test/entt/entity/sparse_set.cpp | 224 +++++++++++++++++++++++++------- test/entt/entity/view.cpp | 158 ++++++++-------------- 6 files changed, 440 insertions(+), 207 deletions(-) diff --git a/TODO b/TODO index aed6ea809..f901b9fb1 100644 --- a/TODO +++ b/TODO @@ -10,4 +10,7 @@ * improve CMake interface, see mail from Malte * is registry/utility.hpp really required? * "singleton mode" for tags (see #66) +* add a shortcut to destroy all the entities that have components X, Y, Z (view and registry?) +* add operator[] to views if possible +* C++17. That's all. * AOB diff --git a/src/entt/entity/entt_traits.hpp b/src/entt/entity/entt_traits.hpp index 1114938b1..667f9dd85 100644 --- a/src/entt/entity/entt_traits.hpp +++ b/src/entt/entity/entt_traits.hpp @@ -32,6 +32,8 @@ struct entt_traits { using entity_type = std::uint16_t; /*! @brief Underlying version type. */ using version_type = std::uint8_t; + /*! @brief Difference type. */ + using difference_type = std::int32_t; /*! @brief Mask to use to get the entity number out of an identifier. */ static constexpr auto entity_mask = 0xFFF; @@ -56,6 +58,8 @@ struct entt_traits { using entity_type = std::uint32_t; /*! @brief Underlying version type. */ using version_type = std::uint16_t; + /*! @brief Difference type. */ + using difference_type = std::int64_t; /*! @brief Mask to use to get the entity number out of an identifier. */ static constexpr auto entity_mask = 0xFFFFF; @@ -71,8 +75,8 @@ struct entt_traits { * * A 64 bits entity identifier guarantees: * - * * 40 bits for the entity number (an indecently large number). - * * 24 bit for the version (an indecently large number). + * * 32 bits for the entity number (an indecently large number). + * * 32 bit for the version (an indecently large number). */ template<> struct entt_traits { @@ -80,13 +84,15 @@ struct entt_traits { using entity_type = std::uint64_t; /*! @brief Underlying version type. */ using version_type = std::uint32_t; + /*! @brief Difference type. */ + using difference_type = std::int64_t; /*! @brief Mask to use to get the entity number out of an identifier. */ - static constexpr auto entity_mask = 0xFFFFFFFFFF; + static constexpr auto entity_mask = 0xFFFFFFFF; /*! @brief Mask to use to get the version out of an identifier. */ - static constexpr auto version_mask = 0xFFFFFF; + static constexpr auto version_mask = 0xFFFFFFFF; /*! @brief Extent of the entity number within an identifier. */ - static constexpr auto entity_shift = 40; + static constexpr auto entity_shift = 32; }; diff --git a/src/entt/entity/sparse_set.hpp b/src/entt/entity/sparse_set.hpp index bd4d9575d..eaf888ac3 100644 --- a/src/entt/entity/sparse_set.hpp +++ b/src/entt/entity/sparse_set.hpp @@ -59,17 +59,34 @@ template class SparseSet { using traits_type = entt_traits; - struct Iterator final { - using difference_type = std::size_t; - using value_type = Entity; - using pointer = const value_type *; - using reference = value_type; - using iterator_category = std::input_iterator_tag; + class Iterator final { + friend class SparseSet; - Iterator(pointer direct, std::size_t pos) + using entity_type = Entity; + using pos_type = typename traits_type::difference_type; + + Iterator(const entity_type *direct, pos_type pos) ENTT_NOEXCEPT : direct{direct}, pos{pos} {} + public: + using difference_type = pos_type; + using value_type = const entity_type; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::random_access_iterator_tag; + + Iterator() ENTT_NOEXCEPT = default; + + Iterator(const Iterator &) ENTT_NOEXCEPT = default; + Iterator & operator=(const Iterator &) ENTT_NOEXCEPT = default; + + friend void swap(Iterator &lhs, Iterator &rhs) ENTT_NOEXCEPT { + using std::swap; + swap(lhs.direct, rhs.direct); + swap(lhs.pos, rhs.pos); + } + Iterator & operator++() ENTT_NOEXCEPT { return --pos, *this; } @@ -79,6 +96,15 @@ class SparseSet { return ++(*this), orig; } + Iterator & operator--() ENTT_NOEXCEPT { + return ++pos, *this; + } + + Iterator operator--(int) ENTT_NOEXCEPT { + Iterator orig = *this; + return --(*this), orig; + } + Iterator & operator+=(const difference_type value) ENTT_NOEXCEPT { pos -= value; return *this; @@ -88,6 +114,22 @@ class SparseSet { return Iterator{direct, pos-value}; } + inline Iterator & operator-=(const difference_type value) ENTT_NOEXCEPT { + return (*this += -value); + } + + inline Iterator operator-(const difference_type value) const ENTT_NOEXCEPT { + return (*this + -value); + } + + difference_type operator-(const Iterator &other) const ENTT_NOEXCEPT { + return other.pos - pos; + } + + reference operator[](const difference_type value) const ENTT_NOEXCEPT { + return direct[pos-value-1]; + } + bool operator==(const Iterator &other) const ENTT_NOEXCEPT { return other.pos == pos; } @@ -96,13 +138,33 @@ class SparseSet { return !(*this == other); } - reference operator*() const ENTT_NOEXCEPT { - return direct[pos-1]; + bool operator<(const Iterator &other) const ENTT_NOEXCEPT { + return pos > other.pos; + } + + bool operator>(const Iterator &other) const ENTT_NOEXCEPT { + return pos < other.pos; + } + + inline bool operator<=(const Iterator &other) const ENTT_NOEXCEPT { + return !(*this > other); + } + + inline bool operator>=(const Iterator &other) const ENTT_NOEXCEPT { + return !(*this < other); + } + + pointer operator->() const ENTT_NOEXCEPT { + return (direct+pos-1); + } + + inline reference operator*() const ENTT_NOEXCEPT { + return *operator->(); } private: pointer direct; - std::size_t pos; + pos_type pos; }; static constexpr auto pending = ~typename traits_type::entity_type{}; @@ -215,7 +277,8 @@ public: * @return An iterator to the first entity of the internal packed array. */ const_iterator_type cbegin() const ENTT_NOEXCEPT { - return const_iterator_type{direct.data(), direct.size()}; + const typename traits_type::difference_type pos = direct.size(); + return const_iterator_type{direct.data(), pos}; } /** @@ -500,19 +563,37 @@ private: template class SparseSet: public SparseSet { using underlying_type = SparseSet; + using traits_type = entt_traits; template - struct Iterator final { - using difference_type = std::size_t; - using value_type = std::conditional_t; - using pointer = value_type *; - using reference = value_type &; - using iterator_category = std::input_iterator_tag; + class Iterator final { + friend class SparseSet; - Iterator(pointer instances, std::size_t pos) + using instance_type = std::conditional_t; + using pos_type = typename traits_type::difference_type; + + Iterator(instance_type *instances, pos_type pos) ENTT_NOEXCEPT : instances{instances}, pos{pos} {} + public: + using difference_type = pos_type; + using value_type = instance_type; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::random_access_iterator_tag; + + Iterator() ENTT_NOEXCEPT = default; + + Iterator(const Iterator &) ENTT_NOEXCEPT = default; + Iterator & operator=(const Iterator &) ENTT_NOEXCEPT = default; + + friend void swap(Iterator &lhs, Iterator &rhs) ENTT_NOEXCEPT { + using std::swap; + swap(lhs.instances, rhs.instances); + swap(lhs.pos, rhs.pos); + } + Iterator & operator++() ENTT_NOEXCEPT { return --pos, *this; } @@ -522,6 +603,15 @@ class SparseSet: public SparseSet { return ++(*this), orig; } + Iterator & operator--() ENTT_NOEXCEPT { + return ++pos, *this; + } + + Iterator operator--(int) ENTT_NOEXCEPT { + Iterator orig = *this; + return --(*this), orig; + } + Iterator & operator+=(const difference_type value) ENTT_NOEXCEPT { pos -= value; return *this; @@ -531,6 +621,22 @@ class SparseSet: public SparseSet { return Iterator{instances, pos-value}; } + inline Iterator & operator-=(const difference_type value) ENTT_NOEXCEPT { + return (*this += -value); + } + + inline Iterator operator-(const difference_type value) const ENTT_NOEXCEPT { + return (*this + -value); + } + + difference_type operator-(const Iterator &other) const ENTT_NOEXCEPT { + return other.pos - pos; + } + + reference operator[](const difference_type value) const ENTT_NOEXCEPT { + return instances[pos-value-1]; + } + bool operator==(const Iterator &other) const ENTT_NOEXCEPT { return other.pos == pos; } @@ -539,17 +645,33 @@ class SparseSet: public SparseSet { return !(*this == other); } - reference operator*() const ENTT_NOEXCEPT { - return instances[pos-1]; + bool operator<(const Iterator &other) const ENTT_NOEXCEPT { + return pos > other.pos; + } + + bool operator>(const Iterator &other) const ENTT_NOEXCEPT { + return pos < other.pos; + } + + inline bool operator<=(const Iterator &other) const ENTT_NOEXCEPT { + return !(*this > other); + } + + inline bool operator>=(const Iterator &other) const ENTT_NOEXCEPT { + return !(*this < other); } pointer operator->() const ENTT_NOEXCEPT { return (instances+pos-1); } + inline reference operator*() const ENTT_NOEXCEPT { + return *operator->(); + } + private: pointer instances; - std::size_t pos; + difference_type pos; }; public: @@ -643,7 +765,8 @@ public: * @return An iterator to the first instance of the given type. */ const_iterator_type cbegin() const ENTT_NOEXCEPT { - return const_iterator_type{instances.data(), instances.size()}; + const typename traits_type::difference_type pos = instances.size(); + return const_iterator_type{instances.data(), pos}; } /** @@ -675,7 +798,8 @@ public: * @return An iterator to the first instance of the given type. */ iterator_type begin() ENTT_NOEXCEPT { - return iterator_type{instances.data(), instances.size()}; + const typename traits_type::difference_type pos = instances.size(); + return iterator_type{instances.data(), pos}; } /** diff --git a/src/entt/entity/view.hpp b/src/entt/entity/view.hpp index 9e3ccb604..3754734c6 100644 --- a/src/entt/entity/view.hpp +++ b/src/entt/entity/view.hpp @@ -2,6 +2,7 @@ #define ENTT_ENTITY_VIEW_HPP +#include #include #include #include @@ -469,8 +470,26 @@ class View final { using traits_type = entt_traits; class Iterator { + friend class View; + using size_type = typename view_type::size_type; + Iterator(unchecked_type unchecked, underlying_iterator_type begin, underlying_iterator_type end) ENTT_NOEXCEPT + : unchecked{unchecked}, + begin{begin}, + end{end}, + extent{min(std::make_index_sequence{})} + { + if(begin != end && !valid()) { + ++(*this); + } + } + + template + size_type min(std::index_sequence) const ENTT_NOEXCEPT { + return std::min({ std::get(unchecked)->extent()... }); + } + bool valid() const ENTT_NOEXCEPT { const auto entity = *begin; const auto sz = size_type(entity & traits_type::entity_mask); @@ -485,17 +504,19 @@ class View final { using value_type = typename underlying_iterator_type::value_type; using pointer = typename underlying_iterator_type::pointer; using reference = typename underlying_iterator_type::reference; - using iterator_category = typename underlying_iterator_type::iterator_category; + using iterator_category = std::forward_iterator_tag; - Iterator(unchecked_type unchecked, size_type extent, underlying_iterator_type begin, underlying_iterator_type end) ENTT_NOEXCEPT - : unchecked{unchecked}, - extent{extent}, - begin{begin}, - end{end} - { - if(begin != end && !valid()) { - ++(*this); - } + Iterator() ENTT_NOEXCEPT = default; + + Iterator(const Iterator &) ENTT_NOEXCEPT = default; + Iterator & operator=(const Iterator &) ENTT_NOEXCEPT = default; + + friend void swap(Iterator &lhs, Iterator &rhs) ENTT_NOEXCEPT { + using std::swap; + swap(lhs.unchecked, rhs.unchecked); + swap(lhs.extent, rhs.extent); + swap(lhs.begin, rhs.begin); + swap(lhs.end, rhs.end); } Iterator & operator++() ENTT_NOEXCEPT { @@ -507,14 +528,6 @@ class View final { return ++(*this), orig; } - Iterator & operator+=(const difference_type value) ENTT_NOEXCEPT { - return ((begin += value) != end && !valid()) ? ++(*this) : *this; - } - - Iterator operator+(const difference_type value) const ENTT_NOEXCEPT { - return Iterator{unchecked, extent, begin+value, end}; - } - bool operator==(const Iterator &other) const ENTT_NOEXCEPT { return other.begin == begin; } @@ -523,15 +536,19 @@ class View final { return !(*this == other); } - value_type operator*() const ENTT_NOEXCEPT { - return *begin; + pointer operator->() const ENTT_NOEXCEPT { + return begin.operator->(); + } + + inline reference operator*() const ENTT_NOEXCEPT { + return *operator->(); } private: - const unchecked_type unchecked; - const size_type extent; + unchecked_type unchecked; underlying_iterator_type begin; underlying_iterator_type end; + size_type extent; }; View(pool_type &... pools) ENTT_NOEXCEPT @@ -563,10 +580,6 @@ class View final { return other; } - typename view_type::size_type extent() const ENTT_NOEXCEPT { - return std::min({ pool().extent()... }); - } - template inline std::enable_if_t::value, const Other &> get(const component_iterator_type &it, const Entity) const ENTT_NOEXCEPT { return *it; } @@ -592,15 +605,15 @@ class View final { } } + const auto extent = std::min({ pool().extent()... }); auto it = std::get>(raw); - const auto ext = extent(); // fallback to visit what remains using indirections for(; data[0] != end; ++data[0], ++it) { const auto entity = *data[0]; const auto sz = size_type(entity & traits_type::entity_mask); - if(sz < ext && std::all_of(other.cbegin(), other.cend(), [entity](const view_type *view) { return view->fast(entity); })) { + if(sz < extent && std::all_of(other.cbegin(), other.cend(), [entity](const view_type *view) { return view->fast(entity); })) { // avoided at least the indirection due to the sparse set for the pivot type (see get for more details) func(entity, get(it, entity)...); } @@ -649,7 +662,7 @@ public: */ const_iterator_type cbegin() const ENTT_NOEXCEPT { const auto *view = candidate(); - return iterator_type{ unchecked(view), extent(), view->cbegin(), view->cend() }; + return iterator_type{ unchecked(view), view->cbegin(), view->cend() }; } /** @@ -705,7 +718,7 @@ public: */ const_iterator_type cend() const ENTT_NOEXCEPT { const auto *view = candidate(); - return iterator_type{ unchecked(view), extent(), view->cend(), view->cend() }; + return iterator_type{ unchecked(view), view->cend(), view->cend() }; } /** @@ -753,7 +766,8 @@ public: */ bool contains(const entity_type entity) const ENTT_NOEXCEPT { const auto sz = size_type(entity & traits_type::entity_mask); - return sz < extent() && std::min({ (pool().has(entity) && (pool().data()[pool().view_type::get(entity)] == entity))... }); + const auto extent = std::min({ pool().extent()... }); + return sz < extent && std::min({ (pool().has(entity) && (pool().data()[pool().view_type::get(entity)] == entity))... }); } /** diff --git a/test/entt/entity/sparse_set.cpp b/test/entt/entity/sparse_set.cpp index 6c6c98f2a..37612d100 100644 --- a/test/entt/entity/sparse_set.cpp +++ b/test/entt/entity/sparse_set.cpp @@ -2,6 +2,10 @@ #include #include +struct Type { + int value; +}; + TEST(SparseSetNoType, Functionalities) { entt::SparseSet set; const auto &cset = set; @@ -54,7 +58,97 @@ TEST(SparseSetNoType, Functionalities) { other = std::move(set); } -TEST(SparseSetNoType, DataBeginEnd) { +TEST(SparseSetNoType, Iterator) { + using iterator_type = typename entt::SparseSet::iterator_type; + + entt::SparseSet set; + set.construct(3); + + iterator_type end{set.begin()}; + iterator_type begin{}; + begin = set.end(); + std::swap(begin, end); + + ASSERT_EQ(begin, set.begin()); + ASSERT_EQ(end, set.end()); + ASSERT_NE(begin, end); + + ASSERT_EQ(begin++, set.begin()); + ASSERT_EQ(begin--, set.end()); + + ASSERT_EQ(begin+1, set.end()); + ASSERT_EQ(end-1, set.begin()); + + ASSERT_EQ(++begin, set.end()); + ASSERT_EQ(--begin, set.begin()); + + ASSERT_EQ(begin += 1, set.end()); + ASSERT_EQ(begin -= 1, set.begin()); + + ASSERT_EQ(begin + (end - begin), set.end()); + ASSERT_EQ(begin - (begin - end), set.end()); + + ASSERT_EQ(end - (end - begin), set.begin()); + ASSERT_EQ(end + (begin - end), set.begin()); + + ASSERT_EQ(begin[0], *set.begin()); + + ASSERT_LT(begin, end); + ASSERT_LE(begin, set.begin()); + + ASSERT_GT(end, begin); + ASSERT_GE(end, set.end()); + + ASSERT_EQ(*begin, 3); + ASSERT_EQ(*begin.operator->(), 3); +} + +TEST(SparseSetNoType, ConstIterator) { + using iterator_type = typename entt::SparseSet::const_iterator_type; + + entt::SparseSet set; + set.construct(3); + + iterator_type cend{set.cbegin()}; + iterator_type cbegin{}; + cbegin = set.cend(); + std::swap(cbegin, cend); + + ASSERT_EQ(cbegin, set.cbegin()); + ASSERT_EQ(cend, set.cend()); + ASSERT_NE(cbegin, cend); + + ASSERT_EQ(cbegin++, set.cbegin()); + ASSERT_EQ(cbegin--, set.cend()); + + ASSERT_EQ(cbegin+1, set.cend()); + ASSERT_EQ(cend-1, set.cbegin()); + + ASSERT_EQ(++cbegin, set.cend()); + ASSERT_EQ(--cbegin, set.cbegin()); + + ASSERT_EQ(cbegin += 1, set.cend()); + ASSERT_EQ(cbegin -= 1, set.cbegin()); + + ASSERT_EQ(cbegin + (cend - cbegin), set.cend()); + ASSERT_EQ(cbegin - (cbegin - cend), set.cend()); + + ASSERT_EQ(cend - (cend - cbegin), set.cbegin()); + ASSERT_EQ(cend + (cbegin - cend), set.cbegin()); + + ASSERT_EQ(cbegin[0], *set.cbegin()); + + ASSERT_LT(cbegin, cend); + ASSERT_LE(cbegin, set.cbegin()); + + ASSERT_GT(cend, cbegin); + ASSERT_GE(cend, set.cend()); + + ASSERT_EQ(*cbegin, 3); + ASSERT_EQ(*cbegin.operator->(), 3); +} + +TEST(SparseSetNoType, Data) { entt::SparseSet set; set.construct(3); @@ -68,31 +162,6 @@ TEST(SparseSetNoType, DataBeginEnd) { ASSERT_EQ(*(set.data() + 0u), 3u); ASSERT_EQ(*(set.data() + 1u), 12u); ASSERT_EQ(*(set.data() + 2u), 42u); - - auto it = set.begin(); - - ASSERT_EQ(*it, 42u); - ASSERT_EQ(*(it+1), 12u); - ASSERT_EQ(*(it+2), 3u); - ASSERT_EQ(it += 3, set.end()); - - auto begin = set.begin(); - auto end = set.end(); - - ASSERT_EQ(*(begin++), 42u); - ASSERT_EQ(*(begin++), 12u); - ASSERT_EQ(*(begin++), 3u); - - ASSERT_EQ(begin, end); - - auto cbegin = set.cbegin(); - auto cend = set.cend(); - - ASSERT_NE(cbegin, cend); - ASSERT_EQ(cbegin+3, cend); - ASSERT_NE(cbegin, cend); - ASSERT_EQ(cbegin += 3, cend); - ASSERT_EQ(cbegin, cend); } TEST(SparseSetNoType, RespectDisjoint) { @@ -320,7 +389,91 @@ TEST(SparseSetWithType, TypesFromStandardTemplateLibraryMustWork) { set.destroy(0); } -TEST(SparseSetWithType, RawBeginEnd) { +TEST(SparseSetWithType, Iterator) { + using iterator_type = typename entt::SparseSet::iterator_type; + + entt::SparseSet set; + set.construct(3, 42); + + iterator_type end{set.begin()}; + iterator_type begin{}; + begin = set.end(); + std::swap(begin, end); + + ASSERT_EQ(begin, set.begin()); + ASSERT_EQ(end, set.end()); + ASSERT_NE(begin, end); + + ASSERT_EQ(begin++, set.begin()); + ASSERT_EQ(begin--, set.end()); + + ASSERT_EQ(begin+1, set.end()); + ASSERT_EQ(end-1, set.begin()); + + ASSERT_EQ(++begin, set.end()); + ASSERT_EQ(--begin, set.begin()); + + ASSERT_EQ(begin += 1, set.end()); + ASSERT_EQ(begin -= 1, set.begin()); + + ASSERT_EQ(begin + (end - begin), set.end()); + ASSERT_EQ(begin - (begin - end), set.end()); + + ASSERT_EQ(end - (end - begin), set.begin()); + ASSERT_EQ(end + (begin - end), set.begin()); + + ASSERT_EQ(begin[0].value, set.begin()->value); + + ASSERT_LT(begin, end); + ASSERT_LE(begin, set.begin()); + + ASSERT_GT(end, begin); + ASSERT_GE(end, set.end()); +} + +TEST(SparseSetWithType, ConstIterator) { + using iterator_type = typename entt::SparseSet::const_iterator_type; + + entt::SparseSet set; + set.construct(3, 42); + + iterator_type cend{set.cbegin()}; + iterator_type cbegin{}; + cbegin = set.cend(); + std::swap(cbegin, cend); + + ASSERT_EQ(cbegin, set.cbegin()); + ASSERT_EQ(cend, set.cend()); + ASSERT_NE(cbegin, cend); + + ASSERT_EQ(cbegin++, set.cbegin()); + ASSERT_EQ(cbegin--, set.cend()); + + ASSERT_EQ(cbegin+1, set.cend()); + ASSERT_EQ(cend-1, set.cbegin()); + + ASSERT_EQ(++cbegin, set.cend()); + ASSERT_EQ(--cbegin, set.cbegin()); + + ASSERT_EQ(cbegin += 1, set.cend()); + ASSERT_EQ(cbegin -= 1, set.cbegin()); + + ASSERT_EQ(cbegin + (cend - cbegin), set.cend()); + ASSERT_EQ(cbegin - (cbegin - cend), set.cend()); + + ASSERT_EQ(cend - (cend - cbegin), set.cbegin()); + ASSERT_EQ(cend + (cbegin - cend), set.cbegin()); + + ASSERT_EQ(cbegin[0].value, set.cbegin()->value); + + ASSERT_LT(cbegin, cend); + ASSERT_LE(cbegin, set.cbegin()); + + ASSERT_GT(cend, cbegin); + ASSERT_GE(cend, set.cend()); +} + +TEST(SparseSetWithType, Raw) { entt::SparseSet set; set.construct(3, 3); @@ -334,23 +487,6 @@ TEST(SparseSetWithType, RawBeginEnd) { ASSERT_EQ(*(set.raw() + 0u), 3); ASSERT_EQ(*(set.raw() + 1u), 6); ASSERT_EQ(*(set.raw() + 2u), 9); - - auto begin = set.begin(); - auto end = set.end(); - - ASSERT_EQ(*(begin++), 9); - ASSERT_EQ(*(begin++), 6); - ASSERT_EQ(*(begin++), 3); - ASSERT_EQ(begin, end); - - auto cbegin = set.cbegin(); - auto cend = set.cend(); - - ASSERT_NE(cbegin, cend); - ASSERT_EQ(cbegin+3, cend); - ASSERT_NE(cbegin, cend); - ASSERT_EQ(cbegin += 3, cend); - ASSERT_EQ(cbegin, cend); } TEST(SparseSetWithType, SortOrdered) { diff --git a/test/entt/entity/view.cpp b/test/entt/entity/view.cpp index 1c4b92c11..80f581d77 100644 --- a/test/entt/entity/view.cpp +++ b/test/entt/entity/view.cpp @@ -1,8 +1,9 @@ +#include #include #include #include -TEST(View, SingleComponent) { +TEST(SingleComponentView, Functionalities) { entt::DefaultRegistry registry; auto view = registry.view(); @@ -43,34 +44,11 @@ TEST(View, SingleComponent) { registry.remove(e1); ASSERT_EQ(view.begin(), view.end()); + ASSERT_EQ(view.cbegin(), view.cend()); ASSERT_TRUE(view.empty()); } -TEST(View, SingleComponentBeginEnd) { - entt::DefaultRegistry registry; - auto view = registry.view(); - const auto &cview = view; - - for(auto i = 0; i < 3; ++i) { - registry.assign(registry.create()); - } - - auto test = [](auto begin, auto end) { - ASSERT_NE(begin, end); - ASSERT_NE(++begin, end); - ASSERT_NE(begin++, end); - ASSERT_EQ(begin+1, end); - ASSERT_NE(begin, end); - ASSERT_EQ((begin += 1), end); - ASSERT_EQ(begin, end); - }; - - test(view.begin(), view.end()); - test(cview.begin(), cview.end()); - test(view.cbegin(), view.cend()); -} - -TEST(View, SingleComponentContains) { +TEST(SingleComponentView, Contains) { entt::DefaultRegistry registry; const auto e0 = registry.create(); @@ -87,7 +65,7 @@ TEST(View, SingleComponentContains) { ASSERT_TRUE(view.contains(e1)); } -TEST(View, SingleComponentEmpty) { +TEST(SingleComponentView, Empty) { entt::DefaultRegistry registry; const auto e0 = registry.create(); @@ -107,7 +85,7 @@ TEST(View, SingleComponentEmpty) { } } -TEST(View, SingleComponentEach) { +TEST(SingleComponentView, Each) { entt::DefaultRegistry registry; registry.assign(registry.create()); @@ -126,7 +104,7 @@ TEST(View, SingleComponentEach) { ASSERT_EQ(cnt, std::size_t{0}); } -TEST(View, MultipleComponent) { +TEST(MultipleComponentView, Functionalities) { entt::DefaultRegistry registry; auto view = registry.view(); @@ -152,7 +130,6 @@ TEST(View, MultipleComponent) { ASSERT_NO_THROW((++registry.view().begin())); ASSERT_NE(view.begin(), view.end()); - ASSERT_EQ(view.begin()+1, view.end()); ASSERT_EQ(view.size(), decltype(view.size()){1}); registry.get(e0) = '1'; @@ -170,33 +147,53 @@ TEST(View, MultipleComponent) { registry.remove(e1); } -TEST(View, MultipleComponentBeginEnd) { +TEST(MultipleComponentView, Iterator) { + using iterator_type = typename decltype(std::declval().view())::iterator_type; + entt::DefaultRegistry registry; - auto view = registry.view(); - const auto &cview = view; + const auto entity = registry.create(); + registry.assign(entity); + registry.assign(entity); - for(auto i = 0; i < 3; ++i) { - const auto entity = registry.create(); - registry.assign(entity); - registry.assign(entity); - } + const auto view = registry.view(); - auto test = [](auto begin, auto end) { - ASSERT_NE(begin, end); - ASSERT_NE(++begin, end); - ASSERT_NE(begin++, end); - ASSERT_EQ(begin+1, end); - ASSERT_NE(begin, end); - ASSERT_EQ((begin += 1), end); - ASSERT_EQ(begin, end); - }; + iterator_type end{view.begin()}; + iterator_type begin{}; + begin = view.end(); + std::swap(begin, end); - test(cview.begin(), cview.end()); - test(view.begin(), view.end()); - test(view.cbegin(), view.cend()); + ASSERT_EQ(begin, view.begin()); + ASSERT_EQ(end, view.end()); + ASSERT_NE(begin, end); + + ASSERT_EQ(view.begin()++, view.begin()); + ASSERT_EQ(++view.begin(), view.end()); } -TEST(View, MultipleComponentContains) { +TEST(MultipleComponentView, ConstIterator) { + using iterator_type = typename decltype(std::declval().view())::const_iterator_type; + + entt::DefaultRegistry registry; + const auto entity = registry.create(); + registry.assign(entity); + registry.assign(entity); + + const auto view = registry.view(); + + iterator_type cend{view.cbegin()}; + iterator_type cbegin{}; + cbegin = view.cend(); + std::swap(cbegin, cend); + + ASSERT_EQ(cbegin, view.cbegin()); + ASSERT_EQ(cend, view.cend()); + ASSERT_NE(cbegin, cend); + + ASSERT_EQ(view.cbegin()++, view.cbegin()); + ASSERT_EQ(++view.cbegin(), view.cend()); +} + +TEST(MultipleComponentView, Contains) { entt::DefaultRegistry registry; const auto e0 = registry.create(); @@ -215,7 +212,7 @@ TEST(View, MultipleComponentContains) { ASSERT_TRUE(view.contains(e1)); } -TEST(View, MultipleComponentEmpty) { +TEST(MultipleComponentView, Empty) { entt::DefaultRegistry registry; const auto e0 = registry.create(); @@ -235,7 +232,7 @@ TEST(View, MultipleComponentEmpty) { } } -TEST(View, MultipleComponentEach) { +TEST(MultipleComponentView, Each) { entt::DefaultRegistry registry; const auto e0 = registry.create(); @@ -259,7 +256,7 @@ TEST(View, MultipleComponentEach) { ASSERT_EQ(cnt, std::size_t{0}); } -TEST(View, MultipleComponentEachWithHoles) { +TEST(MultipleComponentView, EachWithHoles) { entt::DefaultRegistry registry; const auto e0 = registry.create(); @@ -330,6 +327,7 @@ TEST(PersistentView, Prepare) { registry.remove(e1); ASSERT_EQ(view.begin(), view.end()); + ASSERT_EQ(view.cbegin(), view.cend()); ASSERT_TRUE(view.empty()); } @@ -378,35 +376,10 @@ TEST(PersistentView, NoPrepare) { registry.remove(e1); ASSERT_EQ(view.begin(), view.end()); + ASSERT_EQ(view.cbegin(), view.cend()); ASSERT_TRUE(view.empty()); } -TEST(PersistentView, BeginEnd) { - entt::DefaultRegistry registry; - auto view = registry.view(entt::persistent_t{}); - const auto &cview = view; - - for(auto i = 0; i < 3; ++i) { - const auto entity = registry.create(); - registry.assign(entity); - registry.assign(entity); - } - - auto test = [](auto begin, auto end) { - ASSERT_NE(begin, end); - ASSERT_NE(++begin, end); - ASSERT_NE(begin++, end); - ASSERT_EQ(begin+1, end); - ASSERT_NE(begin, end); - ASSERT_EQ((begin += 1), end); - ASSERT_EQ(begin, end); - }; - - test(cview.begin(), cview.end()); - test(view.begin(), view.end()); - test(view.cbegin(), view.cend()); -} - TEST(PersistentView, Contains) { entt::DefaultRegistry registry; @@ -558,33 +531,10 @@ TEST(RawView, Functionalities) { registry.remove(e1); ASSERT_EQ(view.begin(), view.end()); + ASSERT_EQ(view.cbegin(), view.cend()); ASSERT_TRUE(view.empty()); } -TEST(RawView, BeginEnd) { - entt::DefaultRegistry registry; - auto view = registry.view(entt::raw_t{}); - const auto &cview = view; - - for(auto i = 0; i < 3; ++i) { - registry.assign(registry.create()); - } - - auto test = [](auto begin, auto end) { - ASSERT_NE(begin, end); - ASSERT_NE(++begin, end); - ASSERT_NE(begin++, end); - ASSERT_EQ(begin+1, end); - ASSERT_NE(begin, end); - ASSERT_EQ((begin += 1), end); - ASSERT_EQ(begin, end); - }; - - test(cview.begin(), cview.end()); - test(view.begin(), view.end()); - test(view.cbegin(), view.cend()); -} - TEST(RawView, Empty) { entt::DefaultRegistry registry;