diff --git a/src/entt/entity/group.hpp b/src/entt/entity/group.hpp index 4cf4e577a..5dccfb0ad 100644 --- a/src/entt/entity/group.hpp +++ b/src/entt/entity/group.hpp @@ -71,68 +71,46 @@ class basic_group, get_t, exclude_t> final using basic_common_type = std::common_type_t::base_type...>; - class iterable final { - struct iterable_iterator final { - using difference_type = std::ptrdiff_t; - using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); - using pointer = input_iterator_pointer; - using reference = value_type; - using iterator_category = std::input_iterator_tag; + struct extended_group_iterator final { + using difference_type = std::ptrdiff_t; + using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); + using pointer = input_iterator_pointer; + using reference = value_type; + using iterator_category = std::input_iterator_tag; - template - iterable_iterator(typename basic_common_type::iterator from, const std::tuple *...> &args) ENTT_NOEXCEPT - : it{from}, - pools{args} {} + extended_group_iterator(typename basic_common_type::iterator from, const std::tuple *...> &args) ENTT_NOEXCEPT + : it{from}, + pools{args} {} - iterable_iterator &operator++() ENTT_NOEXCEPT { - return ++it, *this; - } - - iterable_iterator operator++(int) ENTT_NOEXCEPT { - iterable_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - const auto entt = *it; - return std::tuple_cat(std::make_tuple(entt), std::get *>(pools)->get_as_tuple(entt)...); - } - - [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT { - return operator*(); - } - - [[nodiscard]] bool operator==(const iterable_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - typename basic_common_type::iterator it; - std::tuple *...> pools; - }; - - public: - using iterator = iterable_iterator; - - iterable(basic_common_type *const ref, const std::tuple *...> &cpools) - : handler{ref}, - pools{cpools} {} - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return handler ? iterator{handler->begin(), pools} : iterator{{}, pools}; + extended_group_iterator &operator++() ENTT_NOEXCEPT { + return ++it, *this; } - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return handler ? iterator{handler->end(), pools} : iterator{{}, pools}; + extended_group_iterator operator++(int) ENTT_NOEXCEPT { + extended_group_iterator orig = *this; + return ++(*this), orig; + } + + [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { + const auto entt = *it; + return std::tuple_cat(std::make_tuple(entt), std::get *>(pools)->get_as_tuple(entt)...); + } + + [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT { + return operator*(); + } + + [[nodiscard]] bool operator==(const extended_group_iterator &other) const ENTT_NOEXCEPT { + return other.it == it; + } + + [[nodiscard]] bool operator!=(const extended_group_iterator &other) const ENTT_NOEXCEPT { + return !(*this == other); } private: - basic_common_type *const handler; - const std::tuple *...> pools; + typename basic_common_type::iterator it; + std::tuple *...> pools; }; basic_group(basic_common_type &ref, storage_type &...gpool) ENTT_NOEXCEPT @@ -151,7 +129,7 @@ public: /*! @brief Reversed iterator type. */ using reverse_iterator = typename base_type::reverse_iterator; /*! @brief Iterable group type. */ - using iterable_group = iterable; + using iterable = iterable_adaptor; /*! @brief Default constructor to use to create empty, invalid groups. */ basic_group() ENTT_NOEXCEPT @@ -401,8 +379,9 @@ public: * * @return An iterable object to use to _visit_ the group. */ - [[nodiscard]] iterable_group each() const ENTT_NOEXCEPT { - return iterable_group{handler, pools}; + [[nodiscard]] iterable each() const ENTT_NOEXCEPT { + return handler ? iterable{extended_group_iterator{handler->begin(), pools}, extended_group_iterator{handler->end(), pools}} + : iterable{extended_group_iterator{{}, pools}, extended_group_iterator{{}, pools}}; } /** @@ -545,78 +524,55 @@ class basic_group, get_t, exclude_t::base_type..., typename storage_type::base_type...>; - class iterable final { - template - struct iterable_iterator; + template + struct extended_group_iterator; - template - struct iterable_iterator> final { - using difference_type = std::ptrdiff_t; - using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); - using pointer = input_iterator_pointer; - using reference = value_type; - using iterator_category = std::input_iterator_tag; + template + struct extended_group_iterator> final { + using difference_type = std::ptrdiff_t; + using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); + using pointer = input_iterator_pointer; + using reference = value_type; + using iterator_category = std::input_iterator_tag; - template - iterable_iterator(typename basic_common_type::iterator from, const std::tuple &other, const std::tuple *...> &cpools) ENTT_NOEXCEPT - : it{from}, - owned{std::get(other)...}, - get{cpools} {} + template + extended_group_iterator(typename basic_common_type::iterator from, const std::tuple &other, const std::tuple *...> &cpools) ENTT_NOEXCEPT + : it{from}, + owned{std::get(other)...}, + get{cpools} {} - iterable_iterator &operator++() ENTT_NOEXCEPT { - return ++it, (++std::get(owned), ...), *this; - } - - iterable_iterator operator++(int) ENTT_NOEXCEPT { - iterable_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return std::tuple_cat( - std::make_tuple(*it), - std::forward_as_tuple(*std::get(owned)...), - std::get *>(get)->get_as_tuple(*it)...); - } - - [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT { - return operator*(); - } - - [[nodiscard]] bool operator==(const iterable_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - typename basic_common_type::iterator it; - std::tuple owned; - std::tuple *...> get; - }; - - public: - using iterator = iterable_iterator>, type_list<>, type_list>().end())>>...>>; - - iterable(std::tuple *..., storage_type *...> cpools, const std::size_t *const extent) - : pools{cpools}, - length{extent} {} - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - auto it = length ? (std::get<0>(pools)->basic_common_type::end() - *length) : typename basic_common_type::iterator{}; - return iterator{std::move(it), std::make_tuple((std::get *>(pools)->end() - *length)...), std::make_tuple(std::get *>(pools)...)}; + extended_group_iterator &operator++() ENTT_NOEXCEPT { + return ++it, (++std::get(owned), ...), *this; } - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - auto it = length ? std::get<0>(pools)->basic_common_type::end() : typename basic_common_type::iterator{}; - return iterator{std::move(it), std::make_tuple((std::get *>(pools)->end())...), std::make_tuple(std::get *>(pools)...)}; + extended_group_iterator operator++(int) ENTT_NOEXCEPT { + extended_group_iterator orig = *this; + return ++(*this), orig; + } + + [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { + return std::tuple_cat( + std::make_tuple(*it), + std::forward_as_tuple(*std::get(owned)...), + std::get *>(get)->get_as_tuple(*it)...); + } + + [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT { + return operator*(); + } + + [[nodiscard]] bool operator==(const extended_group_iterator &other) const ENTT_NOEXCEPT { + return other.it == it; + } + + [[nodiscard]] bool operator!=(const extended_group_iterator &other) const ENTT_NOEXCEPT { + return !(*this == other); } private: - const std::tuple *..., storage_type *...> pools; - const std::size_t *const length; + typename basic_common_type::iterator it; + std::tuple owned; + std::tuple *...> get; }; basic_group(const std::size_t &extent, storage_type &...opool, storage_type &...gpool) ENTT_NOEXCEPT @@ -635,7 +591,7 @@ public: /*! @brief Reversed iterator type. */ using reverse_iterator = typename base_type::reverse_iterator; /*! @brief Iterable group type. */ - using iterable_group = iterable; + using iterable = iterable_adaptor>, type_list<>, type_list>().end())>>...>>>; /*! @brief Default constructor to use to create empty, invalid groups. */ basic_group() ENTT_NOEXCEPT @@ -861,8 +817,12 @@ public: * * @return An iterable object to use to _visit_ the group. */ - [[nodiscard]] iterable_group each() const ENTT_NOEXCEPT { - return iterable_group{pools, length}; + [[nodiscard]] iterable each() const ENTT_NOEXCEPT { + using extended_iterator_type = typename iterable::iterator; + iterator last = length ? std::get<0>(pools)->basic_common_type::end() : iterator{}; + auto from = extended_iterator_type{last - *length, std::make_tuple((std::get *>(pools)->end() - *length)...), std::make_tuple(std::get *>(pools)...)}; + auto to = extended_iterator_type{last, std::make_tuple((std::get *>(pools)->end())...), std::make_tuple(std::get *>(pools)...)}; + return {std::move(from), std::move(to)}; } /** diff --git a/src/entt/entity/storage.hpp b/src/entt/entity/storage.hpp index 9b776d557..ee3d92dff 100644 --- a/src/entt/entity/storage.hpp +++ b/src/entt/entity/storage.hpp @@ -12,6 +12,7 @@ #include "../core/algorithm.hpp" #include "../core/any.hpp" #include "../core/compressed_pair.hpp" +#include "../core/iterator.hpp" #include "../core/memory.hpp" #include "../core/type_info.hpp" #include "../core/type_traits.hpp" @@ -155,6 +156,63 @@ template return !(lhs < rhs); } +template +class extended_storage_iterator final { + template + friend class extended_storage_iterator; + +public: + using iterator_type = It; + using difference_type = typename std::iterator_traits::difference_type; + using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval()), std::forward_as_tuple(*std::declval()...))); + using pointer = input_iterator_pointer; + using reference = value_type; + using iterator_category = std::input_iterator_tag; + + extended_storage_iterator() ENTT_NOEXCEPT = default; + + extended_storage_iterator(It base, Other... other) ENTT_NOEXCEPT + : it{base, other...} {} + + template && ...) && (std::is_constructible_v && ...)>> + extended_storage_iterator(const extended_storage_iterator &other) ENTT_NOEXCEPT + : it{other.it} {} + + extended_storage_iterator &operator++() ENTT_NOEXCEPT { + return ++std::get(it), (++std::get(it), ...), *this; + } + + extended_storage_iterator operator++(int) ENTT_NOEXCEPT { + extended_storage_iterator orig = *this; + return ++(*this), orig; + } + + [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT { + return operator*(); + } + + [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { + return {*std::get(it), *std::get(it)...}; + } + + [[nodiscard]] iterator_type base() const ENTT_NOEXCEPT { + return std::get(it); + } + +private: + std::tuple it; +}; + +template +[[nodiscard]] bool operator==(const extended_storage_iterator &lhs, const extended_storage_iterator &rhs) ENTT_NOEXCEPT { + return lhs.base() == rhs.base(); +} + +template +[[nodiscard]] bool operator!=(const extended_storage_iterator &lhs, const extended_storage_iterator &rhs) ENTT_NOEXCEPT { + return !(lhs == rhs); +} + } // namespace internal /** @@ -165,15 +223,6 @@ template /** * @brief Basic storage implementation. * - * This class is a refinement of a sparse set that associates an object to an - * entity. The main purpose of this class is to extend sparse sets to store - * components in a registry. It guarantees fast access both to the elements and - * to the entities. - * - * @note - * Entities and objects have the same order. - * - * @note * Internal data structures arrange elements to maximize performance. There are * no guarantees that objects are returned in the insertion order when iterate * a storage. Do not make assumption on the order in any case. @@ -182,8 +231,6 @@ template * Empty types aren't explicitly instantiated. Therefore, many of the functions * normally available for non-empty types will not be available for empty ones. * - * @sa sparse_set - * * @tparam Entity A valid entity type (see entt_traits for more details). * @tparam Type Type of objects assigned to the entities. * @tparam Allocator Type of allocator used to manage memory and elements. @@ -379,6 +426,10 @@ public: using reverse_iterator = std::reverse_iterator; /*! @brief Constant reverse iterator type. */ using const_reverse_iterator = std::reverse_iterator; + /*! @brief Extended iterable storage proxy. */ + using iterable = iterable_adaptor>; + /*! @brief Constant extended iterable storage proxy. */ + using const_iterable = iterable_adaptor>; /*! @brief Default constructor. */ basic_storage() @@ -705,6 +756,23 @@ public: consume_range(std::move(first), std::move(last), [&from]() -> decltype(auto) { return *(from++); }); } + /** + * @brief Returns an iterable object to use to _visit_ the storage. + * + * The iterable object returns a tuple that contains the current entity and + * a reference to its component. + * + * @return An iterable object to use to _visit_ the storage. + */ + [[nodiscard]] iterable each() ENTT_NOEXCEPT { + return {internal::extended_storage_iterator{base_type::begin(), begin()}, internal::extended_storage_iterator{base_type::end(), end()}}; + } + + /*! @copydoc each */ + [[nodiscard]] const_iterable each() const ENTT_NOEXCEPT { + return {internal::extended_storage_iterator{base_type::cbegin(), cbegin()}, internal::extended_storage_iterator{base_type::cend(), cend()}}; + } + private: compressed_pair packed; }; @@ -727,6 +795,10 @@ public: using entity_type = Entity; /*! @brief Unsigned integer type. */ using size_type = std::size_t; + /*! @brief Extended iterable storage proxy. */ + using iterable = iterable_adaptor>; + /*! @brief Constant extended iterable storage proxy. */ + using const_iterable = iterable_adaptor>; /*! @brief Default constructor. */ basic_storage() @@ -844,6 +916,22 @@ public: emplace(*first); } } + + /** + * @brief Returns an iterable object to use to _visit_ the storage. + * + * The iterable object returns a tuple that contains the current entity. + * + * @return An iterable object to use to _visit_ the storage. + */ + [[nodiscard]] iterable each() ENTT_NOEXCEPT { + return {internal::extended_storage_iterator{base_type::begin()}, internal::extended_storage_iterator{base_type::end()}}; + } + + /*! @copydoc each */ + [[nodiscard]] const_iterable each() const ENTT_NOEXCEPT { + return {internal::extended_storage_iterator{base_type::cbegin()}, internal::extended_storage_iterator{base_type::cend()}}; + } }; /** diff --git a/src/entt/entity/view.hpp b/src/entt/entity/view.hpp index 0cf6603e8..d67b65757 100644 --- a/src/entt/entity/view.hpp +++ b/src/entt/entity/view.hpp @@ -26,133 +26,6 @@ namespace entt { namespace internal { -template -class iterable_storage final { - using base_type = typename Storage::base_type; - - template - struct iterable_storage_iterator final { - using difference_type = std::ptrdiff_t; - using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get_as_tuple({}))>())); - using pointer = input_iterator_pointer; - using reference = value_type; - using iterator_category = std::input_iterator_tag; - - template - iterable_storage_iterator(It... from, Discard...) ENTT_NOEXCEPT - : it{from...} {} - - iterable_storage_iterator &operator++() ENTT_NOEXCEPT { - return (++std::get(it), ...), *this; - } - - iterable_storage_iterator operator++(int) ENTT_NOEXCEPT { - iterable_storage_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return {*std::get(it)...}; - } - - [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT { - return operator*(); - } - - [[nodiscard]] bool operator==(const iterable_storage_iterator &other) const ENTT_NOEXCEPT { - return std::get<0>(other.it) == std::get<0>(it); - } - - [[nodiscard]] bool operator!=(const iterable_storage_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - std::tuple it; - }; - -public: - using iterator = std::conditional_t< - ignore_as_empty_v, - iterable_storage_iterator, - iterable_storage_iterator().begin())>>; - - iterable_storage(Storage &ref) - : pool{&ref} {} - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return iterator{pool->base_type::begin(), pool->begin()}; - } - - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return iterator{pool->base_type::end(), pool->end()}; - } - -private: - Storage *const pool; -}; - -template -class iterable_view final { - struct iterable_view_iterator final { - using difference_type = std::ptrdiff_t; - using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); - using pointer = input_iterator_pointer; - using reference = value_type; - using iterator_category = std::input_iterator_tag; - - iterable_view_iterator(typename View::iterator from, const View *parent) ENTT_NOEXCEPT - : it{from}, - view{parent} {} - - iterable_view_iterator &operator++() ENTT_NOEXCEPT { - return ++it, *this; - } - - iterable_view_iterator operator++(int) ENTT_NOEXCEPT { - iterable_view_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return std::tuple_cat(std::make_tuple(*it), view->get(*it)); - } - - [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT { - return operator*(); - } - - [[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_view_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - typename View::iterator it; - const View *view; - }; - -public: - using iterator = iterable_view_iterator; - - iterable_view(const View &parent) - : view{parent} {} - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return {view.begin(), &view}; - } - - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return {view.end(), &view}; - } - -private: - const View view; -}; - template class view_iterator final { [[nodiscard]] bool valid() const { @@ -195,14 +68,6 @@ public: return ++(*this), orig; } - [[nodiscard]] bool operator==(const view_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const view_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - [[nodiscard]] pointer operator->() const { return &*it; } @@ -211,6 +76,10 @@ public: return *operator->(); } + [[nodiscard]] iterator_type base() const ENTT_NOEXCEPT { + return it; + } + private: iterator_type it; iterator_type last; @@ -218,6 +87,65 @@ private: std::array filter; }; +template +[[nodiscard]] bool operator==(const view_iterator &lhs, const view_iterator &rhs) ENTT_NOEXCEPT { + return lhs.base() == rhs.base(); +} + +template +[[nodiscard]] bool operator!=(const view_iterator &lhs, const view_iterator &rhs) ENTT_NOEXCEPT { + return !(lhs == rhs); +} + +template +struct extended_view_iterator final { + using iterator_type = It; + using difference_type = std::ptrdiff_t; + using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval()), std::declval().get_as_tuple({})...)); + using pointer = input_iterator_pointer; + using reference = value_type; + using iterator_category = std::input_iterator_tag; + + extended_view_iterator(It from, std::tuple storage) ENTT_NOEXCEPT + : it{from}, + pools{storage} {} + + extended_view_iterator &operator++() ENTT_NOEXCEPT { + return ++it, *this; + } + + extended_view_iterator operator++(int) ENTT_NOEXCEPT { + extended_view_iterator orig = *this; + return ++(*this), orig; + } + + [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { + return std::apply([entt = *it](auto *...curr) { return std::tuple_cat(std::make_tuple(entt), curr->get_as_tuple(entt)...); }, pools); + } + + [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT { + return operator*(); + } + + [[nodiscard]] iterator_type base() const ENTT_NOEXCEPT { + return it; + } + +private: + It it; + std::tuple pools; +}; + +template +[[nodiscard]] bool operator==(const extended_view_iterator &lhs, const extended_view_iterator &rhs) ENTT_NOEXCEPT { + return lhs.base() == rhs.base(); +} + +template +[[nodiscard]] bool operator!=(const extended_view_iterator &lhs, const extended_view_iterator &rhs) ENTT_NOEXCEPT { + return !(lhs == rhs); +} + } // namespace internal /** @@ -285,7 +213,7 @@ class basic_view, exclude_t> { template void each(Func func, std::index_sequence) const { - for(const auto curr: internal::iterable_storage{*std::get(pools)}) { + for(const auto curr: std::get(pools)->each()) { const auto entt = std::get<0>(curr); if(((sizeof...(Component) != 1u) || (entt != tombstone)) @@ -315,7 +243,7 @@ public: /*! @brief Bidirectional iterator type. */ using iterator = internal::view_iterator; /*! @brief Iterable view type. */ - using iterable_view = internal::iterable_view; + using iterable = iterable_adaptor...>>; /*! @brief Default constructor to use to create empty, invalid views. */ basic_view() ENTT_NOEXCEPT @@ -549,14 +477,14 @@ public: /** * @brief Returns an iterable object to use to _visit_ the view. * - * The iterable object returns tuples that contain the current entity and a - * set of references to its non-empty components. The _constness_ of the + * The iterable object returns a tuple that contains the current entity and + * a set of references to its non-empty components. The _constness_ of the * components is as requested. * * @return An iterable object to use to _visit_ the view. */ - [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT { - return iterable_view{*this}; + [[nodiscard]] iterable each() const ENTT_NOEXCEPT { + return {internal::extended_view_iterator{begin(), pools}, internal::extended_view_iterator{end(), pools}}; } /** @@ -623,7 +551,7 @@ public: /*! @brief Reversed iterator type. */ using reverse_iterator = typename base_type::reverse_iterator; /*! @brief Iterable view type. */ - using iterable_view = internal::iterable_storage; + using iterable = decltype(std::declval().each()); /*! @brief Default constructor to use to create empty, invalid views. */ basic_view() ENTT_NOEXCEPT @@ -874,14 +802,14 @@ public: /** * @brief Returns an iterable object to use to _visit_ the view. * - * The iterable object returns tuples that contain the current entity and a - * reference to its component if it's a non-empty one. The _constness_ of + * The iterable object returns a tuple that contains the current entity and + * a reference to its component if it's a non-empty one. The _constness_ of * the component is as requested. * * @return An iterable object to use to _visit_ the view. */ - [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT { - return iterable_view{*std::get<0>(pools)}; + [[nodiscard]] iterable each() const ENTT_NOEXCEPT { + return std::get<0>(pools)->each(); } /** diff --git a/test/entt/entity/group.cpp b/test/entt/entity/group.cpp index d2724b43d..27c2951f2 100644 --- a/test/entt/entity/group.cpp +++ b/test/entt/entity/group.cpp @@ -183,15 +183,15 @@ TEST(NonOwningGroup, Each) { auto group = registry.group(entt::get); auto cgroup = std::as_const(registry).group_if_exists(entt::get); - auto iterable = group.each(); - auto citerable = cgroup.each(); - registry.emplace(entity[0u], 0); registry.emplace(entity[0u], 0); registry.emplace(entity[1u], 1); registry.emplace(entity[1u], 1); + auto iterable = group.each(); + auto citerable = cgroup.each(); + ASSERT_NE(citerable.begin(), citerable.end()); ASSERT_NO_THROW(iterable.begin()->operator=(*iterable.begin())); @@ -826,15 +826,15 @@ TEST(OwningGroup, Each) { auto group = registry.group(entt::get); auto cgroup = std::as_const(registry).group_if_exists(entt::get); - auto iterable = group.each(); - auto citerable = cgroup.each(); - registry.emplace(entity[0u], 0); registry.emplace(entity[0u], 0); registry.emplace(entity[1u], 1); registry.emplace(entity[1u], 1); + auto iterable = group.each(); + auto citerable = cgroup.each(); + ASSERT_NE(citerable.begin(), citerable.end()); ASSERT_NO_THROW(iterable.begin()->operator=(*iterable.begin())); diff --git a/test/entt/entity/storage.cpp b/test/entt/entity/storage.cpp index 62b32f550..bb2999d46 100644 --- a/test/entt/entity/storage.cpp +++ b/test/entt/entity/storage.cpp @@ -1037,6 +1037,140 @@ TEST(Storage, IteratorConversion) { ASSERT_NE(++cit, it); } +TEST(Storage, Iterable) { + using iterator = typename entt::storage::iterable::iterator; + + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>>); + static_assert(std::is_same_v); + + entt::storage pool; + pool.emplace(entt::entity{1}, 99); + pool.emplace(entt::entity{3}, 42); + auto iterable = pool.each(); + + iterator end{iterable.begin()}; + iterator begin{}; + begin = iterable.end(); + std::swap(begin, end); + + ASSERT_EQ(begin, iterable.begin()); + ASSERT_EQ(end, iterable.end()); + ASSERT_NE(begin, end); + + ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{3}); + ASSERT_EQ(std::get<1>(*begin.operator->().operator->()), boxed_int{42}); + ASSERT_EQ(std::get<0>(*begin), entt::entity{3}); + ASSERT_EQ(std::get<1>(*begin), boxed_int{42}); + + ASSERT_EQ(begin++, iterable.begin()); + ASSERT_EQ(++begin, iterable.end()); + + for(auto [entity, element]: iterable) { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + ASSERT_TRUE(entity != entt::entity{1} || element == boxed_int{99}); + ASSERT_TRUE(entity != entt::entity{3} || element == boxed_int{42}); + } +} + +TEST(Storage, ConstIterable) { + using iterator = typename entt::storage::const_iterable::const_iterator; + + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>>); + static_assert(std::is_same_v); + + entt::storage pool; + pool.emplace(entt::entity{1}, 99); + pool.emplace(entt::entity{3}, 42); + auto iterable = std::as_const(pool).each(); + + iterator end{iterable.cbegin()}; + iterator begin{}; + begin = iterable.cend(); + std::swap(begin, end); + + ASSERT_EQ(begin, iterable.cbegin()); + ASSERT_EQ(end, iterable.cend()); + ASSERT_NE(begin, end); + + ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{3}); + ASSERT_EQ(std::get<1>(*begin.operator->().operator->()), boxed_int{42}); + ASSERT_EQ(std::get<0>(*begin), entt::entity{3}); + ASSERT_EQ(std::get<1>(*begin), boxed_int{42}); + + ASSERT_EQ(begin++, iterable.cbegin()); + ASSERT_EQ(++begin, iterable.cend()); + + for(auto [entity, element]: iterable) { + static_assert(std::is_same_v); + static_assert(std::is_same_v); + ASSERT_TRUE(entity != entt::entity{1} || element == boxed_int{99}); + ASSERT_TRUE(entity != entt::entity{3} || element == boxed_int{42}); + } +} + +TEST(Storage, IterableIteratorConversion) { + entt::storage pool; + pool.emplace(entt::entity{3}, 42); + + typename entt::storage::iterable::iterator it = pool.each().begin(); + typename entt::storage::const_iterable::const_iterator cit = it; + + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + + ASSERT_EQ(it, cit); + ASSERT_NE(++cit, it); +} + +TEST(Storage, EmptyTypeIterable) { + using iterator = typename entt::storage::iterable::iterator; + + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>>); + static_assert(std::is_same_v); + + entt::storage pool; + pool.emplace(entt::entity{1}); + pool.emplace(entt::entity{3}); + auto iterable = pool.each(); + + iterator end{iterable.begin()}; + iterator begin{}; + begin = iterable.end(); + std::swap(begin, end); + + ASSERT_EQ(begin, iterable.begin()); + ASSERT_EQ(end, iterable.end()); + ASSERT_NE(begin, end); + + ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{3}); + ASSERT_EQ(std::get<0>(*begin), entt::entity{3}); + + ASSERT_EQ(begin++, iterable.begin()); + ASSERT_EQ(++begin, iterable.end()); + + for(auto [entity]: iterable) { + static_assert(std::is_same_v); + ASSERT_TRUE(entity == entt::entity{1} || entity == entt::entity{3}); + } +} + +TEST(Storage, IterableAlgorithmCompatibility) { + entt::storage pool; + pool.emplace(entt::entity{3}, 42); + + const auto iterable = pool.each(); + const auto it = std::find_if(iterable.begin(), iterable.end(), [](auto args) { return std::get<0>(args) == entt::entity{3}; }); + + ASSERT_EQ(std::get<0>(*it), entt::entity{3}); +} + TEST(Storage, Raw) { entt::storage pool; diff --git a/test/entt/entity/view.cpp b/test/entt/entity/view.cpp index 6c25053f9..53c28fabd 100644 --- a/test/entt/entity/view.cpp +++ b/test/entt/entity/view.cpp @@ -176,12 +176,12 @@ TEST(SingleComponentView, Each) { auto view = registry.view(); auto cview = std::as_const(registry).view(); - auto iterable = view.each(); - auto citerable = cview.each(); - registry.emplace(entity[0u], 0); registry.emplace(entity[1u], 1); + auto iterable = view.each(); + auto citerable = cview.each(); + ASSERT_NE(citerable.begin(), citerable.end()); ASSERT_NO_THROW(iterable.begin()->operator=(*iterable.begin())); @@ -677,15 +677,15 @@ TEST(MultiComponentView, Each) { auto view = registry.view(); auto cview = std::as_const(registry).view(); - auto iterable = view.each(); - auto citerable = cview.each(); - registry.emplace(entity[0u], 0); registry.emplace(entity[0u], 0); registry.emplace(entity[1u], 1); registry.emplace(entity[1u], 1); + auto iterable = view.each(); + auto citerable = cview.each(); + ASSERT_NE(citerable.begin(), citerable.end()); ASSERT_NO_THROW(iterable.begin()->operator=(*iterable.begin()));