storage/view/group:
* added extended_storage_iterator and storage<T...>::each function to return an extended iterable object * use extended_storage_iterator and iterable_adaptor everywhere to avoid code duplication
This commit is contained in:
@@ -71,68 +71,46 @@ class basic_group<Entity, owned_t<>, get_t<Get...>, exclude_t<Exclude...>> final
|
||||
|
||||
using basic_common_type = std::common_type_t<typename storage_type<Get>::base_type...>;
|
||||
|
||||
class iterable final {
|
||||
struct iterable_iterator final {
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
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<Entity>{}, std::declval<basic_group>().get({})));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
template<typename... Args>
|
||||
iterable_iterator(typename basic_common_type::iterator from, const std::tuple<storage_type<Get> *...> &args) ENTT_NOEXCEPT
|
||||
: it{from},
|
||||
pools{args} {}
|
||||
extended_group_iterator(typename basic_common_type::iterator from, const std::tuple<storage_type<Get> *...> &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<storage_type<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<storage_type<Get> *...> pools;
|
||||
};
|
||||
|
||||
public:
|
||||
using iterator = iterable_iterator;
|
||||
|
||||
iterable(basic_common_type *const ref, const std::tuple<storage_type<Get> *...> &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<storage_type<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<storage_type<Get> *...> pools;
|
||||
typename basic_common_type::iterator it;
|
||||
std::tuple<storage_type<Get> *...> pools;
|
||||
};
|
||||
|
||||
basic_group(basic_common_type &ref, storage_type<Get> &...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<extended_group_iterator>;
|
||||
|
||||
/*! @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<Entity, owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...
|
||||
|
||||
using basic_common_type = std::common_type_t<typename storage_type<Owned>::base_type..., typename storage_type<Get>::base_type...>;
|
||||
|
||||
class iterable final {
|
||||
template<typename>
|
||||
struct iterable_iterator;
|
||||
template<typename>
|
||||
struct extended_group_iterator;
|
||||
|
||||
template<typename... OIt>
|
||||
struct iterable_iterator<type_list<OIt...>> final {
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
template<typename... OIt>
|
||||
struct extended_group_iterator<type_list<OIt...>> final {
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
template<typename... Other>
|
||||
iterable_iterator(typename basic_common_type::iterator from, const std::tuple<Other...> &other, const std::tuple<storage_type<Get> *...> &cpools) ENTT_NOEXCEPT
|
||||
: it{from},
|
||||
owned{std::get<OIt>(other)...},
|
||||
get{cpools} {}
|
||||
template<typename... Other>
|
||||
extended_group_iterator(typename basic_common_type::iterator from, const std::tuple<Other...> &other, const std::tuple<storage_type<Get> *...> &cpools) ENTT_NOEXCEPT
|
||||
: it{from},
|
||||
owned{std::get<OIt>(other)...},
|
||||
get{cpools} {}
|
||||
|
||||
iterable_iterator &operator++() ENTT_NOEXCEPT {
|
||||
return ++it, (++std::get<OIt>(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<OIt>(owned)...),
|
||||
std::get<storage_type<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<OIt...> owned;
|
||||
std::tuple<storage_type<Get> *...> get;
|
||||
};
|
||||
|
||||
public:
|
||||
using iterator = iterable_iterator<type_list_cat_t<std::conditional_t<ignore_as_empty_v<std::remove_const_t<Owned>>, type_list<>, type_list<decltype(std::declval<storage_type<Owned>>().end())>>...>>;
|
||||
|
||||
iterable(std::tuple<storage_type<Owned> *..., storage_type<Get> *...> 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<storage_type<Owned> *>(pools)->end() - *length)...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
|
||||
extended_group_iterator &operator++() ENTT_NOEXCEPT {
|
||||
return ++it, (++std::get<OIt>(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<storage_type<Owned> *>(pools)->end())...), std::make_tuple(std::get<storage_type<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<OIt>(owned)...),
|
||||
std::get<storage_type<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<Owned> *..., storage_type<Get> *...> pools;
|
||||
const std::size_t *const length;
|
||||
typename basic_common_type::iterator it;
|
||||
std::tuple<OIt...> owned;
|
||||
std::tuple<storage_type<Get> *...> get;
|
||||
};
|
||||
|
||||
basic_group(const std::size_t &extent, storage_type<Owned> &...opool, storage_type<Get> &...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<extended_group_iterator<type_list_cat_t<std::conditional_t<ignore_as_empty_v<std::remove_const_t<Owned>>, type_list<>, type_list<decltype(std::declval<storage_type<Owned>>().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<storage_type<Owned> *>(pools)->end() - *length)...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
|
||||
auto to = extended_iterator_type{last, std::make_tuple((std::get<storage_type<Owned> *>(pools)->end())...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
|
||||
return {std::move(from), std::move(to)};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<typename CLhs, typename CRhs>
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename It, typename... Other>
|
||||
class extended_storage_iterator final {
|
||||
template<typename Iter, typename... Args>
|
||||
friend class extended_storage_iterator;
|
||||
|
||||
public:
|
||||
using iterator_type = It;
|
||||
using difference_type = typename std::iterator_traits<It>::difference_type;
|
||||
using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::forward_as_tuple(*std::declval<Other>()...)));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
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<typename... Args, typename = std::enable_if_t<(!std::is_same_v<Other, Args> && ...) && (std::is_constructible_v<Other, Args> && ...)>>
|
||||
extended_storage_iterator(const extended_storage_iterator<It, Args...> &other) ENTT_NOEXCEPT
|
||||
: it{other.it} {}
|
||||
|
||||
extended_storage_iterator &operator++() ENTT_NOEXCEPT {
|
||||
return ++std::get<It>(it), (++std::get<Other>(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>(it), *std::get<Other>(it)...};
|
||||
}
|
||||
|
||||
[[nodiscard]] iterator_type base() const ENTT_NOEXCEPT {
|
||||
return std::get<It>(it);
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<It, Other...> it;
|
||||
};
|
||||
|
||||
template<typename... CLhs, typename... CRhs>
|
||||
[[nodiscard]] bool operator==(const extended_storage_iterator<CLhs...> &lhs, const extended_storage_iterator<CRhs...> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.base() == rhs.base();
|
||||
}
|
||||
|
||||
template<typename... CLhs, typename... CRhs>
|
||||
[[nodiscard]] bool operator!=(const extended_storage_iterator<CLhs...> &lhs, const extended_storage_iterator<CRhs...> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
@@ -165,15 +223,6 @@ template<typename CLhs, typename CRhs>
|
||||
/**
|
||||
* @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<typename CLhs, typename CRhs>
|
||||
* 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<Entity>
|
||||
*
|
||||
* @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<iterator>;
|
||||
/*! @brief Constant reverse iterator type. */
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
/*! @brief Extended iterable storage proxy. */
|
||||
using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator, iterator>>;
|
||||
/*! @brief Constant extended iterable storage proxy. */
|
||||
using const_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_iterator, const_iterator>>;
|
||||
|
||||
/*! @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<container_type, alloc> 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<internal::extended_storage_iterator<typename base_type::iterator>>;
|
||||
/*! @brief Constant extended iterable storage proxy. */
|
||||
using const_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_iterator>>;
|
||||
|
||||
/*! @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()}};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,133 +26,6 @@ namespace entt {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Storage>
|
||||
class iterable_storage final {
|
||||
using base_type = typename Storage::base_type;
|
||||
|
||||
template<typename... It>
|
||||
struct iterable_storage_iterator final {
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = decltype(std::tuple_cat(std::tuple<typename Storage::entity_type>{}, std::declval<decltype(std::declval<Storage>().get_as_tuple({}))>()));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
template<typename... Discard>
|
||||
iterable_storage_iterator(It... from, Discard...) ENTT_NOEXCEPT
|
||||
: it{from...} {}
|
||||
|
||||
iterable_storage_iterator &operator++() ENTT_NOEXCEPT {
|
||||
return (++std::get<It>(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>(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...> it;
|
||||
};
|
||||
|
||||
public:
|
||||
using iterator = std::conditional_t<
|
||||
ignore_as_empty_v<typename Storage::value_type>,
|
||||
iterable_storage_iterator<typename base_type::iterator>,
|
||||
iterable_storage_iterator<typename base_type::iterator, decltype(std::declval<Storage>().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<typename View>
|
||||
class iterable_view final {
|
||||
struct iterable_view_iterator final {
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = decltype(std::tuple_cat(std::tuple<typename View::entity_type>{}, std::declval<View>().get({})));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
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<typename Type, std::size_t Component, std::size_t Exclude>
|
||||
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<const Type *, Exclude> filter;
|
||||
};
|
||||
|
||||
template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
|
||||
[[nodiscard]] bool operator==(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.base() == rhs.base();
|
||||
}
|
||||
|
||||
template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
|
||||
[[nodiscard]] bool operator!=(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename It, typename... Storage>
|
||||
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<It>()), std::declval<Storage>().get_as_tuple({})...));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
extended_view_iterator(It from, std::tuple<Storage *...> 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<Storage *...> pools;
|
||||
};
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] bool operator==(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.base() == rhs.base();
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] bool operator!=(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
@@ -285,7 +213,7 @@ class basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>> {
|
||||
|
||||
template<std::size_t Comp, typename Func, std::size_t... Index>
|
||||
void each(Func func, std::index_sequence<Index...>) const {
|
||||
for(const auto curr: internal::iterable_storage{*std::get<Comp>(pools)}) {
|
||||
for(const auto curr: std::get<Comp>(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<base_type, sizeof...(Component) - 1u, sizeof...(Exclude)>;
|
||||
/*! @brief Iterable view type. */
|
||||
using iterable_view = internal::iterable_view<basic_view>;
|
||||
using iterable = iterable_adaptor<internal::extended_view_iterator<iterator, storage_type<Component>...>>;
|
||||
|
||||
/*! @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<storage_type>;
|
||||
using iterable = decltype(std::declval<storage_type>().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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -183,15 +183,15 @@ TEST(NonOwningGroup, Each) {
|
||||
auto group = registry.group(entt::get<int, char>);
|
||||
auto cgroup = std::as_const(registry).group_if_exists(entt::get<const int, const char>);
|
||||
|
||||
auto iterable = group.each();
|
||||
auto citerable = cgroup.each();
|
||||
|
||||
registry.emplace<int>(entity[0u], 0);
|
||||
registry.emplace<char>(entity[0u], 0);
|
||||
|
||||
registry.emplace<int>(entity[1u], 1);
|
||||
registry.emplace<char>(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<int>(entt::get<char>);
|
||||
auto cgroup = std::as_const(registry).group_if_exists<const int>(entt::get<const char>);
|
||||
|
||||
auto iterable = group.each();
|
||||
auto citerable = cgroup.each();
|
||||
|
||||
registry.emplace<int>(entity[0u], 0);
|
||||
registry.emplace<char>(entity[0u], 0);
|
||||
|
||||
registry.emplace<int>(entity[1u], 1);
|
||||
registry.emplace<char>(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()));
|
||||
|
||||
|
||||
@@ -1037,6 +1037,140 @@ TEST(Storage, IteratorConversion) {
|
||||
ASSERT_NE(++cit, it);
|
||||
}
|
||||
|
||||
TEST(Storage, Iterable) {
|
||||
using iterator = typename entt::storage<boxed_int>::iterable::iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, std::tuple<entt::entity, boxed_int &>>);
|
||||
static_assert(std::is_same_v<iterator::value_type, std::tuple<entt::entity, boxed_int &>>);
|
||||
static_assert(std::is_same_v<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity, boxed_int &>>>);
|
||||
static_assert(std::is_same_v<typename iterator::reference, typename iterator::value_type>);
|
||||
|
||||
entt::storage<boxed_int> 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<decltype(entity), entt::entity>);
|
||||
static_assert(std::is_same_v<decltype(element), boxed_int &>);
|
||||
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<boxed_int>::const_iterable::const_iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, std::tuple<entt::entity, const boxed_int &>>);
|
||||
static_assert(std::is_same_v<iterator::value_type, std::tuple<entt::entity, const boxed_int &>>);
|
||||
static_assert(std::is_same_v<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity, const boxed_int &>>>);
|
||||
static_assert(std::is_same_v<typename iterator::reference, typename iterator::value_type>);
|
||||
|
||||
entt::storage<boxed_int> 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<decltype(entity), entt::entity>);
|
||||
static_assert(std::is_same_v<decltype(element), const boxed_int &>);
|
||||
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<boxed_int> pool;
|
||||
pool.emplace(entt::entity{3}, 42);
|
||||
|
||||
typename entt::storage<boxed_int>::iterable::iterator it = pool.each().begin();
|
||||
typename entt::storage<boxed_int>::const_iterable::const_iterator cit = it;
|
||||
|
||||
static_assert(std::is_same_v<decltype(*it), std::tuple<entt::entity, boxed_int &>>);
|
||||
static_assert(std::is_same_v<decltype(*cit), std::tuple<entt::entity, const boxed_int &>>);
|
||||
|
||||
ASSERT_EQ(it, cit);
|
||||
ASSERT_NE(++cit, it);
|
||||
}
|
||||
|
||||
TEST(Storage, EmptyTypeIterable) {
|
||||
using iterator = typename entt::storage<empty_stable_type>::iterable::iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, std::tuple<entt::entity>>);
|
||||
static_assert(std::is_same_v<iterator::value_type, std::tuple<entt::entity>>);
|
||||
static_assert(std::is_same_v<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>);
|
||||
static_assert(std::is_same_v<typename iterator::reference, typename iterator::value_type>);
|
||||
|
||||
entt::storage<empty_stable_type> 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<decltype(entity), entt::entity>);
|
||||
ASSERT_TRUE(entity == entt::entity{1} || entity == entt::entity{3});
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Storage, IterableAlgorithmCompatibility) {
|
||||
entt::storage<boxed_int> 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<int> pool;
|
||||
|
||||
|
||||
@@ -176,12 +176,12 @@ TEST(SingleComponentView, Each) {
|
||||
auto view = registry.view<int>();
|
||||
auto cview = std::as_const(registry).view<const int>();
|
||||
|
||||
auto iterable = view.each();
|
||||
auto citerable = cview.each();
|
||||
|
||||
registry.emplace<int>(entity[0u], 0);
|
||||
registry.emplace<int>(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<int, char>();
|
||||
auto cview = std::as_const(registry).view<const int, const char>();
|
||||
|
||||
auto iterable = view.each();
|
||||
auto citerable = cview.each();
|
||||
|
||||
registry.emplace<int>(entity[0u], 0);
|
||||
registry.emplace<char>(entity[0u], 0);
|
||||
|
||||
registry.emplace<int>(entity[1u], 1);
|
||||
registry.emplace<char>(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()));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user