Class basic_view< Entity, get_t< Component... >, exclude_t< Exclude... > >

Synopsis

#include <src/entt/entity/view.hpp>

template<typename Entity, typename... Component, typename... Exclude>
class basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>>

Description

Multi component view.

Multi component views iterate over those entities that have at least all the given components in their bags. During initialization, a multi component view looks at the number of entities available for each component and uses the smallest set in order to get a performance boost when iterate.

Important

Iterators aren't invalidated if:

  • New instances of the given components are created and assigned to entities.
  • The entity currently pointed is modified (as an example, if one of the given components is removed from the entity to which the iterator points).
  • The entity currently pointed is destroyed.

In all other cases, modifying the pools iterated by the view in any way invalidates all the iterators and using them results in undefined behavior.

Template Parameters

Entity - A valid entity type (see entt_traits for more details).

Component - Types of components iterated by the view.

Exclude - Types of components used to filter the view.

Methods

backReturns the last entity of the view, if any.
basic_view overloadDefault constructor to use to create empty, invalid views.
basic_view overloadConstructs a multi-type view from a set of storage classes.
beginReturns an iterator to the first entity of the view.
containsChecks if a view contains an entity.
each overloadIterates entities and components and applies the given function object to them.
each overloadReturns an iterable object to use to visit a view.
endReturns an iterator that is past the last entity of the view.
findFinds an entity.
frontReturns the first entity of the view, if any.
get overloadReturns the components assigned to the given entity.
handleReturns the leading storage of a view.
operator boolChecks if a view is properly initialized.
operator[]Returns the components assigned to the given entity.
operator|Combines two views in a more specific one (friend function).
size_hintEstimates the number of entities iterated by the view.
storage overloadReturns the storage for a given component type.
use overloadCreates a new view driven by a given component in its iterations.

Source

Lines 185-507 in src/entt/entity/view.hpp.

template<typename Entity, typename... Component, typename... Exclude>
class basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>> {
    template<typename, typename, typename, typename>
    friend class basic_view;

    template<typename Comp>
    using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Comp>>::storage_type, Comp>;

    template<std::size_t... Index>
    [[nodiscard]] auto pools_to_array(std::index_sequence<Index...>) const ENTT_NOEXCEPT {
        std::size_t pos{};
        std::array<const base_type *, sizeof...(Component) - 1u> other{};
        (static_cast<void>(std::get<Index>(pools) == view ? void() : void(other[pos++] = std::get<Index>(pools))), ...);
        return other;
    }

    template<std::size_t Comp, std::size_t Other, typename... Args>
    [[nodiscard]] auto dispatch_get(const std::tuple<Entity, Args...> &curr) const {
        if constexpr(Comp == Other) {
            return std::forward_as_tuple(std::get<Args>(curr)...);
        } else {
            return std::get<Other>(pools)->get_as_tuple(std::get<0>(curr));
        }
    }

    template<std::size_t Comp, typename Func, std::size_t... Index>
    void each(Func func, std::index_sequence<Index...>) const {
        for(const auto curr: std::get<Comp>(pools)->each()) {
            const auto entt = std::get<0>(curr);

            if(((sizeof...(Component) != 1u) || (entt != tombstone))
               && ((Comp == Index || std::get<Index>(pools)->contains(entt)) && ...)
               && std::apply([entt](const auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
                if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
                    std::apply(func, std::tuple_cat(std::make_tuple(entt), dispatch_get<Comp, Index>(curr)...));
                } else {
                    std::apply(func, std::tuple_cat(dispatch_get<Comp, Index>(curr)...));
                }
            }
        }
    }

    template<typename Func, std::size_t... Index>
    void pick_and_each(Func func, std::index_sequence<Index...> seq) const {
        ((std::get<Index>(pools) == view ? each<Index>(std::move(func), seq) : void()), ...);
    }

public:
    /*! @brief Underlying entity identifier. */
    using entity_type = Entity;
    /*! @brief Unsigned integer type. */
    using size_type = std::size_t;
    /*! @brief Common type among all storage types. */
    using base_type = std::common_type_t<typename storage_type<Component>::base_type...>;
    /*! @brief Bidirectional iterator type. */
    using iterator = internal::view_iterator<base_type, sizeof...(Component) - 1u, sizeof...(Exclude)>;
    /*! @brief Iterable view type. */
    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
        : pools{},
          filter{},
          view{} {}

    /**
     * @brief Constructs a multi-type view from a set of storage classes.
     * @param component The storage for the types to iterate.
     * @param epool The storage for the types used to filter the view.
     */
    basic_view(storage_type<Component> &...component, const storage_type<Exclude> &...epool) ENTT_NOEXCEPT
        : pools{&component...},
          filter{&epool...},
          view{(std::min)({&static_cast<const base_type &>(component)...}, [](auto *lhs, auto *rhs) { return lhs->size() < rhs->size(); })} {}

    /**
     * @brief Creates a new view driven by a given component in its iterations.
     * @tparam Comp Type of component used to drive the iteration.
     * @return A new view driven by the given component in its iterations.
     */
    template<typename Comp>
    [[nodiscard]] basic_view use() const ENTT_NOEXCEPT {
        basic_view other{*this};
        other.view = std::get<storage_type<Comp> *>(pools);
        return other;
    }

    /**
     * @brief Creates a new view driven by a given component in its iterations.
     * @tparam Comp Index of the component used to drive the iteration.
     * @return A new view driven by the given component in its iterations.
     */
    template<std::size_t Comp>
    [[nodiscard]] basic_view use() const ENTT_NOEXCEPT {
        basic_view other{*this};
        other.view = std::get<Comp>(pools);
        return other;
    }

    /**
     * @brief Returns the leading storage of a view.
     * @return The leading storage of the view.
     */
    const base_type &handle() const ENTT_NOEXCEPT {
        return *view;
    }

    /**
     * @brief Returns the storage for a given component type.
     * @tparam Comp Type of component of which to return the storage.
     * @return The storage for the given component type.
     */
    template<typename Comp>
    [[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
        return *std::get<storage_type<Comp> *>(pools);
    }

    /**
     * @brief Returns the storage for a given component type.
     * @tparam Comp Index of component of which to return the storage.
     * @return The storage for the given component type.
     */
    template<std::size_t Comp>
    [[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
        return *std::get<Comp>(pools);
    }

    /**
     * @brief Estimates the number of entities iterated by the view.
     * @return Estimated number of entities iterated by the view.
     */
    [[nodiscard]] size_type size_hint() const ENTT_NOEXCEPT {
        return view->size();
    }

    /**
     * @brief Returns an iterator to the first entity of the view.
     *
     * The returned iterator points to the first entity of the view. If the view
     * is empty, the returned iterator will be equal to `end()`.
     *
     * @return An iterator to the first entity of the view.
     */
    [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
        return iterator{view->begin(), view->end(), pools_to_array(std::index_sequence_for<Component...>{}), filter};
    }

    /**
     * @brief Returns an iterator that is past the last entity of the view.
     *
     * The returned iterator points to the entity following the last entity of
     * the view. Attempting to dereference the returned iterator results in
     * undefined behavior.
     *
     * @return An iterator to the entity following the last entity of the view.
     */
    [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
        return iterator{view->end(), view->end(), pools_to_array(std::index_sequence_for<Component...>{}), filter};
    }

    /**
     * @brief Returns the first entity of the view, if any.
     * @return The first entity of the view if one exists, the null entity
     * otherwise.
     */
    [[nodiscard]] entity_type front() const ENTT_NOEXCEPT {
        const auto it = begin();
        return it != end() ? *it : null;
    }

    /**
     * @brief Returns the last entity of the view, if any.
     * @return The last entity of the view if one exists, the null entity
     * otherwise.
     */
    [[nodiscard]] entity_type back() const ENTT_NOEXCEPT {
        auto it = view->rbegin();
        for(const auto last = view->rend(); it != last && !contains(*it); ++it) {}
        return it == view->rend() ? null : *it;
    }

    /**
     * @brief Finds an entity.
     * @param entt A valid identifier.
     * @return An iterator to the given entity if it's found, past the end
     * iterator otherwise.
     */
    [[nodiscard]] iterator find(const entity_type entt) const ENTT_NOEXCEPT {
        return contains(entt) ? iterator{view->find(entt), view->end(), pools_to_array(std::index_sequence_for<Component...>{}), filter} : end();
    }

    /**
     * @brief Returns the components assigned to the given entity.
     * @param entt A valid identifier.
     * @return The components assigned to the given entity.
     */
    [[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
        return get<Component...>(entt);
    }

    /**
     * @brief Checks if a view is properly initialized.
     * @return True if the view is properly initialized, false otherwise.
     */
    [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
        return view != nullptr;
    }

    /**
     * @brief Checks if a view contains an entity.
     * @param entt A valid identifier.
     * @return True if the view contains the given entity, false otherwise.
     */
    [[nodiscard]] bool contains(const entity_type entt) const ENTT_NOEXCEPT {
        return std::apply([entt](const auto *...curr) { return (curr->contains(entt) && ...); }, pools)
               && std::apply([entt](const auto *...curr) { return (!curr->contains(entt) && ...); }, filter);
    }

    /**
     * @brief Returns the components assigned to the given entity.
     *
     * @warning
     * Attempting to use an entity that doesn't belong to the view results in
     * undefined behavior.
     *
     * @tparam Comp Types of components to get.
     * @param entt A valid identifier.
     * @return The components assigned to the entity.
     */
    template<typename... Comp>
    [[nodiscard]] decltype(auto) get(const entity_type entt) const {
        ENTT_ASSERT(contains(entt), "View does not contain entity");

        if constexpr(sizeof...(Comp) == 0) {
            return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, pools);
        } else if constexpr(sizeof...(Comp) == 1) {
            return (std::get<storage_type<Comp> *>(pools)->get(entt), ...);
        } else {
            return std::tuple_cat(std::get<storage_type<Comp> *>(pools)->get_as_tuple(entt)...);
        }
    }

    /**
     * @brief Returns the components assigned to the given entity.
     *
     * @warning
     * Attempting to use an entity that doesn't belong to the view results in
     * undefined behavior.
     *
     * @tparam First Index of a component to get.
     * @tparam Other Indexes of other components to get.
     * @param entt A valid identifier.
     * @return The components assigned to the entity.
     */
    template<std::size_t First, std::size_t... Other>
    [[nodiscard]] decltype(auto) get(const entity_type entt) const {
        ENTT_ASSERT(contains(entt), "View does not contain entity");

        if constexpr(sizeof...(Other) == 0) {
            return std::get<First>(pools)->get(entt);
        } else {
            return std::tuple_cat(std::get<First>(pools)->get_as_tuple(entt), std::get<Other>(pools)->get_as_tuple(entt)...);
        }
    }

    /**
     * @brief Iterates entities and components and applies the given function
     * object to them.
     *
     * The function object is invoked for each entity. It is provided with the
     * entity itself and a set of references to non-empty components. The
     * _constness_ of the components is as requested.<br/>
     * The signature of the function must be equivalent to one of the following
     * forms:
     *
     * @code{.cpp}
     * void(const entity_type, Type &...);
     * void(Type &...);
     * @endcode
     *
     * @tparam Func Type of the function object to invoke.
     * @param func A valid function object.
     */
    template<typename Func>
    void each(Func func) const {
        pick_and_each(std::move(func), std::index_sequence_for<Component...>{});
    }

    /**
     * @brief Returns an iterable object to use to _visit_ a view.
     *
     * 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 each() const ENTT_NOEXCEPT {
        return {internal::extended_view_iterator{begin(), pools}, internal::extended_view_iterator{end(), pools}};
    }

    /**
     * @brief Combines two views in a _more specific_ one (friend function).
     * @tparam Get Component list of the view to combine with.
     * @tparam Excl Filter list of the view to combine with.
     * @param other The view to combine with.
     * @return A more specific view.
     */
    template<typename... Get, typename... Excl>
    [[nodiscard]] auto operator|(const basic_view<Entity, get_t<Get...>, exclude_t<Excl...>> &other) const ENTT_NOEXCEPT {
        using view_type = basic_view<Entity, get_t<Component..., Get...>, exclude_t<Exclude..., Excl...>>;
        return std::make_from_tuple<view_type>(std::tuple_cat(
            std::apply([](auto *...curr) { return std::forward_as_tuple(*curr...); }, pools),
            std::apply([](auto *...curr) { return std::forward_as_tuple(*curr...); }, other.pools),
            std::apply([](const auto *...curr) { return std::forward_as_tuple(static_cast<const storage_type<Exclude> &>(*curr)...); }, filter),
            std::apply([](const auto *...curr) { return std::forward_as_tuple(static_cast<const storage_type<Excl> &>(*curr)...); }, other.filter)));
    }

private:
    std::tuple<storage_type<Component> *...> pools;
    std::array<const base_type *, sizeof...(Exclude)> filter;
    const base_type *view;
};





Add Discussion

Log in to comment