view: rbegin/rend
This commit is contained in:
@@ -74,14 +74,14 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
|
||||
template<typename Comp>
|
||||
using component_iterator = decltype(std::declval<pool_type<Comp>>().begin());
|
||||
|
||||
using underlying_iterator = typename sparse_set<Entity>::iterator;
|
||||
using unchecked_type = std::array<const sparse_set<Entity> *, (sizeof...(Component) - 1)>;
|
||||
using filter_type = std::array<const sparse_set<Entity> *, sizeof...(Exclude)>;
|
||||
|
||||
template<typename It>
|
||||
class view_iterator final {
|
||||
friend class basic_view<Entity, exclude_t<Exclude...>, Component...>;
|
||||
|
||||
view_iterator(underlying_iterator from, underlying_iterator to, underlying_iterator curr, unchecked_type other, filter_type ignore) ENTT_NOEXCEPT
|
||||
view_iterator(It from, It to, It curr, unchecked_type other, filter_type ignore) ENTT_NOEXCEPT
|
||||
: first{from},
|
||||
last{to},
|
||||
it{curr},
|
||||
@@ -99,10 +99,10 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
|
||||
}
|
||||
|
||||
public:
|
||||
using difference_type = typename underlying_iterator::difference_type;
|
||||
using value_type = typename underlying_iterator::value_type;
|
||||
using pointer = typename underlying_iterator::pointer;
|
||||
using reference = typename underlying_iterator::reference;
|
||||
using difference_type = typename std::iterator_traits<It>::difference_type;
|
||||
using value_type = typename std::iterator_traits<It>::value_type;
|
||||
using pointer = typename std::iterator_traits<It>::pointer;
|
||||
using reference = typename std::iterator_traits<It>::reference;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
|
||||
view_iterator() ENTT_NOEXCEPT = default;
|
||||
@@ -136,7 +136,7 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
|
||||
}
|
||||
|
||||
[[nodiscard]] pointer operator->() const {
|
||||
return it.operator->();
|
||||
return &*it;
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const {
|
||||
@@ -144,9 +144,9 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
|
||||
}
|
||||
|
||||
private:
|
||||
underlying_iterator first;
|
||||
underlying_iterator last;
|
||||
underlying_iterator it;
|
||||
It first;
|
||||
It last;
|
||||
It it;
|
||||
unchecked_type unchecked;
|
||||
filter_type filter;
|
||||
};
|
||||
@@ -154,12 +154,14 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
|
||||
class view_proxy {
|
||||
friend class basic_view<Entity, exclude_t<Exclude...>, Component...>;
|
||||
|
||||
using proxy_view_iterator = view_iterator<typename sparse_set<Entity>::iterator>;
|
||||
|
||||
class proxy_iterator {
|
||||
friend class view_proxy;
|
||||
|
||||
using ref_type = decltype(std::tuple_cat(std::declval<std::conditional_t<ENTT_IS_EMPTY(Component), std::tuple<>, std::tuple<pool_type<Component> *>>>()...));
|
||||
|
||||
proxy_iterator(view_iterator from, ref_type ref) ENTT_NOEXCEPT
|
||||
proxy_iterator(proxy_view_iterator from, ref_type ref) ENTT_NOEXCEPT
|
||||
: it{from},
|
||||
pools{ref}
|
||||
{}
|
||||
@@ -199,11 +201,11 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
|
||||
}
|
||||
|
||||
private:
|
||||
view_iterator it{};
|
||||
proxy_view_iterator it{};
|
||||
const ref_type pools{};
|
||||
};
|
||||
|
||||
view_proxy(view_iterator from, view_iterator to, std::tuple<pool_type<Component> *...> ref)
|
||||
view_proxy(proxy_view_iterator from, proxy_view_iterator to, std::tuple<pool_type<Component> *...> ref)
|
||||
: first{from},
|
||||
last{to},
|
||||
pools{ref}
|
||||
@@ -233,8 +235,8 @@ class basic_view<Entity, exclude_t<Exclude...>, Component...> {
|
||||
}
|
||||
|
||||
private:
|
||||
view_iterator first;
|
||||
view_iterator last;
|
||||
proxy_view_iterator first;
|
||||
proxy_view_iterator last;
|
||||
const std::tuple<pool_type<Component> *...> pools;
|
||||
};
|
||||
|
||||
@@ -331,7 +333,9 @@ public:
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Bidirectional iterator type. */
|
||||
using iterator = view_iterator;
|
||||
using iterator = view_iterator<typename sparse_set<entity_type>::iterator>;
|
||||
/*! @brief Reverse iterator type. */
|
||||
using reverse_iterator = view_iterator<typename sparse_set<entity_type>::reverse_iterator>;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of existing components of the given type.
|
||||
@@ -446,6 +450,43 @@ public:
|
||||
return iterator{view.begin(), view.end(), view.end(), unchecked(view), filter};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the first entity of the reversed view.
|
||||
*
|
||||
* The returned iterator points to the first entity of the reversed view. If
|
||||
* the view is empty, the returned iterator will be equal to `rend()`.
|
||||
*
|
||||
* @note
|
||||
* Iterators stay true to the order imposed to the underlying data
|
||||
* structures.
|
||||
*
|
||||
* @return An iterator to the first entity of the reversed view.
|
||||
*/
|
||||
[[nodiscard]] reverse_iterator rbegin() const {
|
||||
const auto& view = candidate();
|
||||
return reverse_iterator{view.rbegin(), view.rend(), view.rbegin(), unchecked(view), filter};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator that is past the last entity of the reversed
|
||||
* view.
|
||||
*
|
||||
* The returned iterator points to the entity following the last entity of
|
||||
* the reversed view. Attempting to dereference the returned iterator
|
||||
* results in undefined behavior.
|
||||
*
|
||||
* @note
|
||||
* Iterators stay true to the order imposed to the underlying data
|
||||
* structures.
|
||||
*
|
||||
* @return An iterator to the entity following the last entity of the
|
||||
* reversed view.
|
||||
*/
|
||||
[[nodiscard]] reverse_iterator rend() const {
|
||||
const auto& view = candidate();
|
||||
return reverse_iterator{view.rbegin(), view.rend(), view.rend(), unchecked(view), filter};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the first entity of the view, if any.
|
||||
* @return The first entity of the view if one exists, the null entity
|
||||
@@ -462,8 +503,8 @@ public:
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] entity_type back() const {
|
||||
const auto it = std::make_reverse_iterator(end());
|
||||
return it != std::make_reverse_iterator(begin()) ? *it : null;
|
||||
const auto it = rbegin();
|
||||
return it != rend() ? *it : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -776,6 +817,8 @@ public:
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = typename sparse_set<Entity>::iterator;
|
||||
/*! @brief Reversed iterator type. */
|
||||
using reverse_iterator = typename sparse_set<Entity>::reverse_iterator;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of entities that have the given component.
|
||||
@@ -858,6 +901,41 @@ public:
|
||||
return pool->sparse_set<Entity>::end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the first entity of the reversed view.
|
||||
*
|
||||
* The returned iterator points to the first entity of the reversed view. If
|
||||
* the view is empty, the returned iterator will be equal to `rend()`.
|
||||
*
|
||||
* @note
|
||||
* Iterators stay true to the order imposed to the underlying data
|
||||
* structures.
|
||||
*
|
||||
* @return An iterator to the first entity of the reversed view.
|
||||
*/
|
||||
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
|
||||
return pool->sparse_set<Entity>::rbegin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator that is past the last entity of the reversed
|
||||
* view.
|
||||
*
|
||||
* The returned iterator points to the entity following the last entity of
|
||||
* the reversed view. Attempting to dereference the returned iterator
|
||||
* results in undefined behavior.
|
||||
*
|
||||
* @note
|
||||
* Iterators stay true to the order imposed to the underlying data
|
||||
* structures.
|
||||
*
|
||||
* @return An iterator to the entity following the last entity of the
|
||||
* reversed view.
|
||||
*/
|
||||
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
|
||||
return pool->sparse_set<Entity>::rend();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the first entity of the view, if any.
|
||||
* @return The first entity of the view if one exists, the null entity
|
||||
@@ -874,8 +952,8 @@ public:
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] entity_type back() const {
|
||||
const auto it = std::make_reverse_iterator(end());
|
||||
return it != std::make_reverse_iterator(begin()) ? *it : null;
|
||||
const auto it = rbegin();
|
||||
return it != rend() ? *it : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,11 +19,15 @@ TEST(SingleComponentView, Functionalities) {
|
||||
registry.emplace<int>(e1);
|
||||
registry.emplace<char>(e1);
|
||||
|
||||
ASSERT_NO_THROW(registry.view<char>().begin()++);
|
||||
ASSERT_NO_THROW(++registry.view<char>().begin());
|
||||
ASSERT_NO_THROW(view.begin()++);
|
||||
ASSERT_NO_THROW(++cview.begin());
|
||||
ASSERT_NO_THROW(view.rbegin() + 1u);
|
||||
ASSERT_NO_THROW(1u + cview.rbegin());
|
||||
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_NE(cview.begin(), cview.end());
|
||||
ASSERT_NE(view.rbegin(), view.rend());
|
||||
ASSERT_NE(cview.rbegin(), cview.rend());
|
||||
ASSERT_EQ(view.size(), typename decltype(view)::size_type{1});
|
||||
ASSERT_FALSE(view.empty());
|
||||
|
||||
@@ -48,6 +52,7 @@ TEST(SingleComponentView, Functionalities) {
|
||||
registry.remove<char>(e1);
|
||||
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_EQ(view.rbegin(), view.rend());
|
||||
ASSERT_TRUE(view.empty());
|
||||
}
|
||||
|
||||
@@ -99,6 +104,7 @@ TEST(SingleComponentView, Empty) {
|
||||
|
||||
ASSERT_EQ(view.size(), entt::registry::size_type{0});
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_EQ(view.rbegin(), view.rend());
|
||||
}
|
||||
|
||||
TEST(SingleComponentView, Proxy) {
|
||||
@@ -293,16 +299,20 @@ TEST(MultiComponentView, Functionalities) {
|
||||
|
||||
registry.emplace<char>(e1);
|
||||
|
||||
auto it = registry.view<int, char>().begin();
|
||||
ASSERT_EQ(*view.begin(), e1);
|
||||
ASSERT_EQ(*view.rbegin(), e1);
|
||||
ASSERT_EQ(++view.begin(), (view.end()));
|
||||
ASSERT_EQ(++view.rbegin(), (view.rend()));
|
||||
|
||||
ASSERT_EQ(*it, e1);
|
||||
ASSERT_EQ(++it, (registry.view<int, char>().end()));
|
||||
|
||||
ASSERT_NO_THROW((registry.view<int, char>().begin()++));
|
||||
ASSERT_NO_THROW((++registry.view<int, char>().begin()));
|
||||
ASSERT_NO_THROW((view.begin()++));
|
||||
ASSERT_NO_THROW((++cview.begin()));
|
||||
ASSERT_NO_THROW(view.rbegin()++);
|
||||
ASSERT_NO_THROW(++cview.rbegin());
|
||||
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_NE(cview.begin(), cview.end());
|
||||
ASSERT_NE(view.rbegin(), view.rend());
|
||||
ASSERT_NE(cview.rbegin(), cview.rend());
|
||||
ASSERT_EQ(view.size(), decltype(view.size()){1});
|
||||
ASSERT_EQ(view.size<int>(), decltype(view.size()){1});
|
||||
ASSERT_EQ(cview.size<const char>(), decltype(view.size()){2});
|
||||
@@ -354,6 +364,34 @@ TEST(MultiComponentView, Iterator) {
|
||||
ASSERT_EQ(*begin.operator->(), entity);
|
||||
}
|
||||
|
||||
TEST(MultiComponentView, ReverseIterator) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
const auto view = registry.view<int, char>();
|
||||
using iterator = typename decltype(view)::reverse_iterator;
|
||||
|
||||
iterator end{view.rbegin()};
|
||||
iterator begin{};
|
||||
begin = view.rend();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, view.rbegin());
|
||||
ASSERT_EQ(end, view.rend());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin++, view.rbegin());
|
||||
ASSERT_EQ(begin--, view.rend());
|
||||
|
||||
ASSERT_EQ(++begin, view.rend());
|
||||
ASSERT_EQ(--begin, view.rbegin());
|
||||
|
||||
ASSERT_EQ(*begin, entity);
|
||||
ASSERT_EQ(*begin.operator->(), entity);
|
||||
}
|
||||
|
||||
TEST(MultiComponentView, Contains) {
|
||||
entt::registry registry;
|
||||
|
||||
@@ -389,6 +427,7 @@ TEST(MultiComponentView, Empty) {
|
||||
|
||||
ASSERT_EQ(view.size(), entt::registry::size_type{1});
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_EQ(view.rbegin(), view.rend());
|
||||
}
|
||||
|
||||
TEST(MultiComponentView, Proxy) {
|
||||
@@ -462,7 +501,7 @@ TEST(MultiComponentView, EachWithSuggestedType) {
|
||||
|
||||
auto value = registry.view<int, char>().size();
|
||||
|
||||
for(auto curr: registry.view<int, char>().proxy()) {
|
||||
for(auto &&curr: registry.view<int, char>().proxy()) {
|
||||
ASSERT_EQ(std::get<1>(curr), --value);
|
||||
}
|
||||
|
||||
@@ -472,7 +511,7 @@ TEST(MultiComponentView, EachWithSuggestedType) {
|
||||
|
||||
value = {};
|
||||
|
||||
for(auto curr: registry.view<int, char>().proxy<int>()) {
|
||||
for(auto &&curr: registry.view<int, char>().proxy<int>()) {
|
||||
ASSERT_EQ(std::get<1>(curr), value++);
|
||||
}
|
||||
}
|
||||
@@ -498,7 +537,7 @@ TEST(MultiComponentView, EachWithHoles) {
|
||||
ASSERT_EQ(i, 0);
|
||||
});
|
||||
|
||||
for(auto curr: view.proxy()) {
|
||||
for(auto &&curr: view.proxy()) {
|
||||
ASSERT_EQ(std::get<0>(curr), e0);
|
||||
ASSERT_EQ(std::get<1>(curr), '0');
|
||||
ASSERT_EQ(std::get<2>(curr), 0);
|
||||
|
||||
Reference in New Issue
Block a user